mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-05-15 18:35:47 +00:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f14875aa3f | |||
| 6391dceb62 | |||
| 29806b899a | |||
| d63a3c01e4 | |||
| b6fb7ac962 | |||
| 1d22fdc972 | |||
| d135dd5a6f | |||
| 7cae63cb17 | |||
| 232165eff3 | |||
| 2bc4dd8c53 | |||
| cca105e91d | |||
| 3e52490d1b | |||
| d1293276ce | |||
| 4a5e426730 | |||
| fdc2755291 | |||
| b4fbcd8d80 | |||
| 2415cb211e | |||
| 5e51784803 | |||
| 5f0d71b0fe | |||
| 71d41f0a70 |
@@ -0,0 +1,35 @@
|
||||
FROM alpine:latest AS builder
|
||||
|
||||
ARG TARGETPLATFORM
|
||||
|
||||
COPY . /tmp/artifacts
|
||||
RUN mkdir -p /tmp/output; \
|
||||
cd /tmp/artifacts; \
|
||||
ARTIFACT_ARCH=""; \
|
||||
if [ "$TARGETPLATFORM" = "linux/amd64" ]; then \
|
||||
ARTIFACT_ARCH="x86_64"; \
|
||||
elif [ "$TARGETPLATFORM" = "linux/arm64" ]; then \
|
||||
ARTIFACT_ARCH="aarch64"; \
|
||||
else \
|
||||
echo "Unsupported architecture: $TARGETARCH"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
cp /tmp/artifacts/easytier-linux-${ARTIFACT_ARCH}/* /tmp/output;
|
||||
|
||||
FROM alpine:latest
|
||||
|
||||
WORKDIR /app
|
||||
COPY --from=builder --chmod=755 /tmp/output/* /usr/local/bin
|
||||
|
||||
# tcp
|
||||
EXPOSE 11010/tcp
|
||||
# udp
|
||||
EXPOSE 11010/udp
|
||||
# wg
|
||||
EXPOSE 11011/udp
|
||||
# ws
|
||||
EXPOSE 11011/tcp
|
||||
# wss
|
||||
EXPOSE 11012/tcp
|
||||
|
||||
ENTRYPOINT ["easytier-core"]
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
# All of these options are optional, so you can remove them if you are happy with the defaults
|
||||
concurrent_skipping: 'never'
|
||||
skip_after_successful_duplicate: 'true'
|
||||
paths: '["Cargo.toml", "Cargo.lock", "easytier/**", ".github/workflows/core.yml"]'
|
||||
paths: '["Cargo.toml", "Cargo.lock", "easytier/**", ".github/workflows/core.yml", ".github/workflows/install_rust.sh"]'
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
name: EasyTier Docker
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
run_id:
|
||||
description: 'The run id of EasyTier-Core Action in EasyTier repo'
|
||||
type: number
|
||||
default: 10228239965
|
||||
required: true
|
||||
image_tag:
|
||||
description: 'Tag for this image build'
|
||||
type: string
|
||||
default: 'v1.2.0'
|
||||
required: true
|
||||
mark_latest:
|
||||
description: 'Mark this image as latest'
|
||||
type: boolean
|
||||
default: false
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
if: contains('["KKRainbow"]', github.actor)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Download artifact
|
||||
id: download-artifact
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
with:
|
||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||
run_id: ${{ inputs.run_id }}
|
||||
repo: EasyTier/EasyTier
|
||||
path: docker_context
|
||||
- name: List files
|
||||
run: |
|
||||
ls -l -R .
|
||||
-
|
||||
name: Build and push
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: ./docker_context
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
file: .github/workflows/Dockerfile
|
||||
tags: easytier/easytier:${{ inputs.image_tag }}${{ inputs.mark_latest && ',easytier/easytier:latest' || '' }},
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
# All of these options are optional, so you can remove them if you are happy with the defaults
|
||||
concurrent_skipping: 'never'
|
||||
skip_after_successful_duplicate: 'true'
|
||||
paths: '["Cargo.toml", "Cargo.lock", "easytier/**", "easytier-gui/**", ".github/workflows/gui.yml"]'
|
||||
paths: '["Cargo.toml", "Cargo.lock", "easytier/**", "easytier-gui/**", ".github/workflows/gui.yml", ".github/workflows/install_rust.sh"]'
|
||||
build-gui:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
@@ -57,8 +57,8 @@ fi
|
||||
|
||||
# see https://github.com/rust-lang/rustup/issues/3709
|
||||
rustup set auto-self-update disable
|
||||
rustup install 1.79
|
||||
rustup default 1.79
|
||||
rustup install 1.77
|
||||
rustup default 1.77
|
||||
|
||||
# mips/mipsel cannot add target from rustup, need compile by ourselves
|
||||
if [[ $OS =~ ^ubuntu.*$ && $TARGET =~ ^mips.*$ ]]; then
|
||||
@@ -72,7 +72,13 @@ if [[ $OS =~ ^ubuntu.*$ && $TARGET =~ ^mips.*$ ]]; then
|
||||
|
||||
rustup toolchain install nightly-x86_64-unknown-linux-gnu
|
||||
rustup component add rust-src --toolchain nightly-x86_64-unknown-linux-gnu
|
||||
cd -
|
||||
|
||||
# https://github.com/rust-lang/rust/issues/128808
|
||||
# remove it after Cargo or rustc fix this.
|
||||
RUST_LIB_SRC=$HOME/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/
|
||||
if [[ -f $RUST_LIB_SRC/library/Cargo.lock && ! -f $RUST_LIB_SRC/Cargo.lock ]]; then
|
||||
cp -f $RUST_LIB_SRC/library/Cargo.lock $RUST_LIB_SRC/Cargo.lock
|
||||
fi
|
||||
else
|
||||
rustup target add $TARGET
|
||||
if [[ $GUI_TARGET != '' ]]; then
|
||||
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
# All of these options are optional, so you can remove them if you are happy with the defaults
|
||||
concurrent_skipping: 'never'
|
||||
skip_after_successful_duplicate: 'true'
|
||||
paths: '["Cargo.toml", "Cargo.lock", "easytier/**", "easytier-gui/**", "tauri-plugin-vpnservice/**", ".github/workflows/mobile.yml"]'
|
||||
paths: '["Cargo.toml", "Cargo.lock", "easytier/**", "easytier-gui/**", "tauri-plugin-vpnservice/**", ".github/workflows/mobile.yml", ".github/workflows/install_rust.sh"]'
|
||||
build-mobile:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
name: EasyTier Release
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
core_run_id:
|
||||
description: 'The run id of EasyTier-Core Action in EasyTier repo'
|
||||
type: number
|
||||
default: 10322498549
|
||||
required: true
|
||||
gui_run_id:
|
||||
description: 'The run id of EasyTier-GUI Action in EasyTier repo'
|
||||
type: number
|
||||
default: 10322498557
|
||||
required: true
|
||||
mobile_run_id:
|
||||
description: 'The run id of EasyTier-Mobile Action in EasyTier repo'
|
||||
type: number
|
||||
default: 10322498555
|
||||
required: true
|
||||
version:
|
||||
description: 'version for this release'
|
||||
type: string
|
||||
default: 'v1.2.2'
|
||||
required: true
|
||||
make_latest:
|
||||
description: 'Mark this release as latest'
|
||||
type: boolean
|
||||
default: true
|
||||
required: true
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
release:
|
||||
if: contains('["KKRainbow"]', github.actor)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Download Core Artifact
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
with:
|
||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||
run_id: ${{ inputs.core_run_id }}
|
||||
repo: EasyTier/EasyTier
|
||||
path: release_assets
|
||||
|
||||
- name: Download GUI Artifact
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
with:
|
||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||
run_id: ${{ inputs.gui_run_id }}
|
||||
repo: EasyTier/EasyTier
|
||||
path: release_assets
|
||||
|
||||
- name: Download GUI Artifact
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
with:
|
||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||
run_id: ${{ inputs.mobile_run_id }}
|
||||
repo: EasyTier/EasyTier
|
||||
path: release_assets
|
||||
|
||||
- name: Zip release assets
|
||||
env:
|
||||
VERSION: ${{ inputs.version }}
|
||||
run: |
|
||||
cd release_assets
|
||||
ls -l -R ./
|
||||
chmod -R 755 .
|
||||
|
||||
mkdir ../zipped_assets
|
||||
for x in `ls`; do
|
||||
zip ../zipped_assets/$x-${VERSION}.zip $x/*;
|
||||
done
|
||||
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
name: ${{ inputs.version }}
|
||||
draft: true
|
||||
files: |
|
||||
./zipped_assets/*
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
tag_name: ${{ inputs.version }}
|
||||
Generated
+694
-526
File diff suppressed because it is too large
Load Diff
@@ -48,7 +48,18 @@
|
||||
```sh
|
||||
cargo install --git https://github.com/EasyTier/EasyTier.git
|
||||
```
|
||||
|
||||
|
||||
4. **Install by Docker Compose**
|
||||
|
||||
Please visit the [EasyTier Official Website](https://www.easytier.top/en/) to view the full documentation.
|
||||
|
||||
5. **Install by script (For Linux Only)**
|
||||
```sh
|
||||
wget -O /tmp/easytier.sh "https://raw.githubusercontent.com/EasyTier/EasyTier/main/script/easytier.sh" && bash /tmp/easytier.sh install
|
||||
```
|
||||
|
||||
You can also uninstall/update Easytier by the command "uninstall" or "update" of this script
|
||||
|
||||
## Quick Start
|
||||
|
||||
> The following text only describes the use of the command-line tool; the GUI program can be configured by referring to the following concepts.
|
||||
|
||||
@@ -49,6 +49,18 @@
|
||||
cargo install --git https://github.com/EasyTier/EasyTier.git
|
||||
```
|
||||
|
||||
4. **通过Docker Compose安装**
|
||||
|
||||
请访问 [EasyTier 官网](https://www.easytier.top/) 以查看完整的文档。
|
||||
|
||||
|
||||
5. **使用一键脚本安装 (仅适用于 Linux)**
|
||||
```sh
|
||||
wget -O /tmp/easytier.sh "https://raw.githubusercontent.com/EasyTier/EasyTier/main/script/easytier.sh" && bash /tmp/easytier.sh install
|
||||
```
|
||||
|
||||
使用本脚本安装的 Easytier 可以使用脚本的 uninstall/update 对其卸载/升级
|
||||
|
||||
## 快速开始
|
||||
|
||||
> 下文仅描述命令行工具的使用,图形界面程序可参考下述概念自行配置。
|
||||
|
||||
+31
-29
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "easytier-gui",
|
||||
"type": "module",
|
||||
"version": "1.2.0",
|
||||
"version": "1.2.2",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
@@ -12,47 +12,49 @@
|
||||
"lint:fix": "eslint . --ignore-pattern src-tauri --fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"@primevue/themes": "^4.0.0",
|
||||
"@tauri-apps/plugin-clipboard-manager": "2.1.0-beta.4",
|
||||
"@tauri-apps/plugin-os": "2.0.0-beta.6",
|
||||
"@tauri-apps/plugin-process": "2.0.0-beta.6",
|
||||
"@tauri-apps/plugin-shell": "2.0.0-beta.7",
|
||||
"@primevue/themes": "^4.0.4",
|
||||
"@tauri-apps/plugin-clipboard-manager": "2.0.0-rc.0",
|
||||
"@tauri-apps/plugin-os": "2.0.0-rc.0",
|
||||
"@tauri-apps/plugin-process": "2.0.0-rc.0",
|
||||
"@tauri-apps/plugin-shell": "2.0.0-rc.0",
|
||||
"aura": "link:@primevue/themes/aura",
|
||||
"pinia": "^2.1.7",
|
||||
"pinia": "^2.2.1",
|
||||
"primeflex": "^3.3.1",
|
||||
"primeicons": "^7.0.0",
|
||||
"primevue": "^4.0.0",
|
||||
"tauri-plugin-vpnservice-api": "link:../tauri-plugin-vpnservice/",
|
||||
"vue": "^3.4.31",
|
||||
"primevue": "^4.0.4",
|
||||
"tauri-plugin-vpnservice-api": "link:../tauri-plugin-vpnservice",
|
||||
"vue": "^3.4.36",
|
||||
"vue-i18n": "^9.13.1",
|
||||
"vue-router": "^4.4.0"
|
||||
"vue-router": "^4.4.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@antfu/eslint-config": "^2.21.3",
|
||||
"@antfu/eslint-config": "^2.24.1",
|
||||
"@intlify/unplugin-vue-i18n": "^4.0.0",
|
||||
"@primevue/auto-import-resolver": "^4.0.0",
|
||||
"@tauri-apps/api": "2.0.0-beta.14",
|
||||
"@tauri-apps/cli": "2.0.0-beta.21",
|
||||
"@types/node": "^20.14.10",
|
||||
"@primevue/auto-import-resolver": "^4.0.4",
|
||||
"@sveltejs/vite-plugin-svelte": "^3.1.1",
|
||||
"@tauri-apps/api": "2.0.0-rc.0",
|
||||
"@tauri-apps/cli": "2.0.0-rc.1",
|
||||
"@types/node": "^20.14.14",
|
||||
"@types/uuid": "^9.0.8",
|
||||
"@vitejs/plugin-vue": "^5.0.5",
|
||||
"@vitejs/plugin-vue": "^5.1.2",
|
||||
"@vue-macros/volar": "^0.19.1",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"eslint": "^9.6.0",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"eslint": "^9.8.0",
|
||||
"eslint-plugin-format": "^0.1.2",
|
||||
"postcss": "^8.4.39",
|
||||
"tailwindcss": "^3.4.4",
|
||||
"typescript": "^5.5.3",
|
||||
"unplugin-auto-import": "^0.17.6",
|
||||
"unplugin-vue-components": "^0.27.2",
|
||||
"unplugin-vue-macros": "^2.9.5",
|
||||
"internal-ip": "^8.0.0",
|
||||
"postcss": "^8.4.41",
|
||||
"tailwindcss": "^3.4.7",
|
||||
"typescript": "^5.5.4",
|
||||
"unplugin-auto-import": "^0.17.8",
|
||||
"unplugin-vue-components": "^0.27.3",
|
||||
"unplugin-vue-macros": "^2.11.4",
|
||||
"unplugin-vue-markdown": "^0.26.2",
|
||||
"unplugin-vue-router": "^0.8.8",
|
||||
"uuid": "^9.0.1",
|
||||
"vite": "^5.3.3",
|
||||
"vite-plugin-vue-devtools": "^7.3.5",
|
||||
"vite": "^5.3.5",
|
||||
"vite-plugin-vue-devtools": "^7.3.7",
|
||||
"vite-plugin-vue-layouts": "^0.11.0",
|
||||
"vue-i18n": "^9.13.1",
|
||||
"vue-tsc": "^2.0.26"
|
||||
"vue-tsc": "^2.0.29"
|
||||
}
|
||||
}
|
||||
}
|
||||
Generated
+2107
-1314
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "easytier-gui"
|
||||
version = "1.2.0"
|
||||
version = "1.2.2"
|
||||
description = "EasyTier GUI"
|
||||
authors = ["you"]
|
||||
edition = "2021"
|
||||
@@ -12,10 +12,14 @@ name = "app_lib"
|
||||
crate-type = ["staticlib", "cdylib", "rlib"]
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "2.0.0-beta", features = [] }
|
||||
tauri-build = { version = "2.0.0-rc", features = [] }
|
||||
|
||||
[dependencies]
|
||||
tauri = { version = "2.0.0-beta", features = [ "tray-icon", "image-png", "image-ico"] }
|
||||
tauri = { version = "2.0.0-rc", features = [
|
||||
"tray-icon",
|
||||
"image-png",
|
||||
"image-ico",
|
||||
] }
|
||||
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
@@ -26,20 +30,20 @@ anyhow = "1.0"
|
||||
chrono = { version = "0.4.37", features = ["serde"] }
|
||||
|
||||
once_cell = "1.18.0"
|
||||
dashmap = "5.5.3"
|
||||
dashmap = "6.0"
|
||||
|
||||
privilege = "0.3"
|
||||
gethostname = "0.4.3"
|
||||
gethostname = "0.5"
|
||||
|
||||
auto-launch = "0.5.0"
|
||||
dunce = "1.0.4"
|
||||
|
||||
tauri-plugin-shell = "2.0.0-beta.8"
|
||||
tauri-plugin-process = "2.0.0-beta.7"
|
||||
tauri-plugin-clipboard-manager = "2.1.0-beta.5"
|
||||
tauri-plugin-positioner = { version = "2.0.0-beta", features = ["tray-icon"] }
|
||||
tauri-plugin-shell = "2.0.0-rc"
|
||||
tauri-plugin-process = "2.0.0-rc"
|
||||
tauri-plugin-clipboard-manager = "2.0.0-rc"
|
||||
tauri-plugin-positioner = { version = "2.0.0-rc", features = ["tray-icon"] }
|
||||
tauri-plugin-vpnservice = { path = "../../tauri-plugin-vpnservice" }
|
||||
tauri-plugin-os = "2.0.0-beta.7"
|
||||
tauri-plugin-os = "2.0.0-rc"
|
||||
|
||||
|
||||
[features]
|
||||
|
||||
@@ -6,17 +6,17 @@
|
||||
"main"
|
||||
],
|
||||
"permissions": [
|
||||
"path:default",
|
||||
"event:default",
|
||||
"window:default",
|
||||
"window:allow-is-visible",
|
||||
"window:allow-show",
|
||||
"window:allow-hide",
|
||||
"window:allow-set-focus",
|
||||
"app:default",
|
||||
"resources:default",
|
||||
"menu:default",
|
||||
"tray:default",
|
||||
"core:path:default",
|
||||
"core:event:default",
|
||||
"core:window:default",
|
||||
"core:window:allow-is-visible",
|
||||
"core:window:allow-show",
|
||||
"core:window:allow-hide",
|
||||
"core:window:allow-set-focus",
|
||||
"core:app:default",
|
||||
"core:resources:default",
|
||||
"core:menu:default",
|
||||
"core:tray:default",
|
||||
"shell:allow-open",
|
||||
"process:allow-exit",
|
||||
"clipboard-manager:allow-read-text",
|
||||
@@ -24,16 +24,16 @@
|
||||
"shell:default",
|
||||
"process:default",
|
||||
"clipboard-manager:default",
|
||||
"tray:default",
|
||||
"tray:allow-new",
|
||||
"tray:allow-set-menu",
|
||||
"tray:allow-set-title",
|
||||
"tray:allow-remove-by-id",
|
||||
"tray:allow-get-by-id",
|
||||
"tray:allow-set-icon",
|
||||
"tray:allow-set-icon-as-template",
|
||||
"tray:allow-set-show-menu-on-left-click",
|
||||
"tray:allow-set-tooltip",
|
||||
"core:tray:default",
|
||||
"core:tray:allow-new",
|
||||
"core:tray:allow-set-menu",
|
||||
"core:tray:allow-set-title",
|
||||
"core:tray:allow-remove-by-id",
|
||||
"core:tray:allow-get-by-id",
|
||||
"core:tray:allow-set-icon",
|
||||
"core:tray:allow-set-icon-as-template",
|
||||
"core:tray:allow-set-show-menu-on-left-click",
|
||||
"core:tray:allow-set-tooltip",
|
||||
"vpnservice:allow-ping",
|
||||
"vpnservice:allow-prepare-vpn",
|
||||
"vpnservice:allow-start-vpn",
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"createUpdaterArtifacts": false
|
||||
},
|
||||
"productName": "easytier-gui",
|
||||
"version": "1.2.0",
|
||||
"version": "1.2.2",
|
||||
"identifier": "com.kkrainbow.easytier",
|
||||
"plugins": {},
|
||||
"app": {
|
||||
|
||||
Vendored
-95
@@ -201,98 +201,3 @@ declare module 'vue' {
|
||||
readonly watchSyncEffect: UnwrapRef<typeof import('vue')['watchSyncEffect']>
|
||||
}
|
||||
}
|
||||
declare module '@vue/runtime-core' {
|
||||
interface GlobalComponents {}
|
||||
interface ComponentCustomProperties {
|
||||
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
|
||||
readonly MenuItemExit: UnwrapRef<typeof import('./composables/tray')['MenuItemExit']>
|
||||
readonly MenuItemShow: UnwrapRef<typeof import('./composables/tray')['MenuItemShow']>
|
||||
readonly acceptHMRUpdate: UnwrapRef<typeof import('pinia')['acceptHMRUpdate']>
|
||||
readonly collectNetworkInfos: UnwrapRef<typeof import('./composables/network')['collectNetworkInfos']>
|
||||
readonly computed: UnwrapRef<typeof import('vue')['computed']>
|
||||
readonly createApp: UnwrapRef<typeof import('vue')['createApp']>
|
||||
readonly createPinia: UnwrapRef<typeof import('pinia')['createPinia']>
|
||||
readonly customRef: UnwrapRef<typeof import('vue')['customRef']>
|
||||
readonly defineAsyncComponent: UnwrapRef<typeof import('vue')['defineAsyncComponent']>
|
||||
readonly defineComponent: UnwrapRef<typeof import('vue')['defineComponent']>
|
||||
readonly definePage: UnwrapRef<typeof import('unplugin-vue-router/runtime')['definePage']>
|
||||
readonly defineStore: UnwrapRef<typeof import('pinia')['defineStore']>
|
||||
readonly effectScope: UnwrapRef<typeof import('vue')['effectScope']>
|
||||
readonly generateMenuItem: UnwrapRef<typeof import('./composables/tray')['generateMenuItem']>
|
||||
readonly getActivePinia: UnwrapRef<typeof import('pinia')['getActivePinia']>
|
||||
readonly getCurrentInstance: UnwrapRef<typeof import('vue')['getCurrentInstance']>
|
||||
readonly getCurrentScope: UnwrapRef<typeof import('vue')['getCurrentScope']>
|
||||
readonly getOsHostname: UnwrapRef<typeof import('./composables/network')['getOsHostname']>
|
||||
readonly h: UnwrapRef<typeof import('vue')['h']>
|
||||
readonly initMobileVpnService: UnwrapRef<typeof import('./composables/mobile_vpn')['initMobileVpnService']>
|
||||
readonly inject: UnwrapRef<typeof import('vue')['inject']>
|
||||
readonly isProxy: UnwrapRef<typeof import('vue')['isProxy']>
|
||||
readonly isReactive: UnwrapRef<typeof import('vue')['isReactive']>
|
||||
readonly isReadonly: UnwrapRef<typeof import('vue')['isReadonly']>
|
||||
readonly isRef: UnwrapRef<typeof import('vue')['isRef']>
|
||||
readonly loadRunningInstanceIdsFromLocalStorage: UnwrapRef<typeof import('./stores/network')['loadRunningInstanceIdsFromLocalStorage']>
|
||||
readonly mapActions: UnwrapRef<typeof import('pinia')['mapActions']>
|
||||
readonly mapGetters: UnwrapRef<typeof import('pinia')['mapGetters']>
|
||||
readonly mapState: UnwrapRef<typeof import('pinia')['mapState']>
|
||||
readonly mapStores: UnwrapRef<typeof import('pinia')['mapStores']>
|
||||
readonly mapWritableState: UnwrapRef<typeof import('pinia')['mapWritableState']>
|
||||
readonly markRaw: UnwrapRef<typeof import('vue')['markRaw']>
|
||||
readonly nextTick: UnwrapRef<typeof import('vue')['nextTick']>
|
||||
readonly onActivated: UnwrapRef<typeof import('vue')['onActivated']>
|
||||
readonly onBeforeMount: UnwrapRef<typeof import('vue')['onBeforeMount']>
|
||||
readonly onBeforeRouteLeave: UnwrapRef<typeof import('vue-router/auto')['onBeforeRouteLeave']>
|
||||
readonly onBeforeRouteUpdate: UnwrapRef<typeof import('vue-router/auto')['onBeforeRouteUpdate']>
|
||||
readonly onBeforeUnmount: UnwrapRef<typeof import('vue')['onBeforeUnmount']>
|
||||
readonly onBeforeUpdate: UnwrapRef<typeof import('vue')['onBeforeUpdate']>
|
||||
readonly onDeactivated: UnwrapRef<typeof import('vue')['onDeactivated']>
|
||||
readonly onErrorCaptured: UnwrapRef<typeof import('vue')['onErrorCaptured']>
|
||||
readonly onMounted: UnwrapRef<typeof import('vue')['onMounted']>
|
||||
readonly onRenderTracked: UnwrapRef<typeof import('vue')['onRenderTracked']>
|
||||
readonly onRenderTriggered: UnwrapRef<typeof import('vue')['onRenderTriggered']>
|
||||
readonly onScopeDispose: UnwrapRef<typeof import('vue')['onScopeDispose']>
|
||||
readonly onServerPrefetch: UnwrapRef<typeof import('vue')['onServerPrefetch']>
|
||||
readonly onUnmounted: UnwrapRef<typeof import('vue')['onUnmounted']>
|
||||
readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']>
|
||||
readonly parseNetworkConfig: UnwrapRef<typeof import('./composables/network')['parseNetworkConfig']>
|
||||
readonly prepareVpnService: UnwrapRef<typeof import('./composables/mobile_vpn')['prepareVpnService']>
|
||||
readonly provide: UnwrapRef<typeof import('vue')['provide']>
|
||||
readonly reactive: UnwrapRef<typeof import('vue')['reactive']>
|
||||
readonly readonly: UnwrapRef<typeof import('vue')['readonly']>
|
||||
readonly ref: UnwrapRef<typeof import('vue')['ref']>
|
||||
readonly resolveComponent: UnwrapRef<typeof import('vue')['resolveComponent']>
|
||||
readonly retainNetworkInstance: UnwrapRef<typeof import('./composables/network')['retainNetworkInstance']>
|
||||
readonly runNetworkInstance: UnwrapRef<typeof import('./composables/network')['runNetworkInstance']>
|
||||
readonly setActivePinia: UnwrapRef<typeof import('pinia')['setActivePinia']>
|
||||
readonly setAutoLaunchStatus: UnwrapRef<typeof import('./composables/network')['setAutoLaunchStatus']>
|
||||
readonly setLoggingLevel: UnwrapRef<typeof import('./composables/network')['setLoggingLevel']>
|
||||
readonly setMapStoreSuffix: UnwrapRef<typeof import('pinia')['setMapStoreSuffix']>
|
||||
readonly setTrayMenu: UnwrapRef<typeof import('./composables/tray')['setTrayMenu']>
|
||||
readonly setTrayRunState: UnwrapRef<typeof import('./composables/tray')['setTrayRunState']>
|
||||
readonly setTrayTooltip: UnwrapRef<typeof import('./composables/tray')['setTrayTooltip']>
|
||||
readonly setTunFd: UnwrapRef<typeof import('./composables/network')['setTunFd']>
|
||||
readonly shallowReactive: UnwrapRef<typeof import('vue')['shallowReactive']>
|
||||
readonly shallowReadonly: UnwrapRef<typeof import('vue')['shallowReadonly']>
|
||||
readonly shallowRef: UnwrapRef<typeof import('vue')['shallowRef']>
|
||||
readonly storeToRefs: UnwrapRef<typeof import('pinia')['storeToRefs']>
|
||||
readonly toRaw: UnwrapRef<typeof import('vue')['toRaw']>
|
||||
readonly toRef: UnwrapRef<typeof import('vue')['toRef']>
|
||||
readonly toRefs: UnwrapRef<typeof import('vue')['toRefs']>
|
||||
readonly toValue: UnwrapRef<typeof import('vue')['toValue']>
|
||||
readonly triggerRef: UnwrapRef<typeof import('vue')['triggerRef']>
|
||||
readonly unref: UnwrapRef<typeof import('vue')['unref']>
|
||||
readonly useAttrs: UnwrapRef<typeof import('vue')['useAttrs']>
|
||||
readonly useCssModule: UnwrapRef<typeof import('vue')['useCssModule']>
|
||||
readonly useCssVars: UnwrapRef<typeof import('vue')['useCssVars']>
|
||||
readonly useI18n: UnwrapRef<typeof import('vue-i18n')['useI18n']>
|
||||
readonly useLink: UnwrapRef<typeof import('vue-router/auto')['useLink']>
|
||||
readonly useNetworkStore: UnwrapRef<typeof import('./stores/network')['useNetworkStore']>
|
||||
readonly useRoute: UnwrapRef<typeof import('vue-router/auto')['useRoute']>
|
||||
readonly useRouter: UnwrapRef<typeof import('vue-router/auto')['useRouter']>
|
||||
readonly useSlots: UnwrapRef<typeof import('vue')['useSlots']>
|
||||
readonly useTray: UnwrapRef<typeof import('./composables/tray')['useTray']>
|
||||
readonly watch: UnwrapRef<typeof import('vue')['watch']>
|
||||
readonly watchEffect: UnwrapRef<typeof import('vue')['watchEffect']>
|
||||
readonly watchPostEffect: UnwrapRef<typeof import('vue')['watchPostEffect']>
|
||||
readonly watchSyncEffect: UnwrapRef<typeof import('vue')['watchSyncEffect']>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,14 +159,11 @@ async function watchNetworkInstance() {
|
||||
if (subscribe_running) {
|
||||
return
|
||||
}
|
||||
console.log('network instance change')
|
||||
|
||||
subscribe_running = true
|
||||
try {
|
||||
await onNetworkInstanceChange()
|
||||
} catch (_) {
|
||||
}
|
||||
console.log('network instance change done')
|
||||
subscribe_running = false
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getCurrent } from '@tauri-apps/api/window'
|
||||
import { getCurrentWindow } from '@tauri-apps/api/window'
|
||||
import { Menu, MenuItem, PredefinedMenuItem } from '@tauri-apps/api/menu'
|
||||
import { TrayIcon } from '@tauri-apps/api/tray'
|
||||
import pkg from '~/../package.json'
|
||||
@@ -6,11 +6,11 @@ import pkg from '~/../package.json'
|
||||
const DEFAULT_TRAY_NAME = 'main'
|
||||
|
||||
async function toggleVisibility() {
|
||||
if (await getCurrent().isVisible()) {
|
||||
await getCurrent().hide()
|
||||
if (await getCurrentWindow().isVisible()) {
|
||||
await getCurrentWindow().hide()
|
||||
} else {
|
||||
await getCurrent().show()
|
||||
await getCurrent().setFocus()
|
||||
await getCurrentWindow().show()
|
||||
await getCurrentWindow().setFocus()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ export async function generateMenuItem() {
|
||||
await MenuItemExit('Exit'),
|
||||
await PredefinedMenuItem.new({ item: 'Separator' }),
|
||||
await MenuItemShow('Show / Hide'),
|
||||
] || []
|
||||
]
|
||||
}
|
||||
|
||||
export async function MenuItemExit(text: string) {
|
||||
|
||||
@@ -10,6 +10,10 @@ import VueDevTools from 'vite-plugin-vue-devtools'
|
||||
import VueRouter from 'unplugin-vue-router/vite'
|
||||
import { VueRouterAutoImports } from 'unplugin-vue-router'
|
||||
import { PrimeVueResolver } from '@primevue/auto-import-resolver';
|
||||
import { svelte } from '@sveltejs/vite-plugin-svelte';
|
||||
import { internalIpV4Sync } from 'internal-ip';
|
||||
|
||||
const host = process.env.TAURI_DEV_HOST;
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig(async () => ({
|
||||
@@ -19,6 +23,7 @@ export default defineConfig(async () => ({
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
svelte(),
|
||||
VueMacros({
|
||||
plugins: {
|
||||
vue: Vue({
|
||||
@@ -87,15 +92,18 @@ export default defineConfig(async () => ({
|
||||
// 2. tauri expects a fixed port, fail if that port is not available
|
||||
server: {
|
||||
port: 1420,
|
||||
host: '10.147.223.128',
|
||||
host: host || false,
|
||||
strictPort: true,
|
||||
watch: {
|
||||
// 3. tell vite to ignore watching `src-tauri`
|
||||
ignored: ['**/src-tauri/**'],
|
||||
},
|
||||
hmr: {
|
||||
host: "10.147.223.128",
|
||||
protocol: "ws",
|
||||
},
|
||||
hmr: host
|
||||
? {
|
||||
protocol: 'ws',
|
||||
host: internalIpV4Sync(),
|
||||
port: 1430,
|
||||
}
|
||||
: undefined,
|
||||
},
|
||||
}))
|
||||
|
||||
+27
-16
@@ -3,7 +3,7 @@ name = "easytier"
|
||||
description = "A full meshed p2p VPN, connecting all your devices in one network with one command."
|
||||
homepage = "https://github.com/EasyTier/EasyTier"
|
||||
repository = "https://github.com/EasyTier/EasyTier"
|
||||
version = "1.2.0"
|
||||
version = "1.2.2"
|
||||
edition = "2021"
|
||||
authors = ["kkrainbow"]
|
||||
keywords = ["vpn", "p2p", "network", "easytier"]
|
||||
@@ -43,7 +43,7 @@ time = "0.3"
|
||||
toml = "0.8.12"
|
||||
chrono = { version = "0.4.37", features = ["serde"] }
|
||||
|
||||
gethostname = "0.4.3"
|
||||
gethostname = "0.5.0"
|
||||
|
||||
futures = { version = "0.3", features = ["bilock", "unstable"] }
|
||||
|
||||
@@ -54,7 +54,7 @@ tokio-util = { version = "0.7.9", features = ["codec", "net"] }
|
||||
async-stream = "0.3.5"
|
||||
async-trait = "0.1.74"
|
||||
|
||||
dashmap = "5.5.3"
|
||||
dashmap = "6.0"
|
||||
timedmap = "=1.0.1"
|
||||
|
||||
# for full-path zero-copy
|
||||
@@ -62,7 +62,7 @@ zerocopy = { version = "0.7.32", features = ["derive", "simd"] }
|
||||
bytes = "1.5.0"
|
||||
pin-project-lite = "0.2.13"
|
||||
atomicbox = "0.4.0"
|
||||
tachyonix = "0.2.1"
|
||||
tachyonix = "0.3.0"
|
||||
|
||||
quinn = { version = "0.11.0", optional = true, features = ["ring"] }
|
||||
rustls = { version = "0.23.0", features = [
|
||||
@@ -71,7 +71,7 @@ rustls = { version = "0.23.0", features = [
|
||||
rcgen = { version = "0.11.1", optional = true }
|
||||
|
||||
# for websocket
|
||||
tokio-websockets = { version = "0.8.2", optional = true, features = [
|
||||
tokio-websockets = { version = "0.8", optional = true, features = [
|
||||
"rustls-webpki-roots",
|
||||
"client",
|
||||
"server",
|
||||
@@ -84,7 +84,7 @@ http = { version = "1", default-features = false, features = [
|
||||
tokio-rustls = { version = "0.26", default-features = false, optional = true }
|
||||
|
||||
# for tap device
|
||||
tun = { package = "tun-easytier", version = "0.7.1", features = [
|
||||
tun = { package = "tun-easytier", version = "1.1.1", features = [
|
||||
"async",
|
||||
], optional = true }
|
||||
# for net ns
|
||||
@@ -105,8 +105,8 @@ once_cell = "1.18.0"
|
||||
postcard = { "version" = "1.0.8", features = ["alloc"] }
|
||||
|
||||
# for rpc
|
||||
tonic = "0.10"
|
||||
prost = "0.12"
|
||||
tonic = "0.12"
|
||||
prost = "0.13"
|
||||
anyhow = "1.0"
|
||||
tarpc = { version = "0.32", features = ["tokio1", "serde1"] }
|
||||
|
||||
@@ -126,13 +126,18 @@ bytecodec = "0.4.15"
|
||||
rand = "0.8.5"
|
||||
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
pnet = { version = "0.34.0", features = ["serde"] }
|
||||
pnet = { version = "0.35.0", features = ["serde"] }
|
||||
|
||||
clap = { version = "4.4.8", features = ["unicode", "derive", "wrap_help"] }
|
||||
clap = { version = "4.4.8", features = [
|
||||
"string",
|
||||
"unicode",
|
||||
"derive",
|
||||
"wrap_help",
|
||||
] }
|
||||
|
||||
async-recursion = "1.0.5"
|
||||
|
||||
network-interface = "1.1.1"
|
||||
network-interface = "2.0"
|
||||
|
||||
# for ospf route
|
||||
petgraph = "0.6.5"
|
||||
@@ -143,15 +148,16 @@ bitflags = "2.5"
|
||||
aes-gcm = { version = "0.10.3", optional = true }
|
||||
|
||||
# for cli
|
||||
tabled = "0.15.*"
|
||||
tabled = "0.16"
|
||||
humansize = "2.1.3"
|
||||
|
||||
base64 = "0.21.7"
|
||||
base64 = "0.22"
|
||||
|
||||
derivative = "2.2.0"
|
||||
|
||||
mimalloc-rust = { version = "0.2.1", optional = true }
|
||||
|
||||
# for mips
|
||||
indexmap = { version = "~1.9.3", optional = false, features = ["std"] }
|
||||
|
||||
atomic-shim = "0.2.0"
|
||||
@@ -168,6 +174,9 @@ parking_lot = { version = "0.12.0", optional = true }
|
||||
|
||||
wildmatch = "2.3.4"
|
||||
|
||||
rust-i18n = "3"
|
||||
sys-locale = "0.3"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
windows-sys = { version = "0.52", features = [
|
||||
"Win32_Networking_WinSock",
|
||||
@@ -176,10 +185,12 @@ windows-sys = { version = "0.52", features = [
|
||||
"Win32_System_IO",
|
||||
] }
|
||||
encoding = "0.2"
|
||||
winreg = "0.11"
|
||||
winreg = "0.52"
|
||||
|
||||
[build-dependencies]
|
||||
tonic-build = "0.10"
|
||||
tonic-build = "0.12"
|
||||
globwalk = "0.8.1"
|
||||
regex = "1"
|
||||
|
||||
[target.'cfg(windows)'.build-dependencies]
|
||||
reqwest = { version = "0.11", features = ["blocking"] }
|
||||
@@ -205,7 +216,7 @@ full = [
|
||||
"smoltcp",
|
||||
"tun",
|
||||
]
|
||||
mips = ["aes-gcm", "mimalloc", "wireguard"]
|
||||
mips = ["aes-gcm", "mimalloc", "wireguard", "tun", "smoltcp"]
|
||||
bsd = ["aes-gcm", "mimalloc", "smoltcp"]
|
||||
wireguard = ["dep:boringtun", "dep:ring"]
|
||||
quic = ["dep:quinn", "dep:rustls", "dep:rcgen"]
|
||||
|
||||
@@ -86,6 +86,45 @@ impl WindowsBuild {
|
||||
}
|
||||
}
|
||||
|
||||
fn workdir() -> Option<String> {
|
||||
if let Ok(cargo_manifest_dir) = std::env::var("CARGO_MANIFEST_DIR") {
|
||||
return Some(cargo_manifest_dir);
|
||||
}
|
||||
|
||||
let dest = std::env::var("OUT_DIR");
|
||||
if dest.is_err() {
|
||||
return None;
|
||||
}
|
||||
let dest = dest.unwrap();
|
||||
|
||||
let seperator = regex::Regex::new(r"(/target/(.+?)/build/)|(\\target\\(.+?)\\build\\)")
|
||||
.expect("Invalid regex");
|
||||
let parts = seperator.split(dest.as_str()).collect::<Vec<_>>();
|
||||
|
||||
if parts.len() >= 2 {
|
||||
return Some(parts[0].to_string());
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn check_locale() {
|
||||
let workdir = workdir().unwrap_or("./".to_string());
|
||||
|
||||
let locale_path = format!("{workdir}/**/locales/**/*");
|
||||
if let Ok(globs) = globwalk::glob(locale_path) {
|
||||
for entry in globs {
|
||||
if let Err(e) = entry {
|
||||
println!("cargo:i18n-error={}", e);
|
||||
continue;
|
||||
}
|
||||
|
||||
let entry = entry.unwrap().into_path();
|
||||
println!("cargo:rerun-if-changed={}", entry.display());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
#[cfg(target_os = "windows")]
|
||||
WindowsBuild::check_for_win();
|
||||
@@ -98,5 +137,6 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
.compile(&["proto/cli.proto"], &["proto/"])
|
||||
.unwrap();
|
||||
// tonic_build::compile_protos("proto/cli.proto")?;
|
||||
check_locale();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
_version: 2
|
||||
|
||||
core_clap:
|
||||
config_file:
|
||||
en: "path to the config file, NOTE: if this is set, all other options will be ignored"
|
||||
zh-CN: "配置文件路径,注意:如果设置了这个选项,其他所有选项都将被忽略"
|
||||
network_name:
|
||||
en: "network name to identify this vpn network"
|
||||
zh-CN: "用于标识此VPN网络的网络名称"
|
||||
network_secret:
|
||||
en: "network secret to verify this node belongs to the vpn network"
|
||||
zh-CN: "网络密钥,用于验证此节点属于VPN网络"
|
||||
ipv4:
|
||||
en: "ipv4 address of this vpn node, if empty, this node will only forward packets and no TUN device will be created"
|
||||
zh-CN: "此VPN节点的IPv4地址,如果为空,则此节点将仅转发数据包,不会创建TUN设备"
|
||||
dhcp:
|
||||
en: "automatically determine and set IP address by Easytier, and the IP address starts from 10.0.0.1 by default. Warning, if there is an IP conflict in the network when using DHCP, the IP will be automatically changed."
|
||||
zh-CN: "由Easytier自动确定并设置IP地址,默认从10.0.0.1开始。警告:在使用DHCP时,如果网络中出现IP冲突,IP将自动更改。"
|
||||
peers:
|
||||
en: "peers to connect initially"
|
||||
zh-CN: "最初要连接的对等节点"
|
||||
external_node:
|
||||
en: "use a public shared node to discover peers"
|
||||
zh-CN: "使用公共共享节点来发现对等节点"
|
||||
proxy_networks:
|
||||
en: "export local networks to other peers in the vpn"
|
||||
zh-CN: "将本地网络导出到VPN中的其他对等节点"
|
||||
rpc_portal:
|
||||
en: "rpc portal address to listen for management. 0 means random port, 12345 means listen on 12345 of localhost, 0.0.0.0:12345 means listen on 12345 of all interfaces. default is 0 and will try 15888 first"
|
||||
zh-CN: "用于管理的RPC门户地址。0表示随机端口,12345表示在localhost的12345上监听,0.0.0.0:12345表示在所有接口的12345上监听。默认是0,首先尝试15888"
|
||||
listeners:
|
||||
en: |+
|
||||
listeners to accept connections, allow format:
|
||||
port number: <11010>. means tcp/udp will listen on 11010, ws/wss will listen on 11010 and 11011, wg will listen on 11011
|
||||
url: <tcp://0.0.0.0:11010>. tcp can be tcp, udp, ring, wg, ws, wss\n
|
||||
proto & port pair: <proto:port>. wg:11011, means listen on 11011 with wireguard protocol url and proto:port can occur multiple times.
|
||||
zh-CN: |+
|
||||
监听器用于接受连接,允许以下格式:
|
||||
端口号:<11010>,意味着tcp/udp将在11010端口监听,ws/wss将在11010和11011端口监听,wg将在11011端口监听。
|
||||
url:<tcp://0.0.0.0:11010>,其中tcp可以是tcp、udp、ring、wg、ws、wss协议。
|
||||
协议和端口对:<proto:port>,例如wg:11011,表示使用WireGuard协议在11011端口监听。URL 和 协议端口对 可以多次出现。
|
||||
no_listener:
|
||||
en: "do not listen on any port, only connect to peers"
|
||||
zh-CN: "不监听任何端口,只连接到对等节点"
|
||||
console_log_level:
|
||||
en: "console log level"
|
||||
zh-CN: "控制台日志级别"
|
||||
file_log_level:
|
||||
en: "file log level"
|
||||
zh-CN: "文件日志级别"
|
||||
file_log_dir:
|
||||
en: "directory to store log files"
|
||||
zh-CN: "存储日志文件的目录"
|
||||
hostname:
|
||||
en: "host name to identify this device"
|
||||
zh-CN: "用于标识此设备的主机名"
|
||||
instance_name:
|
||||
en: "instance name to identify this vpn node in same machine"
|
||||
zh-CN: "实例名称,用于在同一台机器上标识此VPN节点"
|
||||
vpn_portal:
|
||||
en: "url that defines the vpn portal, allow other vpn clients to connect. example: wg://0.0.0.0:11010/10.14.14.0/24, means the vpn portal is a wireguard server listening on vpn.example.com:11010, and the vpn client is in network of 10.14.14.0/24"
|
||||
zh-CN: "定义VPN门户的URL,允许其他VPN客户端连接。示例:wg://0.0.0.0:11010/10.14.14.0/24,表示VPN门户是监听在vpn.example.com:11010的wireguard服务器,VPN客户端在10.14.14.0/24网络中"
|
||||
default_protocol:
|
||||
en: "default protocol to use when connecting to peers"
|
||||
zh-CN: "连接到对等节点时使用的默认协议"
|
||||
disable_encryption:
|
||||
en: "disable encryption for peers communication, default is false, must be same with peers"
|
||||
zh-CN: "禁用对等节点通信的加密,默认为false,必须与对等节点相同"
|
||||
multi_thread:
|
||||
en: "use multi-thread runtime, default is single-thread"
|
||||
zh-CN: "使用多线程运行时,默认为单线程"
|
||||
disable_ipv6:
|
||||
en: "do not use ipv6"
|
||||
zh-CN: "不使用IPv6"
|
||||
dev_name:
|
||||
en: "optional tun interface name"
|
||||
zh-CN: "可选的TUN接口名称"
|
||||
mtu:
|
||||
en: "mtu of the TUN device, default is 1420 for non-encryption, 1400 for encryption"
|
||||
zh-CN: "TUN设备的MTU,默认为非加密时为1420,加密时为1400"
|
||||
latency_first:
|
||||
en: "latency first mode, will try to relay traffic with lowest latency path, default is using shortest path"
|
||||
zh-CN: "延迟优先模式,将尝试使用最低延迟路径转发流量,默认使用最短路径"
|
||||
exit_nodes:
|
||||
en: "exit nodes to forward all traffic to, a virtual ipv4 address, priority is determined by the order of the list"
|
||||
zh-CN: "转发所有流量的出口节点,虚拟IPv4地址,优先级由列表顺序决定"
|
||||
enable_exit_node:
|
||||
en: "allow this node to be an exit node"
|
||||
zh-CN: "允许此节点成为出口节点"
|
||||
no_tun:
|
||||
en: "do not create TUN device, can use subnet proxy to access node"
|
||||
zh-CN: "不创建TUN设备,可以使用子网代理访问节点"
|
||||
use_smoltcp:
|
||||
en: "enable smoltcp stack for subnet proxy"
|
||||
zh-CN: "为子网代理启用smoltcp堆栈"
|
||||
manual_routes:
|
||||
en: "assign routes cidr manually, will disable subnet proxy and wireguard routes propagated from peers. e.g.: 192.168.0.0/16"
|
||||
zh-CN: "手动分配路由CIDR,将禁用子网代理和从对等节点传播的wireguard路由。例如:192.168.0.0/16"
|
||||
relay_network_whitelist:
|
||||
en: |+
|
||||
only forward traffic from the whitelist networks, supporting wildcard strings, multiple network names can be separated by spaces.
|
||||
if this parameter is empty, forwarding is disabled. by default, all networks are allowed.
|
||||
e.g.: '*' (all networks), 'def*' (networks with the prefix 'def'), 'net1 net2' (only allow net1 and net2)"
|
||||
zh-CN: |+
|
||||
仅转发白名单网络的流量,支持通配符字符串。多个网络名称间可以使用英文空格间隔。
|
||||
如果该参数为空,则禁用转发。默认允许所有网络。
|
||||
例如:'*'(所有网络),'def*'(以def为前缀的网络),'net1 net2'(只允许net1和net2)"
|
||||
disable_p2p:
|
||||
en: "disable p2p communication, will only relay packets with peers specified by --peers"
|
||||
zh-CN: "禁用P2P通信,只通过--peers指定的节点转发数据包"
|
||||
relay_all_peer_rpc:
|
||||
en: "relay all peer rpc packets, even if the peer is not in the relay network whitelist. this can help peers not in relay network whitelist to establish p2p connection."
|
||||
zh-CN: "转发所有对等节点的RPC数据包,即使对等节点不在转发网络白名单中。这可以帮助白名单外网络中的对等节点建立P2P连接。"
|
||||
@@ -171,6 +171,10 @@ pub struct Flags {
|
||||
pub use_smoltcp: bool,
|
||||
#[derivative(Default(value = "\"*\".to_string()"))]
|
||||
pub foreign_network_whitelist: String,
|
||||
#[derivative(Default(value = "false"))]
|
||||
pub disable_p2p: bool,
|
||||
#[derivative(Default(value = "false"))]
|
||||
pub relay_all_peer_rpc: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
|
||||
@@ -258,21 +262,15 @@ impl ConfigLoader for TomlConfigLoader {
|
||||
|
||||
match hostname {
|
||||
Some(hostname) => {
|
||||
let hostname = hostname
|
||||
.chars()
|
||||
.filter(|c| !c.is_control())
|
||||
.take(32)
|
||||
.collect::<String>();
|
||||
|
||||
if !hostname.is_empty() {
|
||||
let mut name = hostname
|
||||
.chars()
|
||||
.filter(|c| c.is_ascii_alphanumeric() || *c == '-' || *c == '_')
|
||||
.take(32)
|
||||
.collect::<String>();
|
||||
|
||||
if name.len() > 32 {
|
||||
name = name.chars().take(32).collect::<String>();
|
||||
}
|
||||
|
||||
if hostname != name {
|
||||
self.set_hostname(Some(name.clone()));
|
||||
}
|
||||
name
|
||||
self.set_hostname(Some(hostname.clone()));
|
||||
hostname
|
||||
} else {
|
||||
self.set_hostname(None);
|
||||
gethostname::gethostname().to_string_lossy().to_string()
|
||||
|
||||
@@ -121,6 +121,10 @@ impl DirectConnectorManager {
|
||||
}
|
||||
|
||||
pub fn run(&mut self) {
|
||||
if self.global_ctx.get_flags().disable_p2p {
|
||||
return;
|
||||
}
|
||||
|
||||
self.run_as_server();
|
||||
self.run_as_client();
|
||||
}
|
||||
|
||||
@@ -316,6 +316,7 @@ impl ManualConnectorManager {
|
||||
ip_versions.push(IpVersion::Both);
|
||||
} else {
|
||||
let addrs = u.socket_addrs(|| Some(1000))?;
|
||||
tracing::info!(?addrs, ?dead_url, "get ip from url done");
|
||||
let mut has_ipv4 = false;
|
||||
let mut has_ipv6 = false;
|
||||
for addr in addrs {
|
||||
|
||||
@@ -602,6 +602,10 @@ impl UdpHolePunchConnector {
|
||||
}
|
||||
|
||||
pub async fn run(&mut self) -> Result<(), Error> {
|
||||
if self.data.global_ctx.get_flags().disable_p2p {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
self.run_as_client().await?;
|
||||
self.run_as_server().await?;
|
||||
|
||||
|
||||
+102
-59
@@ -10,6 +10,9 @@ use std::{
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
#[macro_use]
|
||||
extern crate rust_i18n;
|
||||
|
||||
use anyhow::Context;
|
||||
use clap::Parser;
|
||||
|
||||
@@ -52,19 +55,20 @@ struct Cli {
|
||||
#[arg(
|
||||
short,
|
||||
long,
|
||||
help = "path to the config file, NOTE: if this is set, all other options will be ignored"
|
||||
help = t!("core_clap.config_file").to_string()
|
||||
)]
|
||||
config_file: Option<PathBuf>,
|
||||
|
||||
#[arg(
|
||||
long,
|
||||
help = "network name to identify this vpn network",
|
||||
help = t!("core_clap.network_name").to_string(),
|
||||
default_value = "default"
|
||||
)]
|
||||
network_name: String,
|
||||
|
||||
#[arg(
|
||||
long,
|
||||
help = "network secret to verify this node belongs to the vpn network",
|
||||
help = t!("core_clap.network_secret").to_string(),
|
||||
default_value = ""
|
||||
)]
|
||||
network_secret: String,
|
||||
@@ -72,171 +76,207 @@ struct Cli {
|
||||
#[arg(
|
||||
short,
|
||||
long,
|
||||
help = "ipv4 address of this vpn node, if empty, this node will only forward packets and no TUN device will be created"
|
||||
help = t!("core_clap.ipv4").to_string()
|
||||
)]
|
||||
ipv4: Option<String>,
|
||||
|
||||
#[arg(
|
||||
short,
|
||||
long,
|
||||
help = "automatically determine and set IP address by Easytier, and the
|
||||
IP address starts from 10.0.0.1 by default. Warning, if there is an IP
|
||||
conflict in the network when using DHCP, the IP will be automatically
|
||||
changed."
|
||||
help = t!("core_clap.dhcp").to_string()
|
||||
)]
|
||||
dhcp: bool,
|
||||
|
||||
#[arg(short, long, help = "peers to connect initially", num_args = 0..)]
|
||||
#[arg(
|
||||
short,
|
||||
long,
|
||||
help = t!("core_clap.peers").to_string(),
|
||||
num_args = 0..
|
||||
)]
|
||||
peers: Vec<String>,
|
||||
|
||||
#[arg(short, long, help = "use a public shared node to discover peers")]
|
||||
#[arg(
|
||||
short,
|
||||
long,
|
||||
help = t!("core_clap.external_node").to_string()
|
||||
)]
|
||||
external_node: Option<String>,
|
||||
|
||||
#[arg(
|
||||
short = 'n',
|
||||
long,
|
||||
help = "export local networks to other peers in the vpn"
|
||||
help = t!("core_clap.proxy_networks").to_string()
|
||||
)]
|
||||
proxy_networks: Vec<String>,
|
||||
|
||||
#[arg(
|
||||
short,
|
||||
long,
|
||||
default_value = "0",
|
||||
help = "rpc portal address to listen for management. 0 means random
|
||||
port, 12345 means listen on 12345 of localhost, 0.0.0.0:12345 means
|
||||
listen on 12345 of all interfaces. default is 0 and will try 15888 first"
|
||||
help = t!("core_clap.rpc_portal").to_string(),
|
||||
default_value = "0"
|
||||
)]
|
||||
rpc_portal: String,
|
||||
|
||||
#[arg(short, long, help = "listeners to accept connections, allow format:
|
||||
a port number: 11010, means tcp/udp will listen on 11010, ws/wss will listen on 11010 and 11011, wg will listen on 11011
|
||||
url: tcp://0.0.0.0:11010, tcp can be tcp, udp, ring, wg, ws, wss,
|
||||
proto:port: wg:11011, means listen on 11011 with wireguard protocol
|
||||
url and proto:port can occur multiple times.
|
||||
", default_values_t = ["11010".to_string()],
|
||||
num_args = 0..)]
|
||||
#[arg(
|
||||
short,
|
||||
long,
|
||||
help = t!("core_clap.listeners").to_string(),
|
||||
default_values_t = ["11010".to_string()],
|
||||
num_args = 0..
|
||||
)]
|
||||
listeners: Vec<String>,
|
||||
|
||||
#[arg(
|
||||
long,
|
||||
help = "do not listen on any port, only connect to peers",
|
||||
help = t!("core_clap.no_listener").to_string(),
|
||||
default_value = "false"
|
||||
)]
|
||||
no_listener: bool,
|
||||
|
||||
#[arg(long, help = "console log level",
|
||||
value_parser = clap::builder::PossibleValuesParser::new(["trace", "debug", "info", "warn", "error", "off"]))]
|
||||
#[arg(
|
||||
long,
|
||||
help = t!("core_clap.console_log_level").to_string()
|
||||
)]
|
||||
console_log_level: Option<String>,
|
||||
|
||||
#[arg(long, help = "file log level",
|
||||
value_parser = clap::builder::PossibleValuesParser::new(["trace", "debug", "info", "warn", "error", "off"]))]
|
||||
#[arg(
|
||||
long,
|
||||
help = t!("core_clap.file_log_level").to_string()
|
||||
)]
|
||||
file_log_level: Option<String>,
|
||||
#[arg(long, help = "directory to store log files")]
|
||||
|
||||
#[arg(
|
||||
long,
|
||||
help = t!("core_clap.file_log_dir").to_string()
|
||||
)]
|
||||
file_log_dir: Option<String>,
|
||||
|
||||
#[arg(long, help = "host name to identify this device")]
|
||||
#[arg(
|
||||
long,
|
||||
help = t!("core_clap.hostname").to_string()
|
||||
)]
|
||||
hostname: Option<String>,
|
||||
|
||||
#[arg(
|
||||
short = 'm',
|
||||
long,
|
||||
default_value = "default",
|
||||
help = "instance name to identify this vpn node in same machine"
|
||||
help = t!("core_clap.instance_name").to_string(),
|
||||
default_value = "default"
|
||||
)]
|
||||
instance_name: String,
|
||||
|
||||
#[arg(
|
||||
long,
|
||||
help = "url that defines the vpn portal, allow other vpn clients to connect.
|
||||
example: wg://0.0.0.0:11010/10.14.14.0/24, means the vpn portal is a wireguard server listening on vpn.example.com:11010,
|
||||
and the vpn client is in network of 10.14.14.0/24"
|
||||
help = t!("core_clap.vpn_portal").to_string()
|
||||
)]
|
||||
vpn_portal: Option<String>,
|
||||
|
||||
#[arg(long, help = "default protocol to use when connecting to peers")]
|
||||
#[arg(
|
||||
long,
|
||||
help = t!("core_clap.default_protocol").to_string()
|
||||
)]
|
||||
default_protocol: Option<String>,
|
||||
|
||||
#[arg(
|
||||
short = 'u',
|
||||
long,
|
||||
help = "disable encryption for peers communication, default is false, must be same with peers",
|
||||
help = t!("core_clap.disable_encryption").to_string(),
|
||||
default_value = "false"
|
||||
)]
|
||||
disable_encryption: bool,
|
||||
|
||||
#[arg(
|
||||
long,
|
||||
help = "use multi-thread runtime, default is single-thread",
|
||||
help = t!("core_clap.multi_thread").to_string(),
|
||||
default_value = "false"
|
||||
)]
|
||||
multi_thread: bool,
|
||||
|
||||
#[arg(long, help = "do not use ipv6", default_value = "false")]
|
||||
#[arg(
|
||||
long,
|
||||
help = t!("core_clap.disable_ipv6").to_string(),
|
||||
default_value = "false"
|
||||
)]
|
||||
disable_ipv6: bool,
|
||||
|
||||
#[arg(long, help = "optional tun interface name")]
|
||||
#[arg(
|
||||
long,
|
||||
help = t!("core_clap.dev_name").to_string()
|
||||
)]
|
||||
dev_name: Option<String>,
|
||||
|
||||
#[arg(
|
||||
long,
|
||||
help = "mtu of the TUN device, default is 1420 for non-encryption, 1400 for encryption"
|
||||
help = t!("core_clap.mtu").to_string()
|
||||
)]
|
||||
mtu: Option<u16>,
|
||||
|
||||
#[arg(
|
||||
long,
|
||||
help = "latency first mode, will try to relay traffic with lowest latency path, default is using shortest path",
|
||||
help = t!("core_clap.latency_first").to_string(),
|
||||
default_value = "false"
|
||||
)]
|
||||
latency_first: bool,
|
||||
|
||||
#[arg(
|
||||
long,
|
||||
help = "exit nodes to forward all traffic to, a virtual ipv4 address, priority is determined by the order of the list",
|
||||
help = t!("core_clap.exit_nodes").to_string(),
|
||||
num_args = 0..
|
||||
)]
|
||||
exit_nodes: Vec<Ipv4Addr>,
|
||||
|
||||
#[arg(
|
||||
long,
|
||||
help = "allow this node to be an exit node, default is false",
|
||||
help = t!("core_clap.enable_exit_node").to_string(),
|
||||
default_value = "false"
|
||||
)]
|
||||
enable_exit_node: bool,
|
||||
|
||||
#[arg(
|
||||
long,
|
||||
help = "do not create TUN device, can use subnet proxy to access node",
|
||||
help = t!("core_clap.no_tun").to_string(),
|
||||
default_value = "false"
|
||||
)]
|
||||
no_tun: bool,
|
||||
|
||||
#[arg(
|
||||
long,
|
||||
help = "enable smoltcp stack for subnet proxy",
|
||||
help = t!("core_clap.use_smoltcp").to_string(),
|
||||
default_value = "false"
|
||||
)]
|
||||
use_smoltcp: bool,
|
||||
|
||||
#[arg(
|
||||
long,
|
||||
help = "assign routes cidr manually, will disable subnet proxy and
|
||||
wireguard routes propogated from peers. e.g.: 192.168.0.0/16",
|
||||
help = t!("core_clap.manual_routes").to_string(),
|
||||
num_args = 0..
|
||||
)]
|
||||
manual_routes: Option<Vec<String>>,
|
||||
|
||||
#[arg(
|
||||
long,
|
||||
help = "only relay traffic of whitelisted networks, input is a wildcard
|
||||
string, e.g.: '*' (all networks), 'def*' (network prefixed with def), can specify multiple networks
|
||||
disable relay if arg is empty. default is allowing all networks",
|
||||
num_args = 0..,
|
||||
help = t!("core_clap.relay_network_whitelist").to_string(),
|
||||
num_args = 0..
|
||||
)]
|
||||
relay_network_whitelist: Option<Vec<String>>,
|
||||
|
||||
#[arg(
|
||||
long,
|
||||
help = t!("core_clap.disable_p2p").to_string(),
|
||||
default_value = "false"
|
||||
)]
|
||||
disable_p2p: bool,
|
||||
|
||||
#[arg(
|
||||
long,
|
||||
help = t!("core_clap.relay_all_peer_rpc").to_string(),
|
||||
default_value = "false"
|
||||
)]
|
||||
relay_all_peer_rpc: bool,
|
||||
}
|
||||
|
||||
rust_i18n::i18n!("locales");
|
||||
|
||||
impl Cli {
|
||||
fn parse_listeners(&self) -> Vec<String> {
|
||||
println!("parsing listeners: {:?}", self.listeners);
|
||||
@@ -334,14 +374,12 @@ impl From<Cli> for TomlConfigLoader {
|
||||
|
||||
cfg.set_dhcp(cli.dhcp);
|
||||
|
||||
if !cli.dhcp {
|
||||
if let Some(ipv4) = &cli.ipv4 {
|
||||
cfg.set_ipv4(Some(
|
||||
ipv4.parse()
|
||||
.with_context(|| format!("failed to parse ipv4 address: {}", ipv4))
|
||||
.unwrap(),
|
||||
))
|
||||
}
|
||||
if let Some(ipv4) = &cli.ipv4 {
|
||||
cfg.set_ipv4(Some(
|
||||
ipv4.parse()
|
||||
.with_context(|| format!("failed to parse ipv4 address: {}", ipv4))
|
||||
.unwrap(),
|
||||
))
|
||||
}
|
||||
|
||||
cfg.set_peers(
|
||||
@@ -470,6 +508,8 @@ impl From<Cli> for TomlConfigLoader {
|
||||
if let Some(wl) = cli.relay_network_whitelist {
|
||||
f.foreign_network_whitelist = wl.join(" ");
|
||||
}
|
||||
f.disable_p2p = cli.disable_p2p;
|
||||
f.relay_all_peer_rpc = cli.relay_all_peer_rpc;
|
||||
cfg.set_flags(f);
|
||||
|
||||
cfg.set_exit_nodes(cli.exit_nodes.clone());
|
||||
@@ -628,6 +668,9 @@ pub async fn async_main(cli: Cli) {
|
||||
fn main() {
|
||||
setup_panic_handler();
|
||||
|
||||
let locale = sys_locale::get_locale().unwrap_or_else(|| String::from("en-US"));
|
||||
rust_i18n::set_locale(&locale);
|
||||
|
||||
let cli = Cli::parse();
|
||||
tracing::info!(cli = ?cli, "cli args parsed");
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use std::any::Any;
|
||||
use std::collections::HashSet;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
@@ -91,7 +92,7 @@ impl NicCtx {
|
||||
}
|
||||
}
|
||||
|
||||
type ArcNicCtx = Arc<Mutex<Option<NicCtx>>>;
|
||||
type ArcNicCtx = Arc<Mutex<Option<Box<dyn Any + 'static + Send>>>>;
|
||||
|
||||
pub struct Instance {
|
||||
inst_name: String,
|
||||
@@ -197,14 +198,28 @@ impl Instance {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn clear_nic_ctx(arc_nic_ctx: ArcNicCtx) {
|
||||
// use a mock nic ctx to consume packets.
|
||||
async fn clear_nic_ctx(
|
||||
arc_nic_ctx: ArcNicCtx,
|
||||
packet_recv: Arc<Mutex<PacketRecvChanReceiver>>,
|
||||
) {
|
||||
let _ = arc_nic_ctx.lock().await.take();
|
||||
|
||||
let mut tasks = JoinSet::new();
|
||||
tasks.spawn(async move {
|
||||
let mut packet_recv = packet_recv.lock().await;
|
||||
while let Some(packet) = packet_recv.recv().await {
|
||||
tracing::trace!("packet consumed by mock nic ctx: {:?}", packet);
|
||||
}
|
||||
});
|
||||
arc_nic_ctx.lock().await.replace(Box::new(tasks));
|
||||
|
||||
tracing::debug!("nic ctx cleared.");
|
||||
}
|
||||
|
||||
async fn use_new_nic_ctx(arc_nic_ctx: ArcNicCtx, nic_ctx: NicCtx) {
|
||||
let mut g = arc_nic_ctx.lock().await;
|
||||
*g = Some(nic_ctx);
|
||||
*g = Some(Box::new(nic_ctx));
|
||||
tracing::debug!("nic ctx updated.");
|
||||
}
|
||||
|
||||
@@ -274,7 +289,7 @@ impl Instance {
|
||||
"dhcp start changing ip"
|
||||
);
|
||||
|
||||
Self::clear_nic_ctx(nic_ctx.clone()).await;
|
||||
Self::clear_nic_ctx(nic_ctx.clone(), _peer_packet_receiver.clone()).await;
|
||||
|
||||
if let Some(ip) = candidate_ipv4_addr {
|
||||
if global_ctx_c.no_tun() {
|
||||
@@ -329,9 +344,9 @@ impl Instance {
|
||||
self.listener_manager.lock().await.run().await?;
|
||||
self.peer_manager.run().await?;
|
||||
|
||||
if self.global_ctx.config.get_flags().no_tun {
|
||||
self.peer_packet_receiver.lock().await.close();
|
||||
} else {
|
||||
Self::clear_nic_ctx(self.nic_ctx.clone(), self.peer_packet_receiver.clone()).await;
|
||||
|
||||
if !self.global_ctx.config.get_flags().no_tun {
|
||||
#[cfg(not(target_os = "android"))]
|
||||
if let Some(ipv4_addr) = self.global_ctx.get_ipv4() {
|
||||
let mut new_nic_ctx = NicCtx::new(
|
||||
@@ -532,7 +547,7 @@ impl Instance {
|
||||
fd: i32,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
println!("setup_nic_ctx_for_android, fd: {}", fd);
|
||||
Self::clear_nic_ctx(nic_ctx.clone()).await;
|
||||
Self::clear_nic_ctx(nic_ctx.clone(), peer_packet_receiver.clone()).await;
|
||||
if fd <= 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ use tokio::{
|
||||
task::JoinSet,
|
||||
};
|
||||
use tokio_util::bytes::Bytes;
|
||||
use tun::{create_as_async, AsyncDevice, Configuration, Device as _, Layer};
|
||||
use tun::{AbstractDevice, AsyncDevice, Configuration, Layer};
|
||||
use zerocopy::{NativeEndian, NetworkEndian};
|
||||
|
||||
pin_project! {
|
||||
@@ -237,20 +237,15 @@ impl AsyncWrite for TunAsyncWrite {
|
||||
}
|
||||
|
||||
pub struct VirtualNic {
|
||||
dev_name: String,
|
||||
queue_num: usize,
|
||||
|
||||
global_ctx: ArcGlobalCtx,
|
||||
|
||||
ifname: Option<String>,
|
||||
ifcfg: Box<dyn IfConfiguerTrait + Send + Sync + 'static>,
|
||||
}
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn checkreg() -> io::Result<()> {
|
||||
use winreg::{enums::HKEY_LOCAL_MACHINE, RegKey,enums::KEY_ALL_ACCESS};
|
||||
// 打开根键
|
||||
pub fn checkreg(dev_name:&str) -> io::Result<()> {
|
||||
use winreg::{enums::HKEY_LOCAL_MACHINE, enums::KEY_ALL_ACCESS, RegKey};
|
||||
let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
|
||||
// 打开指定的子键
|
||||
let profiles_key = hklm.open_subkey_with_flags(
|
||||
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkList\\Profiles",
|
||||
KEY_ALL_ACCESS,
|
||||
@@ -259,21 +254,19 @@ pub fn checkreg() -> io::Result<()> {
|
||||
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkList\\Signatures\\Unmanaged",
|
||||
KEY_ALL_ACCESS,
|
||||
)?;
|
||||
// 收集要删除的子键名称
|
||||
// collect subkeys to delete
|
||||
let mut keys_to_delete = Vec::new();
|
||||
let mut keys_to_delete_unmanaged = Vec::new();
|
||||
for subkey_name in profiles_key.enum_keys().filter_map(Result::ok) {
|
||||
let subkey = profiles_key.open_subkey(&subkey_name)?;
|
||||
// 尝试读取 ProfileName 值
|
||||
// check if ProfileName contains "et"
|
||||
match subkey.get_value::<String, _>("ProfileName") {
|
||||
Ok(profile_name) => {
|
||||
// 检查 ProfileName 是否包含 "et"
|
||||
if profile_name.contains("et_") {
|
||||
if profile_name.contains("et_") || (!dev_name.is_empty() && dev_name == profile_name) {
|
||||
keys_to_delete.push(subkey_name);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
// 打印错误信息
|
||||
tracing::error!(
|
||||
"Failed to read ProfileName for subkey {}: {}",
|
||||
subkey_name,
|
||||
@@ -284,16 +277,14 @@ pub fn checkreg() -> io::Result<()> {
|
||||
}
|
||||
for subkey_name in unmanaged_key.enum_keys().filter_map(Result::ok) {
|
||||
let subkey = unmanaged_key.open_subkey(&subkey_name)?;
|
||||
// 尝试读取 ProfileName 值
|
||||
// check if ProfileName contains "et"
|
||||
match subkey.get_value::<String, _>("Description") {
|
||||
Ok(profile_name) => {
|
||||
// 检查 ProfileName 是否包含 "et"
|
||||
if profile_name.contains("et_") {
|
||||
if profile_name.contains("et_") || (!dev_name.is_empty() && dev_name == profile_name) {
|
||||
keys_to_delete_unmanaged.push(subkey_name);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
// 打印错误信息
|
||||
tracing::error!(
|
||||
"Failed to read ProfileName for subkey {}: {}",
|
||||
subkey_name,
|
||||
@@ -302,7 +293,7 @@ pub fn checkreg() -> io::Result<()> {
|
||||
}
|
||||
}
|
||||
}
|
||||
//删除收集到的子键
|
||||
// delete collected subkeys
|
||||
if !keys_to_delete.is_empty() {
|
||||
for subkey_name in keys_to_delete {
|
||||
match profiles_key.delete_subkey_all(&subkey_name) {
|
||||
@@ -325,25 +316,13 @@ pub fn checkreg() -> io::Result<()> {
|
||||
impl VirtualNic {
|
||||
pub fn new(global_ctx: ArcGlobalCtx) -> Self {
|
||||
Self {
|
||||
dev_name: "".to_owned(),
|
||||
queue_num: 1,
|
||||
global_ctx,
|
||||
ifname: None,
|
||||
ifcfg: Box::new(IfConfiger {}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_dev_name(mut self, dev_name: &str) -> Result<Self, Error> {
|
||||
self.dev_name = dev_name.to_owned();
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
pub fn set_queue_num(mut self, queue_num: usize) -> Result<Self, Error> {
|
||||
self.queue_num = queue_num;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
async fn create_tun(&mut self) -> Result<AsyncDevice, Error> {
|
||||
async fn create_tun(&mut self) -> Result<tun::platform::Device, Error> {
|
||||
let mut config = Configuration::default();
|
||||
config.layer(Layer::L3);
|
||||
|
||||
@@ -351,22 +330,25 @@ impl VirtualNic {
|
||||
{
|
||||
let dev_name = self.global_ctx.get_flags().dev_name;
|
||||
if !dev_name.is_empty() {
|
||||
config.name(format!("{}", dev_name));
|
||||
config.tun_name(format!("{}", dev_name));
|
||||
}
|
||||
config.platform(|config| {
|
||||
// detect protocol by ourselves for cross platform
|
||||
config.packet_information(false);
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
config.platform_config(|config| {
|
||||
// disable packet information so we can process the header by ourselves, see tun2 impl for more details
|
||||
config.packet_information(false);
|
||||
});
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
match checkreg(){
|
||||
let dev_name = self.global_ctx.get_flags().dev_name;
|
||||
|
||||
match checkreg(&dev_name) {
|
||||
Ok(_) => tracing::trace!("delete successful!"),
|
||||
Err(e) => tracing::error!("An error occurred: {}", e),
|
||||
}
|
||||
use rand::distributions::Distribution as _;
|
||||
use std::net::IpAddr;
|
||||
let c = crate::arch::windows::interface_count()?;
|
||||
let mut rng = rand::thread_rng();
|
||||
let s: String = rand::distributions::Alphanumeric
|
||||
@@ -375,14 +357,15 @@ impl VirtualNic {
|
||||
.map(char::from)
|
||||
.collect::<String>()
|
||||
.to_lowercase();
|
||||
|
||||
if !dev_name.is_empty() {
|
||||
config.tun_name(format!("{}", dev_name));
|
||||
} else {
|
||||
config.tun_name(format!("et_{}_{}", c, s));
|
||||
}
|
||||
|
||||
config.name(format!("et{}_{}_{}", self.dev_name, c, s));
|
||||
// set a temporary address
|
||||
config.address(format!("172.0.{}.3", c).parse::<IpAddr>().unwrap());
|
||||
|
||||
config.platform(|config| {
|
||||
config.platform_config(|config| {
|
||||
config.skip_config(true);
|
||||
config.guid(None);
|
||||
config.ring_cap(Some(std::cmp::min(
|
||||
config.min_ring_cap() * 32,
|
||||
config.max_ring_cap(),
|
||||
@@ -390,14 +373,10 @@ impl VirtualNic {
|
||||
});
|
||||
}
|
||||
|
||||
if self.queue_num != 1 {
|
||||
todo!("queue_num != 1")
|
||||
}
|
||||
config.queues(self.queue_num);
|
||||
config.up();
|
||||
|
||||
let _g = self.global_ctx.net_ns.guard();
|
||||
Ok(create_as_async(&config)?)
|
||||
Ok(tun::create(&config)?)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
@@ -409,12 +388,11 @@ impl VirtualNic {
|
||||
let mut config = Configuration::default();
|
||||
config.layer(Layer::L3);
|
||||
config.raw_fd(tun_fd);
|
||||
config.platform(|config| {
|
||||
config.no_close_fd_on_drop(true);
|
||||
});
|
||||
config.close_fd_on_drop(false);
|
||||
config.up();
|
||||
|
||||
let dev = create_as_async(&config)?;
|
||||
let dev = tun::create(&config)?;
|
||||
let dev = AsyncDevice::new(dev)?;
|
||||
let (a, b) = BiLock::new(dev);
|
||||
let ft = TunnelWrapper::new(
|
||||
TunStream::new(a, false),
|
||||
@@ -432,9 +410,11 @@ impl VirtualNic {
|
||||
|
||||
pub async fn create_dev(&mut self) -> Result<Box<dyn Tunnel>, Error> {
|
||||
let dev = self.create_tun().await?;
|
||||
let ifname = dev.get_ref().name()?;
|
||||
let ifname = dev.tun_name()?;
|
||||
self.ifcfg.wait_interface_show(ifname.as_str()).await?;
|
||||
|
||||
let dev = AsyncDevice::new(dev)?;
|
||||
|
||||
let flags = self.global_ctx.config.get_flags();
|
||||
let mut mtu_in_config = flags.mtu;
|
||||
if flags.enable_encryption {
|
||||
|
||||
@@ -37,6 +37,7 @@ use super::{
|
||||
struct ForeignNetworkEntry {
|
||||
network: NetworkIdentity,
|
||||
peer_map: Arc<PeerMap>,
|
||||
relay_data: bool,
|
||||
}
|
||||
|
||||
impl ForeignNetworkEntry {
|
||||
@@ -45,9 +46,14 @@ impl ForeignNetworkEntry {
|
||||
packet_sender: PacketRecvChan,
|
||||
global_ctx: ArcGlobalCtx,
|
||||
my_peer_id: PeerId,
|
||||
relay_data: bool,
|
||||
) -> Self {
|
||||
let peer_map = Arc::new(PeerMap::new(packet_sender, global_ctx, my_peer_id));
|
||||
Self { network, peer_map }
|
||||
Self {
|
||||
network,
|
||||
peer_map,
|
||||
relay_data,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,9 +201,30 @@ impl ForeignNetworkManager {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_network_in_whitelist(&self, network_name: &str) -> Result<(), Error> {
|
||||
if self
|
||||
.global_ctx
|
||||
.get_flags()
|
||||
.foreign_network_whitelist
|
||||
.split(" ")
|
||||
.map(wildmatch::WildMatch::new)
|
||||
.any(|wl| wl.matches(network_name))
|
||||
{
|
||||
Ok(())
|
||||
} else {
|
||||
Err(anyhow::anyhow!("network {} not in whitelist", network_name).into())
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn add_peer_conn(&self, peer_conn: PeerConn) -> Result<(), Error> {
|
||||
tracing::info!(peer_conn = ?peer_conn.get_conn_info(), network = ?peer_conn.get_network_identity(), "add new peer conn in foreign network manager");
|
||||
|
||||
let relay_peer_rpc = self.global_ctx.get_flags().relay_all_peer_rpc;
|
||||
let ret = self.check_network_in_whitelist(&peer_conn.get_network_identity().network_name);
|
||||
if ret.is_err() && !relay_peer_rpc {
|
||||
return ret;
|
||||
}
|
||||
|
||||
let entry = self
|
||||
.data
|
||||
.network_peer_maps
|
||||
@@ -208,6 +235,7 @@ impl ForeignNetworkManager {
|
||||
self.packet_sender.clone(),
|
||||
self.global_ctx.clone(),
|
||||
self.my_peer_id,
|
||||
!ret.is_err(),
|
||||
))
|
||||
})
|
||||
.clone();
|
||||
@@ -280,6 +308,10 @@ impl ForeignNetworkManager {
|
||||
}
|
||||
|
||||
if let Some(entry) = data.get_network_entry(&from_network) {
|
||||
if !entry.relay_data && hdr.packet_type == PacketType::Data as u8 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let ret = entry
|
||||
.peer_map
|
||||
.send_msg(packet_bytes, to_peer_id, NextHopPolicy::LeastHop)
|
||||
@@ -424,6 +456,31 @@ mod tests {
|
||||
foreign_network_whitelist_helper("net2abc".to_string()).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn only_relay_peer_rpc() {
|
||||
let pm_center = create_mock_peer_manager_with_mock_stun(crate::rpc::NatType::Unknown).await;
|
||||
let mut flag = pm_center.get_global_ctx().get_flags();
|
||||
flag.foreign_network_whitelist = "".to_string();
|
||||
flag.relay_all_peer_rpc = true;
|
||||
pm_center.get_global_ctx().config.set_flags(flag);
|
||||
tracing::debug!("pm_center: {:?}", pm_center.my_peer_id());
|
||||
|
||||
let pma_net1 = create_mock_peer_manager_for_foreign_network("net1").await;
|
||||
let pmb_net1 = create_mock_peer_manager_for_foreign_network("net1").await;
|
||||
tracing::debug!(
|
||||
"pma_net1: {:?}, pmb_net1: {:?}",
|
||||
pma_net1.my_peer_id(),
|
||||
pmb_net1.my_peer_id()
|
||||
);
|
||||
connect_peer_manager(pma_net1.clone(), pm_center.clone()).await;
|
||||
connect_peer_manager(pmb_net1.clone(), pm_center.clone()).await;
|
||||
wait_route_appear(pma_net1.clone(), pmb_net1.clone())
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(1, pma_net1.list_routes().await.len());
|
||||
assert_eq!(1, pmb_net1.list_routes().await.len());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[should_panic]
|
||||
async fn foreign_network_whitelist_fail() {
|
||||
|
||||
@@ -309,21 +309,6 @@ impl PeerManager {
|
||||
self.add_client_tunnel(t).await
|
||||
}
|
||||
|
||||
fn check_network_in_whitelist(&self, network_name: &str) -> Result<(), Error> {
|
||||
if self
|
||||
.global_ctx
|
||||
.get_flags()
|
||||
.foreign_network_whitelist
|
||||
.split(" ")
|
||||
.map(wildmatch::WildMatch::new)
|
||||
.any(|wl| wl.matches(network_name))
|
||||
{
|
||||
Ok(())
|
||||
} else {
|
||||
Err(anyhow::anyhow!("network {} not in whitelist", network_name).into())
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument]
|
||||
pub async fn add_tunnel_as_server(&self, tunnel: Box<dyn Tunnel>) -> Result<(), Error> {
|
||||
tracing::info!("add tunnel as server start");
|
||||
@@ -334,7 +319,6 @@ impl PeerManager {
|
||||
{
|
||||
self.add_new_peer_conn(peer).await?;
|
||||
} else {
|
||||
self.check_network_in_whitelist(&peer.get_network_identity().network_name)?;
|
||||
self.foreign_network_manager.add_peer_conn(peer).await?;
|
||||
}
|
||||
tracing::info!("add tunnel as server done");
|
||||
|
||||
@@ -205,7 +205,7 @@ impl FromUrl for SocketAddr {
|
||||
fn from_url(url: url::Url, ip_version: IpVersion) -> Result<Self, TunnelError> {
|
||||
let addrs = url.socket_addrs(|| None)?;
|
||||
tracing::debug!(?addrs, ?ip_version, ?url, "convert url to socket addrs");
|
||||
let mut addrs = addrs
|
||||
let addrs = addrs
|
||||
.into_iter()
|
||||
.filter(|addr| match ip_version {
|
||||
IpVersion::V4 => addr.is_ipv4(),
|
||||
@@ -213,7 +213,13 @@ impl FromUrl for SocketAddr {
|
||||
IpVersion::Both => true,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
addrs.pop().ok_or(TunnelError::NoDnsRecordFound(ip_version))
|
||||
|
||||
use rand::seq::SliceRandom;
|
||||
// randomly select one address
|
||||
addrs
|
||||
.choose(&mut rand::thread_rng())
|
||||
.copied()
|
||||
.ok_or(TunnelError::NoDnsRecordFound(ip_version))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,318 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This script copy from alist , Thank for it!
|
||||
|
||||
# INSTALL_PATH='/opt/easytier'
|
||||
VERSION='latest'
|
||||
|
||||
SKIP_FOLDER_VERIFY=false
|
||||
SKIP_FOLDER_FIX=false
|
||||
|
||||
COMMEND=$1
|
||||
shift
|
||||
|
||||
# Check path
|
||||
if [[ "$#" -ge 1 && ! "$1" == --* ]]; then
|
||||
INSTALL_PATH=$1
|
||||
shift
|
||||
fi
|
||||
|
||||
# Check other option
|
||||
while [[ "$#" -gt 0 ]]; do
|
||||
case $1 in
|
||||
--skip-folder-verify) SKIP_FOLDER_VERIFY=true ;;
|
||||
--skip-folder-fix) SKIP_FOLDER_FIX=true ;;
|
||||
*) echo "Unknown option: $1"; exit 1 ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [ -z "$INSTALL_PATH" ]; then
|
||||
INSTALL_PATH='/opt/easytier'
|
||||
fi
|
||||
|
||||
if [[ "$INSTALL_PATH" == */ ]]; then
|
||||
INSTALL_PATH=${INSTALL_PATH%?}
|
||||
fi
|
||||
|
||||
if ! $SKIP_FOLDER_FIX && ! [[ "$INSTALL_PATH" == */easytier ]]; then
|
||||
INSTALL_PATH="$INSTALL_PATH/easytier"
|
||||
fi
|
||||
|
||||
echo INSTALL PATH : $INSTALL_PATH
|
||||
echo SKIP FOLDER FIX : $SKIP_FOLDER_FIX
|
||||
echo SKIP FOLDER VERIFY : $SKIP_FOLDER_VERIFY
|
||||
|
||||
RED_COLOR='\e[1;31m'
|
||||
GREEN_COLOR='\e[1;32m'
|
||||
YELLOW_COLOR='\e[1;33m'
|
||||
BLUE_COLOR='\e[1;34m'
|
||||
PINK_COLOR='\e[1;35m'
|
||||
SHAN='\e[1;33;5m'
|
||||
RES='\e[0m'
|
||||
# clear
|
||||
|
||||
echo -e "\r\n${RED_COLOR}----------------------NOTICE----------------------${RES}\r\n"
|
||||
echo " This is a temporary script to install EasyTier "
|
||||
echo " EasyTier requires a dedicated empty folder to install"
|
||||
echo " EasyTier is a developing product and may have some issues "
|
||||
echo " Using EasyTier requires some basic skills "
|
||||
echo " You need to face the risks brought by using EasyTier at your own risk "
|
||||
echo -e "\r\n${RED_COLOR}-------------------------------------------------${RES}\r\n"
|
||||
|
||||
read -p "Enter \"yes\" to accept our policy and continue: " -r agreement
|
||||
if [[ ! "$agreement" =~ ^[Yy]es$ ]]
|
||||
then
|
||||
echo "You do not accept your policy, the script will exit ..."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get platform
|
||||
if command -v arch >/dev/null 2>&1; then
|
||||
platform=$(arch)
|
||||
else
|
||||
platform=$(uname -m)
|
||||
fi
|
||||
|
||||
case "$platform" in
|
||||
amd64 | x86_64)
|
||||
ARCH="x86_64"
|
||||
;;
|
||||
arm64 | aarch64 | *armv8*)
|
||||
ARCH="aarch64"
|
||||
;;
|
||||
*armv7*)
|
||||
ARCH="armv7"
|
||||
;;
|
||||
*arm*)
|
||||
ARCH="arm"
|
||||
;;
|
||||
mips)
|
||||
ARCH="mips"
|
||||
;;
|
||||
mipsel)
|
||||
ARCH="mipsel"
|
||||
;;
|
||||
*)
|
||||
ARCH="UNKNOWN"
|
||||
;;
|
||||
esac
|
||||
|
||||
# support hf
|
||||
if [[ "$ARCH" == "armv7" || "$ARCH" == "arm" ]]; then
|
||||
if cat /proc/cpuinfo | grep Features | grep -i 'half' >/dev/null 2>&1; then
|
||||
ARCH=${ARCH}hf
|
||||
fi
|
||||
fi
|
||||
|
||||
echo -e "\r\n${GREEN_COLOR}Your platform: ${ARCH} (${platform}) ${RES}\r\n" 1>&2
|
||||
|
||||
GH_PROXY='https://mirror.ghproxy.com/'
|
||||
|
||||
if [ "$(id -u)" != "0" ]; then
|
||||
echo -e "\r\n${RED_COLOR}This script requires run as Root !${RES}\r\n" 1>&2
|
||||
exit 1
|
||||
elif [ "$ARCH" == "UNKNOWN" ]; then
|
||||
echo -e "\r\n${RED_COLOR}Opus${RES}, this script do not support your platfrom\r\nTry ${GREEN_COLOR}install by band${RES}\r\n"
|
||||
exit 1
|
||||
elif ! command -v systemctl >/dev/null 2>&1; then
|
||||
echo -e "\r\n${RED_COLOR}Opus${RES}, your Linux do not support systemctl\r\nnTry ${GREEN_COLOR}install by band${RES}\r\n"
|
||||
exit 1
|
||||
else
|
||||
if command -v netstat >/dev/null 2>&1; then
|
||||
check_port=$(netstat -lnp | grep 11010 | awk '{print $7}' | awk -F/ '{print $1}')
|
||||
else
|
||||
echo -e "${GREEN_COLOR}Check port ...${RES}"
|
||||
if command -v yum >/dev/null 2>&1; then
|
||||
yum install net-tools -y >/dev/null 2>&1
|
||||
check_port=$(netstat -lnp | grep 11010 | awk '{print $7}' | awk -F/ '{print $1}')
|
||||
else
|
||||
apt-get update >/dev/null 2>&1
|
||||
apt-get install net-tools -y >/dev/null 2>&1
|
||||
check_port=$(netstat -lnp | grep 11010 | awk '{print $7}' | awk -F/ '{print $1}')
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
CHECK() {
|
||||
if ! $SKIP_FOLDER_VERIFY; then
|
||||
if [ -f "$INSTALL_PATH/easytier-core" ]; then
|
||||
echo "There is EasyTier in $INSTALL_PATH. Please choose other path or use \"update\""
|
||||
echo -e "Or use Try ${GREEN_COLOR}--skip-folder-verify${RES} to skip"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
if [ $check_port ]; then
|
||||
kill -9 $check_port
|
||||
fi
|
||||
if [ ! -d "$INSTALL_PATH/" ]; then
|
||||
mkdir -p $INSTALL_PATH
|
||||
else
|
||||
# Check weather path is empty
|
||||
if ! $SKIP_FOLDER_VERIFY; then
|
||||
if [ -n "$(ls -A $INSTALL_PATH)" ]; then
|
||||
echo "EasyTier requires to be installed in an empty directory. Please choose a empty path"
|
||||
echo -e "Or use Try ${GREEN_COLOR}--skip-folder-verify${RES} to skip"
|
||||
echo -e "Current path: $INSTALL_PATH ( use ${GREEN_COLOR}--skip-folder-fix${RES} to disable folder fix )"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
INSTALL() {
|
||||
# Get version number
|
||||
RESPONSE=$(curl -s "https://api.github.com/repos/EasyTier/EasyTier/releases/latest")
|
||||
LATEST_VERSION=$(echo "$RESPONSE" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
|
||||
LATEST_VERSION=$(echo -e "$LATEST_VERSION" | tr -d '[:space:]')
|
||||
|
||||
if [ -z "$LATEST_VERSION" ]; then
|
||||
echo -e "\r\n${RED_COLOR}Opus${RES}, failure to get latest version. Check your internel\r\nOr try ${GREEN_COLOR}install by band${RES}\r\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Download
|
||||
echo -e "\r\n${GREEN_COLOR}Downloading EasyTier $LATEST_VERSION ...${RES}"
|
||||
rm -rf /tmp/easytier_tmp_install.zip
|
||||
curl -L ${GH_PROXY}https://github.com/EasyTier/EasyTier/releases/latest/download/easytier-linux-${ARCH}-${LATEST_VERSION}.zip -o /tmp/easytier_tmp_install.zip $CURL_BAR
|
||||
# Unzip resource
|
||||
echo -e "\r\n${GREEN_COLOR}Unzip resource ...${RES}"
|
||||
unzip -o /tmp/easytier_tmp_install.zip -d $INSTALL_PATH/
|
||||
mv $INSTALL_PATH/easytier-linux-${ARCH}/* $INSTALL_PATH/
|
||||
rm -rf $INSTALL_PATH/easytier-linux-${ARCH}/
|
||||
if [ -f $INSTALL_PATH/easytier-core ] || [ -f $INSTALL_PATH/easytier-cli ]; then
|
||||
echo -e "${GREEN_COLOR} Download successfully! ${RES}"
|
||||
else
|
||||
echo -e "${RED_COLOR} Download failed! ${RES}"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
INIT() {
|
||||
if [ ! -f "$INSTALL_PATH/easytier-core" ]; then
|
||||
echo -e "\r\n${RED_COLOR}Opus${RES}, unable to find EasyTier\r\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create systemd
|
||||
cat >/etc/systemd/system/easytier.service <<EOF
|
||||
[Unit]
|
||||
Description=EasyTier Service
|
||||
Wants=network.target
|
||||
After=network.target network.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=$INSTALL_PATH
|
||||
ExecStart=/bin/bash $INSTALL_PATH/run.sh
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
# Create run script
|
||||
cat >$INSTALL_PATH/run.sh <<EOF
|
||||
$INSTALL_PATH/easytier-core
|
||||
EOF
|
||||
|
||||
# Startup
|
||||
systemctl daemon-reload
|
||||
systemctl enable easytier >/dev/null 2>&1
|
||||
systemctl start easytier
|
||||
|
||||
# For issues from the previous version
|
||||
rm -rf /usr/bin/easytier-core
|
||||
rm -rf /usr/bin/easytier-cli
|
||||
|
||||
# Add link
|
||||
ln -s $INSTALL_PATH/easytier-core /usr/sbin/easytier-core
|
||||
ln -s $INSTALL_PATH/easytier-cli /usr/sbin/easytier-cli
|
||||
}
|
||||
|
||||
SUCCESS() {
|
||||
clear
|
||||
echo " Install EasyTier successfully!"
|
||||
echo -e "\r\nDefault Port: ${GREEN_COLOR}11010(UDP+TCP)${RES}, Notice allowing in firewall!\r\n"
|
||||
|
||||
echo -e "Staartup script path: ${GREEN_COLOR}$INSTALL_PATH/run.sh${RES}\n\r\n\rFor more advanced opinions, please modify the startup script"
|
||||
|
||||
echo
|
||||
echo -e "Status: ${GREEN_COLOR}systemctl status easytier${RES}"
|
||||
echo -e "Start: ${GREEN_COLOR}systemctl start easytier${RES}"
|
||||
echo -e "Restart: ${GREEN_COLOR}systemctl restart easytier${RES}"
|
||||
echo -e "Stop: ${GREEN_COLOR}systemctl stop easytier${RES}"
|
||||
echo
|
||||
}
|
||||
|
||||
UNINSTALL() {
|
||||
echo -e "\r\n${GREEN_COLOR}Uninstall EasyTier ...${RES}\r\n"
|
||||
echo -e "${GREEN_COLOR}Stop process ...${RES}"
|
||||
systemctl disable easytier >/dev/null 2>&1
|
||||
systemctl stop easytier >/dev/null 2>&1
|
||||
echo -e "${GREEN_COLOR}Delete files ...${RES}"
|
||||
rm -rf $INSTALL_PATH /etc/systemd/system/easytier.service /usr/bin/easytier-core /usr/bin/easytier-cli
|
||||
systemctl daemon-reload
|
||||
echo -e "\r\n${GREEN_COLOR}EasyTier was removed successfully! ${RES}\r\n"
|
||||
}
|
||||
|
||||
UPDATE() {
|
||||
if [ ! -f "$INSTALL_PATH/easytier-core" ]; then
|
||||
echo -e "\r\n${RED_COLOR}Opus${RES}, unable to find EasyTier\r\n"
|
||||
exit 1
|
||||
else
|
||||
echo
|
||||
echo -e "${GREEN_COLOR}Stopping EasyTier process${RES}\r\n"
|
||||
systemctl stop easytier
|
||||
# Backup
|
||||
rm -rf /tmp/easytier_tmp_update
|
||||
mkdir -p /tmp/easytier_tmp_update
|
||||
cp -a $INSTALL_PATH/* /tmp/easytier_tmp_update/
|
||||
INSTALL
|
||||
if [ -f $INSTALL_PATH/easytier-core ]; then
|
||||
echo -e "${GREEN_COLOR} Vrify successfully ${RES}"
|
||||
else
|
||||
echo -e "${RED_COLOR} Download failed, unable to update${RES}"
|
||||
echo "Rollback all ..."
|
||||
rm -rf $INSTALL_PATH/*
|
||||
mv /tmp/easytier_tmp_update/* $INSTALL_PATH/
|
||||
systemctl start easytier
|
||||
exit 1
|
||||
fi
|
||||
echo -e "\r\n${GREEN_COLOR} Starting EasyTier process${RES}"
|
||||
systemctl start easytier
|
||||
echo -e "\r\n${GREEN_COLOR} EasyTier was the latest stable version! ${RES}\r\n"
|
||||
fi
|
||||
}
|
||||
|
||||
# CURL progress
|
||||
if curl --help | grep progress-bar >/dev/null 2>&1; then # $CURL_BAR
|
||||
CURL_BAR="--progress-bar"
|
||||
fi
|
||||
|
||||
# The temp directory must exist
|
||||
if [ ! -d "/tmp" ]; then
|
||||
mkdir -p /tmp
|
||||
fi
|
||||
|
||||
echo $COMMEND
|
||||
|
||||
if [ $COMMEND = "uninstall" ]; then
|
||||
UNINSTALL
|
||||
elif [ $COMMEND = "update" ]; then
|
||||
UPDATE
|
||||
elif [ $COMMEND = "install" ]; then
|
||||
CHECK
|
||||
INSTALL
|
||||
INIT
|
||||
if [ -f "$INSTALL_PATH/easytier-core" ]; then
|
||||
SUCCESS
|
||||
else
|
||||
echo -e "${RED_COLOR} Install fail, try install by hand${RES}"
|
||||
fi
|
||||
else
|
||||
echo -e "${RED_COLOR} Error Commend ${RES}\n\r"
|
||||
echo " ALLOW:"
|
||||
echo -e "\n\r${GREEN_COLOR} install, uninstall, update ${RES}"
|
||||
fi
|
||||
|
||||
rm -rf /tmp/easytier_tmp_*
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "tauri-plugin-vpnservice"
|
||||
version = "0.0.0"
|
||||
authors = [ "You" ]
|
||||
authors = ["You"]
|
||||
description = ""
|
||||
edition = "2021"
|
||||
rust-version = "1.70"
|
||||
@@ -9,9 +9,9 @@ exclude = ["/examples", "/webview-dist", "/webview-src", "/node_modules"]
|
||||
links = "tauri-plugin-vpnservice"
|
||||
|
||||
[dependencies]
|
||||
tauri = { version = "2.0.0-beta.23" }
|
||||
tauri = { version = "2.0.0-rc" }
|
||||
serde = "1.0"
|
||||
thiserror = "1.0"
|
||||
|
||||
[build-dependencies]
|
||||
tauri-plugin = { version = "2.0.0-beta.18", features = ["build"] }
|
||||
tauri-plugin = { version = "2.0.0-rc", features = ["build"] }
|
||||
|
||||
@@ -88,9 +88,9 @@ class TauriVpnService : VpnService() {
|
||||
builder.addDnsServer(dns)
|
||||
|
||||
for (route in routes) {
|
||||
val ipParts = ipv4Addr.split("/")
|
||||
val ipParts = route.split("/")
|
||||
if (ipParts.size != 2) throw IllegalArgumentException("Invalid IP addr string")
|
||||
builder.addAddress(ipParts[0], ipParts[1].toInt())
|
||||
builder.addRoute(ipParts[0], ipParts[1].toInt())
|
||||
}
|
||||
|
||||
for (app in disallowedApplications) {
|
||||
|
||||
@@ -22,12 +22,12 @@
|
||||
"pretest": "yarn build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": ">=2.0.0-beta.6"
|
||||
"@tauri-apps/api": "2.0.0-rc.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-typescript": "^11.1.6",
|
||||
"rollup": "^4.9.6",
|
||||
"typescript": "^5.3.3",
|
||||
"tslib": "^2.6.2"
|
||||
"rollup": "^4.20.0",
|
||||
"tslib": "^2.6.3",
|
||||
"typescript": "^5.5.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
Generated
+91
-91
@@ -9,21 +9,21 @@ importers:
|
||||
.:
|
||||
dependencies:
|
||||
'@tauri-apps/api':
|
||||
specifier: '>=2.0.0-beta.6'
|
||||
version: 2.0.0-beta.14
|
||||
specifier: 2.0.0-rc.0
|
||||
version: 2.0.0-rc.0
|
||||
devDependencies:
|
||||
'@rollup/plugin-typescript':
|
||||
specifier: ^11.1.6
|
||||
version: 11.1.6(rollup@4.18.1)(tslib@2.6.3)(typescript@5.5.3)
|
||||
version: 11.1.6(rollup@4.20.0)(tslib@2.6.3)(typescript@5.5.4)
|
||||
rollup:
|
||||
specifier: ^4.9.6
|
||||
version: 4.18.1
|
||||
specifier: ^4.20.0
|
||||
version: 4.20.0
|
||||
tslib:
|
||||
specifier: ^2.6.2
|
||||
specifier: ^2.6.3
|
||||
version: 2.6.3
|
||||
typescript:
|
||||
specifier: ^5.3.3
|
||||
version: 5.5.3
|
||||
specifier: ^5.5.4
|
||||
version: 5.5.4
|
||||
|
||||
packages:
|
||||
|
||||
@@ -49,88 +49,88 @@ packages:
|
||||
rollup:
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-android-arm-eabi@4.18.1':
|
||||
resolution: {integrity: sha512-lncuC4aHicncmbORnx+dUaAgzee9cm/PbIqgWz1PpXuwc+sa1Ct83tnqUDy/GFKleLiN7ZIeytM6KJ4cAn1SxA==}
|
||||
'@rollup/rollup-android-arm-eabi@4.20.0':
|
||||
resolution: {integrity: sha512-TSpWzflCc4VGAUJZlPpgAJE1+V60MePDQnBd7PPkpuEmOy8i87aL6tinFGKBFKuEDikYpig72QzdT3QPYIi+oA==}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@rollup/rollup-android-arm64@4.18.1':
|
||||
resolution: {integrity: sha512-F/tkdw0WSs4ojqz5Ovrw5r9odqzFjb5LIgHdHZG65dFI1lWTWRVy32KDJLKRISHgJvqUeUhdIvy43fX41znyDg==}
|
||||
'@rollup/rollup-android-arm64@4.20.0':
|
||||
resolution: {integrity: sha512-u00Ro/nok7oGzVuh/FMYfNoGqxU5CPWz1mxV85S2w9LxHR8OoMQBuSk+3BKVIDYgkpeOET5yXkx90OYFc+ytpQ==}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@rollup/rollup-darwin-arm64@4.18.1':
|
||||
resolution: {integrity: sha512-vk+ma8iC1ebje/ahpxpnrfVQJibTMyHdWpOGZ3JpQ7Mgn/3QNHmPq7YwjZbIE7km73dH5M1e6MRRsnEBW7v5CQ==}
|
||||
'@rollup/rollup-darwin-arm64@4.20.0':
|
||||
resolution: {integrity: sha512-uFVfvzvsdGtlSLuL0ZlvPJvl6ZmrH4CBwLGEFPe7hUmf7htGAN+aXo43R/V6LATyxlKVC/m6UsLb7jbG+LG39Q==}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@rollup/rollup-darwin-x64@4.18.1':
|
||||
resolution: {integrity: sha512-IgpzXKauRe1Tafcej9STjSSuG0Ghu/xGYH+qG6JwsAUxXrnkvNHcq/NL6nz1+jzvWAnQkuAJ4uIwGB48K9OCGA==}
|
||||
'@rollup/rollup-darwin-x64@4.20.0':
|
||||
resolution: {integrity: sha512-xbrMDdlev53vNXexEa6l0LffojxhqDTBeL+VUxuuIXys4x6xyvbKq5XqTXBCEUA8ty8iEJblHvFaWRJTk/icAQ==}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@rollup/rollup-linux-arm-gnueabihf@4.18.1':
|
||||
resolution: {integrity: sha512-P9bSiAUnSSM7EmyRK+e5wgpqai86QOSv8BwvkGjLwYuOpaeomiZWifEos517CwbG+aZl1T4clSE1YqqH2JRs+g==}
|
||||
'@rollup/rollup-linux-arm-gnueabihf@4.20.0':
|
||||
resolution: {integrity: sha512-jMYvxZwGmoHFBTbr12Xc6wOdc2xA5tF5F2q6t7Rcfab68TT0n+r7dgawD4qhPEvasDsVpQi+MgDzj2faOLsZjA==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.18.1':
|
||||
resolution: {integrity: sha512-5RnjpACoxtS+aWOI1dURKno11d7krfpGDEn19jI8BuWmSBbUC4ytIADfROM1FZrFhQPSoP+KEa3NlEScznBTyQ==}
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.20.0':
|
||||
resolution: {integrity: sha512-1asSTl4HKuIHIB1GcdFHNNZhxAYEdqML/MW4QmPS4G0ivbEcBr1JKlFLKsIRqjSwOBkdItn3/ZDlyvZ/N6KPlw==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-arm64-gnu@4.18.1':
|
||||
resolution: {integrity: sha512-8mwmGD668m8WaGbthrEYZ9CBmPug2QPGWxhJxh/vCgBjro5o96gL04WLlg5BA233OCWLqERy4YUzX3bJGXaJgQ==}
|
||||
'@rollup/rollup-linux-arm64-gnu@4.20.0':
|
||||
resolution: {integrity: sha512-COBb8Bkx56KldOYJfMf6wKeYJrtJ9vEgBRAOkfw6Ens0tnmzPqvlpjZiLgkhg6cA3DGzCmLmmd319pmHvKWWlQ==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.18.1':
|
||||
resolution: {integrity: sha512-dJX9u4r4bqInMGOAQoGYdwDP8lQiisWb9et+T84l2WXk41yEej8v2iGKodmdKimT8cTAYt0jFb+UEBxnPkbXEQ==}
|
||||
'@rollup/rollup-linux-arm64-musl@4.20.0':
|
||||
resolution: {integrity: sha512-+it+mBSyMslVQa8wSPvBx53fYuZK/oLTu5RJoXogjk6x7Q7sz1GNRsXWjn6SwyJm8E/oMjNVwPhmNdIjwP135Q==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-powerpc64le-gnu@4.18.1':
|
||||
resolution: {integrity: sha512-V72cXdTl4EI0x6FNmho4D502sy7ed+LuVW6Ym8aI6DRQ9hQZdp5sj0a2usYOlqvFBNKQnLQGwmYnujo2HvjCxQ==}
|
||||
'@rollup/rollup-linux-powerpc64le-gnu@4.20.0':
|
||||
resolution: {integrity: sha512-yAMvqhPfGKsAxHN8I4+jE0CpLWD8cv4z7CK7BMmhjDuz606Q2tFKkWRY8bHR9JQXYcoLfopo5TTqzxgPUjUMfw==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.18.1':
|
||||
resolution: {integrity: sha512-f+pJih7sxoKmbjghrM2RkWo2WHUW8UbfxIQiWo5yeCaCM0TveMEuAzKJte4QskBp1TIinpnRcxkquY+4WuY/tg==}
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.20.0':
|
||||
resolution: {integrity: sha512-qmuxFpfmi/2SUkAw95TtNq/w/I7Gpjurx609OOOV7U4vhvUhBcftcmXwl3rqAek+ADBwSjIC4IVNLiszoj3dPA==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-s390x-gnu@4.18.1':
|
||||
resolution: {integrity: sha512-qb1hMMT3Fr/Qz1OKovCuUM11MUNLUuHeBC2DPPAWUYYUAOFWaxInaTwTQmc7Fl5La7DShTEpmYwgdt2hG+4TEg==}
|
||||
'@rollup/rollup-linux-s390x-gnu@4.20.0':
|
||||
resolution: {integrity: sha512-I0BtGXddHSHjV1mqTNkgUZLnS3WtsqebAXv11D5BZE/gfw5KoyXSAXVqyJximQXNvNzUo4GKlCK/dIwXlz+jlg==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-x64-gnu@4.18.1':
|
||||
resolution: {integrity: sha512-7O5u/p6oKUFYjRbZkL2FLbwsyoJAjyeXHCU3O4ndvzg2OFO2GinFPSJFGbiwFDaCFc+k7gs9CF243PwdPQFh5g==}
|
||||
'@rollup/rollup-linux-x64-gnu@4.20.0':
|
||||
resolution: {integrity: sha512-y+eoL2I3iphUg9tN9GB6ku1FA8kOfmF4oUEWhztDJ4KXJy1agk/9+pejOuZkNFhRwHAOxMsBPLbXPd6mJiCwew==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.18.1':
|
||||
resolution: {integrity: sha512-pDLkYITdYrH/9Cv/Vlj8HppDuLMDUBmgsM0+N+xLtFd18aXgM9Nyqupb/Uw+HeidhfYg2lD6CXvz6CjoVOaKjQ==}
|
||||
'@rollup/rollup-linux-x64-musl@4.20.0':
|
||||
resolution: {integrity: sha512-hM3nhW40kBNYUkZb/r9k2FKK+/MnKglX7UYd4ZUy5DJs8/sMsIbqWK2piZtVGE3kcXVNj3B2IrUYROJMMCikNg==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-win32-arm64-msvc@4.18.1':
|
||||
resolution: {integrity: sha512-W2ZNI323O/8pJdBGil1oCauuCzmVd9lDmWBBqxYZcOqWD6aWqJtVBQ1dFrF4dYpZPks6F+xCZHfzG5hYlSHZ6g==}
|
||||
'@rollup/rollup-win32-arm64-msvc@4.20.0':
|
||||
resolution: {integrity: sha512-psegMvP+Ik/Bg7QRJbv8w8PAytPA7Uo8fpFjXyCRHWm6Nt42L+JtoqH8eDQ5hRP7/XW2UiIriy1Z46jf0Oa1kA==}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@rollup/rollup-win32-ia32-msvc@4.18.1':
|
||||
resolution: {integrity: sha512-ELfEX1/+eGZYMaCIbK4jqLxO1gyTSOIlZr6pbC4SRYFaSIDVKOnZNMdoZ+ON0mrFDp4+H5MhwNC1H/AhE3zQLg==}
|
||||
'@rollup/rollup-win32-ia32-msvc@4.20.0':
|
||||
resolution: {integrity: sha512-GabekH3w4lgAJpVxkk7hUzUf2hICSQO0a/BLFA11/RMxQT92MabKAqyubzDZmMOC/hcJNlc+rrypzNzYl4Dx7A==}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@rollup/rollup-win32-x64-msvc@4.18.1':
|
||||
resolution: {integrity: sha512-yjk2MAkQmoaPYCSu35RLJ62+dz358nE83VfTePJRp8CG7aMg25mEJYpXFiD+NcevhX8LxD5OP5tktPXnXN7GDw==}
|
||||
'@rollup/rollup-win32-x64-msvc@4.20.0':
|
||||
resolution: {integrity: sha512-aJ1EJSuTdGnM6qbVC4B5DSmozPTqIag9fSzXRNNo+humQLG89XpPgdt16Ia56ORD7s+H8Pmyx44uczDQ0yDzpg==}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@tauri-apps/api@2.0.0-beta.14':
|
||||
resolution: {integrity: sha512-YLYgHqdwWswr4Y70+hRzaLD6kLIUgHhE3shLXNquPiTaQ9+cX3Q2dB0AFfqsua6NXYFNe7LfkmMzaqEzqv3yQg==}
|
||||
'@tauri-apps/api@2.0.0-rc.0':
|
||||
resolution: {integrity: sha512-v454Qs3REHc3Za59U+/eSmBsdmF+3NE5+76+lFDaitVqN4ZglDHENDaMARYKGJVZuxiSkzyqG0SeG7lLQjVkPA==}
|
||||
engines: {node: '>= 18.18', npm: '>= 6.6.0', yarn: '>= 1.19.1'}
|
||||
|
||||
'@types/estree@1.0.5':
|
||||
@@ -151,8 +151,8 @@ packages:
|
||||
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-core-module@2.14.0:
|
||||
resolution: {integrity: sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==}
|
||||
is-core-module@2.15.0:
|
||||
resolution: {integrity: sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
path-parse@1.0.7:
|
||||
@@ -166,8 +166,8 @@ packages:
|
||||
resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==}
|
||||
hasBin: true
|
||||
|
||||
rollup@4.18.1:
|
||||
resolution: {integrity: sha512-Elx2UT8lzxxOXMpy5HWQGZqkrQOtrVDDa/bm9l10+U4rQnVzbL/LgZ4NOM1MPIDyHk69W4InuYDF5dzRh4Kw1A==}
|
||||
rollup@4.20.0:
|
||||
resolution: {integrity: sha512-6rbWBChcnSGzIlXeIdNIZTopKYad8ZG8ajhl78lGRLsI2rX8IkaotQhVas2Ma+GPxJav19wrSzvRvuiv0YKzWw==}
|
||||
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
|
||||
hasBin: true
|
||||
|
||||
@@ -178,79 +178,79 @@ packages:
|
||||
tslib@2.6.3:
|
||||
resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==}
|
||||
|
||||
typescript@5.5.3:
|
||||
resolution: {integrity: sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==}
|
||||
typescript@5.5.4:
|
||||
resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==}
|
||||
engines: {node: '>=14.17'}
|
||||
hasBin: true
|
||||
|
||||
snapshots:
|
||||
|
||||
'@rollup/plugin-typescript@11.1.6(rollup@4.18.1)(tslib@2.6.3)(typescript@5.5.3)':
|
||||
'@rollup/plugin-typescript@11.1.6(rollup@4.20.0)(tslib@2.6.3)(typescript@5.5.4)':
|
||||
dependencies:
|
||||
'@rollup/pluginutils': 5.1.0(rollup@4.18.1)
|
||||
'@rollup/pluginutils': 5.1.0(rollup@4.20.0)
|
||||
resolve: 1.22.8
|
||||
typescript: 5.5.3
|
||||
typescript: 5.5.4
|
||||
optionalDependencies:
|
||||
rollup: 4.18.1
|
||||
rollup: 4.20.0
|
||||
tslib: 2.6.3
|
||||
|
||||
'@rollup/pluginutils@5.1.0(rollup@4.18.1)':
|
||||
'@rollup/pluginutils@5.1.0(rollup@4.20.0)':
|
||||
dependencies:
|
||||
'@types/estree': 1.0.5
|
||||
estree-walker: 2.0.2
|
||||
picomatch: 2.3.1
|
||||
optionalDependencies:
|
||||
rollup: 4.18.1
|
||||
rollup: 4.20.0
|
||||
|
||||
'@rollup/rollup-android-arm-eabi@4.18.1':
|
||||
'@rollup/rollup-android-arm-eabi@4.20.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-android-arm64@4.18.1':
|
||||
'@rollup/rollup-android-arm64@4.20.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-darwin-arm64@4.18.1':
|
||||
'@rollup/rollup-darwin-arm64@4.20.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-darwin-x64@4.18.1':
|
||||
'@rollup/rollup-darwin-x64@4.20.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm-gnueabihf@4.18.1':
|
||||
'@rollup/rollup-linux-arm-gnueabihf@4.20.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.18.1':
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.20.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm64-gnu@4.18.1':
|
||||
'@rollup/rollup-linux-arm64-gnu@4.20.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.18.1':
|
||||
'@rollup/rollup-linux-arm64-musl@4.20.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-powerpc64le-gnu@4.18.1':
|
||||
'@rollup/rollup-linux-powerpc64le-gnu@4.20.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.18.1':
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.20.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-s390x-gnu@4.18.1':
|
||||
'@rollup/rollup-linux-s390x-gnu@4.20.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-x64-gnu@4.18.1':
|
||||
'@rollup/rollup-linux-x64-gnu@4.20.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.18.1':
|
||||
'@rollup/rollup-linux-x64-musl@4.20.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-arm64-msvc@4.18.1':
|
||||
'@rollup/rollup-win32-arm64-msvc@4.20.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-ia32-msvc@4.18.1':
|
||||
'@rollup/rollup-win32-ia32-msvc@4.20.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-x64-msvc@4.18.1':
|
||||
'@rollup/rollup-win32-x64-msvc@4.20.0':
|
||||
optional: true
|
||||
|
||||
'@tauri-apps/api@2.0.0-beta.14': {}
|
||||
'@tauri-apps/api@2.0.0-rc.0': {}
|
||||
|
||||
'@types/estree@1.0.5': {}
|
||||
|
||||
@@ -265,7 +265,7 @@ snapshots:
|
||||
dependencies:
|
||||
function-bind: 1.1.2
|
||||
|
||||
is-core-module@2.14.0:
|
||||
is-core-module@2.15.0:
|
||||
dependencies:
|
||||
hasown: 2.0.2
|
||||
|
||||
@@ -275,34 +275,34 @@ snapshots:
|
||||
|
||||
resolve@1.22.8:
|
||||
dependencies:
|
||||
is-core-module: 2.14.0
|
||||
is-core-module: 2.15.0
|
||||
path-parse: 1.0.7
|
||||
supports-preserve-symlinks-flag: 1.0.0
|
||||
|
||||
rollup@4.18.1:
|
||||
rollup@4.20.0:
|
||||
dependencies:
|
||||
'@types/estree': 1.0.5
|
||||
optionalDependencies:
|
||||
'@rollup/rollup-android-arm-eabi': 4.18.1
|
||||
'@rollup/rollup-android-arm64': 4.18.1
|
||||
'@rollup/rollup-darwin-arm64': 4.18.1
|
||||
'@rollup/rollup-darwin-x64': 4.18.1
|
||||
'@rollup/rollup-linux-arm-gnueabihf': 4.18.1
|
||||
'@rollup/rollup-linux-arm-musleabihf': 4.18.1
|
||||
'@rollup/rollup-linux-arm64-gnu': 4.18.1
|
||||
'@rollup/rollup-linux-arm64-musl': 4.18.1
|
||||
'@rollup/rollup-linux-powerpc64le-gnu': 4.18.1
|
||||
'@rollup/rollup-linux-riscv64-gnu': 4.18.1
|
||||
'@rollup/rollup-linux-s390x-gnu': 4.18.1
|
||||
'@rollup/rollup-linux-x64-gnu': 4.18.1
|
||||
'@rollup/rollup-linux-x64-musl': 4.18.1
|
||||
'@rollup/rollup-win32-arm64-msvc': 4.18.1
|
||||
'@rollup/rollup-win32-ia32-msvc': 4.18.1
|
||||
'@rollup/rollup-win32-x64-msvc': 4.18.1
|
||||
'@rollup/rollup-android-arm-eabi': 4.20.0
|
||||
'@rollup/rollup-android-arm64': 4.20.0
|
||||
'@rollup/rollup-darwin-arm64': 4.20.0
|
||||
'@rollup/rollup-darwin-x64': 4.20.0
|
||||
'@rollup/rollup-linux-arm-gnueabihf': 4.20.0
|
||||
'@rollup/rollup-linux-arm-musleabihf': 4.20.0
|
||||
'@rollup/rollup-linux-arm64-gnu': 4.20.0
|
||||
'@rollup/rollup-linux-arm64-musl': 4.20.0
|
||||
'@rollup/rollup-linux-powerpc64le-gnu': 4.20.0
|
||||
'@rollup/rollup-linux-riscv64-gnu': 4.20.0
|
||||
'@rollup/rollup-linux-s390x-gnu': 4.20.0
|
||||
'@rollup/rollup-linux-x64-gnu': 4.20.0
|
||||
'@rollup/rollup-linux-x64-musl': 4.20.0
|
||||
'@rollup/rollup-win32-arm64-msvc': 4.20.0
|
||||
'@rollup/rollup-win32-ia32-msvc': 4.20.0
|
||||
'@rollup/rollup-win32-x64-msvc': 4.20.0
|
||||
fsevents: 2.3.3
|
||||
|
||||
supports-preserve-symlinks-flag@1.0.0: {}
|
||||
|
||||
tslib@2.6.3: {}
|
||||
|
||||
typescript@5.5.3: {}
|
||||
typescript@5.5.4: {}
|
||||
|
||||
Reference in New Issue
Block a user