Update On Thu Jul 25 20:31:36 CEST 2024

This commit is contained in:
github-action[bot]
2024-07-25 20:31:37 +02:00
parent d0946d6fd2
commit 142e9a4419
100 changed files with 3481 additions and 1772 deletions
+1
View File
@@ -713,3 +713,4 @@ Update On Sun Jul 21 20:28:53 CEST 2024
Update On Mon Jul 22 20:31:05 CEST 2024
Update On Tue Jul 23 20:31:31 CEST 2024
Update On Wed Jul 24 20:33:56 CEST 2024
Update On Thu Jul 25 20:31:26 CEST 2024
+43
View File
@@ -0,0 +1,43 @@
# Simple workflow for deploying static content to GitHub Pages
name: Deploy static content to Pages
on:
# Runs on pushes targeting the default branch
push:
branches: ["master"]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
concurrency:
group: "pages"
cancel-in-progress: false
jobs:
# Single deploy job since we're just deploying
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Pages
uses: actions/configure-pages@v5
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
# Upload entire repository
path: './docs'
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
+202 -68
View File
@@ -21,7 +21,7 @@ nami install brook
brook server -l :9999 -p hello
```
## GUI Client
## Client
| iOS | Android | Mac |Windows |Linux |OpenWrt |
| --- | --- | --- | --- | --- | --- |
@@ -29,22 +29,121 @@ brook server -l :9999 -p hello
| / | / | [App Mode](https://www.txthinking.com/talks/articles/macos-app-mode-en.article) | [How](https://www.txthinking.com/talks/articles/msix-brook-en.article) | [How](https://www.txthinking.com/talks/articles/linux-app-brook-en.article) | [How](https://www.txthinking.com/talks/articles/brook-openwrt-en.article) |
> You may want to use `brook link` to customize some parameters
# GUI Documentation
## Software for which this article applies
- [Brook](https://github.com/txthinking/brook)
- [Shiliew](https://www.txthinking.com/shiliew.html)
- [tun2brook](https://github.com/txthinking/tun2brook)
## Programmable
# Client
Brook GUI will pass different _global variables_ to the script at different times, and the script only needs to assign the processing result to the global variable `out`
- address: We call it address which includes both host and port. For example, an ip address contains an ip and a port; a domain address contains a domain and a port.
- Fake DNS: Fake DNS can allow you to obtain domain address on `in_address` step. [How Fake DNS works](https://www.txthinking.com/talks/articles/brook-fakedns-en.article)
## CLI
### Variables
Before discussing the GUI client, let's first talk about the command line client `brook`. As we know, after you have deployed the server, you can use the command line client `brook` to create a local socks5 proxy or http proxy on your machine, and then configure it in your system proxy settings or in your browser to use this proxy. However:
1. Not all apps will use this proxy, whether they use it is up to the app itself.
2. Generally, all UDP protocols will not go through this proxy, such as http3.
For the specifics of socks5 and http proxy, you can read [this article](https://www.txthinking.com/talks/articles/socks5-and-http-proxy.article).
## GUI
The GUI client does not use socks5 and http proxy mode, so there is no issue with some software not using the system proxy. Instead, it uses a virtual network card to take over the entire system's network, including UDP-based http3. Moreover, Brook allows us to control network requests programmatically, so it is necessary to have basic knowledge of network requests.
## Without Brook: Basic Knowledge of Network Requests
> Note: When we talk about addresses, we mean addresses that include the port number, such as a domain address: `google.com:443`, or an IP address: `8.8.8.8:53`
1. When an app requests a domain address, such as `google.com:443`
2. It will first perform a DNS resolution, which means that the app will send a network request to the system-configured DNS, such as `8.8.8.8:53`, to inquire about the IP of `google.com`
1. The system DNS will return the IP of `google.com`, such as `1.2.3.4`, to the app
3. The app will combine the IP and port into an IP address, such as: `1.2.3.4:443`
4. The app makes a network request to this IP address `1.2.3.4:443`
5. The app receives the response data
In the above process, the app actually makes two network requests: one to the IP address `8.8.8.8:53` and another to the IP address `1.2.3.4:443`. In other words, the domain name is essentially an alias for the IP, and must obtain the domain's IP to establish a connection.
## With Brook: Fake DNS On
Brook has a Fake DNS feature, which can parse the domain name out of the query requests that an app sends to the system DNS and decide how to respond to the app.
1. When an app requests a domain name address, such as `google.com:443`
2. A DNS resolution will be performed first. That is, the app will send a network request to the system-configured DNS, such as `8.8.8.8:53`, to inquire about the IP of `google.com`
3. The Brook client detects that an app is sending a network request to `8.8.8.8:53`. <mark>This will trigger the `in_dnsquery` variable, carrying information such as `domain`</mark>
1. The Brook client returns a fake IP to the app, such as `240.0.0.1`
4. The app combines the IP and port into an IP address, such as: `240.0.0.1:443`
5. The app makes a network request to the IP address `240.0.0.1:443`
6. The Brook client detects that an app is sending a network request to `240.0.0.1:443`, discovers that this is a fake IP, and will convert the fake IP address back to the domain address `google.com:443`. <mark>This will trigger the `in_address` variable, carrying information such as `domainaddress`</mark>
1. The Brook client sends `google.com:443` to the Brook Server
2. The Brook Server first requests its own DNS to resolve the domain name to find out the IP of `google.com`, such as receiving `1.2.3.4`
3. The Brook Server combines the IP and port into an IP address, such as: `1.2.3.4:443`
4. The Brook Server sends a network request to `1.2.3.4:443` and returns the data to the Brook client
5. The Brook client then returns the data to the app
7. The app receives the response data
However, if the following situations occur, the domain name will not/cannot be parsed, meaning that the Brook client will not/cannot know what the domain name is and will treat it as a normal request sent to an IP address:
- Fake DNS not enabled: in this case, the Brook client will not attempt to parse the domain name from the request sent to the system DNS and will treat it as a normal request sent to an IP address.
- Even with Fake DNS enabled, but the app uses the system's secure DNS or the app's own secure DNS: in this case, the Brook client cannot parse the domain name from the request sent to the secure DNS and will treat it as a normal request sent to an IP address.
To avoid the ineffectiveness of Fake DNS, please refer to [this article](https://www.txthinking.com/talks/articles/brook-fakedns.article).
## With Brook: Fake DNS Off
1. When an app requests a domain address, such as `google.com:443`
2. A DNS resolution will be performed first. That is, the app will send a network request to the system-configured DNS, such as `8.8.8.8:53`, to inquire about the IP of `google.com`
3. The Brook client detects that an app is sending a network request to `8.8.8.8:53`. <mark>This will trigger the `in_address` variable, carrying information such as `ipaddress`</mark>
1. The Brook client sends `8.8.8.8:53` to the Brook Server
2. The Brook Server sends a network request to `8.8.8.8:53` and returns the result, such as `1.2.3.4`, to the Brook client
3. The Brook client then returns the result to the app
4. The app combines the IP and port into an IP address, such as: `1.2.3.4:443`
5. The app makes a network request to the IP address `1.2.3.4:443`
6. The Brook client detects that an app is sending a network request to `1.2.3.4:443`. <mark>This will trigger the `in_address` variable, carrying information such as `ipaddress`</mark>
1. The Brook client sends `1.2.3.4:443` to the Brook Server
2. The Brook Server sends a network request to `1.2.3.4:443` and returns the data to the Brook client
3. The Brook client then returns the data to the app
7. The app receives the response data
## With Brook: Fake DNS On, But the App Uses the System's Secure DNS or Its Own Secure DNS
1. When an app requests a domain name address, such as `google.com:443`
2. A DNS resolution will be performed first. That is, the app will send a network request to the secure DNS, such as `8.8.8.8:443`, to inquire about the IP of `google.com`
3. The Brook client detects that an app is sending a network request to `8.8.8.8:443`. <mark>This will trigger the `in_address` variable, carrying information such as `ipaddress`</mark>
1. The Brook client sends `8.8.8.8:443` to the Brook Server
2. The Brook Server sends a network request to `8.8.8.8:443`, and returns the result, such as `1.2.3.4`, to the Brook client
3. The Brook client then returns the result to the app
4. The app combines the IP and port into an IP address, such as: `1.2.3.4:443`
5. The app makes a network request to the IP address `1.2.3.4:443`
6. The Brook client detects that an app is sending a network request to `1.2.3.4:443`. <mark>This will trigger the `in_address` variable, carrying information such as `ipaddress`</mark>
1. The Brook client sends `1.2.3.4:443` to the Brook Server
2. The Brook Server sends a network request to `1.2.3.4:443` and returns the data to the Brook client
3. The Brook client then returns the data to the app
7. The app receives the response data
## Handle Variable Trigger
- When the `in_brooklinks` variable is triggered:
- This is currently the only variable that gets triggered before the Brook client starts.
- We know that Brook starts with your choice of a Brook Server, and this variable lets you specify multiple Brook Servers.
- Then during runtime, you can use one of these Brook Servers as needed.
- When the `in_dnsquery` variable is triggered, you can process as needed, such as:
- Blocking, such as to prevent ad domain names.
- Directly specifying the response IP.
- Letting the system DNS resolve this domain.
- Letting Bypass DNS resolve this domain.
- And so on.
- When the `in_address` variable is triggered, you can process as needed, such as:
- Block this connection.
- Rewrite the destination.
- If it's a domain address, you can specify that Bypass DNS is responsible for resolving the IP of this domain.
- Allow it to connect directly without going through a proxy.
- If it's HTTP/HTTPS, you can start MITM (Man-In-The-Middle), which will subsequently trigger `in_httprequest` and `in_httpresponse`.
- And so on.
- When the `in_httprequest` variable is triggered, you can process as needed, such as:
- Modifying the HTTP request.
- Returning a custom HTTP response directly.
- When the `in_httpresponse` variable is triggered, you can process as needed, such as:
- Modifying the HTTP response.
For detailed information on the properties and responses of variables, please refer to the following content.
## Variables
| variable | type | condition | timing | description | out type |
| ------------------------------ | ---- | ----------- | --------------------------------- | ------------------------------------------------- | -------- |
@@ -54,7 +153,7 @@ Brook GUI will pass different _global variables_ to the script at different time
| in_httprequest | map | / | When an HTTP(S) request comes in | the script can decide how to handle this request | map |
| in_httprequest,in_httpresponse | map | / | when an HTTP(S) response comes in | the script can decide how to handle this response | map |
### in_brooklinks
## in_brooklinks
| Key | Type | Description | Example |
| ------ | ------ | -------- | ---------- |
@@ -68,7 +167,7 @@ Brook GUI will pass different _global variables_ to the script at different time
| custom name | string | brook link | brook://... |
| ... | ... | ... | ... |
### in_dnsquery
## in_dnsquery
| Key | Type | Description | Example |
| ------ | ------ | ----------- | ---------- |
@@ -87,7 +186,7 @@ Brook GUI will pass different _global variables_ to the script at different time
| bypass | bool | Resolve by Bypass DNS, default `false` | false |
| brooklinkkey | string | When need to connect the Serverinstead, connect to the Server specified by the key in_brooklinks | custom name |
### in_address
## in_address
| Key | Type | Description | Example |
| ------------- | ------ | ------------------------------------------------------------------------------------------------------------------- | -------------- |
@@ -115,7 +214,7 @@ Brook GUI will pass different _global variables_ to the script at different time
| mitmserverwritetimeout | int | Timeout for MITM write to client, second, default 0 | 0 |
| brooklinkkey | string | When need to connect the Serverinstead, connect to the Server specified by the key in_brooklinks | custom name |
### in_httprequest
## in_httprequest
| Key | Type | Description | Example |
| ------ | ------ | ----------------------------- | --------------------------- |
@@ -126,7 +225,7 @@ Brook GUI will pass different _global variables_ to the script at different time
`out`, must be set to a request or response
### in_httpresponse
## in_httpresponse
| Key | Type | Description | Example |
| ---------- | ------ | ----------------------------- | ------- |
@@ -136,13 +235,9 @@ Brook GUI will pass different _global variables_ to the script at different time
`out`, must be set to a response
## Module
## Modules
There are already some modules: https://github.com/txthinking/brook/blob/master/programmable/modules/
### Brook GUI
In Brook GUI, scripts are abstracted into modules, and it will automatically combine [_header.tengo](https://github.com/txthinking/brook/blob/master/programmable/modules/_header.tengo) and [_footer.tengo](https://github.com/txthinking/brook/blob/master/programmable/modules/_footer.tengo), so you only need to write the module itself.
In Brook GUI, scripts are abstracted into **Modules**. There are already [some modules](https://github.com/txthinking/brook/blob/master/programmable/modules/), and thre is no magic, it just automatically combine [_header.tengo](https://github.com/txthinking/brook/blob/master/programmable/modules/_header.tengo) and [_footer.tengo](https://github.com/txthinking/brook/blob/master/programmable/modules/_footer.tengo), so you only need to write the module itself.
```
modules = append(modules, {
@@ -169,9 +264,11 @@ modules = append(modules, {
})
```
### tun2brook
## tun2brook
If you are using tun2brook, you can combine multiple modules into a complete script in the following way. For example:
https://github.com/txthinking/tun2brook
If you are using tun2brook, you can manually combine multiple modules into a complete script in the following way. For example:
```
cat _header.tengo > my.tengo
@@ -233,7 +330,7 @@ Library
If you are writing complex scripts, the GUI may not be convenient for debugging. It is recommended to use [tun2brook](https://github.com/txthinking/tun2brook) on desktop to debug with `fmt.println`
## Install CA
## CA
https://txthinking.github.io/ca/ca.pem
@@ -246,39 +343,58 @@ https://txthinking.github.io/ca/ca.pem
> Some software may not read the system CAyou can use `curl --cacert ~/.nami/bin/ca.pem` to debug
# Resources
## OpenWrt
| CLI | Description |
| --- | --- |
| [nami](https://github.com/txthinking/nami) | A clean and tidy decentralized package manager |
| [joker](https://github.com/txthinking/joker) | Joker can turn process into daemon. Zero-Configuration |
| [nico](https://github.com/txthinking/nico) | Nico can work with brook wsserver together |
| [zhen](https://github.com/txthinking/zhen) | zhen - process and cron manager |
| [tun2brook](https://github.com/txthinking/tun2brook) | Proxy all traffic just one line command |
| [mad](https://github.com/txthinking/mad) | Generate root CA and derivative certificate for any domains and any IPs |
| [hancock](https://github.com/txthinking/hancock) | Manage multiple remote servers and execute commands remotely |
| [sshexec](https://github.com/txthinking/sshexec) | A command-line tool to execute remote command through ssh |
| [jb](https://github.com/txthinking/jb) | write script in an easier way than bash |
| [bash](https://github.com/txthinking/bash) | Many one-click scripts |
| [pacman](https://archlinux.org/packages/extra/x86_64/brook/) | `pacman -S brook` |
| [brew](https://formulae.brew.sh/formula/brook) | `brew install brook` |
| [docker](https://hub.docker.com/r/txthinking/brook) | `docker run txthinking/brook` |
https://www.txthinking.com/talks/articles/brook-openwrt-en.article
| Resources | Description |
| --- | --- |
| [Protocol](https://github.com/txthinking/brook/tree/master/protocol) | Brook Protocol |
| [Blog](https://www.txthinking.com/talks/) | Some articles you should read |
| [YouTube](https://www.youtube.com/txthinking) | Some videos you should watch |
| [Telegram](https://t.me/txthinking) | Ask questions here |
| [Announce](https://t.me/s/txthinking_news) | All news you should care |
| [GitHub](https://github.com/txthinking) | Other useful repos |
| [Socks5 Configurator](https://chromewebstore.google.com/detail/socks5-configurator/hnpgnjkeaobghpjjhaiemlahikgmnghb) | If you prefer CLI brook client |
| [IPvBar](https://chromewebstore.google.com/detail/ipvbar/nepjlegfiihpkcdhlmaebfdfppckonlj) | See domain, IP and country in browser |
| [TxThinking SSH](https://www.txthinking.com/ssh.html) | A SSH Terminal |
| [brook-user-system](https://github.com/txthinkinginc/brook-user-system) | A Brook User System |
| [TxThinking](https://www.txthinking.com) | Everything |
## IPv6
Brook's stance on IPv6 is positive, if your server or local environment doesn't have an IPv6 stack, read [this article](https://www.txthinking.com/talks/articles/brook-ipv6-en.article).
## Troubleshooting Steps
1. After adding your Server to the Brook client
2. If your Server uses a domain and has not specified an IP address via `brook link --address`, then Brook client will attempt to resolve the domain's IP using local DNS, preferring AAAA record. For example:
- domain.com:9999
- ws://domain.com:9999
- wss://domain.com:9999
- quic://domain.com:9999
3. Connectivity check: Go to the Server details page and click `Connectivity Check`. If it works sometimes but not others, this indicates instability.
4. After connected
1. Brook will change your system DNS to the System DNS configured in Brook (by default Google's DNS). In very rare cases, this change may be ignored on Windows, you can confirm this in the system settings.
5. Test IPv4 TCP: Use `Test IPv4 TCP` for testing; this test has hardcoded the IP address, so does not trigger DNS resolution.
5. Test IPv4 UDP: Use `Test IPv4 UDP` for testing; this test has hardcoded the IP address, so does not trigger DNS resolution.
6. Test IPv6 TCP: Use `Test IPv6 TCP` for testing; this test has hardcoded the IP address, so does not trigger DNS resolution.
6. Test IPv6 UDP: Use `Test IPv6 UDP` for testing; this test has hardcoded the IP address, so does not trigger DNS resolution.
7. Test TCP and UDP: Use the `Echo Client` for testing. If the echo server entered is a domain address, it will trigger DNS resolution.
8. Ensure the effectiveness of Fake DNS: Fake DNS is essential to do something with a domain or domain address. Generally, enable the `Block Google Secure DNS` module is sufficient. For other cases, refer to [this article](https://www.txthinking.com/talks/articles/brook-fakedns-en.article).
9. If your local or Server does not support IPv6: Refer to [this article](https://www.txthinking.com/talks/articles/brook-ipv6-en.article).
10. macOS App Mode: Refer to [this article](https://www.txthinking.com/talks/articles/macos-app-mode.article).
11. Windows:
- The client can pass the tests without any special configuration on a brand-new, genuine Windows 11.
- Be aware that the Windows system time is often incorrect.
- Do not have other similar network software installed; they can cause conflicting network settings in the system.
- Try restarting the computer.
- Windows Defender may ask for permission to connect to the network or present other issues.
- System DNS may need to be set to 8.8.8.8 and/or 2001:4860:4860::8888
12. Android:
- The client can pass the tests without any special configuration on the official Google ROM.
- Different ROMs may have made different modifications to the system.
- Permission for background running might require separate settings.
- System DNS may need to be set to 8.8.8.8 and/or 2001:4860:4860::8888
13. Bypass traffic such as China, usually requires the following modules to be activated:
- `Block Google Secure DNS`
- `Bypass Geo`
- `Bypass Apple`: To prevent issues receiving Apple message notifications.
- `Bypass China domain` or `Bypass China domain A`: The former uses `Bypass DNS` to obtain the IP, then `Bypass Geo` or other modules decide whether to bypass; the latter bypasses directly after obtaining the IP with `Bypass DNS` using A records. The latter is needed if your local does not support IPv6.
- If you are a [Shiliew](https://www.txthinking.com/shiliew.html) user, some modules are enabled by default, which is usually sufficient.
14. Search [GitHub issues](https://github.com/txthinking/brook/issues?q=is%3Aissue)
15. Read the [blog](https://www.txthinking.com/talks/)
16. Read the [documentation](https://brook.app)
14. Submit [new issue](https://github.com/txthinking/brook/issues?q=is%3Aissue)
17. Seek help in the [group](https://t.me/txthinking)
# CLI Documentation
Each subcommand has a `--example` parameter that can print the minimal example of usage
# NAME
Brook - A cross-platform programmable network tool
@@ -1191,16 +1307,34 @@ brook relay --from :9999 --to 1.2.3.4:9999
brook socks5tohttp --socks5 127.0.0.1:1080 --listen 127.0.0.1:8010
```
## brook pac creates pac server
```
brook pac --listen 127.0.0.1:8080 --proxy 'SOCKS5 127.0.0.1:1080; SOCKS 127.0.0.1:1080; DIRECT' --bypassDomainList ...
```
## brook pac creates pac file
```
brook pac --file proxy.pac --proxy 'SOCKS5 127.0.0.1:1080; SOCKS 127.0.0.1:1080; DIRECT' --bypassDomainList ...
```
## There are countless examples; for more feature suggestions, it's best to look at the commands and parameters in the CLI documentation one by one, and blog, YouTube...
# Resources
| CLI | Description |
| --- | --- |
| [nami](https://github.com/txthinking/nami) | A clean and tidy decentralized package manager |
| [joker](https://github.com/txthinking/joker) | Joker can turn process into daemon. Zero-Configuration |
| [nico](https://github.com/txthinking/nico) | Nico can work with brook wsserver together |
| [z](https://github.com/txthinking/z) | z - process manager |
| [tun2brook](https://github.com/txthinking/tun2brook) | Proxy all traffic just one line command |
| [mad](https://github.com/txthinking/mad) | Generate root CA and derivative certificate for any domains and any IPs |
| [hancock](https://github.com/txthinking/hancock) | Manage multiple remote servers and execute commands remotely |
| [sshexec](https://github.com/txthinking/sshexec) | A command-line tool to execute remote command through ssh |
| [jb](https://github.com/txthinking/jb) | write script in an easier way than bash |
| [bash](https://github.com/txthinking/bash) | Many one-click scripts |
| [docker](https://hub.docker.com/r/txthinking/brook) | `docker run txthinking/brook` |
| Resources | Description |
| --- | --- |
| [Protocol](https://github.com/txthinking/brook/tree/master/protocol) | Brook Protocol |
| [Blog](https://www.txthinking.com/talks/) | Some articles you should read |
| [YouTube](https://www.youtube.com/txthinking) | Some videos you should watch |
| [Telegram](https://t.me/txthinking) | Ask questions here |
| [Announce](https://t.me/s/txthinking_news) | All news you should care |
| [GitHub](https://github.com/txthinking) | Other useful repos |
| [Socks5 Configurator](https://chromewebstore.google.com/detail/socks5-configurator/hnpgnjkeaobghpjjhaiemlahikgmnghb) | If you prefer CLI brook client |
| [IPvBar](https://chromewebstore.google.com/detail/ipvbar/nepjlegfiihpkcdhlmaebfdfppckonlj) | See domain, IP and country in browser |
| [TxThinking SSH](https://www.txthinking.com/ssh.html) | A SSH Terminal |
| [brook-user-system](https://github.com/txthinkinginc/brook-user-system) | A Brook User System |
| [TxThinking](https://www.txthinking.com) | Everything |
+2 -1
View File
@@ -10,12 +10,13 @@ echo '**❤️ [Shiliew - A network app designed for those who value their time
cat getting-started.md >> ../readme.md
cat gui.md >> ../readme.md
cat resources.md >> ../readme.md
echo '# CLI Documentation' >> ../readme.md
echo 'Each subcommand has a `--example` parameter that can print the minimal example of usage' >> ../readme.md
jb '$1`brook mdpage`.split("\n").filter(v=>!v.startsWith("[")).join("\n").replace("```\n```", "```\nbrook --help\n```").split("\n").forEach(v=> echo(v.startsWith("**") && !v.startsWith("**Usage") ? "- "+v : v))' >> ../readme.md
cat example.md >> ../readme.md
cat resources.md >> ../readme.md
markdown ../readme.md ./index.html
-12
View File
@@ -262,16 +262,4 @@ brook relay --from :9999 --to 1.2.3.4:9999
brook socks5tohttp --socks5 127.0.0.1:1080 --listen 127.0.0.1:8010
```
## brook pac creates pac server
```
brook pac --listen 127.0.0.1:8080 --proxy 'SOCKS5 127.0.0.1:1080; SOCKS 127.0.0.1:1080; DIRECT' --bypassDomainList ...
```
## brook pac creates pac file
```
brook pac --file proxy.pac --proxy 'SOCKS5 127.0.0.1:1080; SOCKS 127.0.0.1:1080; DIRECT' --bypassDomainList ...
```
## There are countless examples; for more feature suggestions, it's best to look at the commands and parameters in the CLI documentation one by one, and blog, YouTube...
+1 -1
View File
@@ -14,7 +14,7 @@ nami install brook
brook server -l :9999 -p hello
```
## GUI Client
## Client
| iOS | Android | Mac |Windows |Linux |OpenWrt |
| --- | --- | --- | --- | --- | --- |
+173 -26
View File
@@ -1,19 +1,118 @@
# GUI Documentation
## Software for which this article applies
- [Brook](https://github.com/txthinking/brook)
- [Shiliew](https://www.txthinking.com/shiliew.html)
- [tun2brook](https://github.com/txthinking/tun2brook)
## Programmable
# Client
Brook GUI will pass different _global variables_ to the script at different times, and the script only needs to assign the processing result to the global variable `out`
- address: We call it address which includes both host and port. For example, an ip address contains an ip and a port; a domain address contains a domain and a port.
- Fake DNS: Fake DNS can allow you to obtain domain address on `in_address` step. [How Fake DNS works](https://www.txthinking.com/talks/articles/brook-fakedns-en.article)
## CLI
### Variables
Before discussing the GUI client, let's first talk about the command line client `brook`. As we know, after you have deployed the server, you can use the command line client `brook` to create a local socks5 proxy or http proxy on your machine, and then configure it in your system proxy settings or in your browser to use this proxy. However:
1. Not all apps will use this proxy, whether they use it is up to the app itself.
2. Generally, all UDP protocols will not go through this proxy, such as http3.
For the specifics of socks5 and http proxy, you can read [this article](https://www.txthinking.com/talks/articles/socks5-and-http-proxy.article).
## GUI
The GUI client does not use socks5 and http proxy mode, so there is no issue with some software not using the system proxy. Instead, it uses a virtual network card to take over the entire system's network, including UDP-based http3. Moreover, Brook allows us to control network requests programmatically, so it is necessary to have basic knowledge of network requests.
## Without Brook: Basic Knowledge of Network Requests
> Note: When we talk about addresses, we mean addresses that include the port number, such as a domain address: `google.com:443`, or an IP address: `8.8.8.8:53`
1. When an app requests a domain address, such as `google.com:443`
2. It will first perform a DNS resolution, which means that the app will send a network request to the system-configured DNS, such as `8.8.8.8:53`, to inquire about the IP of `google.com`
1. The system DNS will return the IP of `google.com`, such as `1.2.3.4`, to the app
3. The app will combine the IP and port into an IP address, such as: `1.2.3.4:443`
4. The app makes a network request to this IP address `1.2.3.4:443`
5. The app receives the response data
In the above process, the app actually makes two network requests: one to the IP address `8.8.8.8:53` and another to the IP address `1.2.3.4:443`. In other words, the domain name is essentially an alias for the IP, and must obtain the domain's IP to establish a connection.
## With Brook: Fake DNS On
Brook has a Fake DNS feature, which can parse the domain name out of the query requests that an app sends to the system DNS and decide how to respond to the app.
1. When an app requests a domain name address, such as `google.com:443`
2. A DNS resolution will be performed first. That is, the app will send a network request to the system-configured DNS, such as `8.8.8.8:53`, to inquire about the IP of `google.com`
3. The Brook client detects that an app is sending a network request to `8.8.8.8:53`. <mark>This will trigger the `in_dnsquery` variable, carrying information such as `domain`</mark>
1. The Brook client returns a fake IP to the app, such as `240.0.0.1`
4. The app combines the IP and port into an IP address, such as: `240.0.0.1:443`
5. The app makes a network request to the IP address `240.0.0.1:443`
6. The Brook client detects that an app is sending a network request to `240.0.0.1:443`, discovers that this is a fake IP, and will convert the fake IP address back to the domain address `google.com:443`. <mark>This will trigger the `in_address` variable, carrying information such as `domainaddress`</mark>
1. The Brook client sends `google.com:443` to the Brook Server
2. The Brook Server first requests its own DNS to resolve the domain name to find out the IP of `google.com`, such as receiving `1.2.3.4`
3. The Brook Server combines the IP and port into an IP address, such as: `1.2.3.4:443`
4. The Brook Server sends a network request to `1.2.3.4:443` and returns the data to the Brook client
5. The Brook client then returns the data to the app
7. The app receives the response data
However, if the following situations occur, the domain name will not/cannot be parsed, meaning that the Brook client will not/cannot know what the domain name is and will treat it as a normal request sent to an IP address:
- Fake DNS not enabled: in this case, the Brook client will not attempt to parse the domain name from the request sent to the system DNS and will treat it as a normal request sent to an IP address.
- Even with Fake DNS enabled, but the app uses the system's secure DNS or the app's own secure DNS: in this case, the Brook client cannot parse the domain name from the request sent to the secure DNS and will treat it as a normal request sent to an IP address.
To avoid the ineffectiveness of Fake DNS, please refer to [this article](https://www.txthinking.com/talks/articles/brook-fakedns.article).
## With Brook: Fake DNS Off
1. When an app requests a domain address, such as `google.com:443`
2. A DNS resolution will be performed first. That is, the app will send a network request to the system-configured DNS, such as `8.8.8.8:53`, to inquire about the IP of `google.com`
3. The Brook client detects that an app is sending a network request to `8.8.8.8:53`. <mark>This will trigger the `in_address` variable, carrying information such as `ipaddress`</mark>
1. The Brook client sends `8.8.8.8:53` to the Brook Server
2. The Brook Server sends a network request to `8.8.8.8:53` and returns the result, such as `1.2.3.4`, to the Brook client
3. The Brook client then returns the result to the app
4. The app combines the IP and port into an IP address, such as: `1.2.3.4:443`
5. The app makes a network request to the IP address `1.2.3.4:443`
6. The Brook client detects that an app is sending a network request to `1.2.3.4:443`. <mark>This will trigger the `in_address` variable, carrying information such as `ipaddress`</mark>
1. The Brook client sends `1.2.3.4:443` to the Brook Server
2. The Brook Server sends a network request to `1.2.3.4:443` and returns the data to the Brook client
3. The Brook client then returns the data to the app
7. The app receives the response data
## With Brook: Fake DNS On, But the App Uses the System's Secure DNS or Its Own Secure DNS
1. When an app requests a domain name address, such as `google.com:443`
2. A DNS resolution will be performed first. That is, the app will send a network request to the secure DNS, such as `8.8.8.8:443`, to inquire about the IP of `google.com`
3. The Brook client detects that an app is sending a network request to `8.8.8.8:443`. <mark>This will trigger the `in_address` variable, carrying information such as `ipaddress`</mark>
1. The Brook client sends `8.8.8.8:443` to the Brook Server
2. The Brook Server sends a network request to `8.8.8.8:443`, and returns the result, such as `1.2.3.4`, to the Brook client
3. The Brook client then returns the result to the app
4. The app combines the IP and port into an IP address, such as: `1.2.3.4:443`
5. The app makes a network request to the IP address `1.2.3.4:443`
6. The Brook client detects that an app is sending a network request to `1.2.3.4:443`. <mark>This will trigger the `in_address` variable, carrying information such as `ipaddress`</mark>
1. The Brook client sends `1.2.3.4:443` to the Brook Server
2. The Brook Server sends a network request to `1.2.3.4:443` and returns the data to the Brook client
3. The Brook client then returns the data to the app
7. The app receives the response data
## Handle Variable Trigger
- When the `in_brooklinks` variable is triggered:
- This is currently the only variable that gets triggered before the Brook client starts.
- We know that Brook starts with your choice of a Brook Server, and this variable lets you specify multiple Brook Servers.
- Then during runtime, you can use one of these Brook Servers as needed.
- When the `in_dnsquery` variable is triggered, you can process as needed, such as:
- Blocking, such as to prevent ad domain names.
- Directly specifying the response IP.
- Letting the system DNS resolve this domain.
- Letting Bypass DNS resolve this domain.
- And so on.
- When the `in_address` variable is triggered, you can process as needed, such as:
- Block this connection.
- Rewrite the destination.
- If it's a domain address, you can specify that Bypass DNS is responsible for resolving the IP of this domain.
- Allow it to connect directly without going through a proxy.
- If it's HTTP/HTTPS, you can start MITM (Man-In-The-Middle), which will subsequently trigger `in_httprequest` and `in_httpresponse`.
- And so on.
- When the `in_httprequest` variable is triggered, you can process as needed, such as:
- Modifying the HTTP request.
- Returning a custom HTTP response directly.
- When the `in_httpresponse` variable is triggered, you can process as needed, such as:
- Modifying the HTTP response.
For detailed information on the properties and responses of variables, please refer to the following content.
## Variables
| variable | type | condition | timing | description | out type |
| ------------------------------ | ---- | ----------- | --------------------------------- | ------------------------------------------------- | -------- |
@@ -23,7 +122,7 @@ Brook GUI will pass different _global variables_ to the script at different time
| in_httprequest | map | / | When an HTTP(S) request comes in | the script can decide how to handle this request | map |
| in_httprequest,in_httpresponse | map | / | when an HTTP(S) response comes in | the script can decide how to handle this response | map |
### in_brooklinks
## in_brooklinks
| Key | Type | Description | Example |
| ------ | ------ | -------- | ---------- |
@@ -37,7 +136,7 @@ Brook GUI will pass different _global variables_ to the script at different time
| custom name | string | brook link | brook://... |
| ... | ... | ... | ... |
### in_dnsquery
## in_dnsquery
| Key | Type | Description | Example |
| ------ | ------ | ----------- | ---------- |
@@ -56,7 +155,7 @@ Brook GUI will pass different _global variables_ to the script at different time
| bypass | bool | Resolve by Bypass DNS, default `false` | false |
| brooklinkkey | string | When need to connect the Serverinstead, connect to the Server specified by the key in_brooklinks | custom name |
### in_address
## in_address
| Key | Type | Description | Example |
| ------------- | ------ | ------------------------------------------------------------------------------------------------------------------- | -------------- |
@@ -84,7 +183,7 @@ Brook GUI will pass different _global variables_ to the script at different time
| mitmserverwritetimeout | int | Timeout for MITM write to client, second, default 0 | 0 |
| brooklinkkey | string | When need to connect the Serverinstead, connect to the Server specified by the key in_brooklinks | custom name |
### in_httprequest
## in_httprequest
| Key | Type | Description | Example |
| ------ | ------ | ----------------------------- | --------------------------- |
@@ -95,7 +194,7 @@ Brook GUI will pass different _global variables_ to the script at different time
`out`, must be set to a request or response
### in_httpresponse
## in_httpresponse
| Key | Type | Description | Example |
| ---------- | ------ | ----------------------------- | ------- |
@@ -105,13 +204,9 @@ Brook GUI will pass different _global variables_ to the script at different time
`out`, must be set to a response
## Module
## Modules
There are already some modules: https://github.com/txthinking/brook/blob/master/programmable/modules/
### Brook GUI
In Brook GUI, scripts are abstracted into modules, and it will automatically combine [_header.tengo](https://github.com/txthinking/brook/blob/master/programmable/modules/_header.tengo) and [_footer.tengo](https://github.com/txthinking/brook/blob/master/programmable/modules/_footer.tengo), so you only need to write the module itself.
In Brook GUI, scripts are abstracted into **Modules**. There are already [some modules](https://github.com/txthinking/brook/blob/master/programmable/modules/), and thre is no magic, it just automatically combine [_header.tengo](https://github.com/txthinking/brook/blob/master/programmable/modules/_header.tengo) and [_footer.tengo](https://github.com/txthinking/brook/blob/master/programmable/modules/_footer.tengo), so you only need to write the module itself.
```
modules = append(modules, {
@@ -138,9 +233,11 @@ modules = append(modules, {
})
```
### tun2brook
## tun2brook
If you are using tun2brook, you can combine multiple modules into a complete script in the following way. For example:
https://github.com/txthinking/tun2brook
If you are using tun2brook, you can manually combine multiple modules into a complete script in the following way. For example:
```
cat _header.tengo > my.tengo
@@ -202,7 +299,7 @@ Library
If you are writing complex scripts, the GUI may not be convenient for debugging. It is recommended to use [tun2brook](https://github.com/txthinking/tun2brook) on desktop to debug with `fmt.println`
## Install CA
## CA
https://txthinking.github.io/ca/ca.pem
@@ -215,3 +312,53 @@ https://txthinking.github.io/ca/ca.pem
> Some software may not read the system CAyou can use `curl --cacert ~/.nami/bin/ca.pem` to debug
## OpenWrt
https://www.txthinking.com/talks/articles/brook-openwrt-en.article
## IPv6
Brook's stance on IPv6 is positive, if your server or local environment doesn't have an IPv6 stack, read [this article](https://www.txthinking.com/talks/articles/brook-ipv6-en.article).
## Troubleshooting Steps
1. After adding your Server to the Brook client
2. If your Server uses a domain and has not specified an IP address via `brook link --address`, then Brook client will attempt to resolve the domain's IP using local DNS, preferring AAAA record. For example:
- domain.com:9999
- ws://domain.com:9999
- wss://domain.com:9999
- quic://domain.com:9999
3. Connectivity check: Go to the Server details page and click `Connectivity Check`. If it works sometimes but not others, this indicates instability.
4. After connected
1. Brook will change your system DNS to the System DNS configured in Brook (by default Google's DNS). In very rare cases, this change may be ignored on Windows, you can confirm this in the system settings.
5. Test IPv4 TCP: Use `Test IPv4 TCP` for testing; this test has hardcoded the IP address, so does not trigger DNS resolution.
5. Test IPv4 UDP: Use `Test IPv4 UDP` for testing; this test has hardcoded the IP address, so does not trigger DNS resolution.
6. Test IPv6 TCP: Use `Test IPv6 TCP` for testing; this test has hardcoded the IP address, so does not trigger DNS resolution.
6. Test IPv6 UDP: Use `Test IPv6 UDP` for testing; this test has hardcoded the IP address, so does not trigger DNS resolution.
7. Test TCP and UDP: Use the `Echo Client` for testing. If the echo server entered is a domain address, it will trigger DNS resolution.
8. Ensure the effectiveness of Fake DNS: Fake DNS is essential to do something with a domain or domain address. Generally, enable the `Block Google Secure DNS` module is sufficient. For other cases, refer to [this article](https://www.txthinking.com/talks/articles/brook-fakedns-en.article).
9. If your local or Server does not support IPv6: Refer to [this article](https://www.txthinking.com/talks/articles/brook-ipv6-en.article).
10. macOS App Mode: Refer to [this article](https://www.txthinking.com/talks/articles/macos-app-mode.article).
11. Windows:
- The client can pass the tests without any special configuration on a brand-new, genuine Windows 11.
- Be aware that the Windows system time is often incorrect.
- Do not have other similar network software installed; they can cause conflicting network settings in the system.
- Try restarting the computer.
- Windows Defender may ask for permission to connect to the network or present other issues.
- System DNS may need to be set to 8.8.8.8 and/or 2001:4860:4860::8888
12. Android:
- The client can pass the tests without any special configuration on the official Google ROM.
- Different ROMs may have made different modifications to the system.
- Permission for background running might require separate settings.
- System DNS may need to be set to 8.8.8.8 and/or 2001:4860:4860::8888
13. Bypass traffic such as China, usually requires the following modules to be activated:
- `Block Google Secure DNS`
- `Bypass Geo`
- `Bypass Apple`: To prevent issues receiving Apple message notifications.
- `Bypass China domain` or `Bypass China domain A`: The former uses `Bypass DNS` to obtain the IP, then `Bypass Geo` or other modules decide whether to bypass; the latter bypasses directly after obtaining the IP with `Bypass DNS` using A records. The latter is needed if your local does not support IPv6.
- If you are a [Shiliew](https://www.txthinking.com/shiliew.html) user, some modules are enabled by default, which is usually sufficient.
14. Search [GitHub issues](https://github.com/txthinking/brook/issues?q=is%3Aissue)
15. Read the [blog](https://www.txthinking.com/talks/)
16. Read the [documentation](https://brook.app)
14. Submit [new issue](https://github.com/txthinking/brook/issues?q=is%3Aissue)
17. Seek help in the [group](https://t.me/txthinking)
+331 -172
View File
@@ -1157,31 +1157,33 @@
<li><a href="#sponsor">Sponsor</a></li>
<li><a href="#getting-started">Getting Started</a><ul>
<li><a href="#server">Server</a></li>
<li><a href="#gui-client">GUI Client</a></li>
<li><a href="#client">Client</a></li>
</ul>
</li>
<li><a href="#gui-documentation">GUI Documentation</a><ul>
<li><a href="#software-for-which-this-article-applies">Software for which this article applies</a></li>
<li><a href="#programmable">Programmable</a><ul>
<li><a href="#client-1">Client</a><ul>
<li><a href="#cli">CLI</a></li>
<li><a href="#gui">GUI</a></li>
<li><a href="#without-brook-basic-knowledge-of-network-requests">Without Brook: Basic Knowledge of Network Requests</a></li>
<li><a href="#with-brook-fake-dns-on">With Brook: Fake DNS On</a></li>
<li><a href="#with-brook-fake-dns-off">With Brook: Fake DNS Off</a></li>
<li><a href="#with-brook-fake-dns-on-but-the-app-uses-the-systems-secure-dns-or-its-own-secure-dns">With Brook: Fake DNS On, But the App Uses the System&#39;s Secure DNS or Its Own Secure DNS</a></li>
<li><a href="#handle-variable-trigger">Handle Variable Trigger</a></li>
<li><a href="#variables">Variables</a></li>
<li><a href="#in_brooklinks">in_brooklinks</a></li>
<li><a href="#in_dnsquery">in_dnsquery</a></li>
<li><a href="#in_address">in_address</a></li>
<li><a href="#in_httprequest">in_httprequest</a></li>
<li><a href="#in_httpresponse">in_httpresponse</a></li>
</ul>
</li>
<li><a href="#module">Module</a><ul>
<li><a href="#brook-gui">Brook GUI</a></li>
<li><a href="#modules">Modules</a></li>
<li><a href="#tun2brook">tun2brook</a></li>
</ul>
</li>
<li><a href="#syntax">Syntax</a></li>
<li><a href="#debug">Debug</a></li>
<li><a href="#install-ca">Install CA</a></li>
<li><a href="#ca">CA</a></li>
<li><a href="#openwrt">OpenWrt</a></li>
<li><a href="#ipv6">IPv6</a></li>
<li><a href="#troubleshooting-steps">Troubleshooting Steps</a></li>
</ul>
</li>
<li><a href="#resources">Resources</a></li>
<li><a href="#cli-documentation">CLI Documentation</a></li>
<li><a href="#name">NAME</a></li>
<li><a href="#synopsis">SYNOPSIS</a></li>
@@ -1242,11 +1244,10 @@
<li><a href="#turn-linux-into-a-gateway-with-brook">Turn Linux into a Gateway with Brook</a></li>
<li><a href="#brook-relay-can-relay-a-address-to-a-remote-address-it-can-relay-any-tcp-and-udp-server">brook relay can relay a address to a remote address. It can relay any tcp and udp server</a></li>
<li><a href="#brook-socks5tohttp-can-convert-a-socks5-to-a-http-proxy">brook socks5tohttp can convert a socks5 to a http proxy</a></li>
<li><a href="#brook-pac-creates-pac-server">brook pac creates pac server</a></li>
<li><a href="#brook-pac-creates-pac-file">brook pac creates pac file</a></li>
<li><a href="#there-are-countless-examples-for-more-feature-suggestions-its-best-to-look-at-the-commands-and-parameters-in-the-cli-documentation-one-by-one-and-blog-youtube">There are countless examples; for more feature suggestions, it&#39;s best to look at the commands and parameters in the CLI documentation one by one, and blog, YouTube...</a></li>
</ul>
</li>
<li><a href="#resources">Resources</a></li>
</ul>
</div>
@@ -1259,31 +1260,33 @@
<li><a href="#sponsor">Sponsor</a></li>
<li><a href="#getting-started">Getting Started</a><ul>
<li><a href="#server">Server</a></li>
<li><a href="#gui-client">GUI Client</a></li>
<li><a href="#client">Client</a></li>
</ul>
</li>
<li><a href="#gui-documentation">GUI Documentation</a><ul>
<li><a href="#software-for-which-this-article-applies">Software for which this article applies</a></li>
<li><a href="#programmable">Programmable</a><ul>
<li><a href="#client-1">Client</a><ul>
<li><a href="#cli">CLI</a></li>
<li><a href="#gui">GUI</a></li>
<li><a href="#without-brook-basic-knowledge-of-network-requests">Without Brook: Basic Knowledge of Network Requests</a></li>
<li><a href="#with-brook-fake-dns-on">With Brook: Fake DNS On</a></li>
<li><a href="#with-brook-fake-dns-off">With Brook: Fake DNS Off</a></li>
<li><a href="#with-brook-fake-dns-on-but-the-app-uses-the-systems-secure-dns-or-its-own-secure-dns">With Brook: Fake DNS On, But the App Uses the System&#39;s Secure DNS or Its Own Secure DNS</a></li>
<li><a href="#handle-variable-trigger">Handle Variable Trigger</a></li>
<li><a href="#variables">Variables</a></li>
<li><a href="#in_brooklinks">in_brooklinks</a></li>
<li><a href="#in_dnsquery">in_dnsquery</a></li>
<li><a href="#in_address">in_address</a></li>
<li><a href="#in_httprequest">in_httprequest</a></li>
<li><a href="#in_httpresponse">in_httpresponse</a></li>
</ul>
</li>
<li><a href="#module">Module</a><ul>
<li><a href="#brook-gui">Brook GUI</a></li>
<li><a href="#modules">Modules</a></li>
<li><a href="#tun2brook">tun2brook</a></li>
</ul>
</li>
<li><a href="#syntax">Syntax</a></li>
<li><a href="#debug">Debug</a></li>
<li><a href="#install-ca">Install CA</a></li>
<li><a href="#ca">CA</a></li>
<li><a href="#openwrt">OpenWrt</a></li>
<li><a href="#ipv6">IPv6</a></li>
<li><a href="#troubleshooting-steps">Troubleshooting Steps</a></li>
</ul>
</li>
<li><a href="#resources">Resources</a></li>
<li><a href="#cli-documentation">CLI Documentation</a></li>
<li><a href="#name">NAME</a></li>
<li><a href="#synopsis">SYNOPSIS</a></li>
@@ -1344,11 +1347,10 @@
<li><a href="#turn-linux-into-a-gateway-with-brook">Turn Linux into a Gateway with Brook</a></li>
<li><a href="#brook-relay-can-relay-a-address-to-a-remote-address-it-can-relay-any-tcp-and-udp-server">brook relay can relay a address to a remote address. It can relay any tcp and udp server</a></li>
<li><a href="#brook-socks5tohttp-can-convert-a-socks5-to-a-http-proxy">brook socks5tohttp can convert a socks5 to a http proxy</a></li>
<li><a href="#brook-pac-creates-pac-server">brook pac creates pac server</a></li>
<li><a href="#brook-pac-creates-pac-file">brook pac creates pac file</a></li>
<li><a href="#there-are-countless-examples-for-more-feature-suggestions-its-best-to-look-at-the-commands-and-parameters-in-the-cli-documentation-one-by-one-and-blog-youtube">There are countless examples; for more feature suggestions, it&#39;s best to look at the commands and parameters in the CLI documentation one by one, and blog, YouTube...</a></li>
</ul>
</li>
<li><a href="#resources">Resources</a></li>
</ul>
</div>
@@ -1365,7 +1367,7 @@
</code></pre>
<pre><code>brook server -l :9999 -p hello
</code></pre>
<h2 id="gui-client">GUI Client</h2>
<h2 id="client">Client</h2>
<table>
<thead>
<tr>
@@ -1397,20 +1399,136 @@
<blockquote>
<p>You may want to use <code>brook link</code> to customize some parameters</p>
</blockquote>
<h1 id="gui-documentation">GUI Documentation</h1>
<h2 id="software-for-which-this-article-applies">Software for which this article applies</h2>
<ul>
<li><a href="https://github.com/txthinking/brook">Brook</a></li>
<li><a href="https://www.txthinking.com/shiliew.html">Shiliew</a></li>
<li><a href="https://github.com/txthinking/tun2brook">tun2brook</a></li>
</ul>
<h2 id="programmable">Programmable</h2>
<h1 id="client-1">Client</h1>
<p>Brook GUI will pass different <em>global variables</em> to the script at different times, and the script only needs to assign the processing result to the global variable <code>out</code></p>
<h2 id="cli">CLI</h2>
<p>Before discussing the GUI client, let&#39;s first talk about the command line client <code>brook</code>. As we know, after you have deployed the server, you can use the command line client <code>brook</code> to create a local socks5 proxy or http proxy on your machine, and then configure it in your system proxy settings or in your browser to use this proxy. However:</p>
<ol>
<li>Not all apps will use this proxy, whether they use it is up to the app itself.</li>
<li>Generally, all UDP protocols will not go through this proxy, such as http3.</li>
</ol>
<p>For the specifics of socks5 and http proxy, you can read <a href="https://www.txthinking.com/talks/articles/socks5-and-http-proxy.article">this article</a>.</p>
<h2 id="gui">GUI</h2>
<p>The GUI client does not use socks5 and http proxy mode, so there is no issue with some software not using the system proxy. Instead, it uses a virtual network card to take over the entire system&#39;s network, including UDP-based http3. Moreover, Brook allows us to control network requests programmatically, so it is necessary to have basic knowledge of network requests.</p>
<h2 id="without-brook-basic-knowledge-of-network-requests">Without Brook: Basic Knowledge of Network Requests</h2>
<blockquote>
<p>Note: When we talk about addresses, we mean addresses that include the port number, such as a domain address: <code>google.com:443</code>, or an IP address: <code>8.8.8.8:53</code></p>
</blockquote>
<ol>
<li>When an app requests a domain address, such as <code>google.com:443</code></li>
<li>It will first perform a DNS resolution, which means that the app will send a network request to the system-configured DNS, such as <code>8.8.8.8:53</code>, to inquire about the IP of <code>google.com</code><ol>
<li>The system DNS will return the IP of <code>google.com</code>, such as <code>1.2.3.4</code>, to the app</li>
</ol>
</li>
<li>The app will combine the IP and port into an IP address, such as: <code>1.2.3.4:443</code></li>
<li>The app makes a network request to this IP address <code>1.2.3.4:443</code></li>
<li>The app receives the response data</li>
</ol>
<p>In the above process, the app actually makes two network requests: one to the IP address <code>8.8.8.8:53</code> and another to the IP address <code>1.2.3.4:443</code>. In other words, the domain name is essentially an alias for the IP, and must obtain the domain&#39;s IP to establish a connection.</p>
<h2 id="with-brook-fake-dns-on">With Brook: Fake DNS On</h2>
<p>Brook has a Fake DNS feature, which can parse the domain name out of the query requests that an app sends to the system DNS and decide how to respond to the app.</p>
<ol>
<li>When an app requests a domain name address, such as <code>google.com:443</code></li>
<li>A DNS resolution will be performed first. That is, the app will send a network request to the system-configured DNS, such as <code>8.8.8.8:53</code>, to inquire about the IP of <code>google.com</code></li>
<li>The Brook client detects that an app is sending a network request to <code>8.8.8.8:53</code>. <mark>This will trigger the <code>in_dnsquery</code> variable, carrying information such as <code>domain</code></mark><ol>
<li>The Brook client returns a fake IP to the app, such as <code>240.0.0.1</code></li>
</ol>
</li>
<li>The app combines the IP and port into an IP address, such as: <code>240.0.0.1:443</code></li>
<li>The app makes a network request to the IP address <code>240.0.0.1:443</code></li>
<li>The Brook client detects that an app is sending a network request to <code>240.0.0.1:443</code>, discovers that this is a fake IP, and will convert the fake IP address back to the domain address <code>google.com:443</code>. <mark>This will trigger the <code>in_address</code> variable, carrying information such as <code>domainaddress</code></mark><ol>
<li>The Brook client sends <code>google.com:443</code> to the Brook Server</li>
<li>The Brook Server first requests its own DNS to resolve the domain name to find out the IP of <code>google.com</code>, such as receiving <code>1.2.3.4</code></li>
<li>The Brook Server combines the IP and port into an IP address, such as: <code>1.2.3.4:443</code></li>
<li>The Brook Server sends a network request to <code>1.2.3.4:443</code> and returns the data to the Brook client</li>
<li>The Brook client then returns the data to the app</li>
</ol>
</li>
<li>The app receives the response data</li>
</ol>
<p>However, if the following situations occur, the domain name will not/cannot be parsed, meaning that the Brook client will not/cannot know what the domain name is and will treat it as a normal request sent to an IP address:</p>
<ul>
<li>address: We call it address which includes both host and port. For example, an ip address contains an ip and a port; a domain address contains a domain and a port.</li>
<li>Fake DNS: Fake DNS can allow you to obtain domain address on <code>in_address</code> step. <a href="https://www.txthinking.com/talks/articles/brook-fakedns-en.article">How Fake DNS works</a></li>
<li>Fake DNS not enabled: in this case, the Brook client will not attempt to parse the domain name from the request sent to the system DNS and will treat it as a normal request sent to an IP address.</li>
<li>Even with Fake DNS enabled, but the app uses the system&#39;s secure DNS or the app&#39;s own secure DNS: in this case, the Brook client cannot parse the domain name from the request sent to the secure DNS and will treat it as a normal request sent to an IP address.</li>
</ul>
<h3 id="variables">Variables</h3>
<p>To avoid the ineffectiveness of Fake DNS, please refer to <a href="https://www.txthinking.com/talks/articles/brook-fakedns.article">this article</a>.</p>
<h2 id="with-brook-fake-dns-off">With Brook: Fake DNS Off</h2>
<ol>
<li>When an app requests a domain address, such as <code>google.com:443</code></li>
<li>A DNS resolution will be performed first. That is, the app will send a network request to the system-configured DNS, such as <code>8.8.8.8:53</code>, to inquire about the IP of <code>google.com</code></li>
<li>The Brook client detects that an app is sending a network request to <code>8.8.8.8:53</code>. <mark>This will trigger the <code>in_address</code> variable, carrying information such as <code>ipaddress</code></mark><ol>
<li>The Brook client sends <code>8.8.8.8:53</code> to the Brook Server</li>
<li>The Brook Server sends a network request to <code>8.8.8.8:53</code> and returns the result, such as <code>1.2.3.4</code>, to the Brook client</li>
<li>The Brook client then returns the result to the app</li>
</ol>
</li>
<li>The app combines the IP and port into an IP address, such as: <code>1.2.3.4:443</code></li>
<li>The app makes a network request to the IP address <code>1.2.3.4:443</code></li>
<li>The Brook client detects that an app is sending a network request to <code>1.2.3.4:443</code>. <mark>This will trigger the <code>in_address</code> variable, carrying information such as <code>ipaddress</code></mark><ol>
<li>The Brook client sends <code>1.2.3.4:443</code> to the Brook Server</li>
<li>The Brook Server sends a network request to <code>1.2.3.4:443</code> and returns the data to the Brook client</li>
<li>The Brook client then returns the data to the app</li>
</ol>
</li>
<li>The app receives the response data</li>
</ol>
<h2 id="with-brook-fake-dns-on-but-the-app-uses-the-systems-secure-dns-or-its-own-secure-dns">With Brook: Fake DNS On, But the App Uses the System&#39;s Secure DNS or Its Own Secure DNS</h2>
<ol>
<li>When an app requests a domain name address, such as <code>google.com:443</code></li>
<li>A DNS resolution will be performed first. That is, the app will send a network request to the secure DNS, such as <code>8.8.8.8:443</code>, to inquire about the IP of <code>google.com</code></li>
<li>The Brook client detects that an app is sending a network request to <code>8.8.8.8:443</code>. <mark>This will trigger the <code>in_address</code> variable, carrying information such as <code>ipaddress</code></mark><ol>
<li>The Brook client sends <code>8.8.8.8:443</code> to the Brook Server</li>
<li>The Brook Server sends a network request to <code>8.8.8.8:443</code>, and returns the result, such as <code>1.2.3.4</code>, to the Brook client</li>
<li>The Brook client then returns the result to the app</li>
</ol>
</li>
<li>The app combines the IP and port into an IP address, such as: <code>1.2.3.4:443</code></li>
<li>The app makes a network request to the IP address <code>1.2.3.4:443</code></li>
<li>The Brook client detects that an app is sending a network request to <code>1.2.3.4:443</code>. <mark>This will trigger the <code>in_address</code> variable, carrying information such as <code>ipaddress</code></mark><ol>
<li>The Brook client sends <code>1.2.3.4:443</code> to the Brook Server</li>
<li>The Brook Server sends a network request to <code>1.2.3.4:443</code> and returns the data to the Brook client</li>
<li>The Brook client then returns the data to the app</li>
</ol>
</li>
<li>The app receives the response data</li>
</ol>
<h2 id="handle-variable-trigger">Handle Variable Trigger</h2>
<ul>
<li>When the <code>in_brooklinks</code> variable is triggered:<ul>
<li>This is currently the only variable that gets triggered before the Brook client starts.</li>
<li>We know that Brook starts with your choice of a Brook Server, and this variable lets you specify multiple Brook Servers.</li>
<li>Then during runtime, you can use one of these Brook Servers as needed.</li>
</ul>
</li>
<li>When the <code>in_dnsquery</code> variable is triggered, you can process as needed, such as:<ul>
<li>Blocking, such as to prevent ad domain names.</li>
<li>Directly specifying the response IP.</li>
<li>Letting the system DNS resolve this domain.</li>
<li>Letting Bypass DNS resolve this domain.</li>
<li>And so on.</li>
</ul>
</li>
<li>When the <code>in_address</code> variable is triggered, you can process as needed, such as:<ul>
<li>Block this connection.</li>
<li>Rewrite the destination.</li>
<li>If it&#39;s a domain address, you can specify that Bypass DNS is responsible for resolving the IP of this domain.</li>
<li>Allow it to connect directly without going through a proxy.</li>
<li>If it&#39;s HTTP/HTTPS, you can start MITM (Man-In-The-Middle), which will subsequently trigger <code>in_httprequest</code> and <code>in_httpresponse</code>.</li>
<li>And so on.</li>
</ul>
</li>
<li>When the <code>in_httprequest</code> variable is triggered, you can process as needed, such as:<ul>
<li>Modifying the HTTP request.</li>
<li>Returning a custom HTTP response directly.</li>
</ul>
</li>
<li>When the <code>in_httpresponse</code> variable is triggered, you can process as needed, such as:<ul>
<li>Modifying the HTTP response.</li>
</ul>
</li>
</ul>
<p>For detailed information on the properties and responses of variables, please refer to the following content.</p>
<h2 id="variables">Variables</h2>
<table>
<thead>
<tr>
@@ -1463,7 +1581,7 @@
<td>map</td>
</tr>
</tbody></table>
<h3 id="in_brooklinks">in_brooklinks</h3>
<h2 id="in_brooklinks">in_brooklinks</h2>
<table>
<thead>
<tr>
@@ -1509,7 +1627,7 @@
<td>...</td>
</tr>
</tbody></table>
<h3 id="in_dnsquery">in_dnsquery</h3>
<h2 id="in_dnsquery">in_dnsquery</h2>
<table>
<thead>
<tr>
@@ -1585,7 +1703,7 @@
<td>custom name</td>
</tr>
</tbody></table>
<h3 id="in_address">in_address</h3>
<h2 id="in_address">in_address</h2>
<table>
<thead>
<tr>
@@ -1715,7 +1833,7 @@
<td>custom name</td>
</tr>
</tbody></table>
<h3 id="in_httprequest">in_httprequest</h3>
<h2 id="in_httprequest">in_httprequest</h2>
<table>
<thead>
<tr>
@@ -1751,7 +1869,7 @@
</tr>
</tbody></table>
<p><code>out</code>, must be set to a request or response</p>
<h3 id="in_httpresponse">in_httpresponse</h3>
<h2 id="in_httpresponse">in_httpresponse</h2>
<table>
<thead>
<tr>
@@ -1781,10 +1899,8 @@
</tr>
</tbody></table>
<p><code>out</code>, must be set to a response</p>
<h2 id="module">Module</h2>
<p>There are already some modules: <a href="https://github.com/txthinking/brook/blob/master/programmable/modules/">https://github.com/txthinking/brook/blob/master/programmable/modules/</a></p>
<h3 id="brook-gui">Brook GUI</h3>
<p>In Brook GUI, scripts are abstracted into modules, and it will automatically combine <a href="https://github.com/txthinking/brook/blob/master/programmable/modules/_header.tengo">_header.tengo</a> and <a href="https://github.com/txthinking/brook/blob/master/programmable/modules/_footer.tengo">_footer.tengo</a>, so you only need to write the module itself.</p>
<h2 id="modules">Modules</h2>
<p>In Brook GUI, scripts are abstracted into <strong>Modules</strong>. There are already <a href="https://github.com/txthinking/brook/blob/master/programmable/modules/">some modules</a>, and thre is no magic, it just automatically combine <a href="https://github.com/txthinking/brook/blob/master/programmable/modules/_header.tengo">_header.tengo</a> and <a href="https://github.com/txthinking/brook/blob/master/programmable/modules/_footer.tengo">_footer.tengo</a>, so you only need to write the module itself.</p>
<pre><code>modules = append(modules, {
// If you want to predefine multiple brook links, and then programmatically specify which one to connect to, then define `brooklinks` key a function
brooklinks: func(m) {
@@ -1808,8 +1924,9 @@
}
})
</code></pre>
<h3 id="tun2brook">tun2brook</h3>
<p>If you are using tun2brook, you can combine multiple modules into a complete script in the following way. For example:</p>
<h2 id="tun2brook">tun2brook</h2>
<p><a href="https://github.com/txthinking/tun2brook">https://github.com/txthinking/tun2brook</a></p>
<p>If you are using tun2brook, you can manually combine multiple modules into a complete script in the following way. For example:</p>
<pre><code>cat _header.tengo &gt; my.tengo
cat block_google_secure_dns.tengo &gt;&gt; my.tengo
@@ -1872,7 +1989,7 @@ Functions
</ul>
<h2 id="debug">Debug</h2>
<p>If you are writing complex scripts, the GUI may not be convenient for debugging. It is recommended to use <a href="https://github.com/txthinking/tun2brook">tun2brook</a> on desktop to debug with <code>fmt.println</code></p>
<h2 id="install-ca">Install CA</h2>
<h2 id="ca">CA</h2>
<p><a href="https://txthinking.github.io/ca/ca.pem">https://txthinking.github.io/ca/ca.pem</a></p>
<table>
<thead>
@@ -1901,120 +2018,63 @@ Functions
<blockquote>
<p>Some software may not read the system CAyou can use <code>curl --cacert ~/.nami/bin/ca.pem</code> to debug</p>
</blockquote>
<h1 id="resources">Resources</h1>
<table>
<thead>
<tr>
<th>CLI</th>
<th>Description</th>
</tr>
</thead>
<tbody><tr>
<td><a href="https://github.com/txthinking/nami">nami</a></td>
<td>A clean and tidy decentralized package manager</td>
</tr>
<tr>
<td><a href="https://github.com/txthinking/joker">joker</a></td>
<td>Joker can turn process into daemon. Zero-Configuration</td>
</tr>
<tr>
<td><a href="https://github.com/txthinking/nico">nico</a></td>
<td>Nico can work with brook wsserver together</td>
</tr>
<tr>
<td><a href="https://github.com/txthinking/zhen">zhen</a></td>
<td>zhen - process and cron manager</td>
</tr>
<tr>
<td><a href="https://github.com/txthinking/tun2brook">tun2brook</a></td>
<td>Proxy all traffic just one line command</td>
</tr>
<tr>
<td><a href="https://github.com/txthinking/mad">mad</a></td>
<td>Generate root CA and derivative certificate for any domains and any IPs</td>
</tr>
<tr>
<td><a href="https://github.com/txthinking/hancock">hancock</a></td>
<td>Manage multiple remote servers and execute commands remotely</td>
</tr>
<tr>
<td><a href="https://github.com/txthinking/sshexec">sshexec</a></td>
<td>A command-line tool to execute remote command through ssh</td>
</tr>
<tr>
<td><a href="https://github.com/txthinking/jb">jb</a></td>
<td>write script in an easier way than bash</td>
</tr>
<tr>
<td><a href="https://github.com/txthinking/bash">bash</a></td>
<td>Many one-click scripts</td>
</tr>
<tr>
<td><a href="https://archlinux.org/packages/extra/x86_64/brook/">pacman</a></td>
<td><code>pacman -S brook</code></td>
</tr>
<tr>
<td><a href="https://formulae.brew.sh/formula/brook">brew</a></td>
<td><code>brew install brook</code></td>
</tr>
<tr>
<td><a href="https://hub.docker.com/r/txthinking/brook">docker</a></td>
<td><code>docker run txthinking/brook</code></td>
</tr>
</tbody></table>
<table>
<thead>
<tr>
<th>Resources</th>
<th>Description</th>
</tr>
</thead>
<tbody><tr>
<td><a href="https://github.com/txthinking/brook/tree/master/protocol">Protocol</a></td>
<td>Brook Protocol</td>
</tr>
<tr>
<td><a href="https://www.txthinking.com/talks/">Blog</a></td>
<td>Some articles you should read</td>
</tr>
<tr>
<td><a href="https://www.youtube.com/txthinking">YouTube</a></td>
<td>Some videos you should watch</td>
</tr>
<tr>
<td><a href="https://t.me/txthinking">Telegram</a></td>
<td>Ask questions here</td>
</tr>
<tr>
<td><a href="https://t.me/s/txthinking_news">Announce</a></td>
<td>All news you should care</td>
</tr>
<tr>
<td><a href="https://github.com/txthinking">GitHub</a></td>
<td>Other useful repos</td>
</tr>
<tr>
<td><a href="https://chromewebstore.google.com/detail/socks5-configurator/hnpgnjkeaobghpjjhaiemlahikgmnghb">Socks5 Configurator</a></td>
<td>If you prefer CLI brook client</td>
</tr>
<tr>
<td><a href="https://chromewebstore.google.com/detail/ipvbar/nepjlegfiihpkcdhlmaebfdfppckonlj">IPvBar</a></td>
<td>See domain, IP and country in browser</td>
</tr>
<tr>
<td><a href="https://www.txthinking.com/ssh.html">TxThinking SSH</a></td>
<td>A SSH Terminal</td>
</tr>
<tr>
<td><a href="https://github.com/txthinkinginc/brook-user-system">brook-user-system</a></td>
<td>A Brook User System</td>
</tr>
<tr>
<td><a href="https://www.txthinking.com">TxThinking</a></td>
<td>Everything</td>
</tr>
</tbody></table>
<h2 id="openwrt">OpenWrt</h2>
<p><a href="https://www.txthinking.com/talks/articles/brook-openwrt-en.article">https://www.txthinking.com/talks/articles/brook-openwrt-en.article</a></p>
<h2 id="ipv6">IPv6</h2>
<p>Brook&#39;s stance on IPv6 is positive, if your server or local environment doesn&#39;t have an IPv6 stack, read <a href="https://www.txthinking.com/talks/articles/brook-ipv6-en.article">this article</a>.</p>
<h2 id="troubleshooting-steps">Troubleshooting Steps</h2>
<ol>
<li>After adding your Server to the Brook client</li>
<li>If your Server uses a domain and has not specified an IP address via <code>brook link --address</code>, then Brook client will attempt to resolve the domain&#39;s IP using local DNS, preferring AAAA record. For example:<ul>
<li>domain.com:9999</li>
<li>ws://domain.com:9999</li>
<li>wss://domain.com:9999</li>
<li>quic://domain.com:9999</li>
</ul>
</li>
<li>Connectivity check: Go to the Server details page and click <code>Connectivity Check</code>. If it works sometimes but not others, this indicates instability.</li>
<li>After connected</li>
<li>Brook will change your system DNS to the System DNS configured in Brook (by default Google&#39;s DNS). In very rare cases, this change may be ignored on Windows, you can confirm this in the system settings.</li>
<li>Test IPv4 TCP: Use <code>Test IPv4 TCP</code> for testing; this test has hardcoded the IP address, so does not trigger DNS resolution.</li>
<li>Test IPv4 UDP: Use <code>Test IPv4 UDP</code> for testing; this test has hardcoded the IP address, so does not trigger DNS resolution.</li>
<li>Test IPv6 TCP: Use <code>Test IPv6 TCP</code> for testing; this test has hardcoded the IP address, so does not trigger DNS resolution.</li>
<li>Test IPv6 UDP: Use <code>Test IPv6 UDP</code> for testing; this test has hardcoded the IP address, so does not trigger DNS resolution.</li>
<li>Test TCP and UDP: Use the <code>Echo Client</code> for testing. If the echo server entered is a domain address, it will trigger DNS resolution.</li>
<li>Ensure the effectiveness of Fake DNS: Fake DNS is essential to do something with a domain or domain address. Generally, enable the <code>Block Google Secure DNS</code> module is sufficient. For other cases, refer to <a href="https://www.txthinking.com/talks/articles/brook-fakedns-en.article">this article</a>.</li>
<li>If your local or Server does not support IPv6: Refer to <a href="https://www.txthinking.com/talks/articles/brook-ipv6-en.article">this article</a>.</li>
<li>macOS App Mode: Refer to <a href="https://www.txthinking.com/talks/articles/macos-app-mode.article">this article</a>.</li>
<li>Windows:<ul>
<li>The client can pass the tests without any special configuration on a brand-new, genuine Windows 11.</li>
<li>Be aware that the Windows system time is often incorrect.</li>
<li>Do not have other similar network software installed; they can cause conflicting network settings in the system.</li>
<li>Try restarting the computer.</li>
<li>Windows Defender may ask for permission to connect to the network or present other issues.</li>
<li>System DNS may need to be set to 8.8.8.8 and/or 2001:4860:4860::8888</li>
</ul>
</li>
<li>Android:<ul>
<li>The client can pass the tests without any special configuration on the official Google ROM.</li>
<li>Different ROMs may have made different modifications to the system.</li>
<li>Permission for background running might require separate settings.</li>
<li>System DNS may need to be set to 8.8.8.8 and/or 2001:4860:4860::8888</li>
</ul>
</li>
<li>Bypass traffic such as China, usually requires the following modules to be activated:<ul>
<li><code>Block Google Secure DNS</code></li>
<li><code>Bypass Geo</code></li>
<li><code>Bypass Apple</code>: To prevent issues receiving Apple message notifications.</li>
<li><code>Bypass China domain</code> or <code>Bypass China domain A</code>: The former uses <code>Bypass DNS</code> to obtain the IP, then <code>Bypass Geo</code> or other modules decide whether to bypass; the latter bypasses directly after obtaining the IP with <code>Bypass DNS</code> using A records. The latter is needed if your local does not support IPv6.</li>
<li>If you are a <a href="https://www.txthinking.com/shiliew.html">Shiliew</a> user, some modules are enabled by default, which is usually sufficient.</li>
</ul>
</li>
<li>Search <a href="https://github.com/txthinking/brook/issues?q=is%3Aissue">GitHub issues</a></li>
<li>Read the <a href="https://www.txthinking.com/talks/">blog</a></li>
<li>Read the <a href="https://brook.app">documentation</a></li>
<li>Submit <a href="https://github.com/txthinking/brook/issues?q=is%3Aissue">new issue</a></li>
<li>Seek help in the <a href="https://t.me/txthinking">group</a></li>
</ol>
<h1 id="cli-documentation">CLI Documentation</h1>
<p>Each subcommand has a <code>--example</code> parameter that can print the minimal example of usage</p>
<h1 id="name">NAME</h1>
<p>Brook - A cross-platform programmable network tool</p>
<h1 id="synopsis">SYNOPSIS</h1>
@@ -2118,7 +2178,7 @@ Functions
<li><p><strong>--updateListInterval</strong>=&quot;&quot;: This option will be removed in a future version, please use the global option instead (default: 0)</p>
</li>
</ul>
<h2 id="client">client</h2>
<h2 id="client-2">client</h2>
<p>Start a brook client that supports tcp and udp. It can open a socks5 proxy, [src &lt;-&gt; socks5 &lt;-&gt; $ brook client &lt;-&gt; $ brook server &lt;-&gt; dst]</p>
<ul>
<li><p><strong>--example</strong>: Show a minimal example of usage</p>
@@ -2805,13 +2865,112 @@ Functions
<h2 id="brook-socks5tohttp-can-convert-a-socks5-to-a-http-proxy">brook socks5tohttp can convert a socks5 to a http proxy</h2>
<pre><code>brook socks5tohttp --socks5 127.0.0.1:1080 --listen 127.0.0.1:8010
</code></pre>
<h2 id="brook-pac-creates-pac-server">brook pac creates pac server</h2>
<pre><code>brook pac --listen 127.0.0.1:8080 --proxy &#39;SOCKS5 127.0.0.1:1080; SOCKS 127.0.0.1:1080; DIRECT&#39; --bypassDomainList ...
</code></pre>
<h2 id="brook-pac-creates-pac-file">brook pac creates pac file</h2>
<pre><code>brook pac --file proxy.pac --proxy &#39;SOCKS5 127.0.0.1:1080; SOCKS 127.0.0.1:1080; DIRECT&#39; --bypassDomainList ...
</code></pre>
<h2 id="there-are-countless-examples-for-more-feature-suggestions-its-best-to-look-at-the-commands-and-parameters-in-the-cli-documentation-one-by-one-and-blog-youtube">There are countless examples; for more feature suggestions, it&#39;s best to look at the commands and parameters in the CLI documentation one by one, and blog, YouTube...</h2>
<h1 id="resources">Resources</h1>
<table>
<thead>
<tr>
<th>CLI</th>
<th>Description</th>
</tr>
</thead>
<tbody><tr>
<td><a href="https://github.com/txthinking/nami">nami</a></td>
<td>A clean and tidy decentralized package manager</td>
</tr>
<tr>
<td><a href="https://github.com/txthinking/joker">joker</a></td>
<td>Joker can turn process into daemon. Zero-Configuration</td>
</tr>
<tr>
<td><a href="https://github.com/txthinking/nico">nico</a></td>
<td>Nico can work with brook wsserver together</td>
</tr>
<tr>
<td><a href="https://github.com/txthinking/z">z</a></td>
<td>z - process manager</td>
</tr>
<tr>
<td><a href="https://github.com/txthinking/tun2brook">tun2brook</a></td>
<td>Proxy all traffic just one line command</td>
</tr>
<tr>
<td><a href="https://github.com/txthinking/mad">mad</a></td>
<td>Generate root CA and derivative certificate for any domains and any IPs</td>
</tr>
<tr>
<td><a href="https://github.com/txthinking/hancock">hancock</a></td>
<td>Manage multiple remote servers and execute commands remotely</td>
</tr>
<tr>
<td><a href="https://github.com/txthinking/sshexec">sshexec</a></td>
<td>A command-line tool to execute remote command through ssh</td>
</tr>
<tr>
<td><a href="https://github.com/txthinking/jb">jb</a></td>
<td>write script in an easier way than bash</td>
</tr>
<tr>
<td><a href="https://github.com/txthinking/bash">bash</a></td>
<td>Many one-click scripts</td>
</tr>
<tr>
<td><a href="https://hub.docker.com/r/txthinking/brook">docker</a></td>
<td><code>docker run txthinking/brook</code></td>
</tr>
</tbody></table>
<table>
<thead>
<tr>
<th>Resources</th>
<th>Description</th>
</tr>
</thead>
<tbody><tr>
<td><a href="https://github.com/txthinking/brook/tree/master/protocol">Protocol</a></td>
<td>Brook Protocol</td>
</tr>
<tr>
<td><a href="https://www.txthinking.com/talks/">Blog</a></td>
<td>Some articles you should read</td>
</tr>
<tr>
<td><a href="https://www.youtube.com/txthinking">YouTube</a></td>
<td>Some videos you should watch</td>
</tr>
<tr>
<td><a href="https://t.me/txthinking">Telegram</a></td>
<td>Ask questions here</td>
</tr>
<tr>
<td><a href="https://t.me/s/txthinking_news">Announce</a></td>
<td>All news you should care</td>
</tr>
<tr>
<td><a href="https://github.com/txthinking">GitHub</a></td>
<td>Other useful repos</td>
</tr>
<tr>
<td><a href="https://chromewebstore.google.com/detail/socks5-configurator/hnpgnjkeaobghpjjhaiemlahikgmnghb">Socks5 Configurator</a></td>
<td>If you prefer CLI brook client</td>
</tr>
<tr>
<td><a href="https://chromewebstore.google.com/detail/ipvbar/nepjlegfiihpkcdhlmaebfdfppckonlj">IPvBar</a></td>
<td>See domain, IP and country in browser</td>
</tr>
<tr>
<td><a href="https://www.txthinking.com/ssh.html">TxThinking SSH</a></td>
<td>A SSH Terminal</td>
</tr>
<tr>
<td><a href="https://github.com/txthinkinginc/brook-user-system">brook-user-system</a></td>
<td>A Brook User System</td>
</tr>
<tr>
<td><a href="https://www.txthinking.com">TxThinking</a></td>
<td>Everything</td>
</tr>
</tbody></table>
</div>
</div>
+1 -3
View File
@@ -5,15 +5,13 @@
| [nami](https://github.com/txthinking/nami) | A clean and tidy decentralized package manager |
| [joker](https://github.com/txthinking/joker) | Joker can turn process into daemon. Zero-Configuration |
| [nico](https://github.com/txthinking/nico) | Nico can work with brook wsserver together |
| [zhen](https://github.com/txthinking/zhen) | zhen - process and cron manager |
| [z](https://github.com/txthinking/z) | z - process manager |
| [tun2brook](https://github.com/txthinking/tun2brook) | Proxy all traffic just one line command |
| [mad](https://github.com/txthinking/mad) | Generate root CA and derivative certificate for any domains and any IPs |
| [hancock](https://github.com/txthinking/hancock) | Manage multiple remote servers and execute commands remotely |
| [sshexec](https://github.com/txthinking/sshexec) | A command-line tool to execute remote command through ssh |
| [jb](https://github.com/txthinking/jb) | write script in an easier way than bash |
| [bash](https://github.com/txthinking/bash) | Many one-click scripts |
| [pacman](https://archlinux.org/packages/extra/x86_64/brook/) | `pacman -S brook` |
| [brew](https://formulae.brew.sh/formula/brook) | `brew install brook` |
| [docker](https://hub.docker.com/r/txthinking/brook) | `docker run txthinking/brook` |
| Resources | Description |
+4 -4
View File
@@ -1,7 +1,7 @@
{
"version": "20240606",
"text": "Refer to get Brook Plus for free",
"link": "https://www.txthinking.com/brook.html#referrals",
"text_zh": "邀请以免费获得 Brook Plus",
"link_zh": "https://www.txthinking.com/brook.html#referrals"
"text": "Brook Client Basic Knowledge",
"link": "https://www.txthinking.com/talks/articles/brook-en.article",
"text_zh": "Brook 客户端基础知识",
"link_zh": "https://www.txthinking.com/talks/articles/brook.article"
}
+2
View File
@@ -69,3 +69,5 @@ func WithDSCP(dscp uint8) Addition {
metadata.DSCP = dscp
}
}
func Placeholder(metadata *C.Metadata) {}
+1 -1
View File
@@ -13,7 +13,7 @@ import (
"github.com/metacubex/mihomo/transport/socks5"
)
func newClient(srcConn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) *http.Client {
func newClient(srcConn net.Conn, tunnel C.Tunnel, additions []inbound.Addition) *http.Client { // additions using slice let caller can change its value (without size) after newClient return
return &http.Client{
Transport: &http.Transport{
// from http.DefaultTransport
+32 -35
View File
@@ -10,10 +10,9 @@ import (
"sync"
"github.com/metacubex/mihomo/adapter/inbound"
"github.com/metacubex/mihomo/common/lru"
N "github.com/metacubex/mihomo/common/net"
"github.com/metacubex/mihomo/component/auth"
C "github.com/metacubex/mihomo/constant"
authStore "github.com/metacubex/mihomo/listener/auth"
"github.com/metacubex/mihomo/log"
)
@@ -31,8 +30,10 @@ func (b *bodyWrapper) Read(p []byte) (n int, err error) {
return n, err
}
func HandleConn(c net.Conn, tunnel C.Tunnel, cache *lru.LruCache[string, bool], additions ...inbound.Addition) {
client := newClient(c, tunnel, additions...)
func HandleConn(c net.Conn, tunnel C.Tunnel, authenticator auth.Authenticator, additions ...inbound.Addition) {
additions = append(additions, inbound.Placeholder) // Add a placeholder for InUser
inUserIdx := len(additions) - 1
client := newClient(c, tunnel, additions)
defer client.CloseIdleConnections()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
@@ -41,7 +42,8 @@ func HandleConn(c net.Conn, tunnel C.Tunnel, cache *lru.LruCache[string, bool],
conn := N.NewBufferedConn(c)
keepAlive := true
trusted := cache == nil // disable authenticate if lru is nil
trusted := authenticator == nil // disable authenticate if lru is nil
lastUser := ""
for keepAlive {
peekMutex.Lock()
@@ -57,12 +59,10 @@ func HandleConn(c net.Conn, tunnel C.Tunnel, cache *lru.LruCache[string, bool],
var resp *http.Response
if !trusted {
var user string
resp, user = authenticate(request, cache)
additions = append(additions, inbound.WithInUser(user))
trusted = resp == nil
}
var user string
resp, user = authenticate(request, authenticator) // always call authenticate function to get user
trusted = trusted || resp == nil
additions[inUserIdx] = inbound.WithInUser(user)
if trusted {
if request.Method == http.MethodConnect {
@@ -89,6 +89,13 @@ func HandleConn(c net.Conn, tunnel C.Tunnel, cache *lru.LruCache[string, bool],
return // hijack connection
}
// ensure there is a client with correct additions
// when the authenticated user changed, outbound client should close idle connections
if user != lastUser {
client.CloseIdleConnections()
lastUser = user
}
removeHopByHopHeaders(request.Header)
removeExtraHTTPHostPort(request)
@@ -138,34 +145,24 @@ func HandleConn(c net.Conn, tunnel C.Tunnel, cache *lru.LruCache[string, bool],
_ = conn.Close()
}
func authenticate(request *http.Request, cache *lru.LruCache[string, bool]) (resp *http.Response, u string) {
authenticator := authStore.Authenticator()
func authenticate(request *http.Request, authenticator auth.Authenticator) (resp *http.Response, user string) {
if inbound.SkipAuthRemoteAddress(request.RemoteAddr) {
authenticator = nil
}
if authenticator != nil {
credential := parseBasicProxyAuthorization(request)
if credential == "" {
resp := responseWith(request, http.StatusProxyAuthRequired)
resp.Header.Set("Proxy-Authenticate", "Basic")
return resp, ""
}
authed, exist := cache.Get(credential)
if !exist {
user, pass, err := decodeBasicProxyAuthorization(credential)
authed = err == nil && authenticator.Verify(user, pass)
u = user
cache.Set(credential, authed)
}
if !authed {
log.Infoln("Auth failed from %s", request.RemoteAddr)
return responseWith(request, http.StatusForbidden), u
}
credential := parseBasicProxyAuthorization(request)
if credential == "" && authenticator != nil {
resp = responseWith(request, http.StatusProxyAuthRequired)
resp.Header.Set("Proxy-Authenticate", "Basic")
return
}
return nil, u
user, pass, err := decodeBasicProxyAuthorization(credential)
authed := authenticator == nil || (err == nil && authenticator.Verify(user, pass))
if !authed {
log.Infoln("Auth failed from %s", request.RemoteAddr)
return responseWith(request, http.StatusForbidden), user
}
log.Debugln("Auth success from %s -> %s", request.RemoteAddr, user)
return
}
func responseWith(request *http.Request, statusCode int) *http.Response {
+5 -9
View File
@@ -4,9 +4,10 @@ import (
"net"
"github.com/metacubex/mihomo/adapter/inbound"
"github.com/metacubex/mihomo/common/lru"
"github.com/metacubex/mihomo/component/auth"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/constant/features"
authStore "github.com/metacubex/mihomo/listener/auth"
)
type Listener struct {
@@ -32,10 +33,10 @@ func (l *Listener) Close() error {
}
func New(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener, error) {
return NewWithAuthenticate(addr, tunnel, true, additions...)
return NewWithAuthenticate(addr, tunnel, authStore.Authenticator(), additions...)
}
func NewWithAuthenticate(addr string, tunnel C.Tunnel, authenticate bool, additions ...inbound.Addition) (*Listener, error) {
func NewWithAuthenticate(addr string, tunnel C.Tunnel, authenticator auth.Authenticator, additions ...inbound.Addition) (*Listener, error) {
isDefault := false
if len(additions) == 0 {
isDefault = true
@@ -50,11 +51,6 @@ func NewWithAuthenticate(addr string, tunnel C.Tunnel, authenticate bool, additi
return nil, err
}
var c *lru.LruCache[string, bool]
if authenticate {
c = lru.New[string, bool](lru.WithAge[string, bool](30))
}
hl := &Listener{
listener: l,
addr: addr,
@@ -79,7 +75,7 @@ func NewWithAuthenticate(addr string, tunnel C.Tunnel, authenticate bool, additi
continue
}
}
go HandleConn(conn, tunnel, c, additions...)
go HandleConn(conn, tunnel, authenticator, additions...)
}
}()
+4 -6
View File
@@ -4,9 +4,9 @@ import (
"net"
"github.com/metacubex/mihomo/adapter/inbound"
"github.com/metacubex/mihomo/common/lru"
N "github.com/metacubex/mihomo/common/net"
C "github.com/metacubex/mihomo/constant"
authStore "github.com/metacubex/mihomo/listener/auth"
"github.com/metacubex/mihomo/listener/http"
"github.com/metacubex/mihomo/listener/socks"
"github.com/metacubex/mihomo/transport/socks4"
@@ -16,7 +16,6 @@ import (
type Listener struct {
listener net.Listener
addr string
cache *lru.LruCache[string, bool]
closed bool
}
@@ -53,7 +52,6 @@ func New(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener
ml := &Listener{
listener: l,
addr: addr,
cache: lru.New[string, bool](lru.WithAge[string, bool](30)),
}
go func() {
for {
@@ -70,14 +68,14 @@ func New(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener
continue
}
}
go handleConn(c, tunnel, ml.cache, additions...)
go handleConn(c, tunnel, additions...)
}
}()
return ml, nil
}
func handleConn(conn net.Conn, tunnel C.Tunnel, cache *lru.LruCache[string, bool], additions ...inbound.Addition) {
func handleConn(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) {
N.TCPKeepAlive(conn)
bufConn := N.NewBufferedConn(conn)
@@ -92,6 +90,6 @@ func handleConn(conn net.Conn, tunnel C.Tunnel, cache *lru.LruCache[string, bool
case socks5.Version:
socks.HandleSocks5(bufConn, tunnel, additions...)
default:
http.HandleConn(bufConn, tunnel, cache, additions...)
http.HandleConn(bufConn, tunnel, authStore.Authenticator(), additions...)
}
}
+88
View File
@@ -0,0 +1,88 @@
name: "[Single] Build Linux"
on:
workflow_dispatch:
inputs:
nightly:
description: "Nightly prepare"
required: true
type: boolean
default: false
tag:
description: "Release Tag"
required: true
type: string
workflow_call:
inputs:
nightly:
description: "Nightly prepare"
required: true
type: boolean
default: false
tag:
description: "Release Tag"
required: true
type: string
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Rust stable
run: |
rustup install stable --profile minimal --no-self-update
rustup default stable
- uses: Swatinem/rust-cache@v2
with:
workspaces: "./backend/"
prefix-key: "rust-stable"
key: ubuntu-latest
shared-key: "release"
- name: Install Node latest
uses: actions/setup-node@v4
with:
node-version: latest
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
run_install: false
- name: Install Dependencies
run: |
sudo apt-get update
sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf openssl
- name: Pnpm install deps and download resources
run: |
pnpm i
pnpm check
- name: Nightly Prepare
if: ${{ inputs.nightly == true }}
run: |
pnpm prepare:nightly
- name: Tauri build
uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
with:
tagName: ${{ inputs.tag }}
releaseName: "Clash Nyanpasu Dev"
releaseBody: "More new features are now supported."
releaseDraft: false
prerelease: true
tauriScript: pnpm tauri
args: -f nightly -c ./backend/tauri/tauri.nightly.conf.json
+128
View File
@@ -0,0 +1,128 @@
name: "[Single] Build macOS"
on:
workflow_dispatch:
inputs:
aarch64:
description: "Build aarch64 pkg"
required: true
type: boolean
default: false
nightly:
description: "Nightly prepare"
required: true
type: boolean
default: false
tag:
description: "Release Tag"
required: true
type: string
workflow_call:
inputs:
aarch64:
description: "Build aarch64 pkg"
required: true
type: boolean
default: false
nightly:
description: "Nightly prepare"
required: true
type: boolean
default: false
tag:
description: "Release Tag"
required: true
type: string
jobs:
build:
runs-on: ${{ inputs.aarch64 && 'macos-14' || 'macos-13' }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: install Rust stable
run: |
rustup install stable --profile minimal --no-self-update
rustup default stable
- uses: Swatinem/rust-cache@v2
with:
workspaces: "./backend/"
prefix-key: "rust-stable"
key: ${{ inputs.aarch64 && 'macos-14' || 'macos-13' }}
shared-key: "release"
- name: Install the missing rust target (aarch64 Only)
if: ${{ inputs.aarch64 == 'macos-14' }}
run: |
rustup target add aarch64-apple-darwin
- name: Install Node latest
uses: actions/setup-node@v4
with:
node-version: latest
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
run_install: false
- name: Set xcode version (amd64 Only)
uses: maxim-lobanov/setup-xcode@v1
if: ${{ inputs.aarch64 == false }}
with:
xcode-version: "15.0"
- name: Pnpm install
run: |
pnpm i
pnpm check
- name: Pnpm check (macOS amd64)
if: ${{ inputs.aarch64 == false }}
run: |
pnpm check
- name: Pnpm check (macOS aarch64)
if: ${{ inputs.aarch64 == true }}
run: |
pnpm check --arch arm64 --sidecar-host aarch64-apple-darwin
- name: Nightly Prepare
if: ${{ inputs.nightly == true }}
run: |
pnpm prepare:nightly
- name: Tauri build
if: ${{ inputs.aarch64 == false }}
uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
with:
tagName: ${{ inputs.tag }}
releaseName: "Clash Nyanpasu Dev"
releaseBody: "More new features are now supported."
releaseDraft: false
prerelease: true
tauriScript: pnpm tauri
args: -f nightly -c ./backend/tauri/tauri.nightly.conf.json
- name: Tauri build with Upload (macOS aarch64)
if: ${{ inputs.aarch64 == true }}
env:
TAG_NAME: ${{ inputs.tag }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
run: |
pnpm build:nightly --target aarch64-apple-darwin
pnpm upload:osx-aarch64
@@ -0,0 +1,106 @@
name: "[Single] Build Windows NSIS"
on:
workflow_dispatch:
inputs:
portable:
description: "Build Portable pkg"
required: true
type: boolean
default: false
nightly:
description: "Nightly prepare"
required: true
type: boolean
default: false
tag:
description: "Release Tag"
required: true
type: string
workflow_call:
inputs:
portable:
description: "Build Portable pkg"
required: true
type: boolean
default: false
nightly:
description: "Nightly prepare"
required: true
type: boolean
default: false
tag:
description: "Release Tag"
required: true
type: string
jobs:
build:
runs-on: windows-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Rust stable
run: |
rustup install stable --profile minimal --no-self-update
rustup default stable
- uses: Swatinem/rust-cache@v2
with:
workspaces: "./backend/"
prefix-key: "rust-stable"
key: windows-latest
shared-key: "release"
- name: Install Node latest
uses: actions/setup-node@v4
with:
node-version: latest
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
run_install: false
- name: Pnpm install deps and download resources
run: |
pnpm i
pnpm check
- name: Nightly Prepare (Windows NSIS and Portable)
if: ${{ inputs.nightly == true }}
run: |
pnpm prepare:nightly --nsis
- name: Tauri build
uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
with:
tagName: ${{ inputs.tag }}
releaseName: "Clash Nyanpasu Dev"
releaseBody: "More new features are now supported."
releaseDraft: false
prerelease: true
tauriScript: pnpm tauri
args: -f nightly -c ./backend/tauri/tauri.nightly.conf.json
- name: Portable Bundle
if: ${{ inputs.portable == true }}
run: |
pnpm portable
env:
TAG_NAME: ${{ inputs.tag }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
VITE_WIN_PORTABLE: 1
@@ -0,0 +1,54 @@
name: "[Single] Create Updater"
on:
workflow_dispatch:
inputs:
nightly:
description: "Nightly"
required: true
type: boolean
default: false
workflow_call:
inputs:
nightly:
description: "Nightly"
required: true
type: boolean
default: false
jobs:
updater:
name: Update Nightly Updater
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-tags: true # Fetch all tags
- name: Install Node latest
uses: actions/setup-node@v4
with:
node-version: latest
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
run_install: false
- name: Pnpm install
run: pnpm i
- name: Update Updater
if: ${{ inputs.nightly == true }}
run: pnpm updater:nightly
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Release updater file
if: ${{ inputs.nightly == false }}
run: pnpm updater
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
RELEASE_BODY: ${{ github.event.release.body }}
@@ -0,0 +1,43 @@
name: "[Single] Delete Current Releases"
on:
workflow_dispatch:
inputs:
tag:
description: "Release Tag"
required: true
type: string
workflow_call:
inputs:
tag:
description: "Release Tag"
required: true
type: string
jobs:
delete:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Delete current release assets
uses: mknejp/delete-release-assets@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ inputs.tag }}
fail-if-no-assets: false
fail-if-no-release: false
assets: |
*.zip
*.gz
*.AppImage
*.deb
*.rpm
*.dmg
*.msi
*.sig
*.exe
*.json
@@ -0,0 +1,53 @@
name: "[Single] Send Message to Telegram"
on:
workflow_dispatch:
inputs:
nightly:
description: "Nightly"
required: true
type: boolean
default: false
workflow_call:
inputs:
nightly:
description: "Nightly"
required: true
type: boolean
default: false
jobs:
telegram:
name: Notify Telegram
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: latest
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
run_install: false
- name: Pnpm install
run: pnpm i
- name: Send Releases
run: |
if [ "${{ inputs.nightly }}" = "true" ]; then
pnpm send-notify:nightly
else
pnpm send-notify
fi
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TELEGRAM_TOKEN: ${{ secrets.TELEGRAM_TOKEN }}
TELEGRAM_API_ID: ${{ secrets.TELEGRAM_API_ID }}
TELEGRAM_API_HASH: ${{ secrets.TELEGRAM_API_HASH }}
TELEGRAM_TO: "@keikolog"
TELEGRAM_TO_NIGHTLY: "@ClashNyanpasu"
+58
View File
@@ -0,0 +1,58 @@
name: "[Single] Update Tag"
on:
workflow_dispatch:
inputs:
tag:
description: "Release Tag"
required: true
type: string
workflow_call:
inputs:
tag:
description: "Release Tag"
required: true
type: string
jobs:
update_tag:
name: Update tag
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set Env
run: |
echo "BUILDTIME=$(TZ=Asia/Shanghai date)" >> $GITHUB_ENV
echo "CURRENT_GIT_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV
shell: bash
- name: Update Tag
uses: greenhat616/update-tag@v1
with:
tag_name: ${{ inputs.tag }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Create release body
run: |
cat > release.txt << 'EOF'
## Clash Nyanpasu Nightly Build
Release created at ${{ env.BUILDTIME }}.
Daily build of **Clash Nyanpasu** on *main* branch.
You could download previous Nightly Builds from [here](https://t.me/ClashNyanpasu).
***[See the development log here](https://t.me/s/keikolog/)***
EOF
- name: Update Release
uses: softprops/action-gh-release@v2
with:
name: Clash Nyanpasu Dev
tag_name: ${{ inputs.tag }}
body_path: release.txt
prerelease: true
generate_release_notes: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-233
View File
@@ -1,233 +0,0 @@
name: Dev Build
on:
workflow_dispatch:
schedule:
- cron: "15 0 * * *" # 每天 08:15 UTC+8 自动构建
env:
CARGO_INCREMENTAL: 0
RUST_BACKTRACE: short
jobs:
release:
strategy:
matrix:
targets:
- os: windows-latest
category: nsis # and portable
# - os: windows-latest
# category: msi
- os: ubuntu-latest
category: all
- os: macos-13
category: amd64
- os: macos-13
category: aarch64
runs-on: ${{ matrix.targets.os }}
if: startsWith(github.repository, 'LibNyanpasu')
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: install Rust stable
run: |
rustup install stable --profile minimal --no-self-update
rustup default stable
- uses: Swatinem/rust-cache@v2
with:
workspaces: "./backend/"
prefix-key: "rust-stable"
key: ${{ matrix.targets.os }}
shared-key: "release"
- name: Install the missing rust target (macOS Only)
if: startsWith(matrix.targets.os, 'macos-') && matrix.targets.category == 'aarch64'
run: |
rustup target add aarch64-apple-darwin
- name: Install Node
uses: actions/setup-node@v4
with:
node-version: "20"
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
run_install: false
- name: Delete current release assets
if: startsWith(matrix.targets.os, 'ubuntu-')
uses: mknejp/delete-release-assets@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
tag: pre-release
fail-if-no-assets: false
fail-if-no-release: false
assets: |
*.zip
*.gz
*.AppImage
*.deb
*.dmg
*.msi
*.sig
*.exe
*.json
- name: Install Dependencies (Ubuntu Only)
if: startsWith(matrix.targets.os, 'ubuntu-')
run: |
sudo apt-get update
sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf openssl
- uses: maxim-lobanov/setup-xcode@v1
if: startsWith(matrix.targets.os, 'macos-')
with:
xcode-version: "15.0"
- name: Pnpm install and check
run: |
pnpm i
pnpm check
- name: Nightly Prepare
if: startsWith(matrix.targets.os, 'windows-') == false
run: |
pnpm prepare:nightly
- name: Nightly Prepare (MSI only)
if: startsWith(matrix.targets.os, 'windows-') && matrix.targets.category == 'msi'
run: |
pnpm prepare:nightly --msi
- name: Nightly Prepare (Windows NSIS and Portable)
if: startsWith(matrix.targets.os, 'windows-') && matrix.targets.category == 'nsis'
run: |
pnpm prepare:nightly --nsis
- name: Tauri build
if: startsWith(matrix.targets.os, 'macos-') == false || matrix.targets.category != 'aarch64'
uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
with:
tagName: pre-release
releaseName: "Clash Nyanpasu Dev"
releaseBody: "More new features are now supported."
releaseDraft: false
prerelease: true
tauriScript: pnpm tauri
args: -f nightly -c ./backend/tauri/tauri.nightly.conf.json
- name: Portable Bundle (Windows Only)
if: startsWith(matrix.targets.os, 'windows-') && matrix.targets.category == 'nsis'
run: |
pnpm portable
env:
TAG_NAME: pre-release
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
VITE_WIN_PORTABLE: 1
- name: Pnpm check (macOS aarch64)
if: startsWith(matrix.targets.os, 'macos-') && matrix.targets.category == 'aarch64'
run: |
pnpm check --arch arm64 --sidecar-host aarch64-apple-darwin
- name: Tauri build with Upload (macOS aarch64)
if: startsWith(matrix.targets.os, 'macos-') && matrix.targets.category == 'aarch64'
env:
TAG_NAME: pre-release
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
run: |
pnpm build:nightly --target aarch64-apple-darwin
pnpm upload:osx-aarch64
update_tag:
name: Update tag
runs-on: ubuntu-latest
needs: [release]
if: startsWith(github.repository, 'LibNyanpasu')
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set Env
run: |
echo "BUILDTIME=$(TZ=Asia/Shanghai date)" >> $GITHUB_ENV
echo "CURRENT_GIT_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV
shell: bash
- name: Update Tag
uses: greenhat616/update-tag@v1
with:
tag_name: pre-release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: |
cat > release.txt << 'EOF'
## Clash Nyanpasu Nightly Build
Release created at ${{ env.BUILDTIME }}.
Daily build of **Clash Nyanpasu** on *main* branch.
***[See the development log here](https://t.me/keikolog/462)***
EOF
- name: Update Release
uses: softprops/action-gh-release@v2
with:
name: Clash Nyanpasu Dev
tag_name: pre-release
body_path: release.txt
prerelease: true
generate_release_notes: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
updater:
name: Update Nightly Updater
runs-on: ubuntu-latest
needs: [release, update_tag]
if: startsWith(github.repository, 'LibNyanpasu')
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-tags: true # Fetch all tags
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
run_install: false
- name: Pnpm install
run: pnpm i
- name: Update Updater
run: pnpm updater:nightly
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
telegram:
name: Notify Telegram
runs-on: ubuntu-latest
needs: [release, update_tag]
if: startsWith(github.repository, 'LibNyanpasu')
steps:
- name: Checkout repository
uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: latest
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
run_install: false
- name: Pnpm install
run: pnpm i
- name: Send Releases
run: pnpm send-notify:nightly
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TELEGRAM_TOKEN: ${{ secrets.TELEGRAM_TOKEN }}
TELEGRAM_API_ID: ${{ secrets.TELEGRAM_API_ID }}
TELEGRAM_API_HASH: ${{ secrets.TELEGRAM_API_HASH }}
TELEGRAM_TO: "@keikolog"
TELEGRAM_TO_NIGHTLY: "@ClashNyanpasu"
+80
View File
@@ -0,0 +1,80 @@
name: "[Entire] Build Developer Version"
on:
workflow_dispatch:
schedule:
- cron: "15 0 * * *" # 每天 08:15 UTC+8 自动构建
env:
CARGO_INCREMENTAL: 0
RUST_BACKTRACE: short
jobs:
delete_current_releases:
name: Delete Current Releases
if: ${{ github.event_name == 'workflow_dispatch' || startsWith(github.repository, 'LibNyanpasu') }}
uses: ./.github/workflows/deps-delete-releases.yaml
with:
tag: "pre-release"
windows_build:
name: Windows Build
uses: ./.github/workflows/deps-build-windows-nsis.yaml
needs: [delete_current_releases]
with:
portable: true
nightly: true
tag: "pre-release"
secrets: inherit
linux_build:
name: Linux Build
uses: ./.github/workflows/deps-build-linux.yaml
needs: [delete_current_releases]
with:
nightly: true
tag: "pre-release"
secrets: inherit
macos_amd64_build:
name: macOS amd64 Build
uses: ./.github/workflows/deps-build-macos.yaml
needs: [delete_current_releases]
with:
nightly: true
aarch64: false
tag: "pre-release"
secrets: inherit
macos_aarch64_build:
name: macOS aarch64 Build
uses: ./.github/workflows/deps-build-macos.yaml
needs: [delete_current_releases]
with:
nightly: true
aarch64: true
tag: "pre-release"
secrets: inherit
update_tag:
name: Update tag
needs: [windows_build, linux_build, macos_amd64_build, macos_aarch64_build]
uses: ./.github/workflows/deps-update-tag.yaml
with:
tag: "pre-release"
updater:
name: Create Updater
needs: [update_tag]
uses: ./.github/workflows/deps-create-updater.yaml
with:
nightly: true
telegram:
name: Send Release Message to Telegram
if: startsWith(github.repository, 'LibNyanpasu')
needs: [update_tag]
uses: ./.github/workflows/deps-message-telegram.yaml
with:
nightly: true
secrets: inherit
-30
View File
@@ -1,30 +0,0 @@
name: Updater CI
on: workflow_dispatch
jobs:
release-update:
runs-on: ubuntu-latest
if: |
startsWith(github.repository, 'LibNyanpasu')
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Node
uses: actions/setup-node@v4
with:
node-version: "20"
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
run_install: false
- name: Pnpm install
run: pnpm i
- name: Release updater file
run: pnpm updater
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+89 -123
View File
@@ -208,7 +208,7 @@ checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -409,7 +409,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -444,7 +444,7 @@ checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -581,7 +581,7 @@ dependencies = [
"regex",
"rustc-hash",
"shlex",
"syn 2.0.71",
"syn 2.0.72",
"which 4.4.2",
]
@@ -920,7 +920,7 @@ dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -971,6 +971,7 @@ dependencies = [
"objc",
"once_cell",
"open 5.3.0",
"os_pipe",
"parking_lot",
"percent-encoding",
"port_scanner",
@@ -1113,7 +1114,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f76990911f2267d837d9d0ad060aa63aaad170af40904b29461734c339030d4d"
dependencies = [
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -1323,7 +1324,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
dependencies = [
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -1333,7 +1334,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f"
dependencies = [
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -1373,7 +1374,7 @@ dependencies = [
"proc-macro2",
"quote",
"strsim",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -1384,7 +1385,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
dependencies = [
"darling_core",
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -1477,7 +1478,7 @@ checksum = "d150dea618e920167e5973d70ae6ece4385b7164e0d799fe7c122dd0a5d912ad"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -1488,7 +1489,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -1509,7 +1510,7 @@ dependencies = [
"darling",
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -1519,7 +1520,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "206868b8242f27cecce124c19fd88157fbd0dd334df2587f36417bafbc85097b"
dependencies = [
"derive_builder_core",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -1532,7 +1533,7 @@ dependencies = [
"proc-macro2",
"quote",
"rustc_version 0.4.0",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -1620,7 +1621,7 @@ dependencies = [
[[package]]
name = "dirs-utils"
version = "0.1.0"
source = "git+https://github.com/LibNyanpasu/nyanpasu-utils#aae6449b002bfd36eba878153e2e3b5029b9fd29"
source = "git+https://github.com/LibNyanpasu/nyanpasu-utils#31f59134a7e94922f13b07b21047390b962ce3c4"
dependencies = [
"dirs-next",
"thiserror",
@@ -1658,7 +1659,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -1771,23 +1772,23 @@ checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
name = "env_filter"
version = "0.1.0"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea"
checksum = "c6dc8c8ff84895b051f07a0e65f975cf225131742531338752abfb324e4449ff"
dependencies = [
"log",
]
[[package]]
name = "env_logger"
version = "0.11.3"
version = "0.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9"
checksum = "06676b12debf7bba6903559720abca942d3a66b8acb88815fd2c7c6537e9ade1"
dependencies = [
"anstream",
"anstyle",
@@ -1873,9 +1874,9 @@ dependencies = [
[[package]]
name = "fast_image_resize"
version = "4.2.0"
version = "4.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81cd2f79218cdfe398519739df6872a6f5747ca08e1f4fd3179f4b053a0b05f9"
checksum = "2ca4b58827213977eabab8ee8d8258db8441338f3a1832a1c0f2de3372175531"
dependencies = [
"cfg-if",
"document-features",
@@ -2007,7 +2008,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -2131,7 +2132,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -2949,7 +2950,7 @@ checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -3093,9 +3094,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
[[package]]
name = "jobserver"
version = "0.1.31"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e"
checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0"
dependencies = [
"libc",
]
@@ -3464,7 +3465,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519"
dependencies = [
"cfg-if",
"rayon",
]
[[package]]
@@ -3795,7 +3795,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -3861,7 +3861,7 @@ dependencies = [
[[package]]
name = "nyanpasu-utils"
version = "0.1.0"
source = "git+https://github.com/LibNyanpasu/nyanpasu-utils#aae6449b002bfd36eba878153e2e3b5029b9fd29"
source = "git+https://github.com/LibNyanpasu/nyanpasu-utils#31f59134a7e94922f13b07b21047390b962ce3c4"
dependencies = [
"constcat",
"derive_builder",
@@ -3869,6 +3869,7 @@ dependencies = [
"encoding_rs",
"kill_tree",
"memchr",
"os-utils",
"os_pipe",
"parking_lot",
"serde",
@@ -4020,9 +4021,9 @@ dependencies = [
[[package]]
name = "object"
version = "0.36.1"
version = "0.36.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce"
checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e"
dependencies = [
"memchr",
]
@@ -4083,7 +4084,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -4139,6 +4140,16 @@ dependencies = [
"pin-project-lite",
]
[[package]]
name = "os-utils"
version = "0.1.0"
source = "git+https://github.com/LibNyanpasu/nyanpasu-utils#31f59134a7e94922f13b07b21047390b962ce3c4"
dependencies = [
"nix 0.29.0",
"shared_child",
"windows 0.58.0",
]
[[package]]
name = "os_info"
version = "3.8.2"
@@ -4292,7 +4303,7 @@ dependencies = [
"pest_meta",
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -4430,7 +4441,7 @@ dependencies = [
"phf_shared 0.11.2",
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -4477,7 +4488,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -4597,7 +4608,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e"
dependencies = [
"proc-macro2",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -4674,7 +4685,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8021cf59c8ec9c432cfc2526ac6b8aa508ecaf29cd415f271b8406c1b851c3fd"
dependencies = [
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -4855,16 +4866,15 @@ dependencies = [
[[package]]
name = "ravif"
version = "0.11.8"
version = "0.11.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6ba61c28ba24c0cf8406e025cb29a742637e3f70776e61c27a8a8b72a042d12"
checksum = "5797d09f9bd33604689e87e8380df4951d4912f01b63f71205e2abd4ae25e6b6"
dependencies = [
"avif-serialize",
"imgref",
"loop9",
"quick-error",
"rav1e",
"rayon",
"rgb",
]
@@ -4955,7 +4965,7 @@ checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -5169,7 +5179,7 @@ dependencies = [
"serde",
"serde_json",
"serde_yaml 0.8.26",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -5434,7 +5444,7 @@ checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -5457,7 +5467,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -5508,7 +5518,7 @@ dependencies = [
"darling",
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -5897,9 +5907,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.71"
version = "2.0.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462"
checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af"
dependencies = [
"proc-macro2",
"quote",
@@ -5947,7 +5957,7 @@ dependencies = [
"interfaces",
"iptools",
"thiserror",
"windows 0.57.0",
"windows 0.58.0",
"winreg 0.52.0",
]
@@ -6402,7 +6412,7 @@ checksum = "5999e24eaa32083191ba4e425deb75cdf25efefabe5aaccb7446dd0d4122a3f5"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -6428,7 +6438,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -6550,7 +6560,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -6662,7 +6672,7 @@ dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
"winnow 0.6.14",
"winnow 0.6.15",
]
[[package]]
@@ -6703,7 +6713,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -7066,7 +7076,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
"wasm-bindgen-shared",
]
@@ -7100,7 +7110,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@@ -7482,16 +7492,6 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143"
dependencies = [
"windows-core 0.57.0",
"windows-targets 0.52.6",
]
[[package]]
name = "windows"
version = "0.58.0"
@@ -7533,18 +7533,6 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-core"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d"
dependencies = [
"windows-implement 0.57.0",
"windows-interface 0.57.0",
"windows-result 0.1.2",
"windows-targets 0.52.6",
]
[[package]]
name = "windows-core"
version = "0.58.0"
@@ -7576,18 +7564,7 @@ checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.71",
]
[[package]]
name = "windows-implement"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -7598,7 +7575,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -7609,18 +7586,7 @@ checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.71",
]
[[package]]
name = "windows-interface"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -7631,7 +7597,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -7974,9 +7940,9 @@ dependencies = [
[[package]]
name = "winnow"
version = "0.6.14"
version = "0.6.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "374ec40a2d767a3c1b4972d9475ecd557356637be906f2cb3f7fe17a6eb5e22f"
checksum = "557404e450152cd6795bb558bca69e43c585055f4606e3bcae5894fc6dac9ba0"
dependencies = [
"memchr",
]
@@ -8167,9 +8133,9 @@ dependencies = [
[[package]]
name = "zbus"
version = "4.3.1"
version = "4.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "851238c133804e0aa888edf4a0229481c753544ca12a60fd1c3230c8a500fe40"
checksum = "bb97012beadd29e654708a0fdb4c84bc046f537aecfde2c3ee0a9e4b4d48c725"
dependencies = [
"async-broadcast",
"async-executor",
@@ -8205,14 +8171,14 @@ dependencies = [
[[package]]
name = "zbus_macros"
version = "4.3.1"
version = "4.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d5a3f12c20bd473be3194af6b49d50d7bb804ef3192dc70eddedb26b85d9da7"
checksum = "267db9407081e90bbfa46d841d3cbc60f59c0351838c4bc65199ecd79ab1983e"
dependencies = [
"proc-macro-crate 3.1.0",
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
"zvariant_utils",
]
@@ -8244,7 +8210,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -8264,7 +8230,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
[[package]]
@@ -8384,9 +8350,9 @@ dependencies = [
[[package]]
name = "zvariant"
version = "4.1.2"
version = "4.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1724a2b330760dc7d2a8402d841119dc869ef120b139d29862d6980e9c75bfc9"
checksum = "2084290ab9a1c471c38fc524945837734fbf124487e105daec2bb57fd48c81fe"
dependencies = [
"endi",
"enumflags2",
@@ -8397,24 +8363,24 @@ dependencies = [
[[package]]
name = "zvariant_derive"
version = "4.1.2"
version = "4.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55025a7a518ad14518fb243559c058a2e5b848b015e31f1d90414f36e3317859"
checksum = "73e2ba546bda683a90652bac4a279bc146adad1386f25379cf73200d2002c449"
dependencies = [
"proc-macro-crate 3.1.0",
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
"zvariant_utils",
]
[[package]]
name = "zvariant_utils"
version = "2.0.0"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc242db087efc22bd9ade7aa7809e4ba828132edc312871584a6b4391bdf8786"
checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.71",
"syn 2.0.72",
]
@@ -20,7 +20,7 @@ iptools = "0.2.5"
winreg = { version = "0.52", features = ["transactions"] }
[target.'cfg(target_os = "windows")'.dependencies.windows]
version = "0.57"
version = "0.58"
features = [
"Win32_Networking_WinInet",
# "Win32_Networking_WinHttp",
+2
View File
@@ -15,6 +15,7 @@ serde = "1"
simd-json = "0.13"
chrono = "0.4"
rustc_version = "0.4"
semver = "1.0"
[dependencies]
nyanpasu-utils = { git = "https://github.com/LibNyanpasu/nyanpasu-utils" }
@@ -108,6 +109,7 @@ timeago = "0.4"
ansi-str = "0.8"
humansize = "2.1.3"
convert_case = "0.6.0"
os_pipe = "1.2.0"
[target.'cfg(target_os = "macos")'.dependencies]
cocoa = "0.25.0"
+10 -4
View File
@@ -10,6 +10,8 @@ struct PackageJson {
fn main() {
let mut pkg_json = read("../../package.json").unwrap();
let pkg_json: PackageJson = simd_json::from_slice(&mut pkg_json).unwrap();
let version = semver::Version::parse(pkg_json.version.as_str()).unwrap();
let is_prerelase = !version.pre.is_empty();
println!("cargo:rustc-env=NYANPASU_VERSION={}", pkg_json.version);
// Git Information
let output = Command::new("git")
@@ -42,10 +44,14 @@ fn main() {
// Build Profile
println!(
"cargo:rustc-env=BUILD_PROFILE={}",
match env::var("PROFILE").unwrap().as_str() {
"release" => "Release",
"debug" => "Debug",
_ => "Unknown",
if is_prerelase {
"Nightly"
} else {
match env::var("PROFILE").unwrap().as_str() {
"release" => "Release",
"debug" => "Debug",
_ => "Unknown",
}
}
);
// Build Platform
@@ -0,0 +1,167 @@
use clap::Args;
use crate::core::migration::{
units::{find_migration, get_migrations},
MigrationAdvice, Runner,
};
use colored::Colorize;
#[derive(Debug, Args)]
pub struct MigrateOpts {
/// force to run migration without advice
#[arg(long, default_value = "false")]
skip_advice: bool,
/// Run specific migration
#[arg(long)]
migration: Option<String>,
/// Run migration up to specific version
#[arg(long)]
version: Option<String>,
/// List all migrations
#[arg(long)]
list: bool,
}
pub fn parse(args: &MigrateOpts) {
let runner = if args.skip_advice {
Runner::new_with_skip_advice()
} else {
Runner::default()
};
if args.list {
println!("Available migrations:\n");
let migrations = get_migrations();
for migration in migrations {
let advice = runner.advice_migration(migration.as_ref());
println!(
"[{}] {} - {}",
match &advice {
MigrationAdvice::Pending => format!("{}", advice).yellow(),
MigrationAdvice::Ignored => format!("{}", advice).cyan(),
MigrationAdvice::Done => format!("{}", advice).green(),
},
migration.version(),
migration.name()
);
}
std::process::exit(0);
}
if args.migration.is_some() && args.version.is_some() {
eprintln!("Please specify only one of migration or version.");
std::process::exit(1);
}
if args.migration.is_none() && args.version.is_none() {
match crate::consts::BUILD_INFO.build_profile {
"Nightly" => {
println!("Running all upcoming migrations.");
runner.run_upcoming_units().unwrap();
}
_ => {
println!(
"No migration or version specified. Running migrations up to current version."
);
runner
.run_units_up_to_version(&runner.current_version)
.unwrap();
}
}
}
if let Some(migration) = args.migration.as_ref() {
let migration = find_migration(migration);
match migration {
Some(migration) => {
runner.run_migration(migration.as_ref()).unwrap();
}
None => {
eprintln!("Migration not found.");
std::process::exit(1);
}
}
} else if let Some(version) = args.version.as_deref() {
let version = semver::Version::parse(version).unwrap();
runner.run_units_up_to_version(&version).unwrap();
}
}
#[cfg(target_os = "windows")]
pub fn migrate_home_dir_handler(target_path: &str) -> anyhow::Result<()> {
use crate::utils::{self, dirs};
use anyhow::Context;
use deelevate::{PrivilegeLevel, Token};
use std::{path::PathBuf, process::Command, str::FromStr, thread, time::Duration};
use sysinfo::System;
use tauri::utils::platform::current_exe;
println!("target path {}", target_path);
let token = Token::with_current_process()?;
if let PrivilegeLevel::NotPrivileged = token.privilege_level()? {
eprintln!("Please run this command as admin to prevent authority issue.");
std::process::exit(1);
}
let current_home_dir = dirs::app_config_dir()?;
let target_home_dir = PathBuf::from_str(target_path)?;
// 1. waiting for app exited
println!("waiting for app exited.");
let placeholder = dirs::get_single_instance_placeholder();
let mut single_instance: single_instance::SingleInstance;
loop {
single_instance = single_instance::SingleInstance::new(&placeholder)
.context("failed to create single instance")?;
if single_instance.is_single() {
break;
}
thread::sleep(Duration::from_secs(1));
}
// 2. kill all related processes.
let related_names = [
"clash-verge-service",
"clash-nyanpasu-service", // for upcoming v1.6.x
"clash-rs",
"mihomo",
"mihomo-alpha",
"clash",
];
let sys = System::new_all();
'outer: for process in sys.processes().values() {
let mut process_name = process.name();
if process_name.ends_with(".exe") {
process_name = &process_name[..process_name.len() - 4]; // remove .exe
}
for name in related_names.iter() {
if process_name.ends_with(name) {
println!(
"Process found: {} should be killed. killing...",
process_name
);
if !process.kill() {
eprintln!("failed to kill {}.", process_name)
}
continue 'outer;
}
}
}
// 3. do config migrate and update the registry.
utils::init::do_config_migration(&current_home_dir, &target_home_dir)?;
utils::winreg::set_app_dir(target_home_dir.as_path())?;
println!("migration finished. starting application...");
drop(single_instance); // release single instance lock
let app_path = current_exe()?;
thread::spawn(move || {
Command::new(app_path).spawn().unwrap();
});
thread::sleep(Duration::from_secs(5));
Ok(())
}
#[cfg(not(target_os = "windows"))]
pub fn migrate_home_dir_handler(_target_path: &str) -> anyhow::Result<()> {
Ok(())
}
@@ -2,6 +2,7 @@ use std::str::FromStr;
use anyhow::Ok;
use clap::{Parser, Subcommand};
use migrate::MigrateOpts;
use tauri::utils::platform::current_exe;
use crate::utils;
@@ -24,9 +25,11 @@ pub struct Cli {
#[derive(Subcommand, Debug)]
enum Commands {
/// Migrate home directory to another path.
MigrateHomeDir {
target_path: String,
},
MigrateHomeDir { target_path: String },
/// do migration
Migrate(MigrateOpts),
/// Collect the environment variables.
Collect,
/// A launch bridge to resolve the delay exit issue.
Launch {
@@ -55,6 +58,9 @@ pub fn parse() -> anyhow::Result<()> {
if let Some(commands) = &cli.command {
let guard = DelayedExitGuard::new();
match commands {
Commands::Migrate(opts) => {
migrate::parse(opts);
}
Commands::MigrateHomeDir { target_path } => {
migrate::migrate_home_dir_handler(target_path).unwrap();
}
@@ -1,79 +0,0 @@
#[cfg(target_os = "windows")]
pub fn migrate_home_dir_handler(target_path: &str) -> anyhow::Result<()> {
use crate::utils::{self, dirs};
use anyhow::Context;
use deelevate::{PrivilegeLevel, Token};
use std::{path::PathBuf, process::Command, str::FromStr, thread, time::Duration};
use sysinfo::System;
use tauri::utils::platform::current_exe;
println!("target path {}", target_path);
let token = Token::with_current_process()?;
if let PrivilegeLevel::NotPrivileged = token.privilege_level()? {
eprintln!("Please run this command as admin to prevent authority issue.");
std::process::exit(1);
}
let current_home_dir = dirs::app_home_dir()?;
let target_home_dir = PathBuf::from_str(target_path)?;
// 1. waiting for app exited
println!("waiting for app exited.");
let placeholder = dirs::get_single_instance_placeholder();
let mut single_instance: single_instance::SingleInstance;
loop {
single_instance = single_instance::SingleInstance::new(&placeholder)
.context("failed to create single instance")?;
if single_instance.is_single() {
break;
}
thread::sleep(Duration::from_secs(1));
}
// 2. kill all related processes.
let related_names = [
"clash-verge-service",
"clash-nyanpasu-service", // for upcoming v1.6.x
"clash-rs",
"mihomo",
"mihomo-alpha",
"clash",
];
let sys = System::new_all();
'outer: for process in sys.processes().values() {
let mut process_name = process.name();
if process_name.ends_with(".exe") {
process_name = &process_name[..process_name.len() - 4]; // remove .exe
}
for name in related_names.iter() {
if process_name.ends_with(name) {
println!(
"Process found: {} should be killed. killing...",
process_name
);
if !process.kill() {
eprintln!("failed to kill {}.", process_name)
}
continue 'outer;
}
}
}
// 3. do config migrate and update the registry.
utils::init::do_config_migration(&current_home_dir, &target_home_dir)?;
utils::winreg::set_app_dir(target_home_dir.as_path())?;
println!("migration finished. starting application...");
drop(single_instance); // release single instance lock
let app_path = current_exe()?;
thread::spawn(move || {
Command::new(app_path).spawn().unwrap();
});
thread::sleep(Duration::from_secs(5));
Ok(())
}
#[cfg(not(target_os = "windows"))]
pub fn migrate_home_dir_handler(_target_path: &str) -> anyhow::Result<()> {
Ok(())
}
@@ -0,0 +1,81 @@
use derive_builder::Builder;
use once_cell::sync::Lazy;
use semver::Version;
/// A simple file based database for storing the migration status.
///
use serde::{Deserialize, Serialize};
use std::{borrow::Cow, collections::HashMap, io::Write, path::PathBuf};
use super::MigrationState;
/// A lockfile store the migrated version and the state.
/// The lower version of the migration will be ignored.
static MIGRATION_LOCK_FILE: Lazy<PathBuf> = Lazy::new(|| {
let mut path = crate::utils::dirs::app_config_dir().unwrap();
path.push("migration.lock");
path
});
#[derive(Debug, Clone, Serialize, Deserialize, Builder)]
#[builder(default)]
pub struct MigrationFile<'a> {
pub version: Cow<'a, Version>,
pub states: HashMap<Cow<'a, str>, MigrationState>,
}
impl MigrationFileBuilder<'_> {
pub fn read_file(mut self) -> Self {
let content = std::fs::read_to_string(&*MIGRATION_LOCK_FILE).ok();
if let Some(content) = content {
let file: Option<MigrationFile> = serde_yaml::from_str(&content).ok();
if let Some(file) = file {
self.version = Some(file.version);
self.states = Some(file.states);
}
}
self
}
}
impl Default for MigrationFile<'_> {
fn default() -> Self {
// since 1.6.0, we have introduced the migration system. so the last version of 1.5.x is 1.5.1.
let ver = Version::parse("1.5.1").unwrap();
Self {
version: Cow::Owned(ver),
states: HashMap::new(),
}
}
}
impl<'a> MigrationFile<'a> {
/// Create or Truncate the lock file and write the content.
pub fn write_file(&self) -> Result<(), std::io::Error> {
let content = serde_yaml::to_string(self).map_err(|e| {
log::error!("Failed to serialize the migration file: {}", e);
std::io::Error::new(std::io::ErrorKind::Other, e)
})?;
let mut file = std::fs::OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(&*MIGRATION_LOCK_FILE)?;
file.write(
"# This file is generated by the migration system, do not edit it manually.\n"
.as_bytes(),
)
.map_err(|e| {
log::error!("Failed to write the migration file: {}", e);
e
})?;
file.write_all(content.as_bytes())
}
pub fn get_state(&self, name: &str) -> Option<MigrationState> {
self.states.get(name).copied()
}
pub fn set_state(&mut self, name: Cow<'a, str>, state: MigrationState) {
self.states.insert(name, state);
}
}
@@ -0,0 +1,321 @@
#![allow(dead_code)]
/// A migration mod indicates the migration of the old version to the new version.
/// Because this runner run at the start of the app, it will use eprintln or println to print the migration log.
///
///
use dyn_clone::{clone_trait_object, DynClone};
use semver::Version;
use std::{borrow::Cow, cell::RefCell};
mod db;
pub mod units;
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum MigrationState {
/// The migration is pending.
NotStarted,
/// The migration is in progress.
InProgress,
/// The migration is completed.
Completed,
/// The migration is failed.
Failed,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MigrationAdvice {
/// The migration is required to run.
Pending,
/// The migration is ignored.
Ignored,
/// The migration has been run.
Done,
}
impl std::fmt::Display for MigrationAdvice {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
MigrationAdvice::Pending => write!(f, "Pending"),
MigrationAdvice::Ignored => write!(f, "Ignored"),
MigrationAdvice::Done => write!(f, "Done"),
}
}
}
#[derive(Debug, Clone)]
pub enum Unit<'a, T>
where
T: Clone + Migration<'a> + Send + Sync,
{
/// A List of migrations, it should be used to wrap a list of migrations in a single version.
/// Although the fn signature is T generic, it should use a Vec<DynMigration> as the input.
Batch(Cow<'a, [T]>),
Single(Cow<'a, T>),
}
impl<'a, T> From<T> for Unit<'a, T>
where
T: Clone + Migration<'a> + Send + Sync,
{
fn from(item: T) -> Self {
Unit::Single(Cow::Owned(item))
}
}
impl<'a, T> From<&'a T> for Unit<'a, T>
where
T: Clone + Migration<'a> + Send + Sync,
{
fn from(item: &'a T) -> Self {
Unit::Single(Cow::Borrowed(item))
}
}
impl<'a, T> From<&'a [T]> for Unit<'a, T>
where
T: Clone + Migration<'a> + Send + Sync,
{
fn from(list: &'a [T]) -> Self {
Unit::Batch(Cow::Borrowed(list))
}
}
impl<'a, T> From<Vec<T>> for Unit<'a, T>
where
T: Clone + Migration<'a> + Send + Sync,
{
fn from(list: Vec<T>) -> Self {
Unit::Batch(Cow::Owned(list))
}
}
type DynMigration<'a> = Box<dyn Migration<'a> + Send + Sync + 'a>;
pub trait Migration<'a>: DynClone {
/// A version field to indicate the version of the migration.
/// It used to compare with the current version to determine whether the migration is needed.
fn version(&self) -> &'a Version;
/// A name field to indicate the name of the migration.
fn name(&self) -> Cow<'a, str>;
fn migrate(&self) -> std::io::Result<()> {
unimplemented!()
}
}
clone_trait_object!(Migration<'_>);
auto trait NotDynMigration {}
impl !NotDynMigration for DynMigration<'_> {}
/// Impl From T for DynMigration excludes itself.
impl<'a, T> From<T> for DynMigration<'a>
where
T: Clone + Migration<'a> + Send + Sync + NotDynMigration + 'a,
{
fn from(item: T) -> Self {
Box::new(item)
}
}
impl<'a, T> Migration<'a> for Unit<'a, T>
where
T: Clone + Migration<'a> + Send + Sync,
{
fn version(&self) -> &'a Version {
match self {
Unit::Single(item) => item.version(),
Unit::Batch(list) => list.first().unwrap().version(),
}
}
fn name(&self) -> Cow<'a, str> {
match self {
Unit::Single(item) => item.name(),
Unit::Batch(list) => Cow::Owned(format!(
"{} migrations for v{}",
list.len(),
list.first().unwrap().version()
)),
}
}
fn migrate(&self) -> std::io::Result<()> {
unimplemented!("Batch migrations should be handled by the runner.")
}
}
impl<'a> Migration<'a> for DynMigration<'a> {
fn version(&self) -> &'a Version {
self.as_ref().version()
}
fn name(&self) -> Cow<'a, str> {
self.as_ref().name()
}
fn migrate(&self) -> std::io::Result<()> {
self.as_ref().migrate()
}
}
#[derive(Debug)]
pub struct Runner<'a> {
pub current_version: Cow<'a, Version>,
skip_advice: bool,
store: RefCell<db::MigrationFile<'a>>,
}
impl Default for Runner<'_> {
fn default() -> Self {
let ver = Version::parse(crate::consts::BUILD_INFO.pkg_version).unwrap();
let file = db::MigrationFileBuilder::default()
.read_file()
.build()
.unwrap();
Self {
current_version: Cow::Owned(ver),
skip_advice: false,
store: RefCell::new(file),
}
}
}
impl Drop for Runner<'_> {
fn drop(&mut self) {
let mut store = self.store.take();
store.version = Cow::Borrowed(&self.current_version);
store.write_file().unwrap();
}
}
impl Runner<'_> {
pub fn new_with_skip_advice() -> Self {
let ver = Version::parse(crate::consts::BUILD_INFO.pkg_version).unwrap();
let file = db::MigrationFileBuilder::default()
.read_file()
.build()
.unwrap();
Self {
skip_advice: true,
current_version: Cow::Owned(ver),
store: RefCell::new(file),
}
}
pub fn advice_migration<'a, T>(&self, migration: &T) -> MigrationAdvice
where
T: Clone + Migration<'a> + Send + Sync,
{
let migration_ver = migration.version();
let store = self.store.borrow();
if migration_ver >= &store.version {
// Judge the migration is run or not.
if let Some(state) = store.states.get(&migration.name()) {
match state {
MigrationState::Completed => MigrationAdvice::Done,
MigrationState::Failed => MigrationAdvice::Pending,
_ => MigrationAdvice::Ignored,
}
} else {
MigrationAdvice::Pending
}
} else {
MigrationAdvice::Ignored
}
}
pub fn advice_unit<'a, T>(&self, unit: &Unit<'a, T>) -> MigrationAdvice
where
T: Clone + Migration<'a> + Send + Sync,
{
match unit {
Unit::Single(item) => self.advice_migration(item.as_ref()),
Unit::Batch(list) => {
let mut advice = MigrationAdvice::Ignored;
for item in list.iter() {
let item_advice = self.advice_migration(item);
if item_advice == MigrationAdvice::Pending {
advice = MigrationAdvice::Pending;
break;
} else if item_advice == MigrationAdvice::Done {
advice = MigrationAdvice::Done;
}
}
advice
}
}
}
pub fn run_migration<'a, T>(&self, migration: &T) -> std::io::Result<()>
where
T: Clone + Migration<'a> + Send + Sync,
{
println!("Running migration: {}", migration.name());
let advice = self.advice_migration(migration);
println!("Advice: {:?}", advice);
if matches!(advice, MigrationAdvice::Ignored | MigrationAdvice::Done) {
return Ok(());
}
let name = migration.name();
let mut store = self.store.borrow_mut();
match migration.migrate() {
Ok(_) => {
println!("Migration {} completed.", name);
store.set_state(Cow::Owned(name.to_string()), MigrationState::Completed);
Ok(())
}
Err(e) => {
eprintln!("Migration {} failed: {}", name, e);
store.set_state(Cow::Owned(name.to_string()), MigrationState::Failed);
Err(e)
}
}
}
pub fn run_unit<'a, T>(&self, unit: &Unit<'a, T>) -> std::io::Result<()>
where
T: Clone + Migration<'a> + Send + Sync,
{
println!("Running unit: {}", unit.name());
match unit {
Unit::Single(item) => self.run_migration(item.as_ref()),
Unit::Batch(list) => {
for item in list.iter() {
self.run_migration(item)?;
}
Ok(())
}
}
}
pub fn run_units_up_to_version(&self, to_ver: &Version) -> std::io::Result<()> {
println!("Running units up to version: {}", to_ver);
let version = {
let store = self.store.borrow();
store.version.clone()
};
let units = units::UNITS
.iter()
.filter(|(ver, _)| **ver >= &version && **ver <= to_ver);
for (_, unit) in units {
self.run_unit(unit)?;
}
Ok(())
}
pub fn run_upcoming_units(&self) -> std::io::Result<()> {
println!("Running all upcoming units. It is supposed to run in Nightly build. If you see this message in Stable channel, report it in Github Issues Tracker please.");
let version = {
let store = self.store.borrow();
store.version.clone()
};
let units = units::UNITS.iter().filter(|(ver, _)| **ver >= &version);
for (_, unit) in units {
self.run_unit(unit)?;
}
Ok(())
}
}
@@ -0,0 +1,50 @@
use super::{DynMigration, Migration, Unit};
use once_cell::sync::Lazy;
use semver::Version;
use std::{borrow::Cow, collections::HashMap};
mod unit_160;
pub static UNITS: Lazy<HashMap<&'static Version, Unit<'static, DynMigration>>> = Lazy::new(|| {
let mut units: HashMap<&'static Version, Unit<'static, DynMigration>> = HashMap::new();
let unit = Unit::Batch(Cow::Borrowed(&unit_160::UNITS));
units.insert(unit.version(), unit);
units
});
pub fn find_migration(name: &str) -> Option<Cow<'static, DynMigration<'static>>> {
for unit in UNITS.values() {
match unit {
Unit::Batch(units) => {
for unit in units.iter() {
if unit.name() == name {
return Some(Cow::Borrowed(unit));
}
}
}
Unit::Single(unit) => {
if unit.name() == name {
return Some(Cow::Borrowed(unit));
}
}
}
}
None
}
pub fn get_migrations() -> Vec<Cow<'static, DynMigration<'static>>> {
let mut migrations = Vec::new();
for unit in UNITS.values() {
match unit {
Unit::Batch(units) => {
for unit in units.iter() {
migrations.push(Cow::Borrowed(unit));
}
}
Unit::Single(unit) => {
migrations.push(Cow::Borrowed(unit));
}
}
}
migrations
}
@@ -0,0 +1,107 @@
use once_cell::sync::Lazy;
use crate::{
config::RUNTIME_CONFIG,
core::migration::{DynMigration, Migration},
};
pub static UNITS: Lazy<Vec<DynMigration>> = Lazy::new(|| vec![MigrateAppHomeDir.into()]);
pub static VERSION: Lazy<semver::Version> = Lazy::new(|| semver::Version::parse("1.6.0").unwrap());
#[derive(Debug, Clone)]
pub struct MigrateAppHomeDir;
impl<'a> Migration<'a> for MigrateAppHomeDir {
fn name(&self) -> std::borrow::Cow<'a, str> {
std::borrow::Cow::Borrowed("Split App Home Dir to Config and Data")
}
fn version(&self) -> &'a semver::Version {
&VERSION
}
// Allow deprecated because we are moving deprecated files to new locations
#[allow(deprecated)]
fn migrate(&self) -> std::io::Result<()> {
// create the app config and data dir
println!("Creating app config and data dir");
let app_config_dir = crate::utils::dirs::app_config_dir().unwrap();
fs_extra::dir::create_all(crate::utils::dirs::app_config_dir().unwrap(), false)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidInput, e))?;
let app_data_dir = crate::utils::dirs::app_data_dir().unwrap();
fs_extra::dir::create_all(crate::utils::dirs::app_data_dir().unwrap(), false)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidInput, e))?;
// move the config files to the new config dir
let file_opts = fs_extra::file::CopyOptions::default().skip_exist(true);
let dir_opts = fs_extra::dir::CopyOptions::default()
.skip_exist(true)
.content_only(true);
let home_dir = crate::utils::dirs::app_home_dir().unwrap();
// move clash runtime config
let path = home_dir.join("clash-verge.yaml");
if path.exists() {
println!("Moving clash-verge.yaml to config dir");
fs_extra::file::move_file(path, app_config_dir.join(RUNTIME_CONFIG), &file_opts)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidInput, e))?;
}
// move clash guard overrides
let path = home_dir.join("config.yaml");
if path.exists() {
println!("Moving config.yaml to config dir");
fs_extra::file::move_file(
path,
crate::utils::dirs::clash_guard_overrides_path().unwrap(),
&file_opts,
)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidInput, e))?;
}
// move nyanpasu config
let path = home_dir.join("verge.yaml");
if path.exists() {
println!("Moving verge.yaml to config dir");
fs_extra::file::move_file(
path,
crate::utils::dirs::app_config_dir()
.unwrap()
.join(crate::utils::dirs::NYANPASU_CONFIG),
&file_opts,
)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidInput, e))?;
}
// if app config dir is not set by registry, move the files and dirs to data dir
if home_dir != app_config_dir {
// move profiles.yaml
let path = home_dir.join("profiles.yaml");
if path.exists() {
println!("Moving profiles.yaml to profiles dir");
fs_extra::file::move_file(
path,
crate::utils::dirs::app_profiles_dir()
.unwrap()
.join("profiles.yaml"),
&file_opts,
)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidInput, e))?;
}
// move profiles dir
let path = home_dir.join("profiles");
if path.exists() {
println!("Moving profiles dir to profiles dir");
fs_extra::dir::move_dir(
path,
crate::utils::dirs::app_profiles_dir().unwrap(),
&dir_opts,
)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidInput, e))?;
}
// move other files and dirs to data dir
println!("Moving other files and dirs to data dir");
fs_extra::dir::move_dir(home_dir, app_data_dir, &dir_opts)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidInput, e))?;
}
println!("Migration completed");
Ok(())
}
}
+1 -1
View File
@@ -1,5 +1,4 @@
pub mod clash;
pub mod commands;
pub mod handle;
pub mod hotkey;
pub mod logger;
@@ -12,3 +11,4 @@ pub mod updater;
pub mod win_service;
pub mod win_uwp;
pub use self::clash::core::*;
pub mod migration;
@@ -1,4 +1,4 @@
use crate::{cmds, config::Config, feat, utils, utils::resolve};
use crate::{config::Config, feat, ipc, utils, utils::resolve};
use anyhow::Result;
use rust_i18n::t;
use tauri::{
@@ -153,10 +153,10 @@ impl Tray {
"copy_env_cmd" => feat::copy_clash_env("cmd"),
#[cfg(target_os = "windows")]
"copy_env_ps" => feat::copy_clash_env("ps"),
"open_app_config_dir" => crate::log_err!(cmds::open_app_config_dir()),
"open_app_data_dir" => crate::log_err!(cmds::open_app_config_dir()),
"open_core_dir" => crate::log_err!(cmds::open_core_dir()),
"open_logs_dir" => crate::log_err!(cmds::open_logs_dir()),
"open_app_config_dir" => crate::log_err!(ipc::open_app_config_dir()),
"open_app_data_dir" => crate::log_err!(ipc::open_app_config_dir()),
"open_core_dir" => crate::log_err!(ipc::open_core_dir()),
"open_logs_dir" => crate::log_err!(ipc::open_logs_dir()),
"restart_clash" => feat::restart_clash_core(),
"restart_app" => utils::help::restart_application(app_handle),
"quit" => {
+63 -52
View File
@@ -1,3 +1,4 @@
#![feature(auto_traits, negative_impls)]
#![cfg_attr(
all(not(debug_assertions), target_os = "windows"),
windows_subsystem = "windows"
@@ -17,11 +18,11 @@ mod consts;
mod core;
mod enhance;
mod feat;
mod ipc;
mod utils;
use crate::{
config::Config,
core::{commands, handle::Handle},
core::handle::Handle,
utils::{init, resolve},
};
use tauri::{api, Manager, SystemTray};
@@ -56,7 +57,7 @@ fn main() -> std::io::Result<()> {
deadlock_detection();
// Parse commands
commands::parse().unwrap();
cmds::parse().unwrap();
// Should be in first place in order prevent single instance check block everything
#[cfg(feature = "verge-dev")]
@@ -75,6 +76,16 @@ fn main() -> std::io::Result<()> {
};
rust_i18n::set_locale(locale);
if let Err(e) = init::run_pending_migrations() {
utils::dialog::panic_dialog(
&format!(
"Failed to finish migration event: {}\nYou can see the detailed information at migration.log in your local data dir.\nYou're supposed to submit it as the attachment of new issue.",
e,
)
);
std::process::exit(1);
}
crate::log_err!(init::init_config());
// Panic Hook to show a panic dialog and save logs
@@ -129,63 +140,63 @@ fn main() -> std::io::Result<()> {
.on_system_tray_event(core::tray::Tray::on_system_tray_event)
.invoke_handler(tauri::generate_handler![
// common
cmds::get_sys_proxy,
cmds::open_app_config_dir,
cmds::open_app_data_dir,
cmds::open_logs_dir,
cmds::open_web_url,
cmds::open_core_dir,
ipc::get_sys_proxy,
ipc::open_app_config_dir,
ipc::open_app_data_dir,
ipc::open_logs_dir,
ipc::open_web_url,
ipc::open_core_dir,
// cmds::kill_sidecar,
cmds::restart_sidecar,
cmds::grant_permission,
ipc::restart_sidecar,
ipc::grant_permission,
// clash
cmds::get_clash_info,
cmds::get_clash_logs,
cmds::patch_clash_config,
cmds::change_clash_core,
cmds::get_runtime_config,
cmds::get_runtime_yaml,
cmds::get_runtime_exists,
cmds::get_runtime_logs,
cmds::clash_api_get_proxy_delay,
cmds::uwp::invoke_uwp_tool,
ipc::get_clash_info,
ipc::get_clash_logs,
ipc::patch_clash_config,
ipc::change_clash_core,
ipc::get_runtime_config,
ipc::get_runtime_yaml,
ipc::get_runtime_exists,
ipc::get_runtime_logs,
ipc::clash_api_get_proxy_delay,
ipc::uwp::invoke_uwp_tool,
// updater
cmds::fetch_latest_core_versions,
cmds::update_core,
cmds::inspect_updater,
cmds::get_core_version,
ipc::fetch_latest_core_versions,
ipc::update_core,
ipc::inspect_updater,
ipc::get_core_version,
// utils
cmds::collect_logs,
ipc::collect_logs,
// verge
cmds::get_verge_config,
cmds::patch_verge_config,
ipc::get_verge_config,
ipc::patch_verge_config,
// cmds::update_hotkeys,
// profile
cmds::get_profiles,
cmds::enhance_profiles,
cmds::patch_profiles_config,
cmds::view_profile,
cmds::patch_profile,
cmds::create_profile,
cmds::import_profile,
cmds::reorder_profile,
cmds::update_profile,
cmds::delete_profile,
cmds::read_profile_file,
cmds::save_profile_file,
cmds::save_window_size_state,
cmds::get_custom_app_dir,
cmds::set_custom_app_dir,
ipc::get_profiles,
ipc::enhance_profiles,
ipc::patch_profiles_config,
ipc::view_profile,
ipc::patch_profile,
ipc::create_profile,
ipc::import_profile,
ipc::reorder_profile,
ipc::update_profile,
ipc::delete_profile,
ipc::read_profile_file,
ipc::save_profile_file,
ipc::save_window_size_state,
ipc::get_custom_app_dir,
ipc::set_custom_app_dir,
// service mode
cmds::service::check_service,
cmds::service::install_service,
cmds::service::uninstall_service,
cmds::is_portable,
cmds::get_proxies,
cmds::select_proxy,
cmds::update_proxy_provider,
cmds::restart_application,
cmds::collect_envs,
ipc::service::check_service,
ipc::service::install_service,
ipc::service::uninstall_service,
ipc::is_portable,
ipc::get_proxies,
ipc::select_proxy,
ipc::update_proxy_provider,
ipc::restart_application,
ipc::collect_envs,
]);
#[cfg(target_os = "macos")]
+28 -7
View File
@@ -2,7 +2,7 @@ use crate::core::handle;
use anyhow::Result;
use nyanpasu_utils::dirs::{suggest_config_dir, suggest_data_dir};
use once_cell::sync::Lazy;
use std::{borrow::Cow, path::PathBuf};
use std::{borrow::Cow, fs, path::PathBuf};
use tauri::{
api::path::{home_dir, resource_dir},
Env,
@@ -30,10 +30,10 @@ pub static APP_DIR_PLACEHOLDER: Lazy<Cow<'static, str>> = Lazy::new(|| {
}
});
static CLASH_CFG_GUARD_OVERRIDES: &str = "clash-guard-overrides.yaml";
static NYANPASU_CONFIG: &str = "nyanpasu-config.yaml";
static PROFILE_YAML: &str = "profiles.yaml";
static STORAGE_DB: &str = "storage.db";
pub const CLASH_CFG_GUARD_OVERRIDES: &str = "clash-guard-overrides.yaml";
pub const NYANPASU_CONFIG: &str = "nyanpasu-config.yaml";
pub const PROFILE_YAML: &str = "profiles.yaml";
pub const STORAGE_DB: &str = "storage.db";
/// portable flag
#[allow(unused)]
@@ -90,6 +90,12 @@ pub fn app_config_dir() -> Result<PathBuf> {
}
suggest_config_dir(&APP_DIR_PLACEHOLDER)
.ok_or(anyhow::anyhow!("failed to get the app config dir"))
.and_then(|dir| {
if !dir.exists() {
fs::create_dir_all(&dir)?;
}
Ok(dir)
})
}
pub fn app_data_dir() -> Result<PathBuf> {
@@ -103,10 +109,25 @@ pub fn app_data_dir() -> Result<PathBuf> {
let app_dir = app_exe
.parent()
.ok_or(anyhow::anyhow!("failed to check the old portable app dir"))?;
return Ok(PathBuf::from(app_dir).join(".data").join(PREVIOUS_APP_NAME));
let data_dir = PathBuf::from(app_dir).join(".data").join(PREVIOUS_APP_NAME);
if !data_dir.exists() {
fs::create_dir_all(&data_dir)?;
}
return Ok(data_dir);
}
}
suggest_data_dir(&APP_DIR_PLACEHOLDER).ok_or(anyhow::anyhow!("failed to get the app data dir"))
suggest_data_dir(&APP_DIR_PLACEHOLDER)
.ok_or(anyhow::anyhow!("failed to get the app data dir"))
.and_then(|dir| {
if !dir.exists() {
fs::create_dir_all(&dir)?;
}
Ok(dir)
})
}
pub fn old_app_home_dir() -> Result<PathBuf> {
@@ -2,15 +2,103 @@ use crate::{
config::*,
utils::{dialog::migrate_dialog, dirs, help},
};
use anyhow::{Context, Result};
use anyhow::{anyhow, Context, Result};
use fs_extra::dir::CopyOptions;
#[cfg(windows)]
use runas::Command as RunasCommand;
use rust_i18n::t;
use std::{fs, path::PathBuf};
use std::{
fs,
io::{BufReader, Write},
path::PathBuf,
sync::Arc,
};
use tauri::utils::platform::current_exe;
mod logging;
pub use logging::refresh_logger;
pub fn run_pending_migrations() -> Result<()> {
let current_exe = current_exe()?;
let current_exe = dunce::canonicalize(current_exe)?;
let file = std::fs::OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(crate::utils::dirs::app_data_dir()?.join("migration.log"))?;
let file = Arc::new(parking_lot::Mutex::new(file));
let (stdout_reader, stdout_writer) = os_pipe::pipe()?;
let (stderr_reader, stderr_writer) = os_pipe::pipe()?;
let errs = Arc::new(parking_lot::Mutex::new(String::new()));
let guard = Arc::new(parking_lot::RwLock::new(()));
let mut child = std::process::Command::new(current_exe)
.arg("migrate")
.stderr(stderr_writer)
.stdout(stdout_writer)
.spawn()?;
let file_ = file.clone();
let guard_ = guard.clone();
let errs_ = errs.clone();
std::thread::spawn(move || {
let _l = guard_.read();
let mut reader = BufReader::new(stdout_reader);
let mut buf = Vec::new();
loop {
buf.clear();
match nyanpasu_utils::io::read_line(&mut reader, &mut buf) {
Ok(0) => break,
Ok(_) => {
let mut file = file_.lock();
let _ = file.write_all(&buf);
}
Err(e) => {
eprintln!("failed to read stdout: {:?}", e);
let mut errs = errs_.lock();
errs.push_str(&format!("failed to read stdout: {:?}\n", e));
break;
}
}
}
});
let errs_ = errs.clone();
let guard_ = guard.clone();
std::thread::spawn(move || {
let _l = guard_.read();
let mut reader = BufReader::new(stderr_reader);
let mut buf = Vec::new();
loop {
buf.clear();
match nyanpasu_utils::io::read_line(&mut reader, &mut buf) {
Ok(0) => break,
Ok(_) => {
let mut file = file.lock();
let _ = file.write_all(&buf);
let mut errs = errs_.lock();
errs.push_str(unsafe { std::str::from_utf8_unchecked(&buf) });
}
Err(e) => {
eprintln!("failed to read stderr: {:?}", e);
let mut errs = errs_.lock();
errs.push_str(&format!("failed to read stderr: {:?}\n", e));
break;
}
}
}
});
let result = child.wait();
let _l = guard.write(); // Just for waiting the thread read all the output
let err = errs.lock();
result
.map_err(|e| anyhow!("Failed to wait for child: {:?}, errs: {}", e, err))
.and_then(|status| {
if !status.success() {
Err(anyhow!("child process failed: {:?}, err: {}", status, err))
} else {
Ok(())
}
})
}
/// Initialize all the config files
/// before tauri setup
pub fn init_config() -> Result<()> {
@@ -144,8 +144,12 @@ export const uninstallService = async () => {
return await invoke<void>("uninstall_service");
};
export const openAppDir = async () => {
return await invoke<void>("open_app_dir");
export const openAppConfigDir = async () => {
return await invoke<void>("open_app_config_dir");
};
export const openAppDataDir = async () => {
return await invoke<void>("open_app_data_dir");
};
export const openCoreDir = async () => {
@@ -16,9 +16,9 @@
"@generouted/react-router": "1.19.6",
"@juggle/resize-observer": "3.4.0",
"@material/material-color-utilities": "0.3.0",
"@mui/icons-material": "5.16.4",
"@mui/lab": "5.0.0-alpha.172",
"@mui/material": "5.16.4",
"@mui/icons-material": "5.16.5",
"@mui/lab": "5.0.0-alpha.173",
"@mui/material": "5.16.5",
"@nyanpasu/interface": "workspace:^",
"@nyanpasu/ui": "workspace:^",
"@tauri-apps/api": "1.6.0",
@@ -43,7 +43,7 @@
"react-router-dom": "6.25.1",
"react-split-grid": "1.0.4",
"swr": "2.2.5",
"virtua": "0.33.3"
"virtua": "0.33.4"
},
"devDependencies": {
"@emotion/babel-plugin": "11.12.0",
@@ -58,9 +58,9 @@
"sass": "1.77.8",
"shiki": "1.11.1",
"tailwindcss-textshadow": "2.1.3",
"vite": "5.3.4",
"vite": "5.3.5",
"vite-plugin-monaco-editor": "1.1.3",
"vite-plugin-sass-dts": "1.3.24",
"vite-plugin-sass-dts": "1.3.25",
"vite-plugin-svgr": "4.2.0",
"vite-tsconfig-paths": "4.3.2"
}
@@ -1,13 +1,17 @@
import { classNames } from "@/utils";
import { Bolt } from "@mui/icons-material";
import { CircularProgress } from "@mui/material";
import clsx from "clsx";
import { memo, useState } from "react";
import FeatureChip from "./feature-chip";
import { getColorForDelay } from "./utils";
import { classNames } from "@/utils";
import { CircularProgress } from "@mui/material";
export const DelayChip = memo(function DelayChip({
className,
delay,
onClick,
}: {
className?: string;
delay: number;
onClick: () => Promise<void>;
}) {
@@ -25,6 +29,7 @@ export const DelayChip = memo(function DelayChip({
return (
<FeatureChip
className={clsx(className, loading && "!visible")}
sx={{
ml: "auto",
color: getColorForDelay(delay),
@@ -33,11 +38,17 @@ export const DelayChip = memo(function DelayChip({
<>
<span
className={classNames(
"transition-opacity",
"transition-opacity flex items-center px-[1px]",
loading ? "opacity-0" : "opacity-1",
)}
>
{delay ? `${delay} ms` : "timeout"}
{delay === -1 ? (
<Bolt className="scale-[0.6]" />
) : !!delay && delay < 10000 ? (
`${delay} ms`
) : (
"timeout"
)}
</span>
<CircularProgress
@@ -0,0 +1,13 @@
.Card {
&.NoDelay {
.DelayChip {
visibility: hidden;
}
&:hover {
.DelayChip {
visibility: visible;
}
}
}
}
@@ -0,0 +1,6 @@
declare const classNames: {
readonly Card: "Card";
readonly NoDelay: "NoDelay";
readonly DelayChip: "DelayChip";
};
export default classNames;
@@ -1,10 +1,13 @@
import Box from "@mui/material/Box";
import { Clash } from "@nyanpasu/interface";
import { CSSProperties, memo, useMemo } from "react";
import { filterDelay } from "./utils";
import { PaperSwitchButton } from "../setting/modules/system-proxy";
import Box from "@mui/material/Box";
import FeatureChip from "./feature-chip";
import DelayChip from "./delay-chip";
import FeatureChip from "./feature-chip";
import { filterDelay } from "./utils";
import clsx from "clsx";
import styles from "./node-card.module.scss";
export const NodeCard = memo(function NodeCard({
node,
@@ -30,13 +33,18 @@ export const NodeCard = memo(function NodeCard({
onClick={onClick}
disabled={disabled}
style={style}
className={clsx(styles.Card, delay === -1 && styles.NoDelay)}
>
<Box width="100%" display="flex" gap={0.5}>
<FeatureChip label={node.type} />
{node.udp && <FeatureChip label="UDP" />}
<DelayChip delay={delay} onClick={onClickDelay} />
<DelayChip
className={styles.DelayChip}
delay={delay}
onClick={onClickDelay}
/>
</Box>
</PaperSwitchButton>
);
@@ -5,7 +5,7 @@ export type History = Clash.Proxy["history"];
export const filterDelay = (history?: History): number => {
if (!history || history.length == 0) {
return 0;
return -1;
} else {
return history[history.length - 1].delay;
}
@@ -15,7 +15,8 @@ export const getColorForDelay = (delay: number): string => {
const { palette } = useTheme();
const delayColorMapping: { [key: string]: string } = {
"0": palette.error.main,
"-1": palette.text.primary,
"0": palette.text.secondary,
"1": palette.text.secondary,
"100": palette.success.main,
"500": palette.warning.main,
@@ -1,20 +1,20 @@
import { useMessage } from "@/hooks/use-notification";
import { sleep } from "@/utils";
import Grid from "@mui/material/Unstable_Grid2";
import {
collectLogs,
openAppDir,
openAppConfigDir,
openAppDataDir,
openCoreDir,
openLogsDir,
restartApplication,
setCustomAppDir,
useNyanpasu,
} from "@nyanpasu/interface";
import { BaseCard } from "@nyanpasu/ui";
import { useTranslation } from "react-i18next";
import Grid from "@mui/material/Unstable_Grid2";
import { PaperButton } from "./modules/nyanpasu-path";
import { useLockFn } from "ahooks";
import { open } from "@tauri-apps/api/dialog";
import { useMessage } from "@/hooks/use-notification";
import { sleep } from "@/utils";
import { useLockFn } from "ahooks";
import { useTranslation } from "react-i18next";
import { PaperButton } from "./modules/nyanpasu-path";
export const SettingNyanpasuPath = () => {
const { t } = useTranslation();
@@ -60,7 +60,8 @@ export const SettingNyanpasuPath = () => {
});
const gridLists = [
{ label: t("Open App Dir"), onClick: openAppDir },
{ label: t("Open Config Dir"), onClick: openAppConfigDir },
{ label: t("Open Data Dir"), onClick: openAppDataDir },
{ label: t("Migration App Path"), onClick: migrateAppPath },
{ label: t("Open Core Dir"), onClick: openCoreDir },
{ label: t("Open Logs Dir"), onClick: openLogsDir },
@@ -98,7 +98,8 @@
"Page Transition Animation Transparent": "Transparent",
"Page Transition Animation None": "None",
"Language": "Language",
"Open App Dir": "Open App Dir",
"Open Config Dir": "Open Config Dir",
"Open Data Dir": "Open Data Dir",
"Open Core Dir": "Open Core Dir",
"Open Logs Dir": "Open Logs Dir",
"Auto Check Updates": "Auto Check Updates",
@@ -90,7 +90,8 @@
"Page Transition Animation Transparent": "Прозрачность",
"Page Transition Animation None": "Нет",
"Language": "Язык",
"Open App Dir": "Открыть папку приложения",
"Open Config Dir": "Открыть папку конфигурации",
"Open Data Dir": "Открыть папку данных",
"Open Core Dir": "Открыть папку ядра",
"Open Logs Dir": "Открыть папку логов",
"Nyanpasu Version": "Версия Nyanpasu",
@@ -100,7 +100,8 @@
"Page Transition Animation Transparent": "透明",
"Page Transition Animation None": "无",
"Language": "语言设置",
"Open App Dir": "应用目录",
"Open Config Dir": "配置目录",
"Open Data Dir": "数据目录",
"Open Core Dir": "内核目录",
"Open Logs Dir": "日志目录",
"Auto Check Updates": "自动检查更新",
+3 -3
View File
@@ -5,9 +5,9 @@
"module": "index.ts",
"dependencies": {
"@material/material-color-utilities": "0.3.0",
"@mui/icons-material": "5.16.4",
"@mui/lab": "5.0.0-alpha.172",
"@mui/material": "5.16.4",
"@mui/icons-material": "5.16.5",
"@mui/lab": "5.0.0-alpha.173",
"@mui/material": "5.16.5",
"@radix-ui/react-dialog": "1.1.1",
"@tauri-apps/api": "1.6.0",
"@types/d3": "7.4.3",
+2 -2
View File
@@ -2,7 +2,7 @@
"manifest_version": 1,
"latest": {
"mihomo": "v1.18.6",
"mihomo_alpha": "alpha-4b9fdac",
"mihomo_alpha": "alpha-cc7823d",
"clash_rs": "v0.1.20",
"clash_premium": "2023-09-05-gdcc8d87"
},
@@ -36,5 +36,5 @@
"darwin-x64": "clash-darwin-amd64-n{}.gz"
}
},
"updated_at": "2024-07-23T22:20:23.982Z"
"updated_at": "2024-07-24T22:20:12.911Z"
}
+4 -4
View File
@@ -5,8 +5,8 @@
"license": "GPL-3.0",
"type": "module",
"scripts": {
"dev": "run-p web:devtools tauri:dev",
"dev:diff": "run-p web:devtools tauri:diff",
"dev": "run-p -r web:devtools tauri:dev",
"dev:diff": "run-p -r web:devtools tauri:diff",
"build": "tauri build -c ./backend/tauri/tauri.conf.json",
"build:nightly": "tauri build -f nightly -c ./backend/tauri/tauri.nightly.conf.json",
"tauri": "tauri",
@@ -91,7 +91,7 @@
"eslint-plugin-react": "7.34.3",
"lint-staged": "15.2.7",
"npm-run-all2": "6.2.2",
"postcss": "8.4.39",
"postcss": "8.4.40",
"postcss-html": "1.7.0",
"postcss-import": "16.1.0",
"postcss-scss": "4.0.9",
@@ -105,7 +105,7 @@
"stylelint-declaration-block-no-ignored-properties": "2.8.0",
"stylelint-order": "6.0.4",
"stylelint-scss": "6.4.1",
"tailwindcss": "3.4.6",
"tailwindcss": "3.4.7",
"tsx": "4.16.2",
"typescript": "5.5.4"
},
+149 -267
View File
@@ -42,7 +42,7 @@ importers:
version: 20.14.12
autoprefixer:
specifier: 10.4.19
version: 10.4.19(postcss@8.4.39)
version: 10.4.19(postcss@8.4.40)
conventional-changelog-conventionalcommits:
specifier: 8.0.0
version: 8.0.0
@@ -89,17 +89,17 @@ importers:
specifier: 6.2.2
version: 6.2.2
postcss:
specifier: 8.4.39
version: 8.4.39
specifier: 8.4.40
version: 8.4.40
postcss-html:
specifier: 1.7.0
version: 1.7.0
postcss-import:
specifier: 16.1.0
version: 16.1.0(postcss@8.4.39)
version: 16.1.0(postcss@8.4.40)
postcss-scss:
specifier: 4.0.9
version: 4.0.9(postcss@8.4.39)
version: 4.0.9(postcss@8.4.40)
prettier:
specifier: 3.3.2
version: 3.3.2
@@ -131,8 +131,8 @@ importers:
specifier: 6.4.1
version: 6.4.1(stylelint@16.7.0(typescript@5.5.4))
tailwindcss:
specifier: 3.4.6
version: 3.4.6
specifier: 3.4.7
version: 3.4.7
tsx:
specifier: 4.16.2
version: 4.16.2
@@ -178,7 +178,7 @@ importers:
version: 11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@generouted/react-router':
specifier: 1.19.6
version: 1.19.6(react-router-dom@6.25.1(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(vite@5.3.4(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
version: 1.19.6(react-router-dom@6.25.1(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(vite@5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
'@juggle/resize-observer':
specifier: 3.4.0
version: 3.4.0
@@ -186,14 +186,14 @@ importers:
specifier: 0.3.0
version: 0.3.0
'@mui/icons-material':
specifier: 5.16.4
version: 5.16.4(@mui/material@5.16.4(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
specifier: 5.16.5
version: 5.16.5(@mui/material@5.16.5(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/lab':
specifier: 5.0.0-alpha.172
version: 5.0.0-alpha.172(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@mui/material@5.16.4(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
specifier: 5.0.0-alpha.173
version: 5.0.0-alpha.173(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@mui/material@5.16.5(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/material':
specifier: 5.16.4
version: 5.16.4(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
specifier: 5.16.5
version: 5.16.5(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@nyanpasu/interface':
specifier: workspace:^
version: link:../interface
@@ -229,13 +229,13 @@ importers:
version: 2.9.1(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
material-react-table:
specifier: 2.13.0
version: 2.13.0(4ynhcepbjgqbvzf6cwzaqs6d4a)
version: 2.13.0(ddsnezj33ahd2557amn3vjv3cu)
monaco-editor:
specifier: 0.50.0
version: 0.50.0
mui-color-input:
specifier: 3.0.0
version: 3.0.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@mui/material@5.16.4(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
version: 3.0.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@mui/material@5.16.5(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
react:
specifier: npm:react@rc
version: 19.0.0-rc-df783f9ea1-20240708
@@ -250,7 +250,7 @@ importers:
version: 1.6.5(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)
react-hook-form-mui:
specifier: 7.0.1
version: 7.0.1(kat3osdwizfjcujladrzqoubpe)
version: 7.0.1(csmbkkiu4natw25gzsxr24gk6i)
react-i18next:
specifier: 15.0.0
version: 15.0.0(i18next@23.12.2)(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)
@@ -267,8 +267,8 @@ importers:
specifier: 2.2.5
version: 2.2.5(react@19.0.0-rc-df783f9ea1-20240708)
virtua:
specifier: 0.33.3
version: 0.33.3(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)
specifier: 0.33.4
version: 0.33.4(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)
devDependencies:
'@emotion/babel-plugin':
specifier: 11.12.0
@@ -290,10 +290,10 @@ importers:
version: 7.16.0(eslint@8.57.0)(typescript@5.5.4)
'@vitejs/plugin-react':
specifier: 4.3.1
version: 4.3.1(vite@5.3.4(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
version: 4.3.1(vite@5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
'@vitejs/plugin-react-swc':
specifier: 3.7.0
version: 3.7.0(vite@5.3.4(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
version: 3.7.0(vite@5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
clsx:
specifier: 2.1.1
version: 2.1.1
@@ -307,20 +307,20 @@ importers:
specifier: 2.1.3
version: 2.1.3
vite:
specifier: 5.3.4
version: 5.3.4(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
specifier: 5.3.5
version: 5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
vite-plugin-monaco-editor:
specifier: npm:vite-plugin-monaco-editor-new@1.1.3
version: vite-plugin-monaco-editor-new@1.1.3(monaco-editor@0.50.0)
vite-plugin-sass-dts:
specifier: 1.3.24
version: 1.3.24(postcss@8.4.39)(prettier@3.3.2)(sass@1.77.8)(vite@5.3.4(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
specifier: 1.3.25
version: 1.3.25(postcss@8.4.40)(prettier@3.3.2)(sass@1.77.8)(vite@5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
vite-plugin-svgr:
specifier: 4.2.0
version: 4.2.0(rollup@4.17.2)(typescript@5.5.4)(vite@5.3.4(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
version: 4.2.0(rollup@4.17.2)(typescript@5.5.4)(vite@5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
vite-tsconfig-paths:
specifier: 4.3.2
version: 4.3.2(typescript@5.5.4)(vite@5.3.4(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
version: 4.3.2(typescript@5.5.4)(vite@5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
frontend/ui:
dependencies:
@@ -328,14 +328,14 @@ importers:
specifier: 0.3.0
version: 0.3.0
'@mui/icons-material':
specifier: 5.16.4
version: 5.16.4(@mui/material@5.16.4(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
specifier: 5.16.5
version: 5.16.5(@mui/material@5.16.5(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/lab':
specifier: 5.0.0-alpha.172
version: 5.0.0-alpha.172(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@mui/material@5.16.4(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
specifier: 5.0.0-alpha.173
version: 5.0.0-alpha.173(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@mui/material@5.16.5(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/material':
specifier: 5.16.4
version: 5.16.4(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
specifier: 5.16.5
version: 5.16.5(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@radix-ui/react-dialog':
specifier: 1.1.1
version: 1.1.1(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
@@ -550,10 +550,6 @@ packages:
resolution: {integrity: sha512-Ja18XcETdEl5mzzACGd+DKgaGJzPTCow7EglgwTmHdwokzDFYh/MHua6lU6DV/hjF2IaOJ4oX2nqnjG7RElKOw==}
engines: {node: '>=6.9.0'}
'@babel/runtime@7.24.7':
resolution: {integrity: sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==}
engines: {node: '>=6.9.0'}
'@babel/runtime@7.24.8':
resolution: {integrity: sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==}
engines: {node: '>=6.9.0'}
@@ -701,9 +697,6 @@ packages:
'@emotion/babel-plugin@11.12.0':
resolution: {integrity: sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==}
'@emotion/cache@11.12.0':
resolution: {integrity: sha512-VFo/F1PthkxHwWDCcXkidyXw70eAkdiNiCzthMI2rRQjFiTvmXt8UDlv/VE1DTsd4CIEY2wQf5AnL2QiPgphlw==}
'@emotion/cache@11.13.0':
resolution: {integrity: sha512-hPV345J/tH0Cwk2wnU/3PBzORQ9HeX+kQSbwI+jslzpRCHE6fSGTohswksA/Ensr8znPzwfzKZCmAM9Lmlhp7g==}
@@ -731,9 +724,6 @@ packages:
'@emotion/serialize@1.3.0':
resolution: {integrity: sha512-jACuBa9SlYajnpIVXB+XOXnfJHyckDfe6fOpORIM6yhBDlqGuExvDdZYHDQGoDf3bZXGv7tNr+LpLjJqiEQ6EA==}
'@emotion/sheet@1.3.0':
resolution: {integrity: sha512-vOPwbKw8fj/oSEa7CWqiKCvLZ1AeLIAApmboGP34xUyUjXalFyf+tMtgMDqP7VMevLPhUa+YWJS46cQUA+tr9A==}
'@emotion/sheet@1.4.0':
resolution: {integrity: sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==}
@@ -1139,11 +1129,11 @@ packages:
'@types/react':
optional: true
'@mui/core-downloads-tracker@5.16.4':
resolution: {integrity: sha512-rNdHXhclwjEZnK+//3SR43YRx0VtjdHnUFhMSGYmAMJve+KiwEja/41EYh8V3pZKqF2geKyfcFUenTfDTYUR4w==}
'@mui/core-downloads-tracker@5.16.5':
resolution: {integrity: sha512-ziFn1oPm6VjvHQcdGcAO+fXvOQEgieIj0BuSqcltFU+JXIxjPdVYNTdn2HU7/Ak5Gabk6k2u7+9PV7oZ6JT5sA==}
'@mui/icons-material@5.16.4':
resolution: {integrity: sha512-j9/CWctv6TH6Dou2uR2EH7UOgu79CW/YcozxCYVLJ7l03pCsiOlJ5sBArnWJxJ+nGkFwyL/1d1k8JEPMDR125A==}
'@mui/icons-material@5.16.5':
resolution: {integrity: sha512-bn88xxU/J9UV0s6+eutq7o3TTOrOlbCX+KshFb8kxgIxJZZfYz3JbAXVMivvoMF4Md6jCVUzM9HEkf4Ajab4tw==}
engines: {node: '>=12.0.0'}
peerDependencies:
'@mui/material': ^5.0.0
@@ -1153,8 +1143,8 @@ packages:
'@types/react':
optional: true
'@mui/lab@5.0.0-alpha.172':
resolution: {integrity: sha512-stpa3WTsDE1HamFR4eeS6Bhxalm+u9FhzzNph/PrDMdWSRBHlJs2mqvZ6FEoO22O7MOCwNMqbXTkvEwsyEf0ew==}
'@mui/lab@5.0.0-alpha.173':
resolution: {integrity: sha512-Gt5zopIWwxDgGy/MXcp6GueD84xFFugFai4hYiXY0zowJpTVnIrTQCQXV004Q7rejJ7aaCntX9hpPJqCrioshA==}
engines: {node: '>=12.0.0'}
peerDependencies:
'@emotion/react': ^11.5.0
@@ -1171,8 +1161,8 @@ packages:
'@types/react':
optional: true
'@mui/material@5.16.4':
resolution: {integrity: sha512-dBnh3/zRYgEVIS3OE4oTbujse3gifA0qLMmuUk13ywsDCbngJsdgwW5LuYeiT5pfA8PGPGSqM7mxNytYXgiMCw==}
'@mui/material@5.16.5':
resolution: {integrity: sha512-eQrjjg4JeczXvh/+8yvJkxWIiKNHVptB/AqpsKfZBWp5mUD5U3VsjODMuUl1K2BSq0omV3CiO/mQmWSSMKSmaA==}
engines: {node: '>=12.0.0'}
peerDependencies:
'@emotion/react': ^11.5.0
@@ -1188,8 +1178,8 @@ packages:
'@types/react':
optional: true
'@mui/private-theming@5.16.1':
resolution: {integrity: sha512-2EGCKnAlq9vRIFj61jNWNXlKAxXp56577OVvsts7fAqRx+G1y6F+N7Q198SBaz8jYQeGKSz8ZMXK/M3FqjdEyw==}
'@mui/private-theming@5.16.5':
resolution: {integrity: sha512-CSLg0YkpDqg0aXOxtjo3oTMd3XWMxvNb5d0v4AYVqwOltU8q6GvnZjhWyCLjGSCrcgfwm6/VDjaKLPlR14wxIA==}
engines: {node: '>=12.0.0'}
peerDependencies:
'@types/react': npm:types-react@rc
@@ -1198,29 +1188,6 @@ packages:
'@types/react':
optional: true
'@mui/private-theming@5.16.4':
resolution: {integrity: sha512-ZsAm8cq31SJ37SVWLRlu02v9SRthxnfQofaiv14L5Bht51B0dz6yQEoVU/V8UduZDCCIrWkBHuReVfKhE/UuXA==}
engines: {node: '>=12.0.0'}
peerDependencies:
'@types/react': npm:types-react@rc
react: npm:react@rc
peerDependenciesMeta:
'@types/react':
optional: true
'@mui/styled-engine@5.16.1':
resolution: {integrity: sha512-JwWUBaYR8HHCFefSeos0z6JoTbu0MnjAuNHu4QoDgPxl2EE70XH38CsKay66Iy0QkNWmGTRXVU2sVFgUOPL/Dw==}
engines: {node: '>=12.0.0'}
peerDependencies:
'@emotion/react': ^11.4.1
'@emotion/styled': ^11.3.0
react: npm:react@rc
peerDependenciesMeta:
'@emotion/react':
optional: true
'@emotion/styled':
optional: true
'@mui/styled-engine@5.16.4':
resolution: {integrity: sha512-0+mnkf+UiAmTVB8PZFqOhqf729Yh0Cxq29/5cA3VAyDVTRIUUQ8FXQhiAhUIbijFmM72rY80ahFPXIm4WDbzcA==}
engines: {node: '>=12.0.0'}
@@ -1234,24 +1201,8 @@ packages:
'@emotion/styled':
optional: true
'@mui/system@5.16.1':
resolution: {integrity: sha512-VaFcClC+uhvIEzhzcNmh9FRBvrG9IPjsOokhj6U1HPZsFnLzHV7AD7dJcT6LxWoiIZj9Ej0GK+MGh/b8+BtSlQ==}
engines: {node: '>=12.0.0'}
peerDependencies:
'@emotion/react': ^11.5.0
'@emotion/styled': ^11.3.0
'@types/react': npm:types-react@rc
react: npm:react@rc
peerDependenciesMeta:
'@emotion/react':
optional: true
'@emotion/styled':
optional: true
'@types/react':
optional: true
'@mui/system@5.16.4':
resolution: {integrity: sha512-ET1Ujl2/8hbsD611/mqUuNArMCGv/fIWO/f8B3ZqF5iyPHM2aS74vhTNyjytncc4i6dYwGxNk+tLa7GwjNS0/w==}
'@mui/system@5.16.5':
resolution: {integrity: sha512-uzIUGdrWddUx1HPxW4+B2o4vpgKyRxGe/8BxbfXVDPNPHX75c782TseoCnR/VyfnZJfqX87GcxDmnZEE1c031g==}
engines: {node: '>=12.0.0'}
peerDependencies:
'@emotion/react': ^11.5.0
@@ -1274,18 +1225,8 @@ packages:
'@types/react':
optional: true
'@mui/utils@5.16.1':
resolution: {integrity: sha512-4UQzK46tAEYs2xZv79hRiIc3GxZScd00kGPDadNrGztAEZlmSaUY8cb9ITd2xCiTfzsx5AN6DH8aaQ8QEKJQeQ==}
engines: {node: '>=12.0.0'}
peerDependencies:
'@types/react': npm:types-react@rc
react: npm:react@rc
peerDependenciesMeta:
'@types/react':
optional: true
'@mui/utils@5.16.4':
resolution: {integrity: sha512-nlppYwq10TBIFqp7qxY0SvbACOXeOjeVL3pOcDsK0FT8XjrEXh9/+lkg8AEIzD16z7YfiJDQjaJG2OLkE7BxNg==}
'@mui/utils@5.16.5':
resolution: {integrity: sha512-CwhcA9y44XwK7k2joL3Y29mRUnoBt+gOZZdGyw7YihbEwEErJYBtDwbZwVgH68zAljGe/b+Kd5bzfl63Gi3R2A==}
engines: {node: '>=12.0.0'}
peerDependencies:
'@types/react': npm:types-react@rc
@@ -4927,8 +4868,8 @@ packages:
resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==}
engines: {node: ^10 || ^12 || >=14}
postcss@8.4.39:
resolution: {integrity: sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==}
postcss@8.4.40:
resolution: {integrity: sha512-YF2kKIUzAofPMpfH6hOi2cGnv/HrUlfucspc7pDyvv7kGdqXrfj8SCl/t8owkEgKEuu8ZcRjSOxFxVLqwChZ2Q==}
engines: {node: ^10 || ^12 || >=14}
prelude-ls@1.2.1:
@@ -5598,8 +5539,8 @@ packages:
engines: {node: '>=8.9.0'}
hasBin: true
tailwindcss@3.4.6:
resolution: {integrity: sha512-1uRHzPB+Vzu57ocybfZ4jh5Q3SdlH7XW23J5sQoM9LhE9eIOlzxer/3XPSsycvih3rboRsvt0QCmzSrqyOYUIA==}
tailwindcss@3.4.7:
resolution: {integrity: sha512-rxWZbe87YJb4OcSopb7up2Ba4U82BoiSGUdoDr3Ydrg9ckxFS/YWsvhN323GMcddgU65QRy7JndC7ahhInhvlQ==}
engines: {node: '>=14.0.0'}
hasBin: true
@@ -5861,8 +5802,8 @@ packages:
vfile@6.0.1:
resolution: {integrity: sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==}
virtua@0.33.3:
resolution: {integrity: sha512-Zxr2hhmTHARMHdZjs5fvd17bHH2YJ1uZZGaw4SKmynDEXtHFzJn/pL9xYJeXWZ8UfXNIBbPvGlHGpruCRbLHIg==}
virtua@0.33.4:
resolution: {integrity: sha512-E5PjR2wxebizA0KDFmGnvpPCeRsbAmmJ/Yif+ZH4HPEylrFqIeBOsgNZqHjsMnu5WqfSgEMIq+Qu0WOIC+3UyA==}
peerDependencies:
react: npm:react@rc
react-dom: npm:react-dom@rc
@@ -5886,8 +5827,8 @@ packages:
peerDependencies:
monaco-editor: '>=0.45.0'
vite-plugin-sass-dts@1.3.24:
resolution: {integrity: sha512-t6qxkC8seJJuYmlioKu2QFOJhJgIXwmAGbfOwmZ41QH1eqpqzgQkkXgWVLRf0DlO3FNMPn2y5bO9+R1N7LRgTA==}
vite-plugin-sass-dts@1.3.25:
resolution: {integrity: sha512-HJkblBpM/AWZuAJuR/GO1YIOlLGfk6sPFcD2kKE4wCpqsgIWXgKHn/d6jIpzKuF2so6oLVq7M4AfeXxD0Wfotw==}
engines: {node: '>=20'}
peerDependencies:
postcss: ^8
@@ -5908,8 +5849,8 @@ packages:
vite:
optional: true
vite@5.3.4:
resolution: {integrity: sha512-Cw+7zL3ZG9/NZBB8C+8QbQZmR54GwqIz+WMI4b3JgdYJvX+ny9AjJXqkGQlDXSXRP9rP0B4tbciRMOVEKulVOA==}
vite@5.3.5:
resolution: {integrity: sha512-MdjglKR6AQXQb9JGiS7Rc2wC6uMjcm7Go/NHNO63EwiJXfuk9PgqiP/n5IDJCziMkfw9n4Ubp7lttNwz+8ZVKA==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
peerDependencies:
@@ -6212,10 +6153,6 @@ snapshots:
dependencies:
regenerator-runtime: 0.14.1
'@babel/runtime@7.24.7':
dependencies:
regenerator-runtime: 0.14.1
'@babel/runtime@7.24.8':
dependencies:
regenerator-runtime: 0.14.1
@@ -6432,14 +6369,6 @@ snapshots:
source-map: 0.5.7
stylis: 4.2.0
'@emotion/cache@11.12.0':
dependencies:
'@emotion/memoize': 0.9.0
'@emotion/sheet': 1.3.0
'@emotion/utils': 1.3.0
'@emotion/weak-memoize': 0.4.0
stylis: 4.2.0
'@emotion/cache@11.13.0':
dependencies:
'@emotion/memoize': 0.9.0
@@ -6486,8 +6415,6 @@ snapshots:
'@emotion/utils': 1.4.0
csstype: 3.1.3
'@emotion/sheet@1.3.0': {}
'@emotion/sheet@1.4.0': {}
'@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)':
@@ -6700,13 +6627,13 @@ snapshots:
postcss: 7.0.32
purgecss: 2.3.0
'@generouted/react-router@1.19.6(react-router-dom@6.25.1(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(vite@5.3.4(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))':
'@generouted/react-router@1.19.6(react-router-dom@6.25.1(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(vite@5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))':
dependencies:
fast-glob: 3.3.2
generouted: 1.19.6(vite@5.3.4(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
generouted: 1.19.6(vite@5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
react: 19.0.0-rc-df783f9ea1-20240708
react-router-dom: 6.25.1(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)
vite: 5.3.4(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
vite: 5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
'@humanwhocodes/config-array@0.11.14':
dependencies:
@@ -6755,7 +6682,7 @@ snapshots:
'@babel/runtime': 7.24.8
'@floating-ui/react-dom': 2.0.9(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)
'@mui/types': 7.2.15(types-react@19.0.0-rc.1)
'@mui/utils': 5.16.1(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/utils': 5.16.5(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@popperjs/core': 2.11.8
clsx: 2.1.1
prop-types: 15.8.1
@@ -6764,24 +6691,24 @@ snapshots:
optionalDependencies:
'@types/react': types-react@19.0.0-rc.1
'@mui/core-downloads-tracker@5.16.4': {}
'@mui/core-downloads-tracker@5.16.5': {}
'@mui/icons-material@5.16.4(@mui/material@5.16.4(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)':
'@mui/icons-material@5.16.5(@mui/material@5.16.5(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)':
dependencies:
'@babel/runtime': 7.24.7
'@mui/material': 5.16.4(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@babel/runtime': 7.24.8
'@mui/material': 5.16.5(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
react: 19.0.0-rc-df783f9ea1-20240708
optionalDependencies:
'@types/react': types-react@19.0.0-rc.1
'@mui/lab@5.0.0-alpha.172(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@mui/material@5.16.4(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)':
'@mui/lab@5.0.0-alpha.173(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@mui/material@5.16.5(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)':
dependencies:
'@babel/runtime': 7.24.7
'@babel/runtime': 7.24.8
'@mui/base': 5.0.0-beta.40(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/material': 5.16.4(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/system': 5.16.1(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/material': 5.16.5(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/system': 5.16.5(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/types': 7.2.15(types-react@19.0.0-rc.1)
'@mui/utils': 5.16.1(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/utils': 5.16.5(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
clsx: 2.1.1
prop-types: 15.8.1
react: 19.0.0-rc-df783f9ea1-20240708
@@ -6791,13 +6718,13 @@ snapshots:
'@emotion/styled': 11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@types/react': types-react@19.0.0-rc.1
'@mui/material@5.16.4(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)':
'@mui/material@5.16.5(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)':
dependencies:
'@babel/runtime': 7.24.7
'@mui/core-downloads-tracker': 5.16.4
'@mui/system': 5.16.4(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@babel/runtime': 7.24.8
'@mui/core-downloads-tracker': 5.16.5
'@mui/system': 5.16.5(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/types': 7.2.15(types-react@19.0.0-rc.1)
'@mui/utils': 5.16.4(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/utils': 5.16.5(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@popperjs/core': 2.11.8
'@types/react-transition-group': 4.4.10
clsx: 2.1.1
@@ -6812,39 +6739,19 @@ snapshots:
'@emotion/styled': 11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@types/react': types-react@19.0.0-rc.1
'@mui/private-theming@5.16.1(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)':
'@mui/private-theming@5.16.5(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)':
dependencies:
'@babel/runtime': 7.24.8
'@mui/utils': 5.16.1(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/utils': 5.16.5(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
prop-types: 15.8.1
react: 19.0.0-rc-df783f9ea1-20240708
optionalDependencies:
'@types/react': types-react@19.0.0-rc.1
'@mui/private-theming@5.16.4(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)':
dependencies:
'@babel/runtime': 7.24.8
'@mui/utils': 5.16.4(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
prop-types: 15.8.1
react: 19.0.0-rc-df783f9ea1-20240708
optionalDependencies:
'@types/react': types-react@19.0.0-rc.1
'@mui/styled-engine@5.16.1(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)':
dependencies:
'@babel/runtime': 7.24.8
'@emotion/cache': 11.12.0
csstype: 3.1.3
prop-types: 15.8.1
react: 19.0.0-rc-df783f9ea1-20240708
optionalDependencies:
'@emotion/react': 11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@emotion/styled': 11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/styled-engine@5.16.4(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)':
dependencies:
'@babel/runtime': 7.24.8
'@emotion/cache': 11.12.0
'@emotion/cache': 11.13.0
csstype: 3.1.3
prop-types: 15.8.1
react: 19.0.0-rc-df783f9ea1-20240708
@@ -6852,29 +6759,13 @@ snapshots:
'@emotion/react': 11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@emotion/styled': 11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/system@5.16.1(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)':
'@mui/system@5.16.5(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)':
dependencies:
'@babel/runtime': 7.24.8
'@mui/private-theming': 5.16.1(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/styled-engine': 5.16.1(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)
'@mui/types': 7.2.15(types-react@19.0.0-rc.1)
'@mui/utils': 5.16.1(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
clsx: 2.1.1
csstype: 3.1.3
prop-types: 15.8.1
react: 19.0.0-rc-df783f9ea1-20240708
optionalDependencies:
'@emotion/react': 11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@emotion/styled': 11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@types/react': types-react@19.0.0-rc.1
'@mui/system@5.16.4(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)':
dependencies:
'@babel/runtime': 7.24.8
'@mui/private-theming': 5.16.4(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/private-theming': 5.16.5(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/styled-engine': 5.16.4(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)
'@mui/types': 7.2.15(types-react@19.0.0-rc.1)
'@mui/utils': 5.16.4(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/utils': 5.16.5(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
clsx: 2.1.1
csstype: 3.1.3
prop-types: 15.8.1
@@ -6888,19 +6779,10 @@ snapshots:
optionalDependencies:
'@types/react': types-react@19.0.0-rc.1
'@mui/utils@5.16.1(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)':
dependencies:
'@babel/runtime': 7.24.8
'@types/prop-types': 15.7.12
prop-types: 15.8.1
react: 19.0.0-rc-df783f9ea1-20240708
react-is: 18.3.1
optionalDependencies:
'@types/react': types-react@19.0.0-rc.1
'@mui/utils@5.16.4(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)':
'@mui/utils@5.16.5(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)':
dependencies:
'@babel/runtime': 7.24.8
'@mui/types': 7.2.15(types-react@19.0.0-rc.1)
'@types/prop-types': 15.7.12
clsx: 2.1.1
prop-types: 15.8.1
@@ -6909,13 +6791,13 @@ snapshots:
optionalDependencies:
'@types/react': types-react@19.0.0-rc.1
'@mui/x-date-pickers@7.9.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@mui/material@5.16.4(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(dayjs@1.11.12)(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)':
'@mui/x-date-pickers@7.9.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@mui/material@5.16.5(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(dayjs@1.11.12)(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)':
dependencies:
'@babel/runtime': 7.24.8
'@mui/base': 5.0.0-beta.40(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/material': 5.16.4(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/system': 5.16.4(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/utils': 5.16.4(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/material': 5.16.5(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/system': 5.16.5(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/utils': 5.16.5(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@types/react-transition-group': 4.4.10
clsx: 2.1.1
prop-types: 15.8.1
@@ -7749,11 +7631,11 @@ snapshots:
'@types/postcss-modules-local-by-default@4.0.2':
dependencies:
postcss: 8.4.39
postcss: 8.4.40
'@types/postcss-modules-scope@3.0.4':
dependencies:
postcss: 8.4.39
postcss: 8.4.40
'@types/prop-types@15.7.12': {}
@@ -7857,21 +7739,21 @@ snapshots:
'@ungap/structured-clone@1.2.0': {}
'@vitejs/plugin-react-swc@3.7.0(vite@5.3.4(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))':
'@vitejs/plugin-react-swc@3.7.0(vite@5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))':
dependencies:
'@swc/core': 1.6.1
vite: 5.3.4(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
vite: 5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
transitivePeerDependencies:
- '@swc/helpers'
'@vitejs/plugin-react@4.3.1(vite@5.3.4(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))':
'@vitejs/plugin-react@4.3.1(vite@5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))':
dependencies:
'@babel/core': 7.24.5
'@babel/plugin-transform-react-jsx-self': 7.24.5(@babel/core@7.24.5)
'@babel/plugin-transform-react-jsx-source': 7.24.1(@babel/core@7.24.5)
'@types/babel__core': 7.20.5
react-refresh: 0.14.2
vite: 5.3.4(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
vite: 5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
transitivePeerDependencies:
- supports-color
@@ -8068,14 +7950,14 @@ snapshots:
asynckit@0.4.0: {}
autoprefixer@10.4.19(postcss@8.4.39):
autoprefixer@10.4.19(postcss@8.4.40):
dependencies:
browserslist: 4.23.0
caniuse-lite: 1.0.30001616
fraction.js: 4.3.7
normalize-range: 0.1.2
picocolors: 1.0.1
postcss: 8.4.39
postcss: 8.4.40
postcss-value-parser: 4.2.0
autoprefixer@9.8.8:
@@ -9368,9 +9250,9 @@ snapshots:
functions-have-names@1.2.3: {}
generouted@1.19.6(vite@5.3.4(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)):
generouted@1.19.6(vite@5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)):
dependencies:
vite: 5.3.4(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
vite: 5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
gensync@1.0.0-beta.2: {}
@@ -10107,13 +9989,13 @@ snapshots:
escape-string-regexp: 4.0.0
optional: true
material-react-table@2.13.0(4ynhcepbjgqbvzf6cwzaqs6d4a):
material-react-table@2.13.0(ddsnezj33ahd2557amn3vjv3cu):
dependencies:
'@emotion/react': 11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@emotion/styled': 11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/icons-material': 5.16.4(@mui/material@5.16.4(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/material': 5.16.4(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/x-date-pickers': 7.9.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@mui/material@5.16.4(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(dayjs@1.11.12)(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/icons-material': 5.16.5(@mui/material@5.16.5(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/material': 5.16.5(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/x-date-pickers': 7.9.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@mui/material@5.16.5(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(dayjs@1.11.12)(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@tanstack/match-sorter-utils': 8.15.1
'@tanstack/react-table': 8.16.0(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)
'@tanstack/react-virtual': 3.3.0(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)
@@ -10401,12 +10283,12 @@ snapshots:
ms@2.1.3: {}
mui-color-input@3.0.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@mui/material@5.16.4(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1):
mui-color-input@3.0.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@mui/material@5.16.5(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1):
dependencies:
'@ctrl/tinycolor': 4.1.0
'@emotion/react': 11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@emotion/styled': 11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/material': 5.16.4(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/material': 5.16.5(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
react: 19.0.0-rc-df783f9ea1-20240708
react-dom: 19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708)
optionalDependencies:
@@ -10697,19 +10579,19 @@ snapshots:
dependencies:
htmlparser2: 8.0.2
js-tokens: 9.0.0
postcss: 8.4.39
postcss-safe-parser: 6.0.0(postcss@8.4.39)
postcss: 8.4.40
postcss-safe-parser: 6.0.0(postcss@8.4.40)
postcss-import@15.1.0(postcss@8.4.39):
postcss-import@15.1.0(postcss@8.4.40):
dependencies:
postcss: 8.4.39
postcss: 8.4.40
postcss-value-parser: 4.2.0
read-cache: 1.0.0
resolve: 1.22.8
postcss-import@16.1.0(postcss@8.4.39):
postcss-import@16.1.0(postcss@8.4.40):
dependencies:
postcss: 8.4.39
postcss: 8.4.40
postcss-value-parser: 4.2.0
read-cache: 1.0.0
resolve: 1.22.8
@@ -10719,10 +10601,10 @@ snapshots:
camelcase-css: 2.0.1
postcss: 7.0.39
postcss-js@4.0.1(postcss@8.4.39):
postcss-js@4.0.1(postcss@8.4.40):
dependencies:
camelcase-css: 2.0.1
postcss: 8.4.39
postcss: 8.4.40
postcss-load-config@3.1.4(postcss@8.4.38):
dependencies:
@@ -10731,12 +10613,12 @@ snapshots:
optionalDependencies:
postcss: 8.4.38
postcss-load-config@4.0.2(postcss@8.4.39):
postcss-load-config@4.0.2(postcss@8.4.40):
dependencies:
lilconfig: 3.1.1
yaml: 2.4.2
optionalDependencies:
postcss: 8.4.39
postcss: 8.4.40
postcss-media-query-parser@0.2.3: {}
@@ -10761,24 +10643,24 @@ snapshots:
postcss: 7.0.39
postcss-selector-parser: 6.1.0
postcss-nested@6.0.1(postcss@8.4.39):
postcss-nested@6.0.1(postcss@8.4.40):
dependencies:
postcss: 8.4.39
postcss: 8.4.40
postcss-selector-parser: 6.1.0
postcss-resolve-nested-selector@0.1.1: {}
postcss-safe-parser@6.0.0(postcss@8.4.39):
postcss-safe-parser@6.0.0(postcss@8.4.40):
dependencies:
postcss: 8.4.39
postcss: 8.4.40
postcss-safe-parser@7.0.0(postcss@8.4.39):
postcss-safe-parser@7.0.0(postcss@8.4.40):
dependencies:
postcss: 8.4.39
postcss: 8.4.40
postcss-scss@4.0.9(postcss@8.4.39):
postcss-scss@4.0.9(postcss@8.4.40):
dependencies:
postcss: 8.4.39
postcss: 8.4.40
postcss-selector-parser@6.0.16:
dependencies:
@@ -10790,9 +10672,9 @@ snapshots:
cssesc: 3.0.0
util-deprecate: 1.0.2
postcss-sorting@8.0.2(postcss@8.4.39):
postcss-sorting@8.0.2(postcss@8.4.40):
dependencies:
postcss: 8.4.39
postcss: 8.4.40
postcss-value-parser@3.3.1: {}
@@ -10821,7 +10703,7 @@ snapshots:
picocolors: 1.0.1
source-map-js: 1.2.0
postcss@8.4.39:
postcss@8.4.40:
dependencies:
nanoid: 3.3.7
picocolors: 1.0.1
@@ -10924,14 +10806,14 @@ snapshots:
react: 19.0.0-rc-df783f9ea1-20240708
react-dom: 19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708)
react-hook-form-mui@7.0.1(kat3osdwizfjcujladrzqoubpe):
react-hook-form-mui@7.0.1(csmbkkiu4natw25gzsxr24gk6i):
dependencies:
'@mui/material': 5.16.4(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/material': 5.16.5(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
react: 19.0.0-rc-df783f9ea1-20240708
react-hook-form: 7.52.1(react@19.0.0-rc-df783f9ea1-20240708)
optionalDependencies:
'@mui/icons-material': 5.16.4(@mui/material@5.16.4(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/x-date-pickers': 7.9.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@mui/material@5.16.4(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(dayjs@1.11.12)(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/icons-material': 5.16.5(@mui/material@5.16.5(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
'@mui/x-date-pickers': 7.9.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@mui/material@5.16.5(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(dayjs@1.11.12)(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
react-hook-form@7.52.1(react@19.0.0-rc-df783f9ea1-20240708):
dependencies:
@@ -11442,8 +11324,8 @@ snapshots:
stylelint-order@6.0.4(stylelint@16.7.0(typescript@5.5.4)):
dependencies:
postcss: 8.4.39
postcss-sorting: 8.0.2(postcss@8.4.39)
postcss: 8.4.40
postcss-sorting: 8.0.2(postcss@8.4.40)
stylelint: 16.7.0(typescript@5.5.4)
stylelint-scss@6.4.1(stylelint@16.7.0(typescript@5.5.4)):
@@ -11484,9 +11366,9 @@ snapshots:
micromatch: 4.0.7
normalize-path: 3.0.0
picocolors: 1.0.1
postcss: 8.4.39
postcss: 8.4.40
postcss-resolve-nested-selector: 0.1.1
postcss-safe-parser: 7.0.0(postcss@8.4.39)
postcss-safe-parser: 7.0.0(postcss@8.4.40)
postcss-selector-parser: 6.1.0
postcss-value-parser: 4.2.0
resolve-from: 5.0.0
@@ -11601,7 +11483,7 @@ snapshots:
reduce-css-calc: 2.1.8
resolve: 1.22.8
tailwindcss@3.4.6:
tailwindcss@3.4.7:
dependencies:
'@alloc/quick-lru': 5.2.0
arg: 5.0.2
@@ -11617,11 +11499,11 @@ snapshots:
normalize-path: 3.0.0
object-hash: 3.0.0
picocolors: 1.0.1
postcss: 8.4.39
postcss-import: 15.1.0(postcss@8.4.39)
postcss-js: 4.0.1(postcss@8.4.39)
postcss-load-config: 4.0.2(postcss@8.4.39)
postcss-nested: 6.0.1(postcss@8.4.39)
postcss: 8.4.40
postcss-import: 15.1.0(postcss@8.4.40)
postcss-js: 4.0.1(postcss@8.4.40)
postcss-load-config: 4.0.2(postcss@8.4.40)
postcss-nested: 6.0.1(postcss@8.4.40)
postcss-selector-parser: 6.1.0
resolve: 1.22.8
sucrase: 3.35.0
@@ -11936,7 +11818,7 @@ snapshots:
unist-util-stringify-position: 4.0.0
vfile-message: 4.0.2
virtua@0.33.3(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708):
virtua@0.33.4(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708):
optionalDependencies:
react: 19.0.0-rc-df783f9ea1-20240708
react-dom: 19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708)
@@ -11946,40 +11828,40 @@ snapshots:
esbuild: 0.19.12
monaco-editor: 0.50.0
vite-plugin-sass-dts@1.3.24(postcss@8.4.39)(prettier@3.3.2)(sass@1.77.8)(vite@5.3.4(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)):
vite-plugin-sass-dts@1.3.25(postcss@8.4.40)(prettier@3.3.2)(sass@1.77.8)(vite@5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)):
dependencies:
postcss: 8.4.39
postcss-js: 4.0.1(postcss@8.4.39)
postcss: 8.4.40
postcss-js: 4.0.1(postcss@8.4.40)
prettier: 3.3.2
sass: 1.77.8
vite: 5.3.4(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
vite: 5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
vite-plugin-svgr@4.2.0(rollup@4.17.2)(typescript@5.5.4)(vite@5.3.4(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)):
vite-plugin-svgr@4.2.0(rollup@4.17.2)(typescript@5.5.4)(vite@5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)):
dependencies:
'@rollup/pluginutils': 5.1.0(rollup@4.17.2)
'@svgr/core': 8.1.0(typescript@5.5.4)
'@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.5.4))
vite: 5.3.4(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
vite: 5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
transitivePeerDependencies:
- rollup
- supports-color
- typescript
vite-tsconfig-paths@4.3.2(typescript@5.5.4)(vite@5.3.4(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)):
vite-tsconfig-paths@4.3.2(typescript@5.5.4)(vite@5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)):
dependencies:
debug: 4.3.4
globrex: 0.1.2
tsconfck: 3.0.3(typescript@5.5.4)
optionalDependencies:
vite: 5.3.4(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
vite: 5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
transitivePeerDependencies:
- supports-color
- typescript
vite@5.3.4(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0):
vite@5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0):
dependencies:
esbuild: 0.21.5
postcss: 8.4.39
postcss: 8.4.40
rollup: 4.17.2
optionalDependencies:
'@types/node': 20.14.12
+1 -1
View File
@@ -1,2 +1,2 @@
[toolchain]
channel = "stable"
channel = "nightly"
+1 -1
View File
@@ -39,7 +39,7 @@ const GITHUB_TOKEN = process.env.GITHUB_TOKEN;
const resourceFormats = [
"x64-setup.exe",
"x64_portable.zip",
"amd64.AppImage",
"x86_64.rpm",
"amd64.deb",
"x64.dmg",
"aarch64.dmg",
+6 -7
View File
@@ -223,6 +223,11 @@ menu "Target Images"
depends on GRUB_IMAGES || GRUB_EFI_IMAGES
default y
config GRUB_SERIAL
string "Serial port device"
depends on GRUB_IMAGES || GRUB_EFI_IMAGES
default "ttyS0"
config GRUB_BAUDRATE
int "Serial port baud rate"
depends on GRUB_IMAGES || GRUB_EFI_IMAGES
@@ -231,8 +236,7 @@ menu "Target Images"
config GRUB_FLOWCONTROL
bool "Use RTE/CTS on serial console"
depends on GRUB_IMAGES || GRUB_EFI_IMAGES
depends on TARGET_SERIAL != ""
depends on GRUB_SERIAL != ""
default n
config GRUB_BOOTOPTS
@@ -285,11 +289,6 @@ menu "Target Images"
depends on GRUB_IMAGES || GRUB_EFI_IMAGES
select PACKAGE_kmod-e1000
config TARGET_SERIAL
string "Serial port device"
depends on TARGET_x86 || TARGET_armvirt || TARGET_loongarch64
default "ttyS0"
config TARGET_IMAGES_GZIP
bool "GZip images"
depends on TARGET_ROOTFS_EXT4FS || TARGET_x86 || TARGET_armvirt || TARGET_malta || TARGET_loongarch64
+2
View File
@@ -69,3 +69,5 @@ func WithDSCP(dscp uint8) Addition {
metadata.DSCP = dscp
}
}
func Placeholder(metadata *C.Metadata) {}
+1 -1
View File
@@ -13,7 +13,7 @@ import (
"github.com/metacubex/mihomo/transport/socks5"
)
func newClient(srcConn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) *http.Client {
func newClient(srcConn net.Conn, tunnel C.Tunnel, additions []inbound.Addition) *http.Client { // additions using slice let caller can change its value (without size) after newClient return
return &http.Client{
Transport: &http.Transport{
// from http.DefaultTransport
+32 -35
View File
@@ -10,10 +10,9 @@ import (
"sync"
"github.com/metacubex/mihomo/adapter/inbound"
"github.com/metacubex/mihomo/common/lru"
N "github.com/metacubex/mihomo/common/net"
"github.com/metacubex/mihomo/component/auth"
C "github.com/metacubex/mihomo/constant"
authStore "github.com/metacubex/mihomo/listener/auth"
"github.com/metacubex/mihomo/log"
)
@@ -31,8 +30,10 @@ func (b *bodyWrapper) Read(p []byte) (n int, err error) {
return n, err
}
func HandleConn(c net.Conn, tunnel C.Tunnel, cache *lru.LruCache[string, bool], additions ...inbound.Addition) {
client := newClient(c, tunnel, additions...)
func HandleConn(c net.Conn, tunnel C.Tunnel, authenticator auth.Authenticator, additions ...inbound.Addition) {
additions = append(additions, inbound.Placeholder) // Add a placeholder for InUser
inUserIdx := len(additions) - 1
client := newClient(c, tunnel, additions)
defer client.CloseIdleConnections()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
@@ -41,7 +42,8 @@ func HandleConn(c net.Conn, tunnel C.Tunnel, cache *lru.LruCache[string, bool],
conn := N.NewBufferedConn(c)
keepAlive := true
trusted := cache == nil // disable authenticate if lru is nil
trusted := authenticator == nil // disable authenticate if lru is nil
lastUser := ""
for keepAlive {
peekMutex.Lock()
@@ -57,12 +59,10 @@ func HandleConn(c net.Conn, tunnel C.Tunnel, cache *lru.LruCache[string, bool],
var resp *http.Response
if !trusted {
var user string
resp, user = authenticate(request, cache)
additions = append(additions, inbound.WithInUser(user))
trusted = resp == nil
}
var user string
resp, user = authenticate(request, authenticator) // always call authenticate function to get user
trusted = trusted || resp == nil
additions[inUserIdx] = inbound.WithInUser(user)
if trusted {
if request.Method == http.MethodConnect {
@@ -89,6 +89,13 @@ func HandleConn(c net.Conn, tunnel C.Tunnel, cache *lru.LruCache[string, bool],
return // hijack connection
}
// ensure there is a client with correct additions
// when the authenticated user changed, outbound client should close idle connections
if user != lastUser {
client.CloseIdleConnections()
lastUser = user
}
removeHopByHopHeaders(request.Header)
removeExtraHTTPHostPort(request)
@@ -138,34 +145,24 @@ func HandleConn(c net.Conn, tunnel C.Tunnel, cache *lru.LruCache[string, bool],
_ = conn.Close()
}
func authenticate(request *http.Request, cache *lru.LruCache[string, bool]) (resp *http.Response, u string) {
authenticator := authStore.Authenticator()
func authenticate(request *http.Request, authenticator auth.Authenticator) (resp *http.Response, user string) {
if inbound.SkipAuthRemoteAddress(request.RemoteAddr) {
authenticator = nil
}
if authenticator != nil {
credential := parseBasicProxyAuthorization(request)
if credential == "" {
resp := responseWith(request, http.StatusProxyAuthRequired)
resp.Header.Set("Proxy-Authenticate", "Basic")
return resp, ""
}
authed, exist := cache.Get(credential)
if !exist {
user, pass, err := decodeBasicProxyAuthorization(credential)
authed = err == nil && authenticator.Verify(user, pass)
u = user
cache.Set(credential, authed)
}
if !authed {
log.Infoln("Auth failed from %s", request.RemoteAddr)
return responseWith(request, http.StatusForbidden), u
}
credential := parseBasicProxyAuthorization(request)
if credential == "" && authenticator != nil {
resp = responseWith(request, http.StatusProxyAuthRequired)
resp.Header.Set("Proxy-Authenticate", "Basic")
return
}
return nil, u
user, pass, err := decodeBasicProxyAuthorization(credential)
authed := authenticator == nil || (err == nil && authenticator.Verify(user, pass))
if !authed {
log.Infoln("Auth failed from %s", request.RemoteAddr)
return responseWith(request, http.StatusForbidden), user
}
log.Debugln("Auth success from %s -> %s", request.RemoteAddr, user)
return
}
func responseWith(request *http.Request, statusCode int) *http.Response {
+5 -9
View File
@@ -4,9 +4,10 @@ import (
"net"
"github.com/metacubex/mihomo/adapter/inbound"
"github.com/metacubex/mihomo/common/lru"
"github.com/metacubex/mihomo/component/auth"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/constant/features"
authStore "github.com/metacubex/mihomo/listener/auth"
)
type Listener struct {
@@ -32,10 +33,10 @@ func (l *Listener) Close() error {
}
func New(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener, error) {
return NewWithAuthenticate(addr, tunnel, true, additions...)
return NewWithAuthenticate(addr, tunnel, authStore.Authenticator(), additions...)
}
func NewWithAuthenticate(addr string, tunnel C.Tunnel, authenticate bool, additions ...inbound.Addition) (*Listener, error) {
func NewWithAuthenticate(addr string, tunnel C.Tunnel, authenticator auth.Authenticator, additions ...inbound.Addition) (*Listener, error) {
isDefault := false
if len(additions) == 0 {
isDefault = true
@@ -50,11 +51,6 @@ func NewWithAuthenticate(addr string, tunnel C.Tunnel, authenticate bool, additi
return nil, err
}
var c *lru.LruCache[string, bool]
if authenticate {
c = lru.New[string, bool](lru.WithAge[string, bool](30))
}
hl := &Listener{
listener: l,
addr: addr,
@@ -79,7 +75,7 @@ func NewWithAuthenticate(addr string, tunnel C.Tunnel, authenticate bool, additi
continue
}
}
go HandleConn(conn, tunnel, c, additions...)
go HandleConn(conn, tunnel, authenticator, additions...)
}
}()
+4 -6
View File
@@ -4,9 +4,9 @@ import (
"net"
"github.com/metacubex/mihomo/adapter/inbound"
"github.com/metacubex/mihomo/common/lru"
N "github.com/metacubex/mihomo/common/net"
C "github.com/metacubex/mihomo/constant"
authStore "github.com/metacubex/mihomo/listener/auth"
"github.com/metacubex/mihomo/listener/http"
"github.com/metacubex/mihomo/listener/socks"
"github.com/metacubex/mihomo/transport/socks4"
@@ -16,7 +16,6 @@ import (
type Listener struct {
listener net.Listener
addr string
cache *lru.LruCache[string, bool]
closed bool
}
@@ -53,7 +52,6 @@ func New(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener
ml := &Listener{
listener: l,
addr: addr,
cache: lru.New[string, bool](lru.WithAge[string, bool](30)),
}
go func() {
for {
@@ -70,14 +68,14 @@ func New(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener
continue
}
}
go handleConn(c, tunnel, ml.cache, additions...)
go handleConn(c, tunnel, additions...)
}
}()
return ml, nil
}
func handleConn(conn net.Conn, tunnel C.Tunnel, cache *lru.LruCache[string, bool], additions ...inbound.Addition) {
func handleConn(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) {
N.TCPKeepAlive(conn)
bufConn := N.NewBufferedConn(conn)
@@ -92,6 +90,6 @@ func handleConn(conn net.Conn, tunnel C.Tunnel, cache *lru.LruCache[string, bool
case socks5.Version:
socks.HandleSocks5(bufConn, tunnel, additions...)
default:
http.HandleConn(bufConn, tunnel, cache, additions...)
http.HandleConn(bufConn, tunnel, authStore.Authenticator(), additions...)
}
}
+12 -22
View File
@@ -12,15 +12,9 @@ import (
)
const (
trackerConnectFlag = iota
trackerAnnounceFlag
trackerScrapeFlag
trackerProtocolID = 0x41727101980
trackerConnectMinSize = 16
trackerAnnounceMinSize = 20
trackerScrapeMinSize = 8
trackerConnectFlag = 0
trackerProtocolID = 0x41727101980
trackerConnectMinSize = 16
)
// BitTorrent detects if the stream is a BitTorrent connection.
@@ -91,19 +85,15 @@ func UTP(_ context.Context, metadata *adapter.InboundContext, packet []byte) err
// UDPTracker detects if the packet is a UDP Tracker Protocol packet.
// For the UDP Tracker Protocol specification, see https://www.bittorrent.org/beps/bep_0015.html
func UDPTracker(_ context.Context, metadata *adapter.InboundContext, packet []byte) error {
switch {
case len(packet) >= trackerConnectMinSize &&
binary.BigEndian.Uint64(packet[:8]) == trackerProtocolID &&
binary.BigEndian.Uint32(packet[8:12]) == trackerConnectFlag:
fallthrough
case len(packet) >= trackerAnnounceMinSize &&
binary.BigEndian.Uint32(packet[8:12]) == trackerAnnounceFlag:
fallthrough
case len(packet) >= trackerScrapeMinSize &&
binary.BigEndian.Uint32(packet[8:12]) == trackerScrapeFlag:
metadata.Protocol = C.ProtocolBitTorrent
return nil
default:
if len(packet) < trackerConnectMinSize {
return os.ErrInvalid
}
if binary.BigEndian.Uint64(packet[:8]) != trackerProtocolID {
return os.ErrInvalid
}
if binary.BigEndian.Uint32(packet[8:12]) != trackerConnectFlag {
return os.ErrInvalid
}
metadata.Protocol = C.ProtocolBitTorrent
return nil
}
-11
View File
@@ -56,20 +56,9 @@ func TestSniffUDPTracker(t *testing.T) {
t.Parallel()
connectPackets := []string{
// connect packets
"00000417271019800000000078e90560",
"00000417271019800000000022c5d64d",
"000004172710198000000000b3863541",
// announce packets
"3d7592ead4b8c9e300000001b871a3820000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002092f616e6e6f756e6365",
"3d7592ead4b8c9e30000000188deed1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002092f616e6e6f756e6365",
"3d7592ead4b8c9e300000001ceb948ad0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a3362cdb7020ff920e5aa642c3d4066950dd1f01f4d00000000000000000000000000000000000000000000000000000000000000000000000000000000000002092f616e6e6f756e6365",
// scrape packets
"3d7592ead4b8c9e300000002d2f4bba5a94a8fe5ccb19ba61c4c0873d391e987982fbbd3",
"3d7592ead4b8c9e300000002441243292aae6c35c94fcfb415dbe95f408b9ce91ee846ed",
"3d7592ead4b8c9e300000002b2aa461b1ad1fa9661cf3fe45fb2504ad52ec6c67758e294",
}
for _, pkt := range connectPackets {
+6 -4
View File
@@ -40,9 +40,10 @@ func PeekStream(ctx context.Context, metadata *adapter.InboundContext, conn net.
}
for _, sniffer := range sniffers {
err = sniffer(ctx, metadata, bytes.NewReader(buffer.Bytes()))
if err != nil {
errors = append(errors, err)
if err == nil {
return nil
}
errors = append(errors, err)
}
}
return E.Errors(errors...)
@@ -52,9 +53,10 @@ func PeekPacket(ctx context.Context, metadata *adapter.InboundContext, packet []
var errors []error
for _, sniffer := range sniffers {
err := sniffer(ctx, metadata, packet)
if err != nil {
errors = append(errors, err)
if err == nil {
return nil
}
errors = append(errors, err)
}
return E.Errors(errors...)
}
+4
View File
@@ -2,6 +2,10 @@
icon: material/alert-decagram
---
#### 1.10.0-alpha.24
* Fixes and improvements
#### 1.10.0-alpha.23
* Add Chromium support for QUIC sniffer
+7 -7
View File
@@ -27,7 +27,7 @@ require (
github.com/sagernet/quic-go v0.45.1-beta.2
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691
github.com/sagernet/sing v0.5.0-alpha.13
github.com/sagernet/sing-dns v0.3.0-beta.10
github.com/sagernet/sing-dns v0.3.0-beta.12
github.com/sagernet/sing-mux v0.2.0
github.com/sagernet/sing-quic v0.2.0-beta.12
github.com/sagernet/sing-shadowsocks v0.2.7
@@ -44,9 +44,9 @@ require (
github.com/stretchr/testify v1.9.0
go.uber.org/zap v1.27.0
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
golang.org/x/crypto v0.24.0
golang.org/x/net v0.26.0
golang.org/x/sys v0.21.0
golang.org/x/crypto v0.25.0
golang.org/x/net v0.27.0
golang.org/x/sys v0.22.0
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
google.golang.org/grpc v1.63.2
google.golang.org/protobuf v1.33.0
@@ -89,12 +89,12 @@ require (
github.com/vishvananda/netns v0.0.4 // indirect
github.com/zeebo/blake3 v0.2.3 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect
golang.org/x/mod v0.18.0 // indirect
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
golang.org/x/mod v0.19.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/text v0.16.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.22.0 // indirect
golang.org/x/tools v0.23.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
+15 -15
View File
@@ -117,8 +117,8 @@ github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4Wk
github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
github.com/sagernet/sing v0.5.0-alpha.13 h1:fpR4TFZfu/9V3LbHSAnnnwcaXGMF8ijmAAPoY2WHSKw=
github.com/sagernet/sing v0.5.0-alpha.13/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/sing-dns v0.3.0-beta.10 h1:Js61EjQXVpcu2VDegWEQTH1isCcVwJju8WEHYgG4tQ0=
github.com/sagernet/sing-dns v0.3.0-beta.10/go.mod h1:nXE6EYMXahB5DV3AcXYbFfuorqF7tbQ86kxweSxRKM4=
github.com/sagernet/sing-dns v0.3.0-beta.12 h1:mdTsaVU+0jopEKUDLwLmo8AbiSGZOly97oSPBDX3O8I=
github.com/sagernet/sing-dns v0.3.0-beta.12/go.mod h1:rscgSr5ixOPk8XM9ZMLuMXCyldEQ1nLvdl0nfv+lp00=
github.com/sagernet/sing-mux v0.2.0 h1:4C+vd8HztJCWNYfufvgL49xaOoOHXty2+EAjnzN3IYo=
github.com/sagernet/sing-mux v0.2.0/go.mod h1:khzr9AOPocLa+g53dBplwNDz4gdsyx/YM3swtAhlkHQ=
github.com/sagernet/sing-quic v0.2.0-beta.12 h1:BhvA5mmrDFEyDUQB5eeu+9UhF+ieyuNJ5Rsb0dAG3QY=
@@ -172,16 +172,16 @@ go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBs
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY=
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -192,10 +192,10 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
@@ -203,8 +203,8 @@ golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 h1:CawjfCvYQH2OU3/TnxLx97WDSUDRABfT18pCOYwc2GE=
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6/go.mod h1:3rxYc4HtVcSG9gVaTs2GEBdehh+sYPOwKtyUWEOTb80=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de h1:cZGRis4/ot9uVm639a+rHCUaG0JJHEsdyzSQTMX+suY=
+2 -2
View File
@@ -12,13 +12,13 @@ PKG_MAINTAINER:=Tianling Shen <cnsztl@immortalwrt.org>
include $(INCLUDE_DIR)/package.mk
GEOIP_VER:=202407192357
GEOIP_VER:=202407250045
GEOIP_FILE:=geoip.dat.$(GEOIP_VER)
define Download/geoip
URL:=https://github.com/v2fly/geoip/releases/download/$(GEOIP_VER)/
URL_FILE:=geoip.dat
FILE:=$(GEOIP_FILE)
HASH:=8128db0c1431f4c6854dfb7740b497ee0ac73f0f3a52a1e0040c508f7d79c0a4
HASH:=f83e89edfd3b35acbbbb862a4c88a8ca3e1ddce4d298cc617be79bdaa23a0672
endef
GEOSITE_VER:=20240720181558
@@ -197,6 +197,15 @@ namespace v2rayN.Handler
}
config.clashUIItem ??= new();
if (config.systemProxyItem == null)
{
config.systemProxyItem = new()
{
systemProxyExceptions = config.systemProxyExceptions,
systemProxyAdvancedProtocol = config.systemProxyAdvancedProtocol,
};
}
LazyConfig.Instance.SetConfig(config);
return 0;
}
@@ -22,7 +22,7 @@ namespace v2rayN.Handler
{
try
{
int index = (int)config.sysProxyType;
int index = (int)config.systemProxyItem.sysProxyType;
//Load from routing setting
var createdIcon = GetNotifyIcon4Routing(config);
@@ -56,7 +56,7 @@ namespace v2rayN.Handler
public System.Windows.Media.ImageSource GetAppIcon(Config config)
{
int index = 1;
switch (config.sysProxyType)
switch (config.systemProxyItem.sysProxyType)
{
case ESysProxyType.ForcedClear:
index = 1;
@@ -90,7 +90,7 @@ namespace v2rayN.Handler
}
Color color = ColorTranslator.FromHtml("#3399CC");
int index = (int)config.sysProxyType;
int index = (int)config.systemProxyItem.sysProxyType;
if (index > 0)
{
color = (new[] { Color.Red, Color.Purple, Color.DarkGreen, Color.Orange, Color.DarkSlateBlue, Color.RoyalBlue })[index - 1];
@@ -11,7 +11,7 @@ namespace v2rayN.Handler
public static bool UpdateSysProxy(Config config, bool forceDisable)
{
var type = config.sysProxyType;
var type = config.systemProxyItem.sysProxyType;
if (forceDisable && type != ESysProxyType.Unchanged)
{
@@ -30,19 +30,19 @@ namespace v2rayN.Handler
if (type == ESysProxyType.ForcedChange)
{
var strExceptions = "";
if (config.notProxyLocalAddress)
if (config.systemProxyItem.notProxyLocalAddress)
{
strExceptions = $"<local>;{config.constItem.defIEProxyExceptions};{config.systemProxyExceptions}";
strExceptions = $"<local>;{config.constItem.defIEProxyExceptions};{config.systemProxyItem.systemProxyExceptions}";
}
var strProxy = string.Empty;
if (Utils.IsNullOrEmpty(config.systemProxyAdvancedProtocol))
if (Utils.IsNullOrEmpty(config.systemProxyItem.systemProxyAdvancedProtocol))
{
strProxy = $"{Global.Loopback}:{port}";
}
else
{
strProxy = config.systemProxyAdvancedProtocol
strProxy = config.systemProxyItem.systemProxyAdvancedProtocol
.Replace("{ip}", Global.Loopback)
.Replace("{http_port}", port.ToString())
.Replace("{socks_port}", portSocks.ToString());
+1 -2
View File
@@ -12,9 +12,7 @@ namespace v2rayN.Models
public string indexId { get; set; }
public string subIndexId { get; set; }
public ESysProxyType sysProxyType { get; set; }
public string systemProxyExceptions { get; set; }
public bool notProxyLocalAddress { get; set; } = true;
public string systemProxyAdvancedProtocol { get; set; }
public ECoreType runningCoreType { get; set; }
@@ -48,6 +46,7 @@ namespace v2rayN.Models
public Mux4SboxItem mux4SboxItem { get; set; }
public HysteriaItem hysteriaItem { get; set; }
public ClashUIItem clashUIItem { get; set; }
public SystemProxyItem systemProxyItem { get; set; }
public List<InItem> inbound { get; set; }
public List<KeyEventItem> globalHotkeys { get; set; }
public List<CoreTypeItem> coreTypeItem { get; set; }
@@ -227,4 +227,13 @@ namespace v2rayN.Models
public bool connectionsAutoRefresh { get; set; }
public int connectionsRefreshInterval { get; set; } = 2;
}
[Serializable]
public class SystemProxyItem
{
public ESysProxyType sysProxyType { get; set; }
public string systemProxyExceptions { get; set; }
public bool notProxyLocalAddress { get; set; } = true;
public string systemProxyAdvancedProtocol { get; set; }
}
}
@@ -234,7 +234,7 @@ namespace v2rayN.ViewModels
y => y != null && !y.Text.IsNullOrEmpty())
.Subscribe(c => ServerSelectedChanged(c));
SystemProxySelected = (int)_config.sysProxyType;
SystemProxySelected = (int)_config.systemProxyItem.sysProxyType;
this.WhenAnyValue(
x => x.SystemProxySelected,
y => y >= 0)
@@ -429,7 +429,7 @@ namespace v2rayN.ViewModels
//RefreshServers();
Reload();
ChangeSystemProxyStatus(_config.sysProxyType, true);
ChangeSystemProxyStatus(_config.systemProxyItem.sysProxyType, true);
}
private void OnProgramStarted(object state, bool timeout)
@@ -936,7 +936,7 @@ namespace v2rayN.ViewModels
//ConfigHandler.SaveConfig(_config, false);
ChangeSystemProxyStatus(_config.sysProxyType, false);
ChangeSystemProxyStatus(_config.systemProxyItem.sysProxyType, false);
});
}
@@ -955,21 +955,21 @@ namespace v2rayN.ViewModels
public void SetListenerType(ESysProxyType type)
{
if (_config.sysProxyType == type)
if (_config.systemProxyItem.sysProxyType == type)
{
return;
}
_config.sysProxyType = type;
_config.systemProxyItem.sysProxyType = type;
ChangeSystemProxyStatus(type, true);
SystemProxySelected = (int)_config.sysProxyType;
SystemProxySelected = (int)_config.systemProxyItem.sysProxyType;
ConfigHandler.SaveConfig(_config, false);
}
private void ChangeSystemProxyStatus(ESysProxyType type, bool blChange)
{
SysProxyHandle.UpdateSysProxy(_config, _config.tunModeItem.enableTun ? true : false);
_noticeHandler?.SendMessage($"{ResUI.TipChangeSystemProxy} - {_config.sysProxyType.ToString()}", true);
_noticeHandler?.SendMessage($"{ResUI.TipChangeSystemProxy} - {_config.systemProxyItem.sysProxyType.ToString()}", true);
Application.Current?.Dispatcher.Invoke((Action)(() =>
{
@@ -1046,7 +1046,7 @@ namespace v2rayN.ViewModels
{
return;
}
if (_config.sysProxyType == (ESysProxyType)SystemProxySelected)
if (_config.systemProxyItem.sysProxyType == (ESysProxyType)SystemProxySelected)
{
return;
}
@@ -1223,7 +1223,7 @@ namespace v2rayN.ViewModels
StringBuilder sb = new();
sb.Append($"[{EInboundProtocol.socks}:{LazyConfig.Instance.GetLocalPort(EInboundProtocol.socks)}]");
sb.Append(" | ");
//if (_config.sysProxyType == ESysProxyType.ForcedChange)
//if (_config.systemProxyItem.sysProxyType == ESysProxyType.ForcedChange)
//{
// sb.Append($"[{Global.InboundHttp}({ResUI.SystemProxy}):{LazyConfig.Instance.GetLocalPort(Global.InboundHttp)}]");
//}
@@ -1293,4 +1293,4 @@ namespace v2rayN.ViewModels
#endregion UI
}
}
}
@@ -179,9 +179,9 @@ namespace v2rayN.ViewModels
#region System proxy
notProxyLocalAddress = _config.notProxyLocalAddress;
systemProxyAdvancedProtocol = _config.systemProxyAdvancedProtocol;
systemProxyExceptions = _config.systemProxyExceptions;
notProxyLocalAddress = _config.systemProxyItem.notProxyLocalAddress;
systemProxyAdvancedProtocol = _config.systemProxyItem.systemProxyAdvancedProtocol;
systemProxyExceptions = _config.systemProxyItem.systemProxyExceptions;
#endregion System proxy
@@ -340,9 +340,9 @@ namespace v2rayN.ViewModels
_config.uiItem.mainGirdOrientation = (EGirdOrientation)MainGirdOrientation;
//systemProxy
_config.systemProxyExceptions = systemProxyExceptions;
_config.notProxyLocalAddress = notProxyLocalAddress;
_config.systemProxyAdvancedProtocol = systemProxyAdvancedProtocol;
_config.systemProxyItem.systemProxyExceptions = systemProxyExceptions;
_config.systemProxyItem.notProxyLocalAddress = notProxyLocalAddress;
_config.systemProxyItem.systemProxyAdvancedProtocol = systemProxyAdvancedProtocol;
//tun mode
_config.tunModeItem.strictRoute = TunStrictRoute;
+1 -1
View File
@@ -26,7 +26,7 @@
<PackageReference Include="ReactiveUI.Validation" Version="4.0.9" />
<PackageReference Include="ReactiveUI.WPF" Version="20.1.1" />
<PackageReference Include="Splat.NLog" Version="15.1.1" />
<PackageReference Include="YamlDotNet" Version="15.3.0" />
<PackageReference Include="YamlDotNet" Version="16.0.0" />
</ItemGroup>
<ItemGroup>
@@ -81,7 +81,9 @@
},
{
"protocol": "freedom",
"settings": {},
"settings": {
"domainStrategy": "UseIP"
},
"tag": "direct"
},
{
@@ -173,10 +173,6 @@ object V2rayConfigUtil {
&& settingsStorage?.decodeBool(AppConfig.PREF_FAKE_DNS_ENABLED) == true
) {
v2rayConfig.fakedns = listOf(V2rayConfig.FakednsBean())
v2rayConfig.outbounds.filter { it.protocol == PROTOCOL_FREEDOM && it.tag == TAG_DIRECT }
.forEach {
it.settings?.domainStrategy = "UseIP"
}
}
}
@@ -28,38 +28,47 @@ object TrojanFmt {
var flow = ""
var fingerprint = config.outboundBean?.streamSettings?.tlsSettings?.fingerprint
if (uri.rawQuery.isNullOrEmpty()) return null
val queryParam = uri.rawQuery.split("&")
.associate { it.split("=").let { (k, v) -> k to Utils.urlDecode(v) } }
val sni = config.outboundBean?.streamSettings?.populateTransportSettings(
queryParam["type"] ?: "tcp",
queryParam["headerType"],
queryParam["host"],
queryParam["path"],
queryParam["seed"],
queryParam["quicSecurity"],
queryParam["key"],
queryParam["mode"],
queryParam["serviceName"],
queryParam["authority"]
)
fingerprint = queryParam["fp"] ?: ""
allowInsecure = if ((queryParam["allowInsecure"] ?: "") == "1") true else allowInsecure
config.outboundBean?.streamSettings?.populateTlsSettings(
queryParam["security"] ?: V2rayConfig.TLS,
allowInsecure,
queryParam["sni"] ?: sni ?: "",
fingerprint,
queryParam["alpn"],
null,
null,
null
)
flow = queryParam["flow"] ?: ""
if (uri.rawQuery.isNullOrEmpty()) {
config.outboundBean?.streamSettings?.populateTlsSettings(
V2rayConfig.TLS,
allowInsecure,
"",
fingerprint,
null,
null,
null,
null
)
} else {
val queryParam = uri.rawQuery.split("&")
.associate { it.split("=").let { (k, v) -> k to Utils.urlDecode(v) } }
val sni = config.outboundBean?.streamSettings?.populateTransportSettings(
queryParam["type"] ?: "tcp",
queryParam["headerType"],
queryParam["host"],
queryParam["path"],
queryParam["seed"],
queryParam["quicSecurity"],
queryParam["key"],
queryParam["mode"],
queryParam["serviceName"],
queryParam["authority"]
)
fingerprint = queryParam["fp"] ?: ""
allowInsecure = if ((queryParam["allowInsecure"] ?: "") == "1") true else allowInsecure
config.outboundBean?.streamSettings?.populateTlsSettings(
queryParam["security"] ?: V2rayConfig.TLS,
allowInsecure,
queryParam["sni"] ?: sni ?: "",
fingerprint,
queryParam["alpn"],
null,
null,
null
)
flow = queryParam["flow"] ?: ""
}
config.outboundBean?.settings?.servers?.get(0)?.let { server ->
server.address = uri.idnHost
server.port = uri.port
+1 -1
View File
@@ -57,7 +57,7 @@ OptionDialog::OptionDialog(const std::string& title, GtkWindow* parent, bool mod
gtk_widget_set_margin_right(GTK_WIDGET(grid), 12);
#endif
gtk_grid_set_column_spacing(GTK_GRID(grid), 12);
gtk_grid_set_row_spacing(GTK_GRID(grid), 12);
gtk_grid_set_row_spacing(GTK_GRID(grid), 6);
okay_button_ = GTK_BUTTON(gtk_button_new());
gtk_button_set_label(okay_button_, _("Okay"));
+65 -29
View File
@@ -104,9 +104,11 @@ YASSWindow::YASSWindow() : impl_(GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL))
start_button_ = GTK_BUTTON(gtk_button_new());
gtk_button_set_label(start_button_, _("Start"));
gtk_widget_set_size_request(GTK_WIDGET(start_button_), 84, -1);
stop_button_ = GTK_BUTTON(gtk_button_new());
gtk_button_set_label(stop_button_, _("Stop"));
gtk_widget_set_size_request(GTK_WIDGET(stop_button_), 84, -1);
auto start_callback = [](GtkButton* self, gpointer pointer) {
YASSWindow* window = (YASSWindow*)pointer;
@@ -127,35 +129,69 @@ YASSWindow::YASSWindow() : impl_(GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL))
gtk_grid_attach(grid, GTK_WIDGET(start_button_), 0, 2, 1, 1);
gtk_grid_attach(grid, GTK_WIDGET(stop_button_), 0, 7, 1, 1);
auto server_host_label_ = gtk_label_new(_("Server Host"));
auto server_sni_label_ = gtk_label_new(_("Server SNI"));
auto server_port_label_ = gtk_label_new(_("Server Port"));
auto username_label_ = gtk_label_new(_("Username"));
auto password_label_ = gtk_label_new(_("Password"));
auto method_label_ = gtk_label_new(_("Cipher/Method"));
auto local_host_label_ = gtk_label_new(_("Local Host"));
auto local_port_label_ = gtk_label_new(_("Local Port"));
auto doh_url_label_ = gtk_label_new(_("DNS over HTTPS URL"));
auto dot_host_label_ = gtk_label_new(_("DNS over TLS Host"));
auto limit_rate_label_ = gtk_label_new(_("Limit Rate"));
auto timeout_label_ = gtk_label_new(_("Timeout"));
auto autostart_label_ = gtk_label_new(_("Auto Start"));
auto systemproxy_label_ = gtk_label_new(_("System Proxy"));
auto server_host_label = gtk_label_new(_("Server Host"));
auto server_sni_label = gtk_label_new(_("Server SNI"));
auto server_port_label = gtk_label_new(_("Server Port"));
auto username_label = gtk_label_new(_("Username"));
auto password_label = gtk_label_new(_("Password"));
auto method_label = gtk_label_new(_("Cipher/Method"));
auto local_host_label = gtk_label_new(_("Local Host"));
auto local_port_label = gtk_label_new(_("Local Port"));
auto doh_url_label = gtk_label_new(_("DNS over HTTPS URL"));
auto dot_host_label = gtk_label_new(_("DNS over TLS Host"));
auto limit_rate_label = gtk_label_new(_("Limit Rate"));
auto timeout_label = gtk_label_new(_("Timeout"));
auto autostart_label = gtk_label_new(_("Auto Start"));
auto systemproxy_label = gtk_label_new(_("System Proxy"));
gtk_grid_attach(grid, GTK_WIDGET(server_host_label_), 1, 0, 1, 1);
gtk_grid_attach(grid, GTK_WIDGET(server_sni_label_), 1, 1, 1, 1);
gtk_grid_attach(grid, GTK_WIDGET(server_port_label_), 1, 2, 1, 1);
gtk_grid_attach(grid, GTK_WIDGET(username_label_), 1, 3, 1, 1);
gtk_grid_attach(grid, GTK_WIDGET(password_label_), 1, 4, 1, 1);
gtk_grid_attach(grid, GTK_WIDGET(method_label_), 1, 5, 1, 1);
gtk_grid_attach(grid, GTK_WIDGET(local_host_label_), 1, 6, 1, 1);
gtk_grid_attach(grid, GTK_WIDGET(local_port_label_), 1, 7, 1, 1);
gtk_grid_attach(grid, GTK_WIDGET(doh_url_label_), 1, 8, 1, 1);
gtk_grid_attach(grid, GTK_WIDGET(dot_host_label_), 1, 9, 1, 1);
gtk_grid_attach(grid, GTK_WIDGET(limit_rate_label_), 1, 10, 1, 1);
gtk_grid_attach(grid, GTK_WIDGET(timeout_label_), 1, 11, 1, 1);
gtk_grid_attach(grid, GTK_WIDGET(autostart_label_), 1, 12, 1, 1);
gtk_grid_attach(grid, GTK_WIDGET(systemproxy_label_), 1, 13, 1, 1);
// see https://stackoverflow.com/questions/24994255/how-to-left-align-a-gtk-label-when-its-width-is-set-by-gtksizegroup
#if GTK_CHECK_VERSION(3, 16, 0)
gtk_label_set_xalign(GTK_LABEL(server_host_label), 0.0);
gtk_label_set_xalign(GTK_LABEL(server_sni_label), 0.0);
gtk_label_set_xalign(GTK_LABEL(server_port_label), 0.0);
gtk_label_set_xalign(GTK_LABEL(username_label), 0.0);
gtk_label_set_xalign(GTK_LABEL(password_label), 0.0);
gtk_label_set_xalign(GTK_LABEL(method_label), 0.0);
gtk_label_set_xalign(GTK_LABEL(local_host_label), 0.0);
gtk_label_set_xalign(GTK_LABEL(local_port_label), 0.0);
gtk_label_set_xalign(GTK_LABEL(doh_url_label), 0.0);
gtk_label_set_xalign(GTK_LABEL(dot_host_label), 0.0);
gtk_label_set_xalign(GTK_LABEL(limit_rate_label), 0.0);
gtk_label_set_xalign(GTK_LABEL(timeout_label), 0.0);
gtk_label_set_xalign(GTK_LABEL(autostart_label), 0.0);
gtk_label_set_xalign(GTK_LABEL(systemproxy_label), 0.0);
#else
gtk_misc_set_alignment(GTK_MISC(server_host_label), 0.0, 0.5);
gtk_misc_set_alignment(GTK_MISC(server_host_label), 0.0, 0.5);
gtk_misc_set_alignment(GTK_MISC(server_sni_label), 0.0, 0.5);
gtk_misc_set_alignment(GTK_MISC(server_port_label), 0.0, 0.5);
gtk_misc_set_alignment(GTK_MISC(username_label), 0.0, 0.5);
gtk_misc_set_alignment(GTK_MISC(password_label), 0.0, 0.5);
gtk_misc_set_alignment(GTK_MISC(method_label), 0.0, 0.5);
gtk_misc_set_alignment(GTK_MISC(local_host_label), 0.0, 0.5);
gtk_misc_set_alignment(GTK_MISC(local_port_label), 0.0, 0.5);
gtk_misc_set_alignment(GTK_MISC(doh_url_label), 0.0, 0.5);
gtk_misc_set_alignment(GTK_MISC(dot_host_label), 0.0, 0.5);
gtk_misc_set_alignment(GTK_MISC(limit_rate_label), 0.0, 0.5);
gtk_misc_set_alignment(GTK_MISC(timeout_label), 0.0, 0.5);
gtk_misc_set_alignment(GTK_MISC(autostart_label), 0.0, 0.5);
gtk_misc_set_alignment(GTK_MISC(systemproxy_label), 0.0, 0.5);
#endif
gtk_grid_attach(grid, GTK_WIDGET(server_host_label), 1, 0, 1, 1);
gtk_grid_attach(grid, GTK_WIDGET(server_sni_label), 1, 1, 1, 1);
gtk_grid_attach(grid, GTK_WIDGET(server_port_label), 1, 2, 1, 1);
gtk_grid_attach(grid, GTK_WIDGET(username_label), 1, 3, 1, 1);
gtk_grid_attach(grid, GTK_WIDGET(password_label), 1, 4, 1, 1);
gtk_grid_attach(grid, GTK_WIDGET(method_label), 1, 5, 1, 1);
gtk_grid_attach(grid, GTK_WIDGET(local_host_label), 1, 6, 1, 1);
gtk_grid_attach(grid, GTK_WIDGET(local_port_label), 1, 7, 1, 1);
gtk_grid_attach(grid, GTK_WIDGET(doh_url_label), 1, 8, 1, 1);
gtk_grid_attach(grid, GTK_WIDGET(dot_host_label), 1, 9, 1, 1);
gtk_grid_attach(grid, GTK_WIDGET(limit_rate_label), 1, 10, 1, 1);
gtk_grid_attach(grid, GTK_WIDGET(timeout_label), 1, 11, 1, 1);
gtk_grid_attach(grid, GTK_WIDGET(autostart_label), 1, 12, 1, 1);
gtk_grid_attach(grid, GTK_WIDGET(systemproxy_label), 1, 13, 1, 1);
server_host_ = GTK_ENTRY(gtk_entry_new());
server_sni_ = GTK_ENTRY(gtk_entry_new());
@@ -230,7 +266,7 @@ YASSWindow::YASSWindow() : impl_(GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL))
gtk_widget_set_margin_right(GTK_WIDGET(grid), 12);
#endif
gtk_grid_set_column_spacing(GTK_GRID(grid), 12);
gtk_grid_set_row_spacing(GTK_GRID(grid), 12);
gtk_grid_set_row_spacing(GTK_GRID(grid), 6);
gtk_box_pack_start(vbox, GTK_WIDGET(grid), true, false, 0);
+11 -11
View File
@@ -11,12 +11,12 @@
<property name="margin-end">12</property>
<property name="margin-top">12</property>
<property name="margin-bottom">12</property>
<property name="row-spacing">12</property>
<property name="row-spacing">6</property>
<property name="column-spacing">12</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">TCP keep alive:</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">TCP keep alive</property>
<property name="xalign">0.0</property>
<layout>
<property name="column">0</property>
<property name="row">0</property>
@@ -25,8 +25,8 @@
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">The number of TCP keep-alive probes:</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">The number of TCP keep-alive probes</property>
<property name="xalign">0.0</property>
<layout>
<property name="column">0</property>
<property name="row">1</property>
@@ -35,8 +35,8 @@
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">TCP keep alive after idle:</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">TCP keep alive after idle</property>
<property name="xalign">0.0</property>
<layout>
<property name="column">0</property>
<property name="row">2</property>
@@ -45,8 +45,8 @@
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">TCP keep alive interval:</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">TCP keep alive interval</property>
<property name="xalign">0.0</property>
<layout>
<property name="column">0</property>
<property name="row">3</property>
@@ -55,8 +55,8 @@
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Kyber post-quantum key agreement for TLS:</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">Kyber post-quantum key agreement for TLS</property>
<property name="xalign">0.0</property>
<layout>
<property name="column">0</property>
<property name="row">4</property>
+77 -77
View File
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 1.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-09 09:56+0800\n"
"POT-Creation-Date: 2024-07-25 13:13+0800\n"
"PO-Revision-Date: 2023-05-24 14:35+0800\n"
"Last-Translator: Chilledheart <keeyou-cn@outlook.com>\n"
"Language-Team: Chilledheart <keeyou-cn@outlook.com>\n"
@@ -17,63 +17,63 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: yass.cpp:301
#: yass.cpp:302
msgid "Connected with conns: "
msgstr "Connected with conns: "
#: yass.cpp:303
#: yass.cpp:304
msgid "Connecting"
msgstr "Connecting"
#: yass.cpp:305
#: yass.cpp:306
msgid "Failed to connect due to "
msgstr "Failed to connect due to "
#: yass.cpp:307
#: yass.cpp:308
msgid "Disconnecting"
msgstr "Disconnecting"
#: yass.cpp:309
#: yass.cpp:310
msgid "Disconnected with "
msgstr "Disconnected with "
#: yass.cpp:420
#: yass.cpp:421
msgid "Last Change: "
msgstr "Last Change: "
#: yass.cpp:423
#: yass.cpp:424
msgid "Enabled Feature: "
msgstr "Enabled Feature: "
#: yass.cpp:426
#: yass.cpp:427
msgid "GUI Variant: "
msgstr "GUI Variant: "
#: yass.cpp:435
#: yass.cpp:436
msgid "official-site"
msgstr "official-site"
#: yass.cpp:441
#: yass.cpp:442
msgid "YASS Option"
msgstr "YASS Option"
#: yass_window.cpp:190
#: yass_window.cpp:192
msgid "READY"
msgstr "READY"
#: yass_window.cpp:314
#: yass_window.cpp:319
msgid " tx rate: "
msgstr " tx rate: "
#: yass_window.cpp:317
#: yass_window.cpp:322
msgid " rx rate: "
msgstr " rx rate: "
#: yass_window.cpp:352
#: yass_window.cpp:357
msgid "Start Failed"
msgstr "Start Failed"
#: yass_window.cpp:353
#: yass_window.cpp:358
msgid "OK"
msgstr "OK"
@@ -93,31 +93,31 @@ msgstr "Quit"
msgid "Option"
msgstr "Option"
#: option_dialog.ui:20
msgid "TCP keep alive:"
msgstr "TCP keep alive:"
#: option_dialog.ui:18
msgid "TCP keep alive"
msgstr "TCP keep alive"
#: option_dialog.ui:30
msgid "The number of TCP keep-alive probes:"
msgstr "The number of TCP keep-alive probes:"
#: option_dialog.ui:28
msgid "The number of TCP keep-alive probes"
msgstr "The number of TCP keep-alive probes"
#: option_dialog.ui:40
msgid "TCP keep alive after idle:"
msgstr "TCP keep alive after idle:"
#: option_dialog.ui:38
msgid "TCP keep alive after idle"
msgstr "TCP keep alive after idle"
#: option_dialog.ui:50
msgid "TCP keep alive interval:"
msgstr "TCP keep alive interval:"
#: option_dialog.ui:48
msgid "TCP keep alive interval"
msgstr "TCP keep alive interval"
#: option_dialog.ui:60
msgid "Kyber post-quantum key agreement for TLS:"
msgstr "Kyber post-quantum key agreement for TLS:"
#: option_dialog.ui:58
msgid "Kyber post-quantum key agreement for TLS"
msgstr "Kyber post-quantum key agreement for TLS"
#: option_dialog.ui:110
#: option_dialog.ui:108
msgid "Okay"
msgstr "Okay"
#: option_dialog.ui:119
#: option_dialog.ui:117
msgid "Cancel"
msgstr "Cancel"
@@ -125,66 +125,66 @@ msgstr "Cancel"
msgid "Yet Another Shadow Socket"
msgstr "Yet Another Shadow Socket"
#: yass_window.ui:31
msgid "Server Host:"
msgstr "Server Host:"
#: yass_window.ui:30
msgid "Server Host"
msgstr "Server Host"
#: yass_window.ui:41
msgid "Server SNI:"
msgstr "Server SNI:"
#: yass_window.ui:40
msgid "Server SNI"
msgstr "Server SNI"
#: yass_window.ui:51
msgid "Server Port:"
msgstr "Server Port:"
#: yass_window.ui:50
msgid "Server Port"
msgstr "Server Port"
#: yass_window.ui:61
msgid "Username:"
msgstr "Username:"
#: yass_window.ui:60
msgid "Username"
msgstr "Username"
#: yass_window.ui:71
msgid "Password:"
msgstr "Password:"
#: yass_window.ui:70
msgid "Password"
msgstr "Password"
#: yass_window.ui:81
msgid "Cipher/Method:"
msgstr "Cipher/Method:"
#: yass_window.ui:80
msgid "Cipher/Method"
msgstr "Cipher/Method"
#: yass_window.ui:91
msgid "Local Host:"
msgstr "Local Host:"
#: yass_window.ui:90
msgid "Local Host"
msgstr "Local Host"
#: yass_window.ui:101
msgid "Local Port:"
msgstr "Local Port:"
#: yass_window.ui:100
msgid "Local Port"
msgstr "Local Port"
#: yass_window.ui:111
msgid "DNS over HTTPS URL:"
msgstr "DNS over HTTPS URL:"
#: yass_window.ui:110
msgid "DNS over HTTPS URL"
msgstr "DNS over HTTPS URL"
#: yass_window.ui:121
msgid "DNS over TLS Host:"
msgstr "DNS over TLS Host:"
#: yass_window.ui:120
msgid "DNS over TLS Host"
msgstr "DNS over TLS Host"
#: yass_window.ui:131
msgid "Limit Rate:"
msgstr "Limit Rate:"
#: yass_window.ui:130
msgid "Limit Rate"
msgstr "Limit Rate"
#: yass_window.ui:141
msgid "Timeout:"
msgstr "Timeout:"
#: yass_window.ui:140
msgid "Timeout"
msgstr "Timeout"
#: yass_window.ui:151
msgid "Auto Start:"
msgstr "Auto Start:"
#: yass_window.ui:150
msgid "Auto Start"
msgstr "Auto Start"
#: yass_window.ui:161
msgid "System Proxy:"
msgstr "System Proxy:"
#: yass_window.ui:160
msgid "System Proxy"
msgstr "System Proxy"
#: yass_window.ui:283
#: yass_window.ui:282
msgid "Start"
msgstr "Start"
#: yass_window.ui:292
#: yass_window.ui:291
msgid "Stop"
msgstr "Stop"
+36 -29
View File
@@ -9,6 +9,7 @@
<child type="end">
<object class="GtkMenuButton" id="gears">
<property name="direction">none</property>
<property name="icon-name">yass</property>
</object>
</child>
</object>
@@ -22,13 +23,13 @@
<property name="margin-end">12</property>
<property name="margin-top">12</property>
<property name="margin-bottom">12</property>
<property name="row-spacing">12</property>
<property name="row-spacing">6</property>
<property name="column-spacing">12</property>
<property name="row-homogeneous">true</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Server Host:</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">Server Host</property>
<property name="xalign">0.0</property>
<layout>
<property name="column">1</property>
<property name="row">0</property>
@@ -37,8 +38,8 @@
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Server SNI:</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">Server SNI</property>
<property name="xalign">0.0</property>
<layout>
<property name="column">1</property>
<property name="row">1</property>
@@ -47,8 +48,8 @@
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Server Port:</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">Server Port</property>
<property name="xalign">0.0</property>
<layout>
<property name="column">1</property>
<property name="row">2</property>
@@ -57,8 +58,8 @@
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Username:</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">Username</property>
<property name="xalign">0.0</property>
<layout>
<property name="column">1</property>
<property name="row">3</property>
@@ -67,8 +68,8 @@
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Password:</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">Password</property>
<property name="xalign">0.0</property>
<layout>
<property name="column">1</property>
<property name="row">4</property>
@@ -77,8 +78,8 @@
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Cipher/Method:</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">Cipher/Method</property>
<property name="xalign">0.0</property>
<layout>
<property name="column">1</property>
<property name="row">5</property>
@@ -87,8 +88,8 @@
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Local Host:</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">Local Host</property>
<property name="xalign">0.0</property>
<layout>
<property name="column">1</property>
<property name="row">6</property>
@@ -97,8 +98,8 @@
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Local Port:</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">Local Port</property>
<property name="xalign">0.0</property>
<layout>
<property name="column">1</property>
<property name="row">7</property>
@@ -107,8 +108,8 @@
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">DNS over HTTPS URL:</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">DNS over HTTPS URL</property>
<property name="xalign">0.0</property>
<layout>
<property name="column">1</property>
<property name="row">8</property>
@@ -117,8 +118,8 @@
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">DNS over TLS Host:</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">DNS over TLS Host</property>
<property name="xalign">0.0</property>
<layout>
<property name="column">1</property>
<property name="row">9</property>
@@ -127,8 +128,8 @@
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Limit Rate:</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">Limit Rate</property>
<property name="xalign">0.0</property>
<layout>
<property name="column">1</property>
<property name="row">10</property>
@@ -137,8 +138,8 @@
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Timeout:</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">Timeout</property>
<property name="xalign">0.0</property>
<layout>
<property name="column">1</property>
<property name="row">11</property>
@@ -147,8 +148,8 @@
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Auto Start:</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">Auto Start</property>
<property name="xalign">0.0</property>
<layout>
<property name="column">1</property>
<property name="row">12</property>
@@ -157,8 +158,8 @@
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">System Proxy:</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">System Proxy</property>
<property name="xalign">0.0</property>
<layout>
<property name="column">1</property>
<property name="row">13</property>
@@ -280,6 +281,7 @@
<child>
<object class="GtkButton" id="start_button">
<property name="label" translatable="yes">Start</property>
<property name="width-request">84</property>
<layout>
<property name="column">0</property>
<property name="row">2</property>
@@ -289,6 +291,7 @@
<child>
<object class="GtkButton" id="stop_button">
<property name="label" translatable="yes">Stop</property>
<property name="width-request">84</property>
<layout>
<property name="column">0</property>
<property name="row">7</property>
@@ -299,6 +302,10 @@
</child>
<child type="statusbar">
<object class="GtkStatusbar" id="status_bar">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">6</property>
<property name="margin-bottom">6</property>
</object>
</child>
</object>
+77 -77
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 1.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-09 09:56+0800\n"
"POT-Creation-Date: 2024-07-25 13:13+0800\n"
"PO-Revision-Date: 2023-09-15 11:28+0800\n"
"Last-Translator: Chilledheart <keeyou-cn@outlook.com>\n"
"Language-Team: Chilledheart <keeyou-cn@outlook.com>\n"
@@ -18,63 +18,63 @@ msgstr ""
"X-Generator: Poedit 2.2.4\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: yass.cpp:301
#: yass.cpp:302
msgid "Connected with conns: "
msgstr "已产生连接: "
#: yass.cpp:303
#: yass.cpp:304
msgid "Connecting"
msgstr "连接中"
#: yass.cpp:305
#: yass.cpp:306
msgid "Failed to connect due to "
msgstr "无法连接因为 "
#: yass.cpp:307
#: yass.cpp:308
msgid "Disconnecting"
msgstr "断开连接中"
#: yass.cpp:309
#: yass.cpp:310
msgid "Disconnected with "
msgstr "断开连接于服务器 "
#: yass.cpp:420
#: yass.cpp:421
msgid "Last Change: "
msgstr "最后改动: "
#: yass.cpp:423
#: yass.cpp:424
msgid "Enabled Feature: "
msgstr "启用功能: "
#: yass.cpp:426
#: yass.cpp:427
msgid "GUI Variant: "
msgstr "图形版本: "
#: yass.cpp:435
#: yass.cpp:436
msgid "official-site"
msgstr "官方网站"
#: yass.cpp:441
#: yass.cpp:442
msgid "YASS Option"
msgstr "YASS 选项"
#: yass_window.cpp:190
#: yass_window.cpp:192
msgid "READY"
msgstr "就绪"
#: yass_window.cpp:314
#: yass_window.cpp:319
msgid " tx rate: "
msgstr " 上传速率: "
#: yass_window.cpp:317
#: yass_window.cpp:322
msgid " rx rate: "
msgstr " 下载速率: "
#: yass_window.cpp:352
#: yass_window.cpp:357
msgid "Start Failed"
msgstr "启动失败"
#: yass_window.cpp:353
#: yass_window.cpp:358
msgid "OK"
msgstr "确认"
@@ -94,31 +94,31 @@ msgstr "退出"
msgid "Option"
msgstr "选项"
#: option_dialog.ui:20
msgid "TCP keep alive:"
msgstr "TCP 保活:"
#: option_dialog.ui:18
msgid "TCP keep alive"
msgstr "TCP 保活"
#: option_dialog.ui:30
msgid "The number of TCP keep-alive probes:"
msgstr "TCP 保活测量数:"
#: option_dialog.ui:28
msgid "The number of TCP keep-alive probes"
msgstr "TCP 保活测量数"
#: option_dialog.ui:40
msgid "TCP keep alive after idle:"
msgstr "TCP 在闲置以后的保活次数:"
#: option_dialog.ui:38
msgid "TCP keep alive after idle"
msgstr "TCP 在闲置以后的保活次数"
#: option_dialog.ui:50
msgid "TCP keep alive interval:"
msgstr "TCP 保活间隔:"
#: option_dialog.ui:48
msgid "TCP keep alive interval"
msgstr "TCP 保活间隔"
#: option_dialog.ui:60
msgid "Kyber post-quantum key agreement for TLS:"
msgstr "TLS的Kyber后量子密钥协商:"
#: option_dialog.ui:58
msgid "Kyber post-quantum key agreement for TLS"
msgstr "TLS的Kyber后量子密钥协商"
#: option_dialog.ui:110
#: option_dialog.ui:108
msgid "Okay"
msgstr "确认"
#: option_dialog.ui:119
#: option_dialog.ui:117
msgid "Cancel"
msgstr "取消"
@@ -126,66 +126,66 @@ msgstr "取消"
msgid "Yet Another Shadow Socket"
msgstr "YASS"
#: yass_window.ui:31
msgid "Server Host:"
msgstr "服务器域名:"
#: yass_window.ui:30
msgid "Server Host"
msgstr "服务器域名"
#: yass_window.ui:41
msgid "Server SNI:"
msgstr "服务器名称指示:"
#: yass_window.ui:40
msgid "Server SNI"
msgstr "服务器名称指示"
#: yass_window.ui:51
msgid "Server Port:"
msgstr "服务器端口号:"
#: yass_window.ui:50
msgid "Server Port"
msgstr "服务器端口号"
#: yass_window.ui:61
msgid "Username:"
msgstr "用户名:"
#: yass_window.ui:60
msgid "Username"
msgstr "用户名"
#: yass_window.ui:71
msgid "Password:"
msgstr "密码:"
#: yass_window.ui:70
msgid "Password"
msgstr "密码"
#: yass_window.ui:81
msgid "Cipher/Method:"
msgstr "加密方式:"
#: yass_window.ui:80
msgid "Cipher/Method"
msgstr "加密方式"
#: yass_window.ui:91
msgid "Local Host:"
msgstr "本地域名:"
#: yass_window.ui:90
msgid "Local Host"
msgstr "本地域名"
#: yass_window.ui:101
msgid "Local Port:"
msgstr "本地端口号:"
#: yass_window.ui:100
msgid "Local Port"
msgstr "本地端口号"
#: yass_window.ui:111
msgid "DNS over HTTPS URL:"
msgstr "基于 HTTPS 的 DNS (DoH) URL:"
#: yass_window.ui:110
msgid "DNS over HTTPS URL"
msgstr "基于 HTTPS 的 DNS (DoH) URL"
#: yass_window.ui:121
msgid "DNS over TLS Host:"
msgstr "基于 TLS 的 DNS (DoT) 域名:"
#: yass_window.ui:120
msgid "DNS over TLS Host"
msgstr "基于 TLS 的 DNS (DoT) 域名"
#: yass_window.ui:131
msgid "Limit Rate:"
msgstr "限制速率:"
#: yass_window.ui:130
msgid "Limit Rate"
msgstr "限制速率"
#: yass_window.ui:141
msgid "Timeout:"
msgstr "超时时间:"
#: yass_window.ui:140
msgid "Timeout"
msgstr "超时时间"
#: yass_window.ui:151
msgid "Auto Start:"
msgstr "随系统自启动:"
#: yass_window.ui:150
msgid "Auto Start"
msgstr "随系统自启动"
#: yass_window.ui:161
msgid "System Proxy:"
msgstr "系统代理:"
#: yass_window.ui:160
msgid "System Proxy"
msgstr "系统代理"
#: yass_window.ui:283
#: yass_window.ui:282
msgid "Start"
msgstr "启动"
#: yass_window.ui:292
#: yass_window.ui:291
msgid "Stop"
msgstr "停止"
+90 -90
View File
@@ -75,11 +75,11 @@
<objects>
<viewController storyboardIdentifier="YassViewController" id="XfG-lQ-9wD" customClass="YassViewController" sceneMemberID="viewController">
<view key="view" id="m2S-Jp-Qdl">
<rect key="frame" x="0.0" y="0.0" width="523" height="516"/>
<rect key="frame" x="0.0" y="0.0" width="532" height="438"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<gridView xPlacement="leading" yPlacement="bottom" rowAlignment="firstBaseline" rowSpacing="12" columnSpacing="12" translatesAutoresizingMaskIntoConstraints="NO" id="u4K-Et-hUS">
<rect key="frame" x="12" y="12" width="499" height="492"/>
<gridView xPlacement="leading" yPlacement="bottom" rowAlignment="firstBaseline" columnSpacing="12" translatesAutoresizingMaskIntoConstraints="NO" id="u4K-Et-hUS">
<rect key="frame" x="12" y="12" width="508" height="414"/>
<constraints>
<constraint firstItem="VTW-w6-cOR" firstAttribute="trailing" secondItem="d0Y-hk-xNM" secondAttribute="trailing" id="39R-bq-g6c"/>
<constraint firstItem="VTW-w6-cOR" firstAttribute="trailing" secondItem="z07-tR-0U9" secondAttribute="trailing" id="7C1-f5-V76"/>
@@ -111,15 +111,15 @@
<gridRow height="24" id="1cJ-xv-Xd3"/>
</rows>
<columns>
<gridColumn width="75" id="LO3-Dh-mOI"/>
<gridColumn width="84" id="LO3-Dh-mOI"/>
<gridColumn width="200" id="a9F-Xp-86m"/>
<gridColumn width="200" id="XrQ-Tc-XCS"/>
</columns>
<gridCells>
<gridCell row="cJj-yp-Enp" column="LO3-Dh-mOI" id="Xwk-pR-CCg"/>
<gridCell row="cJj-yp-Enp" column="a9F-Xp-86m" id="Cfs-Zz-VA6">
<textField key="contentView" focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Naa-UR-FJH">
<rect key="frame" x="85" y="471" width="76" height="16"/>
<textField key="contentView" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Naa-UR-FJH">
<rect key="frame" x="94" y="393" width="76" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Server Host" id="g3k-Ab-Oin">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
@@ -128,8 +128,8 @@
</textField>
</gridCell>
<gridCell row="cJj-yp-Enp" column="XrQ-Tc-XCS" id="gUO-L2-R51">
<textField key="contentView" focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="VTW-w6-cOR">
<rect key="frame" x="299" y="468" width="188" height="21"/>
<textField key="contentView" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="VTW-w6-cOR">
<rect key="frame" x="308" y="390" width="188" height="21"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="hcQ-Jk-ceh">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
@@ -139,8 +139,8 @@
</gridCell>
<gridCell row="Wsq-Ny-R0E" column="LO3-Dh-mOI" id="fQT-0E-xvC"/>
<gridCell row="Wsq-Ny-R0E" column="a9F-Xp-86m" id="CgG-pY-O5X">
<textField key="contentView" focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="MAC-gA-ioH">
<rect key="frame" x="85" y="435" width="69" height="16"/>
<textField key="contentView" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="MAC-gA-ioH">
<rect key="frame" x="94" y="363" width="69" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Server SNI" id="bxG-gg-LTc">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
@@ -149,8 +149,8 @@
</textField>
</gridCell>
<gridCell row="Wsq-Ny-R0E" column="XrQ-Tc-XCS" id="dhv-f4-1Be">
<textField key="contentView" focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="5JO-ae-X9H">
<rect key="frame" x="299" y="432" width="188" height="21"/>
<textField key="contentView" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="5JO-ae-X9H">
<rect key="frame" x="308" y="360" width="188" height="21"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="Blg-iu-XaZ">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
@@ -158,10 +158,10 @@
</textFieldCell>
</textField>
</gridCell>
<gridCell row="hyR-W9-a1z" column="LO3-Dh-mOI" id="uOI-bG-SCP">
<gridCell row="hyR-W9-a1z" column="LO3-Dh-mOI" xPlacement="center" id="uOI-bG-SCP">
<button key="contentView" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="oW6-a4-bGz">
<rect key="frame" x="-7" y="389" width="64" height="32"/>
<buttonCell key="cell" type="push" title="Start" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="KPU-2Q-dN7">
<rect key="frame" x="11" y="324" width="62" height="36"/>
<buttonCell key="cell" type="push" title="Start" bezelStyle="rounded" alignment="center" controlSize="large" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="KPU-2Q-dN7">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
@@ -171,8 +171,8 @@
</button>
</gridCell>
<gridCell row="hyR-W9-a1z" column="a9F-Xp-86m" id="3Tp-MP-Iuu">
<textField key="contentView" focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="FpN-6F-ejx">
<rect key="frame" x="85" y="399" width="73" height="16"/>
<textField key="contentView" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="FpN-6F-ejx">
<rect key="frame" x="94" y="333" width="73" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Server Port" id="mcp-Vm-U1E">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
@@ -181,8 +181,8 @@
</textField>
</gridCell>
<gridCell row="hyR-W9-a1z" column="XrQ-Tc-XCS" id="iFI-Oq-jSi">
<textField key="contentView" focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="R0f-I9-5IS">
<rect key="frame" x="299" y="396" width="188" height="21"/>
<textField key="contentView" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="R0f-I9-5IS">
<rect key="frame" x="308" y="330" width="188" height="21"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="aCt-xH-vPZ">
<numberFormatter key="formatter" formatterBehavior="default10_4" usesGroupingSeparator="NO" formatWidth="-1" groupingSize="0" minimumIntegerDigits="1" maximumIntegerDigits="42" id="4Fe-3g-QZ5">
<real key="minimum" value="0.0"/>
@@ -196,8 +196,8 @@
</gridCell>
<gridCell row="pkr-kF-jbx" column="LO3-Dh-mOI" id="hax-GH-sFx"/>
<gridCell row="pkr-kF-jbx" column="a9F-Xp-86m" id="6kp-AQ-bdX">
<textField key="contentView" focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" verticalCompressionResistancePriority="749" translatesAutoresizingMaskIntoConstraints="NO" id="nkM-1Q-VtC">
<rect key="frame" x="85" y="363" width="66" height="16"/>
<textField key="contentView" horizontalHuggingPriority="251" verticalHuggingPriority="750" verticalCompressionResistancePriority="749" translatesAutoresizingMaskIntoConstraints="NO" id="nkM-1Q-VtC">
<rect key="frame" x="94" y="303" width="66" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Username" id="QRy-PK-jJT">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
@@ -206,8 +206,8 @@
</textField>
</gridCell>
<gridCell row="pkr-kF-jbx" column="XrQ-Tc-XCS" id="qFw-l7-IDb">
<textField key="contentView" focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="z07-tR-0U9">
<rect key="frame" x="299" y="360" width="188" height="21"/>
<textField key="contentView" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="z07-tR-0U9">
<rect key="frame" x="308" y="300" width="188" height="21"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="HAi-bY-2sC">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
@@ -217,8 +217,8 @@
</gridCell>
<gridCell row="8qE-4c-4mw" column="LO3-Dh-mOI" id="MHm-pE-P6f"/>
<gridCell row="8qE-4c-4mw" column="a9F-Xp-86m" id="6tg-qc-dBJ">
<textField key="contentView" focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="O29-63-IKZ">
<rect key="frame" x="85" y="327" width="63" height="16"/>
<textField key="contentView" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="O29-63-IKZ">
<rect key="frame" x="94" y="273" width="63" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Password" id="9N4-Lw-6Ob">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
@@ -227,8 +227,8 @@
</textField>
</gridCell>
<gridCell row="8qE-4c-4mw" column="XrQ-Tc-XCS" id="Yil-mh-t4n">
<secureTextField key="contentView" focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="0pr-Eo-W1k">
<rect key="frame" x="299" y="324" width="188" height="21"/>
<secureTextField key="contentView" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="0pr-Eo-W1k">
<rect key="frame" x="308" y="270" width="188" height="21"/>
<secureTextFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" usesSingleLineMode="YES" id="EZ3-1U-Un3">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
@@ -241,8 +241,8 @@
</gridCell>
<gridCell row="Ati-67-7pZ" column="LO3-Dh-mOI" id="2aB-Y2-dTP"/>
<gridCell row="Ati-67-7pZ" column="a9F-Xp-86m" id="F3R-J3-yJX">
<textField key="contentView" focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="hCJ-rP-siw">
<rect key="frame" x="85" y="290" width="94" height="16"/>
<textField key="contentView" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="hCJ-rP-siw">
<rect key="frame" x="94" y="242" width="94" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Cipher/Method" id="tOi-q9-yJY">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
@@ -251,8 +251,8 @@
</textField>
</gridCell>
<gridCell row="Ati-67-7pZ" column="XrQ-Tc-XCS" id="FXV-mY-iWS">
<comboBox key="contentView" focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="4xh-Ub-Yhf">
<rect key="frame" x="298" y="286" width="192" height="23"/>
<comboBox key="contentView" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="4xh-Ub-Yhf">
<rect key="frame" x="307" y="238" width="192" height="23"/>
<comboBoxCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" allowsUndo="NO" borderStyle="bezel" drawsBackground="YES" completes="NO" numberOfVisibleItems="10" id="qHI-jj-mpI">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
@@ -265,8 +265,8 @@
</gridCell>
<gridCell row="Kh8-rv-NWX" column="LO3-Dh-mOI" id="IBD-OY-ImG"/>
<gridCell row="Kh8-rv-NWX" column="a9F-Xp-86m" id="x9M-ta-sLa">
<textField key="contentView" focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="bDw-Ik-ckM">
<rect key="frame" x="85" y="255" width="69" height="16"/>
<textField key="contentView" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="bDw-Ik-ckM">
<rect key="frame" x="94" y="213" width="69" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Local Host" id="rim-zj-Iub">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
@@ -275,8 +275,8 @@
</textField>
</gridCell>
<gridCell row="Kh8-rv-NWX" column="XrQ-Tc-XCS" id="0QG-0P-cDO">
<textField key="contentView" focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Hzm-G4-aes">
<rect key="frame" x="299" y="252" width="188" height="21"/>
<textField key="contentView" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Hzm-G4-aes">
<rect key="frame" x="308" y="210" width="188" height="21"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="Z02-8g-7U6">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
@@ -284,10 +284,10 @@
</textFieldCell>
</textField>
</gridCell>
<gridCell row="wLH-ke-dja" column="LO3-Dh-mOI" id="26B-As-jh6">
<gridCell row="wLH-ke-dja" column="LO3-Dh-mOI" xPlacement="center" id="26B-As-jh6">
<button key="contentView" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="dAY-cJ-YEJ">
<rect key="frame" x="-7" y="209" width="63" height="32"/>
<buttonCell key="cell" type="push" title="Stop" bezelStyle="rounded" alignment="center" enabled="NO" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="JYa-MA-4KH">
<rect key="frame" x="12" y="174" width="61" height="36"/>
<buttonCell key="cell" type="push" title="Stop" bezelStyle="rounded" alignment="center" controlSize="large" enabled="NO" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="JYa-MA-4KH">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
@@ -297,8 +297,8 @@
</button>
</gridCell>
<gridCell row="wLH-ke-dja" column="a9F-Xp-86m" id="NRi-eF-70k">
<textField key="contentView" focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="7Lc-g6-Z1Z">
<rect key="frame" x="85" y="219" width="65" height="16"/>
<textField key="contentView" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="7Lc-g6-Z1Z">
<rect key="frame" x="94" y="183" width="65" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Local Port" id="3bJ-wb-xnh">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
@@ -307,8 +307,8 @@
</textField>
</gridCell>
<gridCell row="wLH-ke-dja" column="XrQ-Tc-XCS" id="tY9-oE-V66">
<textField key="contentView" focusRingType="none" verticalHuggingPriority="751" translatesAutoresizingMaskIntoConstraints="NO" id="4ft-zv-tpp">
<rect key="frame" x="299" y="216" width="188" height="21"/>
<textField key="contentView" verticalHuggingPriority="751" translatesAutoresizingMaskIntoConstraints="NO" id="4ft-zv-tpp">
<rect key="frame" x="308" y="180" width="188" height="21"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="6eq-QO-A6b">
<numberFormatter key="formatter" formatterBehavior="default10_4" usesGroupingSeparator="NO" formatWidth="-1" groupingSize="0" minimumIntegerDigits="1" maximumIntegerDigits="42" id="uWT-vl-bd6">
<real key="minimum" value="0.0"/>
@@ -322,8 +322,8 @@
</gridCell>
<gridCell row="nlG-nP-3oh" column="LO3-Dh-mOI" id="9jK-dz-vSF"/>
<gridCell row="nlG-nP-3oh" column="a9F-Xp-86m" id="a7U-ff-9Pb">
<textField key="contentView" focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="2U7-zl-tc8">
<rect key="frame" x="85" y="183" width="136" height="16"/>
<textField key="contentView" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="2U7-zl-tc8">
<rect key="frame" x="94" y="153" width="136" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="DNS over HTTPS URL" id="yxt-ql-TD8">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
@@ -332,8 +332,8 @@
</textField>
</gridCell>
<gridCell row="nlG-nP-3oh" column="XrQ-Tc-XCS" id="40l-GO-bgp">
<textField key="contentView" focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="VS4-tB-4bb">
<rect key="frame" x="299" y="180" width="188" height="21"/>
<textField key="contentView" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="VS4-tB-4bb">
<rect key="frame" x="308" y="150" width="188" height="21"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" placeholderString="https://1.1.1.1/dns-query" drawsBackground="YES" id="IlA-i9-6tc">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
@@ -343,8 +343,8 @@
</gridCell>
<gridCell row="6aU-Cw-j5C" column="LO3-Dh-mOI" id="49x-3P-I1V"/>
<gridCell row="6aU-Cw-j5C" column="a9F-Xp-86m" id="P0z-mH-Imd">
<textField key="contentView" focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="eZN-yT-YJS">
<rect key="frame" x="85" y="147" width="121" height="16"/>
<textField key="contentView" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="eZN-yT-YJS">
<rect key="frame" x="94" y="123" width="121" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="DNS over TLS Host" id="PXx-nB-Hn1">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
@@ -353,8 +353,8 @@
</textField>
</gridCell>
<gridCell row="6aU-Cw-j5C" column="XrQ-Tc-XCS" id="QvK-s7-HnO">
<textField key="contentView" focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="LsY-AX-mE3">
<rect key="frame" x="299" y="144" width="188" height="21"/>
<textField key="contentView" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="LsY-AX-mE3">
<rect key="frame" x="308" y="120" width="188" height="21"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" placeholderString="1.1.1.1" drawsBackground="YES" id="86y-sR-xrG">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
@@ -364,8 +364,8 @@
</gridCell>
<gridCell row="qX1-aa-MLj" column="LO3-Dh-mOI" id="HLC-Y2-4bN"/>
<gridCell row="qX1-aa-MLj" column="a9F-Xp-86m" id="dOz-Kf-ah3">
<textField key="contentView" focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="aOE-Cb-Jq7">
<rect key="frame" x="85" y="110" width="65" height="16"/>
<textField key="contentView" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="aOE-Cb-Jq7">
<rect key="frame" x="94" y="92" width="65" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Limit Rate" id="Ux8-IL-FUS">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
@@ -374,8 +374,8 @@
</textField>
</gridCell>
<gridCell row="qX1-aa-MLj" column="XrQ-Tc-XCS" id="98I-JF-Dp3">
<textField key="contentView" focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="exc-7i-jLy">
<rect key="frame" x="299" y="108" width="188" height="21"/>
<textField key="contentView" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="exc-7i-jLy">
<rect key="frame" x="308" y="90" width="188" height="21"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" placeholderString="10m" drawsBackground="YES" id="Xbb-ks-3E5">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
@@ -385,8 +385,8 @@
</gridCell>
<gridCell row="mTL-cj-Nle" column="LO3-Dh-mOI" id="0zt-ie-sRL"/>
<gridCell row="mTL-cj-Nle" column="a9F-Xp-86m" id="Pnu-WJ-mBn">
<textField key="contentView" focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="751" translatesAutoresizingMaskIntoConstraints="NO" id="AnO-ZT-CUz">
<rect key="frame" x="85" y="75" width="54" height="16"/>
<textField key="contentView" horizontalHuggingPriority="251" verticalHuggingPriority="751" translatesAutoresizingMaskIntoConstraints="NO" id="AnO-ZT-CUz">
<rect key="frame" x="94" y="63" width="54" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Timeout" id="zY6-tD-aUd">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
@@ -395,8 +395,8 @@
</textField>
</gridCell>
<gridCell row="mTL-cj-Nle" column="XrQ-Tc-XCS" id="NRI-fr-t3C">
<textField key="contentView" focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="d0Y-hk-xNM">
<rect key="frame" x="299" y="72" width="188" height="21"/>
<textField key="contentView" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="d0Y-hk-xNM">
<rect key="frame" x="308" y="60" width="188" height="21"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="Srv-97-Ip1">
<numberFormatter key="formatter" formatterBehavior="default10_4" usesGroupingSeparator="NO" formatWidth="-1" groupingSize="0" minimumIntegerDigits="1" maximumIntegerDigits="42" id="gqX-zp-tFE">
<real key="minimum" value="0.0"/>
@@ -409,8 +409,8 @@
</gridCell>
<gridCell row="e6X-BZ-bV8" column="LO3-Dh-mOI" id="5aI-Pb-YXS"/>
<gridCell row="e6X-BZ-bV8" column="a9F-Xp-86m" id="xkv-I7-ILZ">
<textField key="contentView" focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="OYi-iS-mW2">
<rect key="frame" x="85" y="36" width="66" height="16"/>
<textField key="contentView" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="OYi-iS-mW2">
<rect key="frame" x="94" y="30" width="66" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Auto Start" id="8hL-Qd-hQU">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
@@ -420,7 +420,7 @@
</gridCell>
<gridCell row="e6X-BZ-bV8" column="XrQ-Tc-XCS" id="pI2-ba-pFT">
<button key="contentView" verticalHuggingPriority="749" translatesAutoresizingMaskIntoConstraints="NO" id="Cu9-FF-7Of">
<rect key="frame" x="297" y="35" width="67" height="18"/>
<rect key="frame" x="306" y="29" width="67" height="18"/>
<buttonCell key="cell" type="check" title="Enable" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="hei-7a-ZHr">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
@@ -432,8 +432,8 @@
</gridCell>
<gridCell row="1cJ-xv-Xd3" column="LO3-Dh-mOI" id="0ZG-UH-0MQ"/>
<gridCell row="1cJ-xv-Xd3" column="a9F-Xp-86m" id="dvS-cU-tpD">
<textField key="contentView" focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="gsJ-2M-W13">
<rect key="frame" x="85" y="0.0" width="87" height="16"/>
<textField key="contentView" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="gsJ-2M-W13">
<rect key="frame" x="94" y="0.0" width="87" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="System Proxy" id="g0k-mZ-0JW">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
@@ -443,7 +443,7 @@
</gridCell>
<gridCell row="1cJ-xv-Xd3" column="XrQ-Tc-XCS" id="IsN-Qi-s8F">
<button key="contentView" verticalHuggingPriority="749" translatesAutoresizingMaskIntoConstraints="NO" id="fIt-Cr-IJG">
<rect key="frame" x="297" y="-1" width="67" height="18"/>
<rect key="frame" x="306" y="-1" width="67" height="18"/>
<buttonCell key="cell" type="check" title="Enable" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="Jw2-My-hmB">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
@@ -491,11 +491,11 @@
<objects>
<viewController storyboardIdentifier="OptionViewController" id="Rl3-9N-Ypa" customClass="OptionViewController" sceneMemberID="viewController">
<view key="view" id="zIF-tN-wo1">
<rect key="frame" x="0.0" y="0.0" width="436" height="228"/>
<rect key="frame" x="0.0" y="0.0" width="436" height="198"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<gridView xPlacement="leading" yPlacement="bottom" rowAlignment="none" rowSpacing="12" columnSpacing="12" translatesAutoresizingMaskIntoConstraints="NO" id="XUN-Bn-cfn">
<rect key="frame" x="12" y="12" width="412" height="204"/>
<gridView xPlacement="leading" yPlacement="bottom" rowAlignment="none" columnSpacing="12" translatesAutoresizingMaskIntoConstraints="NO" id="XUN-Bn-cfn">
<rect key="frame" x="12" y="12" width="412" height="174"/>
<constraints>
<constraint firstItem="FCy-Ix-JtV" firstAttribute="trailing" secondItem="vKb-Fc-qV5" secondAttribute="trailing" id="IrF-yb-oaO"/>
<constraint firstAttribute="trailing" secondItem="FCy-Ix-JtV" secondAttribute="trailing" constant="12" id="Lgf-n3-NC8"/>
@@ -515,8 +515,8 @@
</columns>
<gridCells>
<gridCell row="mrN-pz-1Oa" column="hxb-rW-bCk" id="NN6-Wm-nJC">
<textField key="contentView" focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Ntm-zj-sC8">
<rect key="frame" x="-2" y="180" width="96" height="16"/>
<textField key="contentView" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Ntm-zj-sC8">
<rect key="frame" x="-2" y="150" width="96" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="TCP Keep Alive" id="z0q-m8-6KJ">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
@@ -526,7 +526,7 @@
</gridCell>
<gridCell row="mrN-pz-1Oa" column="BSc-hd-WXx" id="Opw-34-sct">
<button key="contentView" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="mtt-Vz-5jG">
<rect key="frame" x="285" y="179" width="67" height="18"/>
<rect key="frame" x="285" y="149" width="67" height="18"/>
<buttonCell key="cell" type="check" title="Enable" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="IpF-Ur-Zlh">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
@@ -534,8 +534,8 @@
</button>
</gridCell>
<gridCell row="pro-5c-Rbh" column="hxb-rW-bCk" id="Zvf-RC-ruS">
<textField key="contentView" focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="BJp-Io-gl8">
<rect key="frame" x="-2" y="144" width="137" height="16"/>
<textField key="contentView" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="BJp-Io-gl8">
<rect key="frame" x="-2" y="120" width="137" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="TCP Keep Alive Count" id="DwU-MU-ncE">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
@@ -544,8 +544,8 @@
</textField>
</gridCell>
<gridCell row="pro-5c-Rbh" column="BSc-hd-WXx" id="zdE-rB-Pec">
<textField key="contentView" focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="aaB-XL-no7">
<rect key="frame" x="287" y="144" width="113" height="21"/>
<textField key="contentView" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="aaB-XL-no7">
<rect key="frame" x="287" y="120" width="113" height="21"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="8tD-KN-XwR">
<numberFormatter key="formatter" formatterBehavior="default10_4" usesGroupingSeparator="NO" formatWidth="-1" groupingSize="0" minimumIntegerDigits="1" maximumIntegerDigits="42" id="NCD-jR-QoX"/>
<font key="font" metaFont="system"/>
@@ -555,8 +555,8 @@
</textField>
</gridCell>
<gridCell row="OaS-mO-GLn" column="hxb-rW-bCk" id="pJ7-Z4-dpM">
<textField key="contentView" focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="hCK-tE-t9g">
<rect key="frame" x="-2" y="108" width="175" height="16"/>
<textField key="contentView" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="hCK-tE-t9g">
<rect key="frame" x="-2" y="90" width="175" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="TCP Keep Alive Idle Timeout" id="EnC-Oa-kda">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
@@ -565,8 +565,8 @@
</textField>
</gridCell>
<gridCell row="OaS-mO-GLn" column="BSc-hd-WXx" id="VAb-Vg-nQf">
<textField key="contentView" focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="vKb-Fc-qV5">
<rect key="frame" x="287" y="108" width="113" height="21"/>
<textField key="contentView" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="vKb-Fc-qV5">
<rect key="frame" x="287" y="90" width="113" height="21"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="nOf-jN-DQX">
<numberFormatter key="formatter" formatterBehavior="default10_4" usesGroupingSeparator="NO" formatWidth="-1" groupingSize="0" minimumIntegerDigits="1" maximumIntegerDigits="42" id="NGY-o4-plc"/>
<font key="font" metaFont="system"/>
@@ -576,8 +576,8 @@
</textField>
</gridCell>
<gridCell row="u9C-AX-ell" column="hxb-rW-bCk" id="Mki-MU-1Xs">
<textField key="contentView" focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="EQc-sT-cRe">
<rect key="frame" x="-2" y="72" width="145" height="16"/>
<textField key="contentView" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="EQc-sT-cRe">
<rect key="frame" x="-2" y="60" width="145" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="TCP Keep Alive Interval" id="dCR-E3-G0W">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
@@ -586,8 +586,8 @@
</textField>
</gridCell>
<gridCell row="u9C-AX-ell" column="BSc-hd-WXx" id="uea-jg-zXU">
<textField key="contentView" focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="FCy-Ix-JtV">
<rect key="frame" x="287" y="72" width="113" height="21"/>
<textField key="contentView" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="FCy-Ix-JtV">
<rect key="frame" x="287" y="60" width="113" height="21"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="fs7-4d-4EQ">
<numberFormatter key="formatter" formatterBehavior="default10_4" usesGroupingSeparator="NO" formatWidth="-1" groupingSize="0" minimumIntegerDigits="1" maximumIntegerDigits="42" id="KMj-84-Y99"/>
<font key="font" metaFont="system"/>
@@ -597,8 +597,8 @@
</textField>
</gridCell>
<gridCell row="dEK-1Q-llb" column="hxb-rW-bCk" id="yXv-wF-rtT">
<textField key="contentView" focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="3br-w1-dtI">
<rect key="frame" x="-2" y="36" width="270" height="16"/>
<textField key="contentView" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="3br-w1-dtI">
<rect key="frame" x="-2" y="30" width="270" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Kyber post-quantum key agreement for TLS" id="EY5-8C-G6C">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
@@ -608,17 +608,17 @@
</gridCell>
<gridCell row="dEK-1Q-llb" column="BSc-hd-WXx" id="WnE-iw-kNO">
<button key="contentView" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="eCq-VL-0xN">
<rect key="frame" x="285" y="35" width="67" height="18"/>
<rect key="frame" x="285" y="29" width="67" height="18"/>
<buttonCell key="cell" type="check" title="Enable" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="aFJ-Zj-eao">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
</gridCell>
<gridCell row="7Cr-lG-X0w" column="hxb-rW-bCk" id="bjc-gh-Yad">
<gridCell row="7Cr-lG-X0w" column="hxb-rW-bCk" xPlacement="trailing" id="bjc-gh-Yad">
<button key="contentView" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="DeI-uB-d4V">
<rect key="frame" x="-7" y="-7" width="53" height="32"/>
<buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="yzs-Gu-p7Y">
<rect key="frame" x="230" y="-6" width="51" height="36"/>
<buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" controlSize="large" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="yzs-Gu-p7Y">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<string key="keyEquivalent" base64-UTF8="YES">
@@ -632,8 +632,8 @@ DQ
</gridCell>
<gridCell row="7Cr-lG-X0w" column="BSc-hd-WXx" id="TvI-Ro-1ez">
<button key="contentView" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="50U-gT-ab3">
<rect key="frame" x="280" y="-7" width="76" height="32"/>
<buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Mei-lK-JLB">
<rect key="frame" x="281" y="-6" width="74" height="36"/>
<buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" controlSize="large" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Mei-lK-JLB">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<string key="keyEquivalent" base64-UTF8="YES">
+6
View File
@@ -374,8 +374,11 @@ CPUType GetCPUType() {
std::string GetModelIdentifier() {
std::string return_string;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
gurl_base::mac::ScopedIOObject<io_service_t> platform_expert(
IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice")));
#pragma clang diagnostic pop
if (platform_expert) {
ScopedCFTypeRef<CFDataRef> model_data(static_cast<CFDataRef>(
IORegistryEntryCreateCFProperty(platform_expert, CFSTR("model"), kCFAllocatorDefault, 0)));
@@ -414,8 +417,11 @@ std::string GetOSDisplayName() {
}
std::string GetPlatformSerialNumber() {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
gurl_base::mac::ScopedIOObject<io_service_t> expert_device(
IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice")));
#pragma clang diagnostic pop
if (!expert_device) {
DLOG(ERROR) << "Error retrieving the machine serial number.";
return std::string();
+2 -1
View File
@@ -20,7 +20,8 @@ OptionDialog::OptionDialog(QWidget* parent) : QDialog(parent) {
QGridLayout* grid = new QGridLayout;
grid->setContentsMargins(12, 12, 12, 12);
grid->setSpacing(12);
grid->setHorizontalSpacing(12);
grid->setVerticalSpacing(6);
auto tcp_keep_alive_label = new QLabel(tr("TCP keep alive"));
auto tcp_keep_alive_cnt_label = new QLabel(tr("The number of TCP keep-alive probes"));
+2 -1
View File
@@ -67,7 +67,8 @@ YASSWindow::YASSWindow(QWidget* parent) : QMainWindow(parent) {
QGridLayout* grid = new QGridLayout;
grid->setContentsMargins(12, 12, 12, 12);
grid->setSpacing(12);
grid->setHorizontalSpacing(12);
grid->setVerticalSpacing(6);
// Left (Column 0) << Grid << Vertical Box
+1 -1
View File
@@ -165,7 +165,7 @@ BOOL CYassApp::InitInstance() {
std::wstring frame_name = LoadStringStdW(m_hInstance, IDS_APP_TITLE);
UINT uDpi = Utils::GetDpiForWindowOrSystem(nullptr);
RECT rect{0, 0, MULDIVDPI(530), MULDIVDPI(540)};
RECT rect{0, 0, MULDIVDPI(500), MULDIVDPI(520)};
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow
int nCmdShow = absl::GetFlag(FLAGS_background) ? SW_HIDE : SW_SHOW;
+45 -37
View File
@@ -35,25 +35,29 @@ __CRT_UUID_DECL(TrayIcon, 0x4324603D, 0x4274, 0x47AA, 0xBA, 0xD5, 0x7C, 0xF6, 0x
#endif
#endif
#define INITIAL_COLUMN_ONE_LEFT 20
#define INITIAL_COLUMN_TWO_LEFT 120
#define INITIAL_COLUMN_THREE_LEFT 240
#define INITIAL_ROW_HEIGHT 12
#define INITIAL_VERTICAL_HEIGHT 30
#define INITIAL_BUTTON_WIDTH 75
#define INITIAL_BUTTON_WIDTH 80
#define INITIAL_BUTTON_HEIGHT 30
#define INITIAL_LABEL_WIDTH 130
#define INITIAL_LABEL_HEIGHT 25
#define INITIAL_EDIT_WIDTH 220
#define INITIAL_EDIT_HEIGHT 25
#define INITIAL_LABEL_WIDTH 200
#define INITIAL_LABEL_HEIGHT 24
#define INITIAL_EDIT_WIDTH 160
#define INITIAL_EDIT_HEIGHT 24
#define INITIAL_STATUS_BAR_HEIGHT 20
static_assert(INITIAL_LABEL_HEIGHT == INITIAL_EDIT_HEIGHT);
#define INITIAL_COLUMN_ONE_LEFT 12
#define INITIAL_COLUMN_TWO_LEFT (INITIAL_COLUMN_ONE_LEFT + INITIAL_BUTTON_WIDTH + 12)
#define INITIAL_COLUMN_THREE_LEFT (INITIAL_COLUMN_TWO_LEFT + INITIAL_LABEL_WIDTH + 12)
#define COLUMN_ONE_LEFT MulDiv(INITIAL_COLUMN_ONE_LEFT, uDpi, 96)
#define COLUMN_TWO_LEFT MulDiv(INITIAL_COLUMN_TWO_LEFT, uDpi, 96)
#define COLUMN_THREE_LEFT MulDiv(INITIAL_COLUMN_THREE_LEFT, uDpi, 96)
#define ROW_HEIGHT MulDiv(INITIAL_ROW_HEIGHT, uDpi, 96)
#define VERTICAL_HEIGHT MulDiv(INITIAL_VERTICAL_HEIGHT, uDpi, 96)
#define BUTTON_WIDTH MulDiv(INITIAL_BUTTON_WIDTH, uDpi, 96)
@@ -841,124 +845,128 @@ void CYassFrame::UpdateLayoutForDpi(UINT uDpi) {
// RIGHT Panel
// Column 2
rect.left = client_rect.left + COLUMN_TWO_LEFT;
rect.top = client_rect.top + VERTICAL_HEIGHT;
rect.top = client_rect.top + ROW_HEIGHT + VERTICAL_HEIGHT * 0;
SetWindowPos(server_host_label_, nullptr, rect.left, rect.top, LABEL_WIDTH, LABEL_HEIGHT,
SWP_NOZORDER | SWP_NOACTIVATE);
rect.left = client_rect.left + COLUMN_TWO_LEFT;
rect.top = client_rect.top + VERTICAL_HEIGHT * 2;
rect.top = client_rect.top + ROW_HEIGHT + VERTICAL_HEIGHT * 1;
SetWindowPos(server_sni_label_, nullptr, rect.left, rect.top, LABEL_WIDTH, LABEL_HEIGHT,
SWP_NOZORDER | SWP_NOACTIVATE);
rect.left = client_rect.left + COLUMN_TWO_LEFT;
rect.top = client_rect.top + VERTICAL_HEIGHT * 3;
rect.top = client_rect.top + ROW_HEIGHT + VERTICAL_HEIGHT * 2;
SetWindowPos(server_port_label_, nullptr, rect.left, rect.top, LABEL_WIDTH, LABEL_HEIGHT,
SWP_NOZORDER | SWP_NOACTIVATE);
rect.left = client_rect.left + COLUMN_TWO_LEFT;
rect.top = client_rect.top + VERTICAL_HEIGHT * 4;
rect.top = client_rect.top + ROW_HEIGHT + VERTICAL_HEIGHT * 3;
SetWindowPos(username_label_, nullptr, rect.left, rect.top, LABEL_WIDTH, LABEL_HEIGHT, SWP_NOZORDER | SWP_NOACTIVATE);
rect.left = client_rect.left + COLUMN_TWO_LEFT;
rect.top = client_rect.top + VERTICAL_HEIGHT * 5;
rect.top = client_rect.top + ROW_HEIGHT + VERTICAL_HEIGHT * 4;
SetWindowPos(password_label_, nullptr, rect.left, rect.top, LABEL_WIDTH, LABEL_HEIGHT, SWP_NOZORDER | SWP_NOACTIVATE);
rect.left = client_rect.left + COLUMN_TWO_LEFT;
rect.top = client_rect.top + VERTICAL_HEIGHT * 6;
rect.top = client_rect.top + ROW_HEIGHT + VERTICAL_HEIGHT * 5;
SetWindowPos(method_label_, nullptr, rect.left, rect.top, LABEL_WIDTH, LABEL_HEIGHT, SWP_NOZORDER | SWP_NOACTIVATE);
rect.left = client_rect.left + COLUMN_TWO_LEFT;
rect.top = client_rect.top + VERTICAL_HEIGHT * 7;
rect.top = client_rect.top + ROW_HEIGHT + VERTICAL_HEIGHT * 6;
SetWindowPos(local_host_label_, nullptr, rect.left, rect.top, LABEL_WIDTH, LABEL_HEIGHT,
SWP_NOZORDER | SWP_NOACTIVATE);
rect.left = client_rect.left + COLUMN_TWO_LEFT;
rect.top = client_rect.top + VERTICAL_HEIGHT * 8;
rect.top = client_rect.top + ROW_HEIGHT + VERTICAL_HEIGHT * 7;
SetWindowPos(local_port_label_, nullptr, rect.left, rect.top, LABEL_WIDTH, LABEL_HEIGHT,
SWP_NOZORDER | SWP_NOACTIVATE);
rect.left = client_rect.left + COLUMN_TWO_LEFT;
rect.top = client_rect.top + VERTICAL_HEIGHT * 9;
rect.top = client_rect.top + ROW_HEIGHT + VERTICAL_HEIGHT * 8;
SetWindowPos(doh_url_label_, nullptr, rect.left, rect.top, LABEL_WIDTH, LABEL_HEIGHT, SWP_NOZORDER | SWP_NOACTIVATE);
rect.left = client_rect.left + COLUMN_TWO_LEFT;
rect.top = client_rect.top + VERTICAL_HEIGHT * 10;
rect.top = client_rect.top + ROW_HEIGHT + VERTICAL_HEIGHT * 9;
SetWindowPos(dot_host_label_, nullptr, rect.left, rect.top, LABEL_WIDTH, LABEL_HEIGHT, SWP_NOZORDER | SWP_NOACTIVATE);
rect.left = client_rect.left + COLUMN_TWO_LEFT;
rect.top = client_rect.top + VERTICAL_HEIGHT * 11;
rect.top = client_rect.top + ROW_HEIGHT + VERTICAL_HEIGHT * 10;
SetWindowPos(limit_rate_label_, nullptr, rect.left, rect.top, LABEL_WIDTH, LABEL_HEIGHT,
SWP_NOZORDER | SWP_NOACTIVATE);
rect.left = client_rect.left + COLUMN_TWO_LEFT;
rect.top = client_rect.top + VERTICAL_HEIGHT * 12;
rect.top = client_rect.top + ROW_HEIGHT + VERTICAL_HEIGHT * 11;
SetWindowPos(timeout_label_, nullptr, rect.left, rect.top, LABEL_WIDTH, LABEL_HEIGHT, SWP_NOZORDER | SWP_NOACTIVATE);
rect.left = client_rect.left + COLUMN_TWO_LEFT;
rect.top = client_rect.top + VERTICAL_HEIGHT * 13;
rect.top = client_rect.top + ROW_HEIGHT + VERTICAL_HEIGHT * 12;
SetWindowPos(autostart_label_, nullptr, rect.left, rect.top, LABEL_WIDTH, LABEL_HEIGHT,
SWP_NOZORDER | SWP_NOACTIVATE);
rect.left = client_rect.left + COLUMN_TWO_LEFT;
rect.top = client_rect.top + VERTICAL_HEIGHT * 14;
rect.top = client_rect.top + ROW_HEIGHT + VERTICAL_HEIGHT * 13;
SetWindowPos(systemproxy_label_, nullptr, rect.left, rect.top, LABEL_WIDTH, LABEL_HEIGHT,
SWP_NOZORDER | SWP_NOACTIVATE);
// Column 3
rect.left = client_rect.left + COLUMN_THREE_LEFT;
rect.top = client_rect.top + VERTICAL_HEIGHT;
rect.top = client_rect.top + ROW_HEIGHT + VERTICAL_HEIGHT * 0;
SetWindowPos(server_host_edit_, nullptr, rect.left, rect.top, EDIT_WIDTH, EDIT_HEIGHT, SWP_NOZORDER | SWP_NOACTIVATE);
rect.left = client_rect.left + COLUMN_THREE_LEFT;
rect.top = client_rect.top + VERTICAL_HEIGHT * 2;
rect.top = client_rect.top + ROW_HEIGHT + VERTICAL_HEIGHT * 1;
SetWindowPos(server_sni_edit_, nullptr, rect.left, rect.top, EDIT_WIDTH, EDIT_HEIGHT, SWP_NOZORDER | SWP_NOACTIVATE);
rect.left = client_rect.left + COLUMN_THREE_LEFT;
rect.top = client_rect.top + VERTICAL_HEIGHT * 3;
rect.top = client_rect.top + ROW_HEIGHT + VERTICAL_HEIGHT * 2;
SetWindowPos(server_port_edit_, nullptr, rect.left, rect.top, EDIT_WIDTH, EDIT_HEIGHT, SWP_NOZORDER | SWP_NOACTIVATE);
rect.left = client_rect.left + COLUMN_THREE_LEFT;
rect.top = client_rect.top + VERTICAL_HEIGHT * 4;
rect.top = client_rect.top + ROW_HEIGHT + VERTICAL_HEIGHT * 3;
SetWindowPos(username_edit_, nullptr, rect.left, rect.top, EDIT_WIDTH, EDIT_HEIGHT, SWP_NOZORDER | SWP_NOACTIVATE);
rect.left = client_rect.left + COLUMN_THREE_LEFT;
rect.top = client_rect.top + VERTICAL_HEIGHT * 5;
rect.top = client_rect.top + ROW_HEIGHT + VERTICAL_HEIGHT * 4;
SetWindowPos(password_edit_, nullptr, rect.left, rect.top, EDIT_WIDTH, EDIT_HEIGHT, SWP_NOZORDER | SWP_NOACTIVATE);
for (int i = 0, cnt = ComboBox_GetCount(method_combo_box_); i < cnt; ++i) {
ComboBox_SetItemHeight(method_combo_box_, i, EDIT_HEIGHT);
}
rect.left = client_rect.left + COLUMN_THREE_LEFT;
rect.top = client_rect.top + VERTICAL_HEIGHT * 6;
rect.top = client_rect.top + ROW_HEIGHT + VERTICAL_HEIGHT * 5;
SetWindowPos(method_combo_box_, nullptr, rect.left, rect.top, EDIT_WIDTH, EDIT_HEIGHT, SWP_NOZORDER | SWP_NOACTIVATE);
rect.left = client_rect.left + COLUMN_THREE_LEFT;
rect.top = client_rect.top + VERTICAL_HEIGHT * 7;
rect.top = client_rect.top + ROW_HEIGHT + VERTICAL_HEIGHT * 6;
SetWindowPos(local_host_edit_, nullptr, rect.left, rect.top, EDIT_WIDTH, EDIT_HEIGHT, SWP_NOZORDER | SWP_NOACTIVATE);
rect.left = client_rect.left + COLUMN_THREE_LEFT;
rect.top = client_rect.top + VERTICAL_HEIGHT * 8;
rect.top = client_rect.top + ROW_HEIGHT + VERTICAL_HEIGHT * 7;
SetWindowPos(local_port_edit_, nullptr, rect.left, rect.top, EDIT_WIDTH, EDIT_HEIGHT, SWP_NOZORDER | SWP_NOACTIVATE);
rect.left = client_rect.left + COLUMN_THREE_LEFT;
rect.top = client_rect.top + VERTICAL_HEIGHT * 9;
rect.top = client_rect.top + ROW_HEIGHT + VERTICAL_HEIGHT * 8;
SetWindowPos(doh_url_edit_, nullptr, rect.left, rect.top, EDIT_WIDTH, EDIT_HEIGHT, SWP_NOZORDER | SWP_NOACTIVATE);
rect.left = client_rect.left + COLUMN_THREE_LEFT;
rect.top = client_rect.top + VERTICAL_HEIGHT * 10;
rect.top = client_rect.top + ROW_HEIGHT + VERTICAL_HEIGHT * 9;
SetWindowPos(dot_host_edit_, nullptr, rect.left, rect.top, EDIT_WIDTH, EDIT_HEIGHT, SWP_NOZORDER | SWP_NOACTIVATE);
rect.left = client_rect.left + COLUMN_THREE_LEFT;
rect.top = client_rect.top + VERTICAL_HEIGHT * 11;
rect.top = client_rect.top + ROW_HEIGHT + VERTICAL_HEIGHT * 10;
SetWindowPos(limit_rate_edit_, nullptr, rect.left, rect.top, EDIT_WIDTH, EDIT_HEIGHT, SWP_NOZORDER | SWP_NOACTIVATE);
rect.left = client_rect.left + COLUMN_THREE_LEFT;
rect.top = client_rect.top + VERTICAL_HEIGHT * 12;
rect.top = client_rect.top + ROW_HEIGHT + VERTICAL_HEIGHT * 11;
SetWindowPos(timeout_edit_, nullptr, rect.left, rect.top, EDIT_WIDTH, EDIT_HEIGHT, SWP_NOZORDER | SWP_NOACTIVATE);
rect.left = client_rect.left + COLUMN_THREE_LEFT;
rect.top = client_rect.top + VERTICAL_HEIGHT * 13;
rect.top = client_rect.top + ROW_HEIGHT + VERTICAL_HEIGHT * 12;
SetWindowPos(autostart_button_, nullptr, rect.left, rect.top, EDIT_WIDTH, EDIT_HEIGHT, SWP_NOZORDER | SWP_NOACTIVATE);
rect.left = client_rect.left + COLUMN_THREE_LEFT;
rect.top = client_rect.top + VERTICAL_HEIGHT * 14;
rect.top = client_rect.top + ROW_HEIGHT + VERTICAL_HEIGHT * 13;
SetWindowPos(systemproxy_button_, nullptr, rect.left, rect.top, EDIT_WIDTH, EDIT_HEIGHT,
SWP_NOZORDER | SWP_NOACTIVATE);
@@ -166,6 +166,14 @@ _NSIG_TESTS = [
'https://www.youtube.com/s/player/b22ef6e7/player_ias.vflset/en_US/base.js',
'b6HcntHGkvBLk_FRf', 'kNPW6A7FyP2l8A',
),
(
'https://www.youtube.com/s/player/3400486c/player_ias.vflset/en_US/base.js',
'lL46g3XifCKUZn1Xfw', 'z767lhet6V2Skl',
),
(
'https://www.youtube.com/s/player/5604538d/player_ias.vflset/en_US/base.js',
'7X-he4jjvMx7BCX', 'sViSydX8IHtdWA',
),
]
+8 -4
View File
@@ -1647,7 +1647,7 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
except JSInterpreter.Exception as e:
self.report_warning(
'%s (%s %s)' % (
'Unable to decode n-parameter: download likely to be throttled',
'Unable to decode n-parameter: expect download to be blocked or throttled',
error_to_compat_str(e),
traceback.format_exc()),
video_id=video_id)
@@ -1659,18 +1659,22 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
def _extract_n_function_name(self, jscode):
func_name, idx = self._search_regex(
# new: (b=String.fromCharCode(110),c=a.get(b))&&c=nfunc[idx](c)
# or: (b="nn"[+a.D],c=a.get(b))&&(c=nfunc[idx](c)s
# old: .get("n"))&&(b=nfunc[idx](b)
# older: .get("n"))&&(b=nfunc(b)
r'''(?x)
(?:\(\s*(?P<b>[a-z])\s*=\s*String\s*\.\s*fromCharCode\s*\(\s*110\s*\)\s*,(?P<c>[a-z])\s*=\s*[a-z]\s*)?
\.\s*get\s*\(\s*(?(b)(?P=b)|"n")(?:\s*\)){2}\s*&&\s*\(\s*(?(c)(?P=c)|b)\s*=\s*
(?:\(\s*(?P<b>[a-z])\s*=\s*(?:
String\s*\.\s*fromCharCode\s*\(\s*110\s*\)|
"n+"\[\s*\+?s*[\w$.]+\s*]
)\s*,(?P<c>[a-z])\s*=\s*[a-z]\s*)?
\.\s*get\s*\(\s*(?(b)(?P=b)|"n{1,2}")(?:\s*\)){2}\s*&&\s*\(\s*(?(c)(?P=c)|b)\s*=\s*
(?P<nfunc>[a-zA-Z_$][\w$]*)(?:\s*\[(?P<idx>\d+)\])?\s*\(\s*[\w$]+\s*\)
''', jscode, 'Initial JS player n function name', group=('nfunc', 'idx'))
if not idx:
return func_name
return self._parse_json(self._search_regex(
r'var {0}\s*=\s*(\[.+?\])\s*[,;]'.format(re.escape(func_name)), jscode,
r'var\s+{0}\s*=\s*(\[.+?\])\s*[,;]'.format(re.escape(func_name)), jscode,
'Initial JS player n function list ({0}.{1})'.format(func_name, idx)),
func_name, transform_source=js_to_json)[int(idx)]
+13
View File
@@ -4,6 +4,19 @@
# To create a release, dispatch the https://github.com/yt-dlp/yt-dlp/actions/workflows/release.yml workflow on master
-->
### 2024.07.25
#### Extractor changes
- **abematv**: [Adapt key retrieval to request handler framework](https://github.com/yt-dlp/yt-dlp/commit/a3bab4752a2b3d56e5a59b4e0411bb8f695c010b) ([#10491](https://github.com/yt-dlp/yt-dlp/issues/10491)) by [bashonly](https://github.com/bashonly)
- **facebook**: [Fix extraction](https://github.com/yt-dlp/yt-dlp/commit/1a34a802f44a1dab8f642c79c3cc810e21541d3b) ([#10531](https://github.com/yt-dlp/yt-dlp/issues/10531)) by [bashonly](https://github.com/bashonly)
- **mlbtv**: [Fix extractor](https://github.com/yt-dlp/yt-dlp/commit/f0993391e6052ec8f7aacc286609564f226943b9) ([#10515](https://github.com/yt-dlp/yt-dlp/issues/10515)) by [bashonly](https://github.com/bashonly)
- **tiktok**: [Fix and deprioritize JSON subtitles](https://github.com/yt-dlp/yt-dlp/commit/2f97779f335ac069ecccd9c7bf81abf4a83cfe7a) ([#10516](https://github.com/yt-dlp/yt-dlp/issues/10516)) by [bashonly](https://github.com/bashonly)
- **vimeo**: [Fix chapters extraction](https://github.com/yt-dlp/yt-dlp/commit/a0a1bc3d8d8e3bb9a48a06e835815a0460e90e77) ([#10544](https://github.com/yt-dlp/yt-dlp/issues/10544)) by [bashonly](https://github.com/bashonly)
- **youtube**: [Fix `n` function name extraction for player `3400486c`](https://github.com/yt-dlp/yt-dlp/commit/713b4cd18f00556771af8cfdd9cea6cc1a09e948) ([#10542](https://github.com/yt-dlp/yt-dlp/issues/10542)) by [bashonly](https://github.com/bashonly)
#### Misc. changes
- **build**: [Pin `setuptools` version](https://github.com/yt-dlp/yt-dlp/commit/e046db8a116b1c320d4785daadd48ea0b22a3987) ([#10493](https://github.com/yt-dlp/yt-dlp/issues/10493)) by [bashonly](https://github.com/bashonly)
### 2024.07.16
#### Core changes
+180 -43
View File
@@ -1,16 +1,21 @@
import json
import re
import urllib.parse
import time
import uuid
from .common import InfoExtractor
from ..networking.exceptions import HTTPError
from ..utils import (
ExtractorError,
determine_ext,
int_or_none,
join_nonempty,
jwt_decode_hs256,
parse_duration,
parse_iso8601,
try_get,
url_or_none,
urlencode_postdata,
)
from ..utils.traversal import traverse_obj
@@ -276,81 +281,213 @@ class MLBVideoIE(MLBBaseIE):
class MLBTVIE(InfoExtractor):
_VALID_URL = r'https?://(?:www\.)?mlb\.com/tv/g(?P<id>\d{6})'
_NETRC_MACHINE = 'mlb'
_TESTS = [{
'url': 'https://www.mlb.com/tv/g661581/vee2eff5f-a7df-4c20-bdb4-7b926fa12638',
'info_dict': {
'id': '661581',
'ext': 'mp4',
'title': '2022-07-02 - St. Louis Cardinals @ Philadelphia Phillies',
'release_date': '20220702',
'release_timestamp': 1656792300,
},
'params': {
'skip_download': True,
},
}]
_GRAPHQL_INIT_QUERY = '''\
mutation initSession($device: InitSessionInput!, $clientType: ClientType!, $experience: ExperienceTypeInput) {
initSession(device: $device, clientType: $clientType, experience: $experience) {
deviceId
sessionId
entitlements {
code
}
location {
countryCode
regionName
zipCode
latitude
longitude
}
clientExperience
features
}
}'''
_GRAPHQL_PLAYBACK_QUERY = '''\
mutation initPlaybackSession(
$adCapabilities: [AdExperienceType]
$mediaId: String!
$deviceId: String!
$sessionId: String!
$quality: PlaybackQuality
) {
initPlaybackSession(
adCapabilities: $adCapabilities
mediaId: $mediaId
deviceId: $deviceId
sessionId: $sessionId
quality: $quality
) {
playbackSessionId
playback {
url
token
expiration
cdn
}
}
}'''
_APP_VERSION = '7.8.2'
_device_id = None
_session_id = None
_access_token = None
_token_expiry = 0
@property
def _api_headers(self):
if (self._token_expiry - 120) <= time.time():
self.write_debug('Access token has expired; re-logging in')
self._perform_login(*self._get_login_info())
return {'Authorization': f'Bearer {self._access_token}'}
def _real_initialize(self):
if not self._access_token:
self.raise_login_required(
'All videos are only available to registered users', method='password')
def _set_device_id(self, username):
if not self._device_id:
self._device_id = self.cache.load(
self._NETRC_MACHINE, 'device_ids', default={}).get(username)
if self._device_id:
return
self._device_id = str(uuid.uuid4())
self.cache.store(self._NETRC_MACHINE, 'device_ids', {username: self._device_id})
def _perform_login(self, username, password):
data = f'grant_type=password&username={urllib.parse.quote(username)}&password={urllib.parse.quote(password)}&scope=openid offline_access&client_id=0oa3e1nutA1HLzAKG356'
access_token = self._download_json(
'https://ids.mlb.com/oauth2/aus1m088yK07noBfh356/v1/token', None,
headers={
'User-Agent': 'okhttp/3.12.1',
'Content-Type': 'application/x-www-form-urlencoded',
}, data=data.encode())['access_token']
try:
self._access_token = self._download_json(
'https://ids.mlb.com/oauth2/aus1m088yK07noBfh356/v1/token', None,
'Logging in', 'Unable to log in', headers={
'User-Agent': 'okhttp/3.12.1',
'Content-Type': 'application/x-www-form-urlencoded',
}, data=urlencode_postdata({
'grant_type': 'password',
'username': username,
'password': password,
'scope': 'openid offline_access',
'client_id': '0oa3e1nutA1HLzAKG356',
}))['access_token']
except ExtractorError as error:
if isinstance(error.cause, HTTPError) and error.cause.status == 400:
raise ExtractorError('Invalid username or password', expected=True)
raise
entitlement = self._download_webpage(
f'https://media-entitlement.mlb.com/api/v3/jwt?os=Android&appname=AtBat&did={uuid.uuid4()}', None,
headers={
'User-Agent': 'okhttp/3.12.1',
'Authorization': f'Bearer {access_token}',
})
self._token_expiry = traverse_obj(self._access_token, ({jwt_decode_hs256}, 'exp', {int})) or 0
self._set_device_id(username)
data = f'grant_type=urn:ietf:params:oauth:grant-type:token-exchange&subject_token={entitlement}&subject_token_type=urn:ietf:params:oauth:token-type:jwt&platform=android-tv'
self._access_token = self._download_json(
'https://us.edge.bamgrid.com/token', None,
self._session_id = self._call_api({
'operationName': 'initSession',
'query': self._GRAPHQL_INIT_QUERY,
'variables': {
'device': {
'appVersion': self._APP_VERSION,
'deviceFamily': 'desktop',
'knownDeviceId': self._device_id,
'languagePreference': 'ENGLISH',
'manufacturer': '',
'model': '',
'os': '',
'osVersion': '',
},
'clientType': 'WEB',
},
}, None, 'session ID')['data']['initSession']['sessionId']
def _call_api(self, data, video_id, description='GraphQL JSON', fatal=True):
return self._download_json(
'https://media-gateway.mlb.com/graphql', video_id,
f'Downloading {description}', f'Unable to download {description}', fatal=fatal,
headers={
**self._api_headers,
'Accept': 'application/json',
'Authorization': 'Bearer bWxidHYmYW5kcm9pZCYxLjAuMA.6LZMbH2r--rbXcgEabaDdIslpo4RyZrlVfWZhsAgXIk',
'Content-Type': 'application/x-www-form-urlencoded',
}, data=data.encode())['access_token']
'Content-Type': 'application/json',
'x-client-name': 'WEB',
'x-client-version': self._APP_VERSION,
}, data=json.dumps(data, separators=(',', ':')).encode())
def _extract_formats_and_subtitles(self, broadcast, video_id):
feed = traverse_obj(broadcast, ('homeAway', {str.title}))
medium = traverse_obj(broadcast, ('type', {str}))
language = traverse_obj(broadcast, ('language', {str.lower}))
format_id = join_nonempty(feed, medium, language)
response = self._call_api({
'operationName': 'initPlaybackSession',
'query': self._GRAPHQL_PLAYBACK_QUERY,
'variables': {
'adCapabilities': ['GOOGLE_STANDALONE_AD_PODS'],
'deviceId': self._device_id,
'mediaId': broadcast['mediaId'],
'quality': 'PLACEHOLDER',
'sessionId': self._session_id,
},
}, video_id, f'{format_id} broadcast JSON', fatal=False)
playback = traverse_obj(response, ('data', 'initPlaybackSession', 'playback', {dict}))
m3u8_url = traverse_obj(playback, ('url', {url_or_none}))
token = traverse_obj(playback, ('token', {str}))
if not (m3u8_url and token):
errors = '; '.join(traverse_obj(response, ('errors', ..., 'message', {str})))
if 'not entitled' in errors:
raise ExtractorError(errors, expected=True)
elif errors: # Only warn when 'blacked out' since radio formats are available
self.report_warning(f'API returned errors for {format_id}: {errors}')
else:
self.report_warning(f'No formats available for {format_id} broadcast; skipping')
return [], {}
cdn_headers = {'x-cdn-token': token}
fmts, subs = self._extract_m3u8_formats_and_subtitles(
m3u8_url.replace(f'/{token}/', '/'), video_id, 'mp4',
m3u8_id=format_id, fatal=False, headers=cdn_headers)
for fmt in fmts:
fmt['http_headers'] = cdn_headers
fmt.setdefault('format_note', join_nonempty(feed, medium, delim=' '))
fmt.setdefault('language', language)
if fmt.get('vcodec') == 'none' and fmt['language'] == 'en':
fmt['source_preference'] = 10
return fmts, subs
def _real_extract(self, url):
video_id = self._match_id(url)
airings = self._download_json(
f'https://search-api-mlbtv.mlb.com/svc/search/v2/graphql/persisted/query/core/Airings?variables=%7B%22partnerProgramIds%22%3A%5B%22{video_id}%22%5D%2C%22applyEsniMediaRightsLabels%22%3Atrue%7D',
video_id)['data']['Airings']
metadata = traverse_obj(self._download_json(
'https://statsapi.mlb.com/api/v1/schedule', video_id, query={
'gamePk': video_id,
'hydrate': 'broadcasts(all),statusFlags',
}), ('dates', ..., 'games', lambda _, v: str(v['gamePk']) == video_id and v['broadcasts'], any))
broadcasts = traverse_obj(metadata, (
'broadcasts', lambda _, v: v['mediaId'] and v['mediaState']['mediaStateCode'] != 'MEDIA_OFF'))
formats, subtitles = [], {}
for airing in traverse_obj(airings, lambda _, v: v['playbackUrls'][0]['href']):
format_id = join_nonempty('feedType', 'feedLanguage', from_dict=airing)
m3u8_url = traverse_obj(self._download_json(
airing['playbackUrls'][0]['href'].format(scenario='browser~csai'), video_id,
note=f'Downloading {format_id} stream info JSON',
errnote=f'Failed to download {format_id} stream info, skipping',
fatal=False, headers={
'Authorization': self._access_token,
'Accept': 'application/vnd.media-service+json; version=2',
}), ('stream', 'complete', {url_or_none}))
if not m3u8_url:
continue
f, s = self._extract_m3u8_formats_and_subtitles(
m3u8_url, video_id, 'mp4', m3u8_id=format_id, fatal=False)
formats.extend(f)
self._merge_subtitles(s, target=subtitles)
for broadcast in broadcasts:
fmts, subs = self._extract_formats_and_subtitles(broadcast, video_id)
formats.extend(fmts)
self._merge_subtitles(subs, target=subtitles)
return {
'id': video_id,
'title': traverse_obj(airings, (..., 'titles', 0, 'episodeName'), get_all=False),
'is_live': traverse_obj(airings, (..., 'mediaConfig', 'productType'), get_all=False) == 'LIVE',
'title': join_nonempty(
traverse_obj(metadata, ('officialDate', {str})),
traverse_obj(metadata, ('teams', ('away', 'home'), 'team', 'name', {str}, all, {' @ '.join})),
delim=' - '),
'is_live': traverse_obj(broadcasts, (..., 'mediaState', 'mediaStateCode', {str}, any)) == 'MEDIA_ON',
'release_timestamp': traverse_obj(metadata, ('gameDate', {parse_iso8601})),
'formats': formats,
'subtitles': subtitles,
'http_headers': {'Authorization': f'Bearer {self._access_token}'},
}
+3 -3
View File
@@ -1,8 +1,8 @@
# Autogenerated by devscripts/update-version.py
__version__ = '2024.07.16'
__version__ = '2024.07.25'
RELEASE_GIT_HEAD = '89a161e8c62569a662deda1c948664152efcb6b4'
RELEASE_GIT_HEAD = 'f0993391e6052ec8f7aacc286609564f226943b9'
VARIANT = None
@@ -12,4 +12,4 @@ CHANNEL = 'stable'
ORIGIN = 'yt-dlp/yt-dlp'
_pkg_version = '2024.07.16'
_pkg_version = '2024.07.25'