Update On Wed Dec 10 19:41:24 CET 2025

This commit is contained in:
github-action[bot]
2025-12-10 19:41:25 +01:00
parent 970b3e529a
commit 616e2d9bd9
93 changed files with 1117 additions and 779 deletions

1
.github/update.log vendored
View File

@@ -1207,3 +1207,4 @@ Update On Sat Dec 6 19:36:39 CET 2025
Update On Sun Dec 7 19:36:46 CET 2025
Update On Mon Dec 8 19:42:31 CET 2025
Update On Tue Dec 9 19:39:21 CET 2025
Update On Wed Dec 10 19:41:17 CET 2025

View File

@@ -30,6 +30,7 @@ type SudokuOption struct {
TableType string `proxy:"table-type,omitempty"` // "prefer_ascii" or "prefer_entropy"
EnablePureDownlink *bool `proxy:"enable-pure-downlink,omitempty"`
HTTPMask bool `proxy:"http-mask,omitempty"`
CustomTable string `proxy:"custom-table,omitempty"` // optional custom byte layout, e.g. xpxvvpvv
}
// DialContext implements C.ProxyAdapter
@@ -178,13 +179,17 @@ func NewSudoku(option SudokuOption) (*Sudoku, error) {
ServerAddress: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)),
Key: option.Key,
AEADMethod: defaultConf.AEADMethod,
Table: sudoku.NewTable(sudoku.ClientAEADSeed(option.Key), tableType),
PaddingMin: paddingMin,
PaddingMax: paddingMax,
EnablePureDownlink: enablePureDownlink,
HandshakeTimeoutSeconds: defaultConf.HandshakeTimeoutSeconds,
DisableHTTPMask: !option.HTTPMask,
}
table, err := sudoku.NewTableWithCustom(sudoku.ClientAEADSeed(option.Key), tableType, option.CustomTable)
if err != nil {
return nil, fmt.Errorf("build table failed: %w", err)
}
baseConf.Table = table
if option.AEADMethod != "" {
baseConf.AEADMethod = option.AEADMethod
}

View File

@@ -609,6 +609,13 @@ func (w *WireGuard) ResolveUDP(ctx context.Context, metadata *C.Metadata) error
return nil
}
// ProxyInfo implements C.ProxyAdapter
func (w *WireGuard) ProxyInfo() C.ProxyInfo {
info := w.Base.ProxyInfo()
info.DialerProxy = w.option.DialerProxy
return info
}
// IsL3Protocol implements C.ProxyAdapter
func (w *WireGuard) IsL3Protocol(metadata *C.Metadata) bool {
return true

View File

@@ -8,6 +8,7 @@ import (
"reflect"
"runtime"
"strings"
"sync"
"time"
"github.com/metacubex/mihomo/adapter"
@@ -43,6 +44,7 @@ type providerForApi struct {
}
type baseProvider struct {
mutex sync.RWMutex
name string
proxies []C.Proxy
healthCheck *HealthCheck
@@ -54,6 +56,8 @@ func (bp *baseProvider) Name() string {
}
func (bp *baseProvider) Version() uint32 {
bp.mutex.RLock()
defer bp.mutex.RUnlock()
return bp.version
}
@@ -73,10 +77,14 @@ func (bp *baseProvider) Type() P.ProviderType {
}
func (bp *baseProvider) Proxies() []C.Proxy {
bp.mutex.RLock()
defer bp.mutex.RUnlock()
return bp.proxies
}
func (bp *baseProvider) Count() int {
bp.mutex.RLock()
defer bp.mutex.RUnlock()
return len(bp.proxies)
}
@@ -93,6 +101,8 @@ func (bp *baseProvider) RegisterHealthCheckTask(url string, expectedStatus utils
}
func (bp *baseProvider) setProxies(proxies []C.Proxy) {
bp.mutex.Lock()
defer bp.mutex.Unlock()
bp.proxies = proxies
bp.version += 1
bp.healthCheck.setProxies(proxies)

View File

@@ -1048,8 +1048,9 @@ proxies: # socks5
padding-min: 2 # 最小填充字节数
padding-max: 7 # 最大填充字节数
table-type: prefer_ascii # 可选值prefer_ascii、prefer_entropy 前者全ascii映射后者保证熵值汉明1低于3
# custom-table: xpxvvpvv # 可选自定义字节布局必须包含2个x、2个p、4个v可随意组合。启用此处则无需配置`table-type`
http-mask: true # 是否启用http掩码
enable-pure-downlink: false # 是否启用混淆下行false的情况下能在保证数据安全的前提下极大提升下行速度
enable-pure-downlink: false # 是否启用混淆下行false的情况下能在保证数据安全的前提下极大提升下行速度,与服务端端保持相同(如果此处为false则要求aead不可为none)
# anytls
- name: anytls
@@ -1589,8 +1590,9 @@ listeners:
padding-min: 1 # 填充最小长度
padding-max: 15 # 填充最大长度,均不建议过大
table-type: prefer_ascii # 可选值prefer_ascii、prefer_entropy 前者全ascii映射后者保证熵值汉明1低于3
# custom-table: xpxvvpvv # 可选自定义字节布局必须包含2个x、2个p、4个v
handshake-timeout: 5 # optional
enable-pure-downlink: false # 是否启用混淆下行false的情况下能在保证数据安全的前提下极大提升下行速度与客户端保持相同
enable-pure-downlink: false # 是否启用混淆下行false的情况下能在保证数据安全的前提下极大提升下行速度与客户端保持相同(如果此处为false则要求aead不可为none)
@@ -1742,4 +1744,3 @@ listeners:
# alpn:
# - h3
# max-udp-relay-packet-size: 1500

View File

@@ -43,7 +43,7 @@ require (
github.com/mroth/weightedrand/v2 v2.1.0
github.com/openacid/low v0.1.21
github.com/oschwald/maxminddb-golang v1.12.0 // lastest version compatible with golang1.20
github.com/saba-futai/sudoku v0.0.2-b
github.com/saba-futai/sudoku v0.0.2-c
github.com/sagernet/cors v1.2.1
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a
github.com/samber/lo v1.52.0

View File

@@ -171,8 +171,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
github.com/saba-futai/sudoku v0.0.2-b h1:IbBjgZe1IzzD4xjaCSAdAy8ZNrwOusT14AwCYm77NwI=
github.com/saba-futai/sudoku v0.0.2-b/go.mod h1:Rvggsoprp7HQM7bMIZUd1M27bPj8THRsZdY1dGbIAvo=
github.com/saba-futai/sudoku v0.0.2-c h1:0CaoCKx4Br8UL97fnIxn8Y7rnQpflBza7kfaIrdg2rI=
github.com/saba-futai/sudoku v0.0.2-c/go.mod h1:Rvggsoprp7HQM7bMIZUd1M27bPj8THRsZdY1dGbIAvo=
github.com/sagernet/cors v1.2.1 h1:Cv5Z8y9YSD6Gm+qSpNrL3LO4lD3eQVvbFYJSG7JCMHQ=
github.com/sagernet/cors v1.2.1/go.mod h1:O64VyOjjhrkLmQIjF4KGRrJO/5dVXFdpEmCW/eISRAI=
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZNjr6sGeT00J8uU7JF4cNUdb44/Duis=

View File

@@ -14,6 +14,7 @@ type SudokuServer struct {
TableType string `json:"table-type,omitempty"`
HandshakeTimeoutSecond *int `json:"handshake-timeout,omitempty"`
EnablePureDownlink *bool `json:"enable-pure-downlink,omitempty"`
CustomTable string `json:"custom-table,omitempty"`
}
func (s SudokuServer) String() string {

View File

@@ -20,6 +20,7 @@ type SudokuOption struct {
TableType string `inbound:"table-type,omitempty"` // "prefer_ascii" or "prefer_entropy"
HandshakeTimeoutSecond *int `inbound:"handshake-timeout,omitempty"`
EnablePureDownlink *bool `inbound:"enable-pure-downlink,omitempty"`
CustomTable string `inbound:"custom-table,omitempty"` // optional custom byte layout, e.g. xpxvvpvv
}
func (o SudokuOption) Equal(config C.InboundConfig) bool {
@@ -52,6 +53,7 @@ func NewSudoku(options *SudokuOption) (*Sudoku, error) {
TableType: options.TableType,
HandshakeTimeoutSecond: options.HandshakeTimeoutSecond,
EnablePureDownlink: options.EnablePureDownlink,
CustomTable: options.CustomTable,
}
return &Sudoku{

View File

@@ -138,3 +138,27 @@ func TestInboundSudoku_PackedDownlink(t *testing.T) {
testInboundSudoku(t, inboundOptions, outboundOptions)
})
}
func TestInboundSudoku_CustomTable(t *testing.T) {
key := "test_key_custom"
custom := "xpxvvpvv"
inboundOptions := inbound.SudokuOption{
Key: key,
TableType: "prefer_entropy",
CustomTable: custom,
}
outboundOptions := outbound.SudokuOption{
Key: key,
TableType: "prefer_entropy",
CustomTable: custom,
}
testInboundSudoku(t, inboundOptions, outboundOptions)
t.Run("ed25519key", func(t *testing.T) {
inboundOptions := inboundOptions
outboundOptions := outboundOptions
inboundOptions.Key = sudokuPublicKey
outboundOptions.Key = sudokuPrivateKey
testInboundSudoku(t, inboundOptions, outboundOptions)
})
}

View File

@@ -152,6 +152,12 @@ func New(config LC.SudokuServer, tunnel C.Tunnel, additions ...inbound.Addition)
enablePureDownlink = *config.EnablePureDownlink
}
table, err := sudoku.NewTableWithCustom(config.Key, tableType, config.CustomTable)
if err != nil {
_ = l.Close()
return nil, err
}
handshakeTimeout := defaultConf.HandshakeTimeoutSeconds
if config.HandshakeTimeoutSecond != nil {
handshakeTimeout = *config.HandshakeTimeoutSecond
@@ -160,7 +166,7 @@ func New(config LC.SudokuServer, tunnel C.Tunnel, additions ...inbound.Addition)
protoConf := sudoku.ProtocolConfig{
Key: config.Key,
AEADMethod: defaultConf.AEADMethod,
Table: sudoku.NewTable(config.Key, tableType),
Table: table,
PaddingMin: paddingMin,
PaddingMax: paddingMax,
EnablePureDownlink: enablePureDownlink,

View File

@@ -146,12 +146,23 @@ func buildHandshakePayload(key string) [16]byte {
}
func NewTable(key string, tableType string) *sudoku.Table {
start := time.Now()
table := sudoku.NewTable(key, tableType)
log.Infoln("[Sudoku] Tables initialized (%s) in %v", tableType, time.Since(start))
table, err := NewTableWithCustom(key, tableType, "")
if err != nil {
panic(fmt.Sprintf("[Sudoku] failed to init tables: %v", err))
}
return table
}
func NewTableWithCustom(key string, tableType string, customTable string) (*sudoku.Table, error) {
start := time.Now()
table, err := sudoku.NewTableWithCustom(key, tableType, customTable)
if err != nil {
return nil, err
}
log.Infoln("[Sudoku] Tables initialized (%s, custom=%v) in %v", tableType, customTable != "", time.Since(start))
return table, nil
}
func ClientAEADSeed(key string) string {
if recovered, err := crypto.RecoverPublicKey(key); err == nil {
return crypto.EncodePoint(recovered)

View File

@@ -228,3 +228,22 @@ func runPackedUoTSession(id int, cfg *apis.ProtocolConfig, errCh chan<- error) {
return
}
}
func TestCustomTableHandshake(t *testing.T) {
table, err := sudokuobfs.NewTableWithCustom("custom-seed", "prefer_entropy", "xpxvvpvv")
if err != nil {
t.Fatalf("build custom table: %v", err)
}
cfg := newPackedConfig(table)
errCh := make(chan error, 2)
runPackedTCPSession(42, cfg, errCh)
runPackedUoTSession(43, cfg, errCh)
close(errCh)
for err := range errCh {
if err != nil {
t.Fatalf("custom table handshake failed: %v", err)
}
}
}

View File

@@ -3,9 +3,9 @@
"latest": {
"mihomo": "v1.19.17",
"mihomo_alpha": "alpha-17b8eb8",
"clash_rs": "v0.9.2",
"clash_rs": "v0.9.3",
"clash_premium": "2023-09-05-gdcc8d87",
"clash_rs_alpha": "0.9.2-alpha+sha.c9fe9e2"
"clash_rs_alpha": "0.9.3-alpha+sha.a6538ac"
},
"arch_template": {
"mihomo": {
@@ -69,5 +69,5 @@
"linux-armv7hf": "clash-armv7-unknown-linux-gnueabihf"
}
},
"updated_at": "2025-12-08T22:21:34.201Z"
"updated_at": "2025-12-09T22:21:41.769Z"
}

View File

@@ -1,4 +1,4 @@
FROM ghcr.io/linuxserver/baseimage-alpine:3.22
FROM ghcr.io/linuxserver/baseimage-alpine:3.23
RUN apk update && \
apk --no-cache add ca-certificates mailcap jq libcap

View File

@@ -71,5 +71,5 @@
"vite-plugin-compression2": "^2.3.1",
"vue-tsc": "^3.1.3"
},
"packageManager": "pnpm@10.24.0+sha512.01ff8ae71b4419903b65c60fb2dc9d34cf8bb6e06d03bde112ef38f7a34d6904c424ba66bea5cdcf12890230bf39f9580473140ed9c946fef328b6e5238a345a"
"packageManager": "pnpm@10.25.0+sha512.5e82639027af37cf832061bcc6d639c219634488e0f2baebe785028a793de7b525ffcd3f7ff574f5e9860654e098fe852ba8ac5dd5cefe1767d23a020a92f501"
}

View File

@@ -25,7 +25,7 @@ importers:
version: 1.11.19
dompurify:
specifier: ^3.2.6
version: 3.3.0
version: 3.3.1
epubjs:
specifier: ^0.3.93
version: 0.3.93
@@ -107,16 +107,16 @@ importers:
version: 4.17.12
'@types/node':
specifier: ^24.10.1
version: 24.10.1
version: 24.10.2
'@typescript-eslint/eslint-plugin':
specifier: ^8.37.0
version: 8.48.1(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)
version: 8.49.0(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)
'@vitejs/plugin-legacy':
specifier: ^7.2.1
version: 7.2.1(terser@5.44.1)(vite@7.2.6(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0))
version: 7.2.1(terser@5.44.1)(vite@7.2.7(@types/node@24.10.2)(terser@5.44.1)(yaml@2.7.0))
'@vitejs/plugin-vue':
specifier: ^6.0.1
version: 6.0.2(vite@7.2.6(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0))(vue@3.5.25(typescript@5.9.3))
version: 6.0.2(vite@7.2.7(@types/node@24.10.2)(terser@5.44.1)(yaml@2.7.0))(vue@3.5.25(typescript@5.9.3))
'@vue/eslint-config-prettier':
specifier: ^10.2.0
version: 10.2.0(eslint@9.39.1)(prettier@3.7.4)
@@ -155,13 +155,13 @@ importers:
version: 5.9.3
vite:
specifier: ^7.2.2
version: 7.2.6(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0)
version: 7.2.7(@types/node@24.10.2)(terser@5.44.1)(yaml@2.7.0)
vite-plugin-compression2:
specifier: ^2.3.1
version: 2.3.1(rollup@4.53.3)
version: 2.4.0(rollup@4.53.3)
vue-tsc:
specifier: ^3.1.3
version: 3.1.5(typescript@5.9.3)
version: 3.1.8(typescript@5.9.3)
packages:
@@ -1110,8 +1110,8 @@ packages:
'@types/lodash@4.17.13':
resolution: {integrity: sha512-lfx+dftrEZcdBPczf9d0Qv0x+j/rfNCMuC6OcfXmO8gkfeNAY88PgKUbvG56whcN23gc27yenwF6oJZXGFpYxg==}
'@types/node@24.10.1':
resolution: {integrity: sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==}
'@types/node@24.10.2':
resolution: {integrity: sha512-WOhQTZ4G8xZ1tjJTvKOpyEVSGgOTvJAfDK3FNFgELyaTpzhdgHVHeqW8V+UJvzF5BT+/B54T/1S2K6gd9c7bbA==}
'@types/trusted-types@2.0.7':
resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==}
@@ -1127,11 +1127,11 @@ packages:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.9.0'
'@typescript-eslint/eslint-plugin@8.48.1':
resolution: {integrity: sha512-X63hI1bxl5ohelzr0LY5coufyl0LJNthld+abwxpCoo6Gq+hSqhKwci7MUWkXo67mzgUK6YFByhmaHmUcuBJmA==}
'@typescript-eslint/eslint-plugin@8.49.0':
resolution: {integrity: sha512-JXij0vzIaTtCwu6SxTh8qBc66kmf1xs7pI4UOiMDFVct6q86G0Zs7KRcEoJgY3Cav3x5Tq0MF5jwgpgLqgKG3A==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
'@typescript-eslint/parser': ^8.48.1
'@typescript-eslint/parser': ^8.49.0
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <6.0.0'
@@ -1154,8 +1154,8 @@ packages:
peerDependencies:
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/project-service@8.48.1':
resolution: {integrity: sha512-HQWSicah4s9z2/HifRPQ6b6R7G+SBx64JlFQpgSSHWPKdvCZX57XCbszg/bapbRsOEv42q5tayTYcEFpACcX1w==}
'@typescript-eslint/project-service@8.49.0':
resolution: {integrity: sha512-/wJN0/DKkmRUMXjZUXYZpD1NEQzQAAn9QWfGwo+Ai8gnzqH7tvqS7oNVdTjKqOcPyVIdZdyCMoqN66Ia789e7g==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <6.0.0'
@@ -1168,8 +1168,8 @@ packages:
resolution: {integrity: sha512-tMDbLGXb1wC+McN1M6QeDx7P7c0UWO5z9CXqp7J8E+xGcJuUuevWKxuG8j41FoweS3+L41SkyKKkia16jpX7CA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/scope-manager@8.48.1':
resolution: {integrity: sha512-rj4vWQsytQbLxC5Bf4XwZ0/CKd362DkWMUkviT7DCS057SK64D5lH74sSGzhI6PDD2HCEq02xAP9cX68dYyg1w==}
'@typescript-eslint/scope-manager@8.49.0':
resolution: {integrity: sha512-npgS3zi+/30KSOkXNs0LQXtsg9ekZ8OISAOLGWA/ZOEn0ZH74Ginfl7foziV8DT+D98WfQ5Kopwqb/PZOaIJGg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/tsconfig-utils@8.37.0':
@@ -1184,8 +1184,8 @@ packages:
peerDependencies:
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/tsconfig-utils@8.48.1':
resolution: {integrity: sha512-k0Jhs4CpEffIBm6wPaCXBAD7jxBtrHjrSgtfCjUvPp9AZ78lXKdTR8fxyZO5y4vWNlOvYXRtngSZNSn+H53Jkw==}
'@typescript-eslint/tsconfig-utils@8.49.0':
resolution: {integrity: sha512-8prixNi1/6nawsRYxet4YOhnbW+W9FK/bQPxsGB1D3ZrDzbJ5FXw5XmzxZv82X3B+ZccuSxo/X8q9nQ+mFecWA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <6.0.0'
@@ -1197,8 +1197,8 @@ packages:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.9.0'
'@typescript-eslint/type-utils@8.48.1':
resolution: {integrity: sha512-1jEop81a3LrJQLTf/1VfPQdhIY4PlGDBc/i67EVWObrtvcziysbLN3oReexHOM6N3jyXgCrkBsZpqwH0hiDOQg==}
'@typescript-eslint/type-utils@8.49.0':
resolution: {integrity: sha512-KTExJfQ+svY8I10P4HdxKzWsvtVnsuCifU5MvXrRwoP2KOlNZ9ADNEWWsQTJgMxLzS5VLQKDjkCT/YzgsnqmZg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
@@ -1212,8 +1212,8 @@ packages:
resolution: {integrity: sha512-USjyxm3gQEePdUwJBFjjGNG18xY9A2grDVGuk7/9AkjIF1L+ZrVnwR5VAU5JXtUnBL/Nwt3H31KlRDaksnM7/w==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/types@8.48.1':
resolution: {integrity: sha512-+fZ3LZNeiELGmimrujsDCT4CRIbq5oXdHe7chLiW8qzqyPMnn1puNstCrMNVAqwcl2FdIxkuJ4tOs/RFDBVc/Q==}
'@typescript-eslint/types@8.49.0':
resolution: {integrity: sha512-e9k/fneezorUo6WShlQpMxXh8/8wfyc+biu6tnAqA81oWrEic0k21RHzP9uqqpyBBeBKu4T+Bsjy9/b8u7obXQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/typescript-estree@8.37.0':
@@ -1228,8 +1228,8 @@ packages:
peerDependencies:
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/typescript-estree@8.48.1':
resolution: {integrity: sha512-/9wQ4PqaefTK6POVTjJaYS0bynCgzh6ClJHGSBj06XEHjkfylzB+A3qvyaXnErEZSaxhIo4YdyBgq6j4RysxDg==}
'@typescript-eslint/typescript-estree@8.49.0':
resolution: {integrity: sha512-jrLdRuAbPfPIdYNppHJ/D0wN+wwNfJ32YTAm10eJVsFmrVpXQnDWBn8niCSMlWjvml8jsce5E/O+86IQtTbJWA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <6.0.0'
@@ -1241,8 +1241,8 @@ packages:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.9.0'
'@typescript-eslint/utils@8.48.1':
resolution: {integrity: sha512-fAnhLrDjiVfey5wwFRwrweyRlCmdz5ZxXz2G/4cLn0YDLjTapmN4gcCsTBR1N2rWnZSDeWpYtgLDsJt+FpmcwA==}
'@typescript-eslint/utils@8.49.0':
resolution: {integrity: sha512-N3W7rJw7Rw+z1tRsHZbK395TWSYvufBXumYtEGzypgMUthlg0/hmCImeA8hgO2d2G4pd7ftpxxul2J8OdtdaFA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
@@ -1256,8 +1256,8 @@ packages:
resolution: {integrity: sha512-/++5CYLQqsO9HFGLI7APrxBJYo+5OCMpViuhV8q5/Qa3o5mMrF//eQHks+PXcsAVaLdn817fMuS7zqoXNNZGaw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/visitor-keys@8.48.1':
resolution: {integrity: sha512-BmxxndzEWhE4TIEEMBs8lP3MBWN3jFPs/p6gPm/wkv02o41hI6cq9AuSmGAaTTHPtA1FTi2jBre4A9rm5ZmX+Q==}
'@typescript-eslint/visitor-keys@8.49.0':
resolution: {integrity: sha512-LlKaciDe3GmZFphXIc79THF/YYBugZ7FS1pO581E/edlVVNbZKDy93evqmrfQ9/Y4uN0vVhX4iuchq26mK/iiA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@videojs/http-streaming@3.17.2':
@@ -1287,14 +1287,14 @@ packages:
vite: ^5.0.0 || ^6.0.0 || ^7.0.0
vue: ^3.2.25
'@volar/language-core@2.4.23':
resolution: {integrity: sha512-hEEd5ET/oSmBC6pi1j6NaNYRWoAiDhINbT8rmwtINugR39loROSlufGdYMF9TaKGfz+ViGs1Idi3mAhnuPcoGQ==}
'@volar/language-core@2.4.26':
resolution: {integrity: sha512-hH0SMitMxnB43OZpyF1IFPS9bgb2I3bpCh76m2WEK7BE0A0EzpYsRp0CCH2xNKshr7kacU5TQBLYn4zj7CG60A==}
'@volar/source-map@2.4.23':
resolution: {integrity: sha512-Z1Uc8IB57Lm6k7q6KIDu/p+JWtf3xsXJqAX/5r18hYOTpJyBn0KXUR8oTJ4WFYOcDzWC9n3IflGgHowx6U6z9Q==}
'@volar/source-map@2.4.26':
resolution: {integrity: sha512-JJw0Tt/kSFsIRmgTQF4JSt81AUSI1aEye5Zl65EeZ8H35JHnTvFGmpDOBn5iOxd48fyGE+ZvZBp5FcgAy/1Qhw==}
'@volar/typescript@2.4.23':
resolution: {integrity: sha512-lAB5zJghWxVPqfcStmAP1ZqQacMpe90UrP5RJ3arDyrhy4aCUQqmxPPLB2PWDKugvylmO41ljK7vZ+t6INMTag==}
'@volar/typescript@2.4.26':
resolution: {integrity: sha512-N87ecLD48Sp6zV9zID/5yuS1+5foj0DfuYGdQ6KHj/IbKvyKv1zNX6VCmnKYwtmHadEO6mFc2EKISiu3RDPAvA==}
'@vue/compiler-core@3.5.25':
resolution: {integrity: sha512-vay5/oQJdsNHmliWoZfHPoVZZRmnSWhug0BYT34njkYTPqClh3DNWLkZNJBVSjsNMrg0CCrBfoKkjZQPM/QVUw==}
@@ -1337,8 +1337,8 @@ packages:
typescript:
optional: true
'@vue/language-core@3.1.5':
resolution: {integrity: sha512-FMcqyzWN+sYBeqRMWPGT2QY0mUasZMVIuHvmb5NT3eeqPrbHBYtCP8JWEUCDCgM+Zr62uuWY/qoeBrPrzfa78w==}
'@vue/language-core@3.1.8':
resolution: {integrity: sha512-PfwAW7BLopqaJbneChNL6cUOTL3GL+0l8paYP5shhgY5toBNidWnMXWM+qDwL7MC9+zDtzCF2enT8r6VPu64iw==}
peerDependencies:
typescript: '*'
peerDependenciesMeta:
@@ -1456,8 +1456,8 @@ packages:
ajv@6.12.6:
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
alien-signals@3.1.0:
resolution: {integrity: sha512-yufC6VpSy8tK3I0lO67pjumo5JvDQVQyr38+3OHqe6CHl1t2VZekKZ7EKKZSqk0cRmE7U7tfZbpXiKNzuc+ckg==}
alien-signals@3.1.1:
resolution: {integrity: sha512-ogkIWbVrLwKtHY6oOAXaYkAxP+cTH7V5FZ5+Tm4NZFd8VDZ6uNMDrfzqctTZ42eTMCSR3ne3otpcxmqSnFfPYA==}
ansi-styles@4.3.0:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
@@ -1606,8 +1606,8 @@ packages:
dom-walk@0.1.2:
resolution: {integrity: sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==}
dompurify@3.3.0:
resolution: {integrity: sha512-r+f6MYR1gGN1eJv0TVQbhA7if/U7P87cdPl3HN5rikqaBSBxLiCb/b9O+2eG0cxz0ghyU+mU1QkbsOwERMYlWQ==}
dompurify@3.3.1:
resolution: {integrity: sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==}
electron-to-chromium@1.5.250:
resolution: {integrity: sha512-/5UMj9IiGDMOFBnN4i7/Ry5onJrAGSbOGo3s9FEKmwobGq6xw832ccET0CE3CkkMBZ8GJSlUIesZofpyurqDXw==}
@@ -2436,11 +2436,11 @@ packages:
videojs-vtt.js@0.15.5:
resolution: {integrity: sha512-yZbBxvA7QMYn15Lr/ZfhhLPrNpI/RmCSCqgIff57GC2gIrV5YfyzLfLyZMj0NnZSAz8syB4N0nHXpZg9MyrMOQ==}
vite-plugin-compression2@2.3.1:
resolution: {integrity: sha512-bnhLTsurtvOiiP6EMISIKVsOMCeTAjE6FJbyqQus3W4mtAxF7pCuC4puUIAiCgNs98tOCpqo6GIXJXTLufzIaw==}
vite-plugin-compression2@2.4.0:
resolution: {integrity: sha512-8J4CBF1+dM1I06azba/eXJuJHinLF0Am7lUvRH8AZpu0otJoBaDEnxrIEr5iPZJSwH0AEglJGYCveh7pN52jCg==}
vite@7.2.6:
resolution: {integrity: sha512-tI2l/nFHC5rLh7+5+o7QjKjSR04ivXDF4jcgV0f/bTQ+OJiITy5S6gaynVsEM+7RqzufMnVbIon6Sr5x1SDYaQ==}
vite@7.2.7:
resolution: {integrity: sha512-ITcnkFeR3+fI8P1wMgItjGrR10170d8auB4EpMLPqmx6uxElH3a/hHGQabSHKdqd4FXWO1nFIp9rRn7JQ34ACQ==}
engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true
peerDependencies:
@@ -2518,8 +2518,8 @@ packages:
peerDependencies:
vue: ^3.0.2
vue-tsc@3.1.5:
resolution: {integrity: sha512-L/G9IUjOWhBU0yun89rv8fKqmKC+T0HfhrFjlIml71WpfBv9eb4E9Bev8FMbyueBIU9vxQqbd+oOsVcDa5amGw==}
vue-tsc@3.1.8:
resolution: {integrity: sha512-deKgwx6exIHeZwF601P1ktZKNF0bepaSN4jBU3AsbldPx9gylUc1JDxYppl82yxgkAgaz0Y0LCLOi+cXe9HMYA==}
hasBin: true
peerDependencies:
typescript: '>=5.0.0'
@@ -3550,7 +3550,7 @@ snapshots:
'@types/lodash@4.17.13': {}
'@types/node@24.10.1':
'@types/node@24.10.2':
dependencies:
undici-types: 7.16.0
@@ -3576,16 +3576,15 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/eslint-plugin@8.48.1(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)':
'@typescript-eslint/eslint-plugin@8.49.0(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)':
dependencies:
'@eslint-community/regexpp': 4.12.2
'@typescript-eslint/parser': 8.37.0(eslint@9.39.1)(typescript@5.9.3)
'@typescript-eslint/scope-manager': 8.48.1
'@typescript-eslint/type-utils': 8.48.1(eslint@9.39.1)(typescript@5.9.3)
'@typescript-eslint/utils': 8.48.1(eslint@9.39.1)(typescript@5.9.3)
'@typescript-eslint/visitor-keys': 8.48.1
'@typescript-eslint/scope-manager': 8.49.0
'@typescript-eslint/type-utils': 8.49.0(eslint@9.39.1)(typescript@5.9.3)
'@typescript-eslint/utils': 8.49.0(eslint@9.39.1)(typescript@5.9.3)
'@typescript-eslint/visitor-keys': 8.49.0
eslint: 9.39.1
graphemer: 1.4.0
ignore: 7.0.5
natural-compare: 1.4.0
ts-api-utils: 2.1.0(typescript@5.9.3)
@@ -3623,10 +3622,10 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/project-service@8.48.1(typescript@5.9.3)':
'@typescript-eslint/project-service@8.49.0(typescript@5.9.3)':
dependencies:
'@typescript-eslint/tsconfig-utils': 8.48.1(typescript@5.9.3)
'@typescript-eslint/types': 8.48.1
'@typescript-eslint/tsconfig-utils': 8.49.0(typescript@5.9.3)
'@typescript-eslint/types': 8.49.0
debug: 4.4.3
typescript: 5.9.3
transitivePeerDependencies:
@@ -3642,10 +3641,10 @@ snapshots:
'@typescript-eslint/types': 8.46.4
'@typescript-eslint/visitor-keys': 8.46.4
'@typescript-eslint/scope-manager@8.48.1':
'@typescript-eslint/scope-manager@8.49.0':
dependencies:
'@typescript-eslint/types': 8.48.1
'@typescript-eslint/visitor-keys': 8.48.1
'@typescript-eslint/types': 8.49.0
'@typescript-eslint/visitor-keys': 8.49.0
'@typescript-eslint/tsconfig-utils@8.37.0(typescript@5.9.3)':
dependencies:
@@ -3655,7 +3654,7 @@ snapshots:
dependencies:
typescript: 5.9.3
'@typescript-eslint/tsconfig-utils@8.48.1(typescript@5.9.3)':
'@typescript-eslint/tsconfig-utils@8.49.0(typescript@5.9.3)':
dependencies:
typescript: 5.9.3
@@ -3671,11 +3670,11 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/type-utils@8.48.1(eslint@9.39.1)(typescript@5.9.3)':
'@typescript-eslint/type-utils@8.49.0(eslint@9.39.1)(typescript@5.9.3)':
dependencies:
'@typescript-eslint/types': 8.48.1
'@typescript-eslint/typescript-estree': 8.48.1(typescript@5.9.3)
'@typescript-eslint/utils': 8.48.1(eslint@9.39.1)(typescript@5.9.3)
'@typescript-eslint/types': 8.49.0
'@typescript-eslint/typescript-estree': 8.49.0(typescript@5.9.3)
'@typescript-eslint/utils': 8.49.0(eslint@9.39.1)(typescript@5.9.3)
debug: 4.4.3
eslint: 9.39.1
ts-api-utils: 2.1.0(typescript@5.9.3)
@@ -3687,7 +3686,7 @@ snapshots:
'@typescript-eslint/types@8.46.4': {}
'@typescript-eslint/types@8.48.1': {}
'@typescript-eslint/types@8.49.0': {}
'@typescript-eslint/typescript-estree@8.37.0(typescript@5.9.3)':
dependencies:
@@ -3721,12 +3720,12 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/typescript-estree@8.48.1(typescript@5.9.3)':
'@typescript-eslint/typescript-estree@8.49.0(typescript@5.9.3)':
dependencies:
'@typescript-eslint/project-service': 8.48.1(typescript@5.9.3)
'@typescript-eslint/tsconfig-utils': 8.48.1(typescript@5.9.3)
'@typescript-eslint/types': 8.48.1
'@typescript-eslint/visitor-keys': 8.48.1
'@typescript-eslint/project-service': 8.49.0(typescript@5.9.3)
'@typescript-eslint/tsconfig-utils': 8.49.0(typescript@5.9.3)
'@typescript-eslint/types': 8.49.0
'@typescript-eslint/visitor-keys': 8.49.0
debug: 4.4.3
minimatch: 9.0.5
semver: 7.7.3
@@ -3747,12 +3746,12 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/utils@8.48.1(eslint@9.39.1)(typescript@5.9.3)':
'@typescript-eslint/utils@8.49.0(eslint@9.39.1)(typescript@5.9.3)':
dependencies:
'@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1)
'@typescript-eslint/scope-manager': 8.48.1
'@typescript-eslint/types': 8.48.1
'@typescript-eslint/typescript-estree': 8.48.1(typescript@5.9.3)
'@typescript-eslint/scope-manager': 8.49.0
'@typescript-eslint/types': 8.49.0
'@typescript-eslint/typescript-estree': 8.49.0(typescript@5.9.3)
eslint: 9.39.1
typescript: 5.9.3
transitivePeerDependencies:
@@ -3768,9 +3767,9 @@ snapshots:
'@typescript-eslint/types': 8.46.4
eslint-visitor-keys: 4.2.1
'@typescript-eslint/visitor-keys@8.48.1':
'@typescript-eslint/visitor-keys@8.49.0':
dependencies:
'@typescript-eslint/types': 8.48.1
'@typescript-eslint/types': 8.49.0
eslint-visitor-keys: 4.2.1
'@videojs/http-streaming@3.17.2(video.js@8.23.4)':
@@ -3795,7 +3794,7 @@ snapshots:
global: 4.4.0
is-function: 1.0.2
'@vitejs/plugin-legacy@7.2.1(terser@5.44.1)(vite@7.2.6(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0))':
'@vitejs/plugin-legacy@7.2.1(terser@5.44.1)(vite@7.2.7(@types/node@24.10.2)(terser@5.44.1)(yaml@2.7.0))':
dependencies:
'@babel/core': 7.28.5
'@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.28.5)
@@ -3810,25 +3809,25 @@ snapshots:
regenerator-runtime: 0.14.1
systemjs: 6.15.1
terser: 5.44.1
vite: 7.2.6(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0)
vite: 7.2.7(@types/node@24.10.2)(terser@5.44.1)(yaml@2.7.0)
transitivePeerDependencies:
- supports-color
'@vitejs/plugin-vue@6.0.2(vite@7.2.6(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0))(vue@3.5.25(typescript@5.9.3))':
'@vitejs/plugin-vue@6.0.2(vite@7.2.7(@types/node@24.10.2)(terser@5.44.1)(yaml@2.7.0))(vue@3.5.25(typescript@5.9.3))':
dependencies:
'@rolldown/pluginutils': 1.0.0-beta.50
vite: 7.2.6(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0)
vite: 7.2.7(@types/node@24.10.2)(terser@5.44.1)(yaml@2.7.0)
vue: 3.5.25(typescript@5.9.3)
'@volar/language-core@2.4.23':
'@volar/language-core@2.4.26':
dependencies:
'@volar/source-map': 2.4.23
'@volar/source-map': 2.4.26
'@volar/source-map@2.4.23': {}
'@volar/source-map@2.4.26': {}
'@volar/typescript@2.4.23':
'@volar/typescript@2.4.26':
dependencies:
'@volar/language-core': 2.4.23
'@volar/language-core': 2.4.26
path-browserify: 1.0.1
vscode-uri: 3.1.0
@@ -3904,12 +3903,12 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@vue/language-core@3.1.5(typescript@5.9.3)':
'@vue/language-core@3.1.8(typescript@5.9.3)':
dependencies:
'@volar/language-core': 2.4.23
'@volar/language-core': 2.4.26
'@vue/compiler-dom': 3.5.25
'@vue/shared': 3.5.25
alien-signals: 3.1.0
alien-signals: 3.1.1
muggle-string: 0.4.1
path-browserify: 1.0.1
picomatch: 4.0.3
@@ -3993,7 +3992,7 @@ snapshots:
json-schema-traverse: 0.4.1
uri-js: 4.4.1
alien-signals@3.1.0: {}
alien-signals@3.1.1: {}
ansi-styles@4.3.0:
dependencies:
@@ -4136,7 +4135,7 @@ snapshots:
dom-walk@0.1.2: {}
dompurify@3.3.0:
dompurify@3.3.1:
optionalDependencies:
'@types/trusted-types': 2.0.7
@@ -4978,14 +4977,14 @@ snapshots:
dependencies:
global: 4.4.0
vite-plugin-compression2@2.3.1(rollup@4.53.3):
vite-plugin-compression2@2.4.0(rollup@4.53.3):
dependencies:
'@rollup/pluginutils': 5.3.0(rollup@4.53.3)
tar-mini: 0.2.0
transitivePeerDependencies:
- rollup
vite@7.2.6(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0):
vite@7.2.7(@types/node@24.10.2)(terser@5.44.1)(yaml@2.7.0):
dependencies:
esbuild: 0.25.12
fdir: 6.5.0(picomatch@4.0.3)
@@ -4994,7 +4993,7 @@ snapshots:
rollup: 4.53.3
tinyglobby: 0.2.15
optionalDependencies:
'@types/node': 24.10.1
'@types/node': 24.10.2
fsevents: 2.3.3
terser: 5.44.1
yaml: 2.7.0
@@ -5042,10 +5041,10 @@ snapshots:
dependencies:
vue: 3.5.25(typescript@5.9.3)
vue-tsc@3.1.5(typescript@5.9.3):
vue-tsc@3.1.8(typescript@5.9.3):
dependencies:
'@volar/typescript': 2.4.23
'@vue/language-core': 3.1.5(typescript@5.9.3)
'@volar/typescript': 2.4.26
'@vue/language-core': 3.1.8(typescript@5.9.3)
typescript: 5.9.3
vue@3.5.25(typescript@5.9.3):

View File

@@ -18,7 +18,7 @@
</template>
<script setup lang="ts">
import { ref, computed, watch, nextTick, defineProps } from "vue";
import { ref, computed, watch, nextTick } from "vue";
import { useRoute } from "vue-router";
import { useFileStore } from "@/stores/file";
import url from "@/utils/url";

View File

@@ -44,7 +44,9 @@
"openFile": "فتح الملف",
"discardChanges": "إلغاء التغييرات",
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
"editAsText": "Edit as Text",
"increaseFontSize": "Increase font size",
"decreaseFontSize": "Decrease font size"
},
"download": {
"downloadFile": "تحميل الملف",
@@ -78,7 +80,14 @@
"sortBySize": "الترتيب بالحجم",
"noPreview": "لا يوجد عرض مسبق لهذا الملف.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
"csvLoadFailed": "Failed to load CSV file.",
"showingRows": "Showing {count} row(s)",
"columnSeparator": "Column Separator",
"csvSeparators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
},
"help": {
"click": "حدد الملف أو المجلد",
@@ -272,10 +281,5 @@
"minutes": "دقائق",
"seconds": "ثواني",
"unit": "وحدة الوقت"
},
"available_csv_separators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
}

View File

@@ -44,7 +44,9 @@
"openFile": "Отвори файл",
"discardChanges": "Изчисти",
"saveChanges": "Запиши промените",
"editAsText": "Edit as Text"
"editAsText": "Edit as Text",
"increaseFontSize": "Increase font size",
"decreaseFontSize": "Decrease font size"
},
"download": {
"downloadFile": "Свали файл",
@@ -78,7 +80,14 @@
"sortBySize": "Подредба по размер",
"noPreview": "За този файл не е наличен преглед.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
"csvLoadFailed": "Failed to load CSV file.",
"showingRows": "Showing {count} row(s)",
"columnSeparator": "Column Separator",
"csvSeparators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
},
"help": {
"click": "избери файл или директория",
@@ -272,10 +281,5 @@
"minutes": "Минути",
"seconds": "Секунди",
"unit": "Единица за време"
},
"available_csv_separators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
}

View File

@@ -44,7 +44,9 @@
"openFile": "Obrir fitxer",
"discardChanges": "Descartar",
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
"editAsText": "Edit as Text",
"increaseFontSize": "Increase font size",
"decreaseFontSize": "Decrease font size"
},
"download": {
"downloadFile": "Descarregar fitxer",
@@ -78,7 +80,14 @@
"sortBySize": "Ordenar per mida",
"noPreview": "La vista prèvia no està disponible per a aquest fitxer.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
"csvLoadFailed": "Failed to load CSV file.",
"showingRows": "Showing {count} row(s)",
"columnSeparator": "Column Separator",
"csvSeparators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
},
"help": {
"click": "seleccionar fitxer o carpeta",
@@ -272,10 +281,5 @@
"minutes": "Minuts",
"seconds": "Segons",
"unit": "Unitat"
},
"available_csv_separators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
}

View File

@@ -44,7 +44,9 @@
"openFile": "Otevřít soubor",
"discardChanges": "Zrušit změny",
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
"editAsText": "Edit as Text",
"increaseFontSize": "Increase font size",
"decreaseFontSize": "Decrease font size"
},
"download": {
"downloadFile": "Stáhnout soubor",
@@ -78,7 +80,14 @@
"sortBySize": "Seřadit podle velikosti",
"noPreview": "Náhled pro tento soubor není k dispozici.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
"csvLoadFailed": "Failed to load CSV file.",
"showingRows": "Showing {count} row(s)",
"columnSeparator": "Column Separator",
"csvSeparators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
},
"help": {
"click": "vyberte soubor nebo adresář",
@@ -272,10 +281,5 @@
"minutes": "Minuty",
"seconds": "Sekundy",
"unit": "Časová jednotka"
},
"available_csv_separators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
}

View File

@@ -44,7 +44,9 @@
"openFile": "Datei öffnen",
"discardChanges": "Verwerfen",
"saveChanges": "Änderungen speichern",
"editAsText": "Als Text bearbeiten"
"editAsText": "Als Text bearbeiten",
"increaseFontSize": "Increase font size",
"decreaseFontSize": "Decrease font size"
},
"download": {
"downloadFile": "Download Datei",
@@ -78,7 +80,14 @@
"sortBySize": "Nach Größe sortieren",
"noPreview": "Für diese Datei ist keine Vorschau verfügbar.",
"csvTooLarge": "Die CSV-Datei ist zu groß für die Vorschau (>5 MB). Bitte herunterladen, um sie anzuzeigen.",
"csvLoadFailed": "Fehler beim Laden der CSV-Datei."
"csvLoadFailed": "Fehler beim Laden der CSV-Datei.",
"showingRows": "Showing {count} row(s)",
"columnSeparator": "Column Separator",
"csvSeparators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
},
"help": {
"click": "Wähle Datei oder Ordner",
@@ -272,10 +281,5 @@
"minutes": "Minuten",
"seconds": "Sekunden",
"unit": "Zeiteinheit"
},
"available_csv_separators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
}

View File

@@ -44,7 +44,9 @@
"openFile": "Άνοιγμα αρχείου",
"discardChanges": "Discard",
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
"editAsText": "Edit as Text",
"increaseFontSize": "Increase font size",
"decreaseFontSize": "Decrease font size"
},
"download": {
"downloadFile": "Λήψη αρχείου",
@@ -78,7 +80,14 @@
"sortBySize": "Ταξινόμηση κατά μέγεθος",
"noPreview": "Η προεπισκόπηση δεν είναι διαθέσιμη για αυτό το αρχείο.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
"csvLoadFailed": "Failed to load CSV file.",
"showingRows": "Showing {count} row(s)",
"columnSeparator": "Column Separator",
"csvSeparators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
},
"help": {
"click": "επιλέξτε αρχείο ή φάκελο",
@@ -272,10 +281,5 @@
"minutes": "Λεπτά",
"seconds": "Δευτερόλεπτα",
"unit": "Μονάδα χρόνου"
},
"available_csv_separators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
}

View File

@@ -44,7 +44,9 @@
"openFile": "Abrir archivo",
"discardChanges": "Discard",
"saveChanges": "Guardar cambios",
"editAsText": "Edit as Text"
"editAsText": "Edit as Text",
"increaseFontSize": "Increase font size",
"decreaseFontSize": "Decrease font size"
},
"download": {
"downloadFile": "Descargar fichero",
@@ -78,7 +80,14 @@
"sortBySize": "Ordenar por tamaño",
"noPreview": "La vista previa no está disponible para este archivo.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
"csvLoadFailed": "Failed to load CSV file.",
"showingRows": "Showing {count} row(s)",
"columnSeparator": "Column Separator",
"csvSeparators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
},
"help": {
"click": "seleccionar archivo o carpeta",
@@ -272,10 +281,5 @@
"minutes": "Minutos",
"seconds": "Segundos",
"unit": "Unidad"
},
"available_csv_separators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
}

View File

@@ -44,7 +44,9 @@
"openFile": "باز کردن فایل",
"discardChanges": "لغو کردن",
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
"editAsText": "Edit as Text",
"increaseFontSize": "Increase font size",
"decreaseFontSize": "Decrease font size"
},
"download": {
"downloadFile": "دانلود فایل",
@@ -78,7 +80,14 @@
"sortBySize": "مرتب سازی اندازه",
"noPreview": "این فایل قابل نمایش نیست",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
"csvLoadFailed": "Failed to load CSV file.",
"showingRows": "Showing {count} row(s)",
"columnSeparator": "Column Separator",
"csvSeparators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
},
"help": {
"click": "انتخاب فایل یا پوشه",
@@ -272,10 +281,5 @@
"minutes": "دقیقه",
"seconds": "ثانیه",
"unit": "واحد زمان"
},
"available_csv_separators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
}

View File

@@ -44,7 +44,9 @@
"openFile": "Ouvrir le fichier",
"discardChanges": "Annuler",
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
"editAsText": "Edit as Text",
"increaseFontSize": "Increase font size",
"decreaseFontSize": "Decrease font size"
},
"download": {
"downloadFile": "Télécharger le fichier",
@@ -78,7 +80,14 @@
"sortBySize": "Trier par taille",
"noPreview": "L'aperçu n'est pas disponible pour ce fichier.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
"csvLoadFailed": "Failed to load CSV file.",
"showingRows": "Showing {count} row(s)",
"columnSeparator": "Column Separator",
"csvSeparators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
},
"help": {
"click": "Sélectionner un fichier ou dossier",
@@ -272,10 +281,5 @@
"minutes": "Minutes",
"seconds": "Secondes",
"unit": "Unité de temps"
},
"available_csv_separators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
}

View File

@@ -44,7 +44,9 @@
"openFile": "פתח קובץ",
"discardChanges": "זריקת השינויים",
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
"editAsText": "Edit as Text",
"increaseFontSize": "Increase font size",
"decreaseFontSize": "Decrease font size"
},
"download": {
"downloadFile": "הורד קובץ",
@@ -78,7 +80,14 @@
"sortBySize": "מיין לפי גודל",
"noPreview": "לא זמינה תצוגה מקדימה לקובץ זה",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
"csvLoadFailed": "Failed to load CSV file.",
"showingRows": "Showing {count} row(s)",
"columnSeparator": "Column Separator",
"csvSeparators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
},
"help": {
"click": "בחר קובץ או תיקייה",
@@ -272,10 +281,5 @@
"minutes": "דקות",
"seconds": "שניות",
"unit": "יחידת זמן"
},
"available_csv_separators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
}

View File

@@ -44,7 +44,9 @@
"openFile": "Otvori datoteku",
"discardChanges": "Odbaci",
"saveChanges": "Spremi promjene",
"editAsText": "Edit as Text"
"editAsText": "Edit as Text",
"increaseFontSize": "Increase font size",
"decreaseFontSize": "Decrease font size"
},
"download": {
"downloadFile": "Preuzmi Datoteku",
@@ -78,7 +80,14 @@
"sortBySize": "Sortiraj po veličini",
"noPreview": "Pregled nije dostupan za ovu datoteku.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
"csvLoadFailed": "Failed to load CSV file.",
"showingRows": "Showing {count} row(s)",
"columnSeparator": "Column Separator",
"csvSeparators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
},
"help": {
"click": "odaberi datoteku ili mapu",
@@ -272,10 +281,5 @@
"minutes": "Minute",
"seconds": "Sekunde",
"unit": "Jedinica vremena"
},
"available_csv_separators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
}

View File

@@ -44,7 +44,9 @@
"openFile": "Fájl megnyitása",
"discardChanges": "Discard",
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
"editAsText": "Edit as Text",
"increaseFontSize": "Increase font size",
"decreaseFontSize": "Decrease font size"
},
"download": {
"downloadFile": "Fájl letöltése",
@@ -78,7 +80,14 @@
"sortBySize": "Rendezés méret szerint",
"noPreview": "Ehhez a fájlhoz nincs előnézet.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
"csvLoadFailed": "Failed to load CSV file.",
"showingRows": "Showing {count} row(s)",
"columnSeparator": "Column Separator",
"csvSeparators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
},
"help": {
"click": "mappa vagy fájl kijelölése",
@@ -272,10 +281,5 @@
"minutes": "Perc",
"seconds": "Másodperc",
"unit": "Időegység"
},
"available_csv_separators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
}

View File

@@ -44,7 +44,9 @@
"openFile": "Open file",
"discardChanges": "Discard",
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
"editAsText": "Edit as Text",
"increaseFontSize": "Increase font size",
"decreaseFontSize": "Decrease font size"
},
"download": {
"downloadFile": "Sækja skjal",
@@ -78,7 +80,14 @@
"sortBySize": "Flokka eftir stærð",
"noPreview": "Preview is not available for this file.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
"csvLoadFailed": "Failed to load CSV file.",
"showingRows": "Showing {count} row(s)",
"columnSeparator": "Column Separator",
"csvSeparators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
},
"help": {
"click": "velja skjal eða möppu",
@@ -272,10 +281,5 @@
"minutes": "Mínútur",
"seconds": "Sekúndur",
"unit": "Tímastilling"
},
"available_csv_separators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
}

View File

@@ -44,7 +44,9 @@
"openFile": "Apri file",
"discardChanges": "Ignora",
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
"editAsText": "Edit as Text",
"increaseFontSize": "Increase font size",
"decreaseFontSize": "Decrease font size"
},
"download": {
"downloadFile": "Scarica file",
@@ -78,7 +80,14 @@
"sortBySize": "Ordina per dimensione",
"noPreview": "L'anteprima non è disponibile per questo file.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
"csvLoadFailed": "Failed to load CSV file.",
"showingRows": "Showing {count} row(s)",
"columnSeparator": "Column Separator",
"csvSeparators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
},
"help": {
"click": "seleziona un file o una cartella",
@@ -272,10 +281,5 @@
"minutes": "Minuti",
"seconds": "Secondi",
"unit": "Unità di tempo"
},
"available_csv_separators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
}

View File

@@ -44,7 +44,9 @@
"openFile": "ファイルを開く",
"discardChanges": "Discard",
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
"editAsText": "Edit as Text",
"increaseFontSize": "Increase font size",
"decreaseFontSize": "Decrease font size"
},
"download": {
"downloadFile": "ファイルのダウンロード",
@@ -78,7 +80,14 @@
"sortBySize": "サイズで並べ替え",
"noPreview": "プレビューはこのファイルでは利用できません",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
"csvLoadFailed": "Failed to load CSV file.",
"showingRows": "Showing {count} row(s)",
"columnSeparator": "Column Separator",
"csvSeparators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
},
"help": {
"click": "ファイルやフォルダーを選択",
@@ -272,10 +281,5 @@
"minutes": "分",
"seconds": "秒",
"unit": "時間の単位"
},
"available_csv_separators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
}

View File

@@ -44,7 +44,9 @@
"openFile": "파일 열기",
"discardChanges": "변경 사항 취소",
"saveChanges": "변경사항 저장",
"editAsText": "Edit as Text"
"editAsText": "Edit as Text",
"increaseFontSize": "Increase font size",
"decreaseFontSize": "Decrease font size"
},
"download": {
"downloadFile": "파일 다운로드",
@@ -78,7 +80,14 @@
"sortBySize": "크기순",
"noPreview": "미리 보기가 지원되지 않는 파일 유형입니다.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
"csvLoadFailed": "Failed to load CSV file.",
"showingRows": "Showing {count} row(s)",
"columnSeparator": "Column Separator",
"csvSeparators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
},
"help": {
"click": "파일이나 디렉토리를 선택해주세요.",
@@ -272,10 +281,5 @@
"minutes": "분",
"seconds": "초",
"unit": "Time Unit"
},
"available_csv_separators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
}

View File

@@ -44,7 +44,9 @@
"openFile": "Open file",
"discardChanges": "Discard",
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
"editAsText": "Edit as Text",
"increaseFontSize": "Increase font size",
"decreaseFontSize": "Decrease font size"
},
"download": {
"downloadFile": "Bestand downloaden",
@@ -78,7 +80,14 @@
"sortBySize": "Sorteren op grootte",
"noPreview": "Preview is not available for this file.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
"csvLoadFailed": "Failed to load CSV file.",
"showingRows": "Showing {count} row(s)",
"columnSeparator": "Column Separator",
"csvSeparators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
},
"help": {
"click": "selecteer bestand of map",
@@ -272,10 +281,5 @@
"minutes": "Minuten",
"seconds": "Seconden",
"unit": "Tijdseenheid"
},
"available_csv_separators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
}

View File

@@ -44,7 +44,9 @@
"openFile": "Open file",
"discardChanges": "Slett",
"saveChanges": "Lagre Endringane ",
"editAsText": "Edit as Text"
"editAsText": "Edit as Text",
"increaseFontSize": "Increase font size",
"decreaseFontSize": "Decrease font size"
},
"download": {
"downloadFile": "Nedlast filen",
@@ -78,7 +80,14 @@
"sortBySize": "Sorter etter størrelse",
"noPreview": "Forhåndsvisning er ikkje tilgjengeleg for denne filen.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
"csvLoadFailed": "Failed to load CSV file.",
"showingRows": "Showing {count} row(s)",
"columnSeparator": "Column Separator",
"csvSeparators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
},
"help": {
"click": "velg fil eller katalog",
@@ -272,10 +281,5 @@
"minutes": "Minutt",
"seconds": "Sekunder",
"unit": "Time format"
},
"available_csv_separators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
}

View File

@@ -44,7 +44,9 @@
"openFile": "Otwórz plik",
"discardChanges": "Odrzuć",
"saveChanges": "Zapisz zmiany",
"editAsText": "Edytuj jako tekst"
"editAsText": "Edytuj jako tekst",
"increaseFontSize": "Zwiększ rozmiar czcionki",
"decreaseFontSize": "Zmniejsz rozmiar czcionki"
},
"download": {
"downloadFile": "Pobierz plik",
@@ -78,7 +80,14 @@
"sortBySize": "Sortuj wg rozmiaru",
"noPreview": "Podgląd tego pliku jest niedostępny.",
"csvTooLarge": "Plik CSV jest za duży do podglądu (>5 MB). Pobierz, aby wyświetlić.",
"csvLoadFailed": "Nie udało się załadować pliku CSV."
"csvLoadFailed": "Nie udało się załadować pliku CSV.",
"showingRows": "Wyświetlanie wierszy: {count}",
"columnSeparator": "Separator kolumn",
"csvSeparators": {
"comma": "Przecinek (,)",
"semicolon": "Średnik (;)",
"both": "Zarówno (,), jak i (;)"
}
},
"help": {
"click": "zaznacz plik lub folder",
@@ -272,10 +281,5 @@
"minutes": "Minuty",
"seconds": "Sekundy",
"unit": "Jednostka czasu"
},
"available_csv_separators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
}

View File

@@ -44,7 +44,9 @@
"openFile": "Abrir",
"discardChanges": "Discard",
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
"editAsText": "Edit as Text",
"increaseFontSize": "Increase font size",
"decreaseFontSize": "Decrease font size"
},
"download": {
"downloadFile": "Baixar arquivo",
@@ -78,7 +80,14 @@
"sortBySize": "Ordenar pelo tamanho",
"noPreview": "Pré-visualização não disponível para este arquivo.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
"csvLoadFailed": "Failed to load CSV file.",
"showingRows": "Showing {count} row(s)",
"columnSeparator": "Column Separator",
"csvSeparators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
},
"help": {
"click": "selecionar pasta ou arquivo",
@@ -272,10 +281,5 @@
"minutes": "Minutos",
"seconds": "Segundos",
"unit": "Unidades de Tempo"
},
"available_csv_separators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
}

View File

@@ -44,7 +44,9 @@
"openFile": "Open file",
"discardChanges": "Discard",
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
"editAsText": "Edit as Text",
"increaseFontSize": "Increase font size",
"decreaseFontSize": "Decrease font size"
},
"download": {
"downloadFile": "Descarregar ficheiro",
@@ -78,7 +80,14 @@
"sortBySize": "Ordenar pelo tamanho",
"noPreview": "Preview is not available for this file.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
"csvLoadFailed": "Failed to load CSV file.",
"showingRows": "Showing {count} row(s)",
"columnSeparator": "Column Separator",
"csvSeparators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
},
"help": {
"click": "selecionar pasta ou ficheiro",
@@ -272,10 +281,5 @@
"minutes": "Minutos",
"seconds": "Segundos",
"unit": "Unidades de tempo"
},
"available_csv_separators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
}

View File

@@ -44,7 +44,9 @@
"openFile": "Open file",
"discardChanges": "Discard",
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
"editAsText": "Edit as Text",
"increaseFontSize": "Increase font size",
"decreaseFontSize": "Decrease font size"
},
"download": {
"downloadFile": "Descarcă fișier",
@@ -78,7 +80,14 @@
"sortBySize": "Ordonează după dimensiune",
"noPreview": "Preview is not available for this file.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
"csvLoadFailed": "Failed to load CSV file.",
"showingRows": "Showing {count} row(s)",
"columnSeparator": "Column Separator",
"csvSeparators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
},
"help": {
"click": "alege fișier sau director",
@@ -272,10 +281,5 @@
"minutes": "Minute",
"seconds": "Secunde",
"unit": "Unitate de timp"
},
"available_csv_separators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
}

View File

@@ -44,7 +44,9 @@
"openFile": "Открыть файл",
"discardChanges": "Отказаться",
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
"editAsText": "Edit as Text",
"increaseFontSize": "Increase font size",
"decreaseFontSize": "Decrease font size"
},
"download": {
"downloadFile": "Скачать файл",
@@ -78,7 +80,14 @@
"sortBySize": "Сортировка по размеру",
"noPreview": "Предварительный просмотр для этого файла недоступен.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
"csvLoadFailed": "Failed to load CSV file.",
"showingRows": "Showing {count} row(s)",
"columnSeparator": "Column Separator",
"csvSeparators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
},
"help": {
"click": "выбрать файл или каталог",
@@ -272,10 +281,5 @@
"minutes": "Минуты",
"seconds": "Секунды",
"unit": "Единица времени"
},
"available_csv_separators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
}

View File

@@ -44,7 +44,9 @@
"openFile": "Otvoriť súbor",
"discardChanges": "Zahodiť",
"saveChanges": "Uložiť zmeny",
"editAsText": "Edit as Text"
"editAsText": "Edit as Text",
"increaseFontSize": "Increase font size",
"decreaseFontSize": "Decrease font size"
},
"download": {
"downloadFile": "Stiahnuť súbor",
@@ -78,7 +80,14 @@
"sortBySize": "Zoradiť podľa veľkosti",
"noPreview": "Pre tento súbor nie je dostupný náhľad.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
"csvLoadFailed": "Failed to load CSV file.",
"showingRows": "Showing {count} row(s)",
"columnSeparator": "Column Separator",
"csvSeparators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
},
"help": {
"click": "vyberie súbor alebo priečinok",
@@ -272,10 +281,5 @@
"minutes": "Minúty",
"seconds": "Sekundy",
"unit": "Jednotka času"
},
"available_csv_separators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
}

View File

@@ -44,7 +44,9 @@
"openFile": "Öppna fil",
"discardChanges": "Förkasta",
"saveChanges": "Spara ändringar",
"editAsText": "Edit as Text"
"editAsText": "Edit as Text",
"increaseFontSize": "Increase font size",
"decreaseFontSize": "Decrease font size"
},
"download": {
"downloadFile": "Ladda ner fil",
@@ -78,7 +80,14 @@
"sortBySize": "Sortera på storlek",
"noPreview": "Förhandsvisning är inte tillgänglig för denna fil.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
"csvLoadFailed": "Failed to load CSV file.",
"showingRows": "Showing {count} row(s)",
"columnSeparator": "Column Separator",
"csvSeparators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
},
"help": {
"click": "välj fil eller mapp",
@@ -272,10 +281,5 @@
"minutes": "Minuter",
"seconds": "Sekunder",
"unit": "Tidsenhet"
},
"available_csv_separators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
}

View File

@@ -44,7 +44,9 @@
"openFile": "Dosyayı aç",
"discardChanges": "Discard",
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
"editAsText": "Edit as Text",
"increaseFontSize": "Increase font size",
"decreaseFontSize": "Decrease font size"
},
"download": {
"downloadFile": "Dosyayı indir",
@@ -78,7 +80,14 @@
"sortBySize": "Boyuta göre sırala",
"noPreview": "Bu dosya için önizleme aktif değil",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
"csvLoadFailed": "Failed to load CSV file.",
"showingRows": "Showing {count} row(s)",
"columnSeparator": "Column Separator",
"csvSeparators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
},
"help": {
"click": "dosya veya klasör seçin",
@@ -272,10 +281,5 @@
"minutes": "Dakika",
"seconds": "Saniye",
"unit": "Zaman birimi"
},
"available_csv_separators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
}

View File

@@ -44,7 +44,9 @@
"openFile": "Відкрити файл",
"discardChanges": "Скасувати",
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
"editAsText": "Edit as Text",
"increaseFontSize": "Increase font size",
"decreaseFontSize": "Decrease font size"
},
"download": {
"downloadFile": "Завантажити файл",
@@ -78,7 +80,14 @@
"sortBySize": "Сортувати за розміром",
"noPreview": "Попередній перегляд для цього файлу недоступний.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
"csvLoadFailed": "Failed to load CSV file.",
"showingRows": "Showing {count} row(s)",
"columnSeparator": "Column Separator",
"csvSeparators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
},
"help": {
"click": "вибрати файл чи каталог",
@@ -272,10 +281,5 @@
"minutes": "Хвилини",
"seconds": "Секунди",
"unit": "Одиниця часу"
},
"available_csv_separators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
}

View File

@@ -44,7 +44,9 @@
"openFile": "Mở tệp",
"discardChanges": "Hủy bỏ thay đổi",
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
"editAsText": "Edit as Text",
"increaseFontSize": "Increase font size",
"decreaseFontSize": "Decrease font size"
},
"download": {
"downloadFile": "Tải xuống tệp tin",
@@ -78,7 +80,14 @@
"sortBySize": "Sắp xếp theo kích thước",
"noPreview": "Không có bản xem trước cho tập tin này.",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
"csvLoadFailed": "Failed to load CSV file.",
"showingRows": "Showing {count} row(s)",
"columnSeparator": "Column Separator",
"csvSeparators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
},
"help": {
"click": "chọn tập tin hoặc thư mục",
@@ -272,10 +281,5 @@
"minutes": "Phút",
"seconds": "Giây",
"unit": "Đơn vị"
},
"available_csv_separators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
}

View File

@@ -44,7 +44,9 @@
"openFile": "打开文件",
"discardChanges": "放弃更改",
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
"editAsText": "Edit as Text",
"increaseFontSize": "Increase font size",
"decreaseFontSize": "Decrease font size"
},
"download": {
"downloadFile": "下载文件",
@@ -78,7 +80,14 @@
"sortBySize": "按大小排序",
"noPreview": "此文件无法预览。",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
"csvLoadFailed": "Failed to load CSV file.",
"showingRows": "Showing {count} row(s)",
"columnSeparator": "Column Separator",
"csvSeparators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
},
"help": {
"click": "选择文件或文件夹",
@@ -272,10 +281,5 @@
"minutes": "分钟",
"seconds": "秒",
"unit": "时间单位"
},
"available_csv_separators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
}

View File

@@ -44,7 +44,9 @@
"openFile": "開啟檔案",
"discardChanges": "放棄變更",
"saveChanges": "Save changes",
"editAsText": "Edit as Text"
"editAsText": "Edit as Text",
"increaseFontSize": "Increase font size",
"decreaseFontSize": "Decrease font size"
},
"download": {
"downloadFile": "下載檔案",
@@ -78,7 +80,14 @@
"sortBySize": "按大小排序",
"noPreview": "此檔案無法預覽。",
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
"csvLoadFailed": "Failed to load CSV file."
"csvLoadFailed": "Failed to load CSV file.",
"showingRows": "Showing {count} row(s)",
"columnSeparator": "Column Separator",
"csvSeparators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
},
"help": {
"click": "選擇檔案或目錄",
@@ -272,10 +281,5 @@
"minutes": "分鐘",
"seconds": "秒",
"unit": "時間單位"
},
"available_csv_separators": {
"comma": "Comma (,)",
"semicolon": "Semicolon (;)",
"both": "Both (,) and (;)"
}
}

View File

@@ -24,9 +24,9 @@ require (
github.com/spf13/viper v1.21.0
github.com/stretchr/testify v1.11.1
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce
golang.org/x/crypto v0.45.0
golang.org/x/image v0.33.0
golang.org/x/text v0.31.0
golang.org/x/crypto v0.46.0
golang.org/x/image v0.34.0
golang.org/x/text v0.32.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1
gopkg.in/yaml.v3 v3.0.1
)
@@ -74,8 +74,8 @@ require (
go.yaml.in/yaml/v3 v3.0.4 // indirect
go4.org v0.0.0-20230225012048-214862532bf5 // indirect
golang.org/x/net v0.47.0 // indirect
golang.org/x/sync v0.18.0 // indirect
golang.org/x/sys v0.38.0 // indirect
golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.39.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)

View File

@@ -266,8 +266,8 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -279,8 +279,8 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.33.0 h1:LXRZRnv1+zGd5XBUVRFmYEphyyKJjQjCRiOuAP3sZfQ=
golang.org/x/image v0.33.0/go.mod h1:DD3OsTYT9chzuzTQt+zMcOlBHgfoKQb1gry8p76Y1sc=
golang.org/x/image v0.34.0 h1:33gCkyw9hmwbZJeZkct8XyR11yH889EQt/QH4VmXMn8=
golang.org/x/image v0.34.0/go.mod h1:2RNFBZRB+vnwwFil8GkMdRvrJOFd1AzdZI6vOY+eJVU=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -333,8 +333,8 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -360,8 +360,8 @@ golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
@@ -372,8 +372,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@@ -7,34 +7,33 @@ include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=r8152
PKG_VERSION:=2.20.1
PKG_VERSION:=2.21.4
PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/wget/realtek-r8152-linux/tar.gz/v$(PKG_VERSION)?
PKG_HASH:=045a1e1d20336d26b61b01d8561216029ff3405894707958b5670a7cd7fa75c1
PKG_HASH:=05041e46b0edb75b53bbdac640fc027b1eac22cf493e76c3018ab3b5c1dc1df8
PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/realtek-$(PKG_NAME)-linux-$(PKG_VERSION)
PKG_MAINTAINER:=Tianling Shen <cnsztl@immortalwrt.org>
include $(INCLUDE_DIR)/package.mk
define KernelPackage/usb-net-rtl8152-vendor
VERSION:=$(LINUX_VERSION)+$(PKG_VERSION)-$(BOARD)-$(PKG_RELEASE)
TITLE:=Realtek RTL8152/RTL8153/RTL8154/RTL8156/RTL8157 driver
SUBMENU:=USB Support
DEPENDS:=+kmod-usb-net +LINUX_6_12:kmod-libphy
define KernelPackage/r8152
SUBMENU:=Network Devices
TITLE:=Realtek RTL815X USB Ethernet driver
DEPENDS:=+kmod-usb-net +kmod-libphy
FILES:=$(PKG_BUILD_DIR)/r8152.ko
AUTOLOAD:=$(call AutoProbe,r8152)
CONFLICTS:=kmod-usb-net-rtl8152
endef
define KernelPackage/usb-net-rtl8152-vendor/description
Kernel module for Realtek Realtek USB 1G / 2.5G / 5G / 10G Ethernet Chipsets
define KernelPackage/r8152/description
Kernel module for Realtek USB Ethernet Chipsets
endef
define Build/Compile
+$(KERNEL_MAKE) M=$(PKG_BUILD_DIR) modules
endef
$(eval $(call KernelPackage,usb-net-rtl8152-vendor))
$(eval $(call KernelPackage,r8152))

View File

@@ -30,6 +30,7 @@ type SudokuOption struct {
TableType string `proxy:"table-type,omitempty"` // "prefer_ascii" or "prefer_entropy"
EnablePureDownlink *bool `proxy:"enable-pure-downlink,omitempty"`
HTTPMask bool `proxy:"http-mask,omitempty"`
CustomTable string `proxy:"custom-table,omitempty"` // optional custom byte layout, e.g. xpxvvpvv
}
// DialContext implements C.ProxyAdapter
@@ -178,13 +179,17 @@ func NewSudoku(option SudokuOption) (*Sudoku, error) {
ServerAddress: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)),
Key: option.Key,
AEADMethod: defaultConf.AEADMethod,
Table: sudoku.NewTable(sudoku.ClientAEADSeed(option.Key), tableType),
PaddingMin: paddingMin,
PaddingMax: paddingMax,
EnablePureDownlink: enablePureDownlink,
HandshakeTimeoutSeconds: defaultConf.HandshakeTimeoutSeconds,
DisableHTTPMask: !option.HTTPMask,
}
table, err := sudoku.NewTableWithCustom(sudoku.ClientAEADSeed(option.Key), tableType, option.CustomTable)
if err != nil {
return nil, fmt.Errorf("build table failed: %w", err)
}
baseConf.Table = table
if option.AEADMethod != "" {
baseConf.AEADMethod = option.AEADMethod
}

View File

@@ -609,6 +609,13 @@ func (w *WireGuard) ResolveUDP(ctx context.Context, metadata *C.Metadata) error
return nil
}
// ProxyInfo implements C.ProxyAdapter
func (w *WireGuard) ProxyInfo() C.ProxyInfo {
info := w.Base.ProxyInfo()
info.DialerProxy = w.option.DialerProxy
return info
}
// IsL3Protocol implements C.ProxyAdapter
func (w *WireGuard) IsL3Protocol(metadata *C.Metadata) bool {
return true

View File

@@ -8,6 +8,7 @@ import (
"reflect"
"runtime"
"strings"
"sync"
"time"
"github.com/metacubex/mihomo/adapter"
@@ -43,6 +44,7 @@ type providerForApi struct {
}
type baseProvider struct {
mutex sync.RWMutex
name string
proxies []C.Proxy
healthCheck *HealthCheck
@@ -54,6 +56,8 @@ func (bp *baseProvider) Name() string {
}
func (bp *baseProvider) Version() uint32 {
bp.mutex.RLock()
defer bp.mutex.RUnlock()
return bp.version
}
@@ -73,10 +77,14 @@ func (bp *baseProvider) Type() P.ProviderType {
}
func (bp *baseProvider) Proxies() []C.Proxy {
bp.mutex.RLock()
defer bp.mutex.RUnlock()
return bp.proxies
}
func (bp *baseProvider) Count() int {
bp.mutex.RLock()
defer bp.mutex.RUnlock()
return len(bp.proxies)
}
@@ -93,6 +101,8 @@ func (bp *baseProvider) RegisterHealthCheckTask(url string, expectedStatus utils
}
func (bp *baseProvider) setProxies(proxies []C.Proxy) {
bp.mutex.Lock()
defer bp.mutex.Unlock()
bp.proxies = proxies
bp.version += 1
bp.healthCheck.setProxies(proxies)

View File

@@ -1048,8 +1048,9 @@ proxies: # socks5
padding-min: 2 # 最小填充字节数
padding-max: 7 # 最大填充字节数
table-type: prefer_ascii # 可选值prefer_ascii、prefer_entropy 前者全ascii映射后者保证熵值汉明1低于3
# custom-table: xpxvvpvv # 可选自定义字节布局必须包含2个x、2个p、4个v可随意组合。启用此处则无需配置`table-type`
http-mask: true # 是否启用http掩码
enable-pure-downlink: false # 是否启用混淆下行false的情况下能在保证数据安全的前提下极大提升下行速度
enable-pure-downlink: false # 是否启用混淆下行false的情况下能在保证数据安全的前提下极大提升下行速度,与服务端端保持相同(如果此处为false则要求aead不可为none)
# anytls
- name: anytls
@@ -1589,8 +1590,9 @@ listeners:
padding-min: 1 # 填充最小长度
padding-max: 15 # 填充最大长度,均不建议过大
table-type: prefer_ascii # 可选值prefer_ascii、prefer_entropy 前者全ascii映射后者保证熵值汉明1低于3
# custom-table: xpxvvpvv # 可选自定义字节布局必须包含2个x、2个p、4个v
handshake-timeout: 5 # optional
enable-pure-downlink: false # 是否启用混淆下行false的情况下能在保证数据安全的前提下极大提升下行速度与客户端保持相同
enable-pure-downlink: false # 是否启用混淆下行false的情况下能在保证数据安全的前提下极大提升下行速度与客户端保持相同(如果此处为false则要求aead不可为none)
@@ -1742,4 +1744,3 @@ listeners:
# alpn:
# - h3
# max-udp-relay-packet-size: 1500

View File

@@ -43,7 +43,7 @@ require (
github.com/mroth/weightedrand/v2 v2.1.0
github.com/openacid/low v0.1.21
github.com/oschwald/maxminddb-golang v1.12.0 // lastest version compatible with golang1.20
github.com/saba-futai/sudoku v0.0.2-b
github.com/saba-futai/sudoku v0.0.2-c
github.com/sagernet/cors v1.2.1
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a
github.com/samber/lo v1.52.0

View File

@@ -171,8 +171,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
github.com/saba-futai/sudoku v0.0.2-b h1:IbBjgZe1IzzD4xjaCSAdAy8ZNrwOusT14AwCYm77NwI=
github.com/saba-futai/sudoku v0.0.2-b/go.mod h1:Rvggsoprp7HQM7bMIZUd1M27bPj8THRsZdY1dGbIAvo=
github.com/saba-futai/sudoku v0.0.2-c h1:0CaoCKx4Br8UL97fnIxn8Y7rnQpflBza7kfaIrdg2rI=
github.com/saba-futai/sudoku v0.0.2-c/go.mod h1:Rvggsoprp7HQM7bMIZUd1M27bPj8THRsZdY1dGbIAvo=
github.com/sagernet/cors v1.2.1 h1:Cv5Z8y9YSD6Gm+qSpNrL3LO4lD3eQVvbFYJSG7JCMHQ=
github.com/sagernet/cors v1.2.1/go.mod h1:O64VyOjjhrkLmQIjF4KGRrJO/5dVXFdpEmCW/eISRAI=
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZNjr6sGeT00J8uU7JF4cNUdb44/Duis=

View File

@@ -14,6 +14,7 @@ type SudokuServer struct {
TableType string `json:"table-type,omitempty"`
HandshakeTimeoutSecond *int `json:"handshake-timeout,omitempty"`
EnablePureDownlink *bool `json:"enable-pure-downlink,omitempty"`
CustomTable string `json:"custom-table,omitempty"`
}
func (s SudokuServer) String() string {

View File

@@ -20,6 +20,7 @@ type SudokuOption struct {
TableType string `inbound:"table-type,omitempty"` // "prefer_ascii" or "prefer_entropy"
HandshakeTimeoutSecond *int `inbound:"handshake-timeout,omitempty"`
EnablePureDownlink *bool `inbound:"enable-pure-downlink,omitempty"`
CustomTable string `inbound:"custom-table,omitempty"` // optional custom byte layout, e.g. xpxvvpvv
}
func (o SudokuOption) Equal(config C.InboundConfig) bool {
@@ -52,6 +53,7 @@ func NewSudoku(options *SudokuOption) (*Sudoku, error) {
TableType: options.TableType,
HandshakeTimeoutSecond: options.HandshakeTimeoutSecond,
EnablePureDownlink: options.EnablePureDownlink,
CustomTable: options.CustomTable,
}
return &Sudoku{

View File

@@ -138,3 +138,27 @@ func TestInboundSudoku_PackedDownlink(t *testing.T) {
testInboundSudoku(t, inboundOptions, outboundOptions)
})
}
func TestInboundSudoku_CustomTable(t *testing.T) {
key := "test_key_custom"
custom := "xpxvvpvv"
inboundOptions := inbound.SudokuOption{
Key: key,
TableType: "prefer_entropy",
CustomTable: custom,
}
outboundOptions := outbound.SudokuOption{
Key: key,
TableType: "prefer_entropy",
CustomTable: custom,
}
testInboundSudoku(t, inboundOptions, outboundOptions)
t.Run("ed25519key", func(t *testing.T) {
inboundOptions := inboundOptions
outboundOptions := outboundOptions
inboundOptions.Key = sudokuPublicKey
outboundOptions.Key = sudokuPrivateKey
testInboundSudoku(t, inboundOptions, outboundOptions)
})
}

View File

@@ -152,6 +152,12 @@ func New(config LC.SudokuServer, tunnel C.Tunnel, additions ...inbound.Addition)
enablePureDownlink = *config.EnablePureDownlink
}
table, err := sudoku.NewTableWithCustom(config.Key, tableType, config.CustomTable)
if err != nil {
_ = l.Close()
return nil, err
}
handshakeTimeout := defaultConf.HandshakeTimeoutSeconds
if config.HandshakeTimeoutSecond != nil {
handshakeTimeout = *config.HandshakeTimeoutSecond
@@ -160,7 +166,7 @@ func New(config LC.SudokuServer, tunnel C.Tunnel, additions ...inbound.Addition)
protoConf := sudoku.ProtocolConfig{
Key: config.Key,
AEADMethod: defaultConf.AEADMethod,
Table: sudoku.NewTable(config.Key, tableType),
Table: table,
PaddingMin: paddingMin,
PaddingMax: paddingMax,
EnablePureDownlink: enablePureDownlink,

View File

@@ -146,12 +146,23 @@ func buildHandshakePayload(key string) [16]byte {
}
func NewTable(key string, tableType string) *sudoku.Table {
start := time.Now()
table := sudoku.NewTable(key, tableType)
log.Infoln("[Sudoku] Tables initialized (%s) in %v", tableType, time.Since(start))
table, err := NewTableWithCustom(key, tableType, "")
if err != nil {
panic(fmt.Sprintf("[Sudoku] failed to init tables: %v", err))
}
return table
}
func NewTableWithCustom(key string, tableType string, customTable string) (*sudoku.Table, error) {
start := time.Now()
table, err := sudoku.NewTableWithCustom(key, tableType, customTable)
if err != nil {
return nil, err
}
log.Infoln("[Sudoku] Tables initialized (%s, custom=%v) in %v", tableType, customTable != "", time.Since(start))
return table, nil
}
func ClientAEADSeed(key string) string {
if recovered, err := crypto.RecoverPublicKey(key); err == nil {
return crypto.EncodePoint(recovered)

View File

@@ -228,3 +228,22 @@ func runPackedUoTSession(id int, cfg *apis.ProtocolConfig, errCh chan<- error) {
return
}
}
func TestCustomTableHandshake(t *testing.T) {
table, err := sudokuobfs.NewTableWithCustom("custom-seed", "prefer_entropy", "xpxvvpvv")
if err != nil {
t.Fatalf("build custom table: %v", err)
}
cfg := newPackedConfig(table)
errCh := make(chan error, 2)
runPackedTCPSession(42, cfg, errCh)
runPackedUoTSession(43, cfg, errCh)
close(errCh)
for err := range errCh {
if err != nil {
t.Fatalf("custom table handshake failed: %v", err)
}
}
}

View File

@@ -7,7 +7,7 @@ jobs:
stale:
runs-on: ubuntu-22.04
steps:
- uses: actions/stale@v7.0.0
- uses: actions/stale@v10
with:
stale-issue-message: "Stale Issue"
stale-pr-message: "Stale PR"

View File

@@ -206,9 +206,9 @@ function gen_outbound(flag, node, tag, proxy_table)
local first = node.tcp_guise_http_path[1]
return (first == "" or not first) and "/" or first
end)() or "/",
headers = {
["User-Agent"] = node.tcp_guise_http_user_agent or nil
},
headers = node.tcp_guise_http_user_agent and {
["User-Agent"] = node.tcp_guise_http_user_agent
} or nil,
idle_timeout = (node.http_h2_health_check == "1") and node.http_h2_read_idle_timeout or nil,
ping_timeout = (node.http_h2_health_check == "1") and node.http_h2_health_check_timeout or nil,
}
@@ -220,9 +220,9 @@ function gen_outbound(flag, node, tag, proxy_table)
type = "http",
host = node.http_host or {},
path = node.http_path or "/",
headers = {
["User-Agent"] = node.http_user_agent or nil
},
headers = node.http_user_agent and {
["User-Agent"] = node.http_user_agent
} or nil,
idle_timeout = (node.http_h2_health_check == "1") and node.http_h2_read_idle_timeout or nil,
ping_timeout = (node.http_h2_health_check == "1") and node.http_h2_health_check_timeout or nil,
}
@@ -233,10 +233,10 @@ function gen_outbound(flag, node, tag, proxy_table)
v2ray_transport = {
type = "ws",
path = node.ws_path or "/",
headers = {
Host = node.ws_host or nil,
["User-Agent"] = node.ws_user_agent or nil
},
headers = (node.ws_host or node.ws_user_agent) and {
Host = node.ws_host,
["User-Agent"] = node.ws_user_agent
} or nil,
max_early_data = tonumber(node.ws_maxEarlyData) or nil,
early_data_header_name = (node.ws_earlyDataHeaderName) and node.ws_earlyDataHeaderName or nil --要与 Xray-core 兼容,请将其设置为 Sec-WebSocket-Protocol。它需要与服务器保持一致。
}
@@ -247,9 +247,9 @@ function gen_outbound(flag, node, tag, proxy_table)
type = "httpupgrade",
host = node.httpupgrade_host,
path = node.httpupgrade_path or "/",
headers = {
["User-Agent"] = node.httpupgrade_user_agent or nil
}
headers = node.httpupgrade_user_agent and {
["User-Agent"] = node.httpupgrade_user_agent
} or nil
}
end

View File

@@ -178,10 +178,10 @@ function gen_outbound(flag, node, tag, proxy_table)
end
return r
end)() or {"/"},
headers = {
Host = node.tcp_guise_http_host or {},
headers = (node.tcp_guise_http_host or node.tcp_guise_http_user_agent) and {
Host = node.tcp_guise_http_host,
["User-Agent"] = node.tcp_guise_http_user_agent and {node.tcp_guise_http_user_agent} or nil
}
} or nil
} or nil
}
} or nil,
@@ -201,10 +201,10 @@ function gen_outbound(flag, node, tag, proxy_table)
} or nil,
wsSettings = (node.transport == "ws") and {
path = node.ws_path or "/",
headers = {
Host = node.ws_host or nil,
["User-Agent"] = node.ws_user_agent or nil
},
headers = (node.ws_host or node.ws_user_agent) and {
Host = node.ws_host,
["User-Agent"] = node.ws_user_agent
} or nil,
maxEarlyData = tonumber(node.ws_maxEarlyData) or nil,
earlyDataHeaderName = (node.ws_earlyDataHeaderName) and node.ws_earlyDataHeaderName or nil,
heartbeatPeriod = tonumber(node.ws_heartbeatPeriod) or nil
@@ -220,9 +220,9 @@ function gen_outbound(flag, node, tag, proxy_table)
httpupgradeSettings = (node.transport == "httpupgrade") and {
path = node.httpupgrade_path or "/",
host = node.httpupgrade_host,
headers = {
["User-Agent"] = node.httpupgrade_user_agent or nil
}
headers = node.httpupgrade_user_agent and {
["User-Agent"] = node.httpupgrade_user_agent
} or nil
} or nil,
xhttpSettings = (node.transport == "xhttp") and {
mode = node.xhttp_mode or "auto",

View File

@@ -1,5 +1,10 @@
<%+cbi/valueheader%>
<%
-- Template Developers:
-- - lwb1978
-- Copyright: copyright(c)20252027
-- Description: Passwall(2) UI template
local cbid = "cbid." .. self.config .. "." .. section .. "." .. self.option
-- 读取 MultiValue
@@ -41,9 +46,62 @@ for _, item in ipairs(values) do
end
%>
<div id="<%=cbid%>" class="cbi-input-select" style="display:inline-block;">
<!-- 搜索 -->
<input type="text" id="<%=cbid%>.search" class="node_search_input cbi-input-text" placeholder="<%:Search nodes...%>"
style="width:100%;padding:6px;margin-bottom:8px;border:1px solid #ccc;border-radius:4px;box-sizing:border-box;max-height:36px;" />
<!-- 主容器 -->
<div style="max-height:300px;overflow:auto;margin-bottom:8px;white-space:nowrap;">
<ul class="cbi-multi" id="<%=cbid%>.node_list" style="padding:0 !important;margin:0 !important;width:100%;box-sizing:border-box;">
<% for _, gname in ipairs(group_order) do %>
<% local items = groups[gname] %>
<li class="group-block" data-group="<%=gname%>" style="list-style:none;padding:0;margin:0 0 8px 0;">
<!-- 组标题 -->
<div class="group-title" style="cursor:pointer;padding:6px;background:#f0f0f0;border-radius:4px;margin-bottom:4px;display:flex;align-items:center;white-space:nowrap;">
<span id="arrow-<%=self.option%>-<%=gname%>" class="mv-arrow-down-small"></span>
<b style="margin-left:8px;"><%=gname%></b>
<span id="group-count-<%=self.option%>-<%=gname%>" style="margin-left:8px;color:#007bff;">
(0/<%=#items%>)
</span>
</div>
<!-- 组内容 -->
<ul id="group-<%=self.option%>-<%=gname%>" style="margin:0 0 8px 16px;padding:0;list-style:none;">
<% for _, item in ipairs(items) do %>
<li data-node-name="<%=pcdata(item.label):lower()%>" title="<%=pcdata(item.label)%>" style="list-style:none;padding:0;margin:0;white-space:nowrap;text-align:left;">
<div style="display:inline-flex;align-items:center;vertical-align:middle;">
<input type="checkbox" class="cbi-input-checkbox" style="vertical-align:middle;margin:0;margin-right:6px;"
<%= attr("id", cbid .. "." .. item.key) ..
attr("name", cbid) ..
attr("value", item.key) ..
ifattr(selected[item.key], "checked", "checked")
%> />
<label for="<%=cbid .. "." .. item.key%>" style="vertical-align:middle;margin:0;padding:0;"><%=pcdata(item.label)%></label>
</div>
</li>
<% end %>
</ul>
</li>
<% end %>
</ul>
</div>
<!-- 控制栏 -->
<div style="margin-top:4px;display:flex;gap:4px;align-items:center;">
<input class="btn cbi-button cbi-button-edit" type="button" onclick="mv_selectAll('<%=cbid%>','<%=self.option%>',true)" value="<%:Select all%>">
<input class="btn cbi-button cbi-button-edit" type="button" onclick="mv_selectAll('<%=cbid%>','<%=self.option%>',false)" value="<%:DeSelect all%>">
<span id="count-<%=self.option%>" style="color:#666;"></span>
</div>
</div>
<%+cbi/valuefooter%>
<%
-- 公共部分(只加载一次)
if not _G.__NODES_MULTIVALUE_CSS_JS__ then
_G.__NODES_MULTIVALUE_CSS_JS__ = true
%>
<style>
/* 组标题的右箭头(折叠) */
.lv-arrow-right {
/* 组标题的右箭头 */
.mv-arrow-right {
width: 0;
height: 0;
border-top: 4px solid transparent;
@@ -52,9 +110,8 @@ end
display: inline-block;
vertical-align: middle;
}
/* 组标题的下箭头(展开) */
.lv-arrow-down-small {
/* 组标题的下箭头 */
.mv-arrow-down-small {
width: 0;
height: 0;
border-left: 4px solid transparent;
@@ -65,120 +122,67 @@ end
}
</style>
<div id="<%=cbid%>" class="cbi-input-select" style="display: inline-block;">
<!-- 搜索 -->
<input type="text"
id="<%=cbid%>.search"
class="node-search-input cbi-input-text"
placeholder="<%:Search nodes...%>"
oninput="filterGroups_<%=self.option%>(this.value)"
style="width:100%;padding:6px;margin-bottom:8px;border:1px solid #ccc;border-radius:4px;box-sizing:border-box;max-height:36px;" />
<!-- 主容器 -->
<div style="max-height:300px; overflow:auto; margin-bottom:8px; white-space:nowrap;">
<ul class="cbi-multi" id="<%=cbid%>.node_list" style="padding:0 !important;margin:0 !important;width:100%;box-sizing:border-box;">
<% for _, gname in ipairs(group_order) do %>
<% local items = groups[gname] %>
<li class="group-block" data-group="<%=gname%>" style="list-style:none; padding:0; margin:0 0 8px 0;">
<!-- 组标题 -->
<div class="group-title"
onclick="toggleGroup_<%=self.option%>('<%=gname%>')"
style="cursor:pointer;padding:6px;background:#f0f0f0;border-radius:4px;margin-bottom:4px;display:flex;align-items:center;white-space:nowrap;">
<span id="arrow-<%=self.option%>-<%=gname%>" class="lv-arrow-down-small"></span>
<b style="margin-left:8px;"><%=gname%></b>
<span id="group-count-<%=self.option%>-<%=gname%>" style="margin-left:8px;color:#007bff;">
(0/<%=#items%>)
</span>
</div>
<!-- 组内容(可折叠)-->
<ul id="group-<%=self.option%>-<%=gname%>" style="margin:0 0 8px 16px; padding:0; list-style:none;">
<% for _, item in ipairs(items) do %>
<li data-node-name="<%=pcdata(item.label):lower()%>" style="list-style:none;padding:0;margin:0;white-space:nowrap;" title="<%=pcdata(item.label)%>">
<input
type="checkbox"
class="cbi-input-checkbox"
style="vertical-align: middle; margin-right:6px;"
<%= attr("id", cbid .. "." .. item.key) ..
attr("name", cbid) ..
attr("value", item.key) ..
ifattr(selected[item.key], "checked", "checked")
%> />
<label for="<%=cbid .. "." .. item.key%>"><%=pcdata(item.label)%></label>
</li>
<% end %>
</ul>
</li>
<% end %>
</ul>
</div>
<!-- 控制栏 -->
<div style="margin-top:4px;display:flex;gap:4px;align-items:center;">
<input class="btn cbi-button cbi-button-edit" type="button" onclick="selectAll_<%=self.option%>(true)" value="<%:Select all%>">
<input class="btn cbi-button cbi-button-edit" type="button" onclick="selectAll_<%=self.option%>(false)" value="<%:DeSelect all%>">
<span id="count-<%=self.option%>" style="color:#666;"></span>
</div>
</div>
<%+cbi/valuefooter%>
<script type="text/javascript">
//<![CDATA[
(function(){
const cbid = "<%=cbid%>";
const opt = "<%=self.option%>";
const listId = cbid + ".node_list";
// 折叠组
window["toggleGroup_" + opt] = function(g){
const ul = document.getElementById("group-" + opt + "-" + g);
const arrow = document.getElementById("arrow-" + opt + "-" + g);
function mv_toggleGroup(opt, nodeList, searchInput, g) {
const ul = nodeList.querySelector("#group-" + opt + "-" + g);
const arrow = nodeList.querySelector("#arrow-" + opt + "-" + g);
if (!ul) return;
// 判断是否在搜索状态
const keyword = document.getElementById(cbid + ".search").value.trim().toLowerCase();
const keyword = searchInput.value.trim().toLowerCase();
const isSearching = keyword.length > 0;
// 搜索状态下,仅切换当前组,不处理其他组
if (isSearching) {
if (ul.style.display === "none") {
ul.style.display = "";
if (arrow) arrow.className = "lv-arrow-down-small";
} else {
ul.style.display = "none";
if (arrow) arrow.className = "lv-arrow-right";
}
if (isSearching){
ul.style.display = ul.style.display === "none" ? "block" : "none";
if (arrow) arrow.className = ul.style.display === "none" ? "mv-arrow-right" : "mv-arrow-down-small";
return;
}
// 非搜索模式:先折叠其他组
const groups = document.querySelectorAll("[id='" + listId + "'] .group-block");
groups.forEach(group=>{
nodeList.querySelectorAll(".group-block").forEach(group=>{
const gname = group.getAttribute("data-group");
const gul = document.getElementById("group-" + opt + "-" + gname);
const garrow = document.getElementById("arrow-" + opt + "-" + gname);
if (gname !== g) {
if (gul) gul.style.display = "none";
if (garrow) arrow.className = "lv-arrow-right";
if (garrow) garrow.className = "mv-arrow-right";
}
});
document.getElementById(listId).parentNode.scrollTop = 0;
nodeList.parentNode.scrollTop = 0;
// 切换当前组
if (ul.style.display === "none") {
ul.style.display = "";
if (arrow) arrow.className = "lv-arrow-down-small";
} else {
ul.style.display = "none";
if (arrow) arrow.className = "lv-arrow-right";
}
ul.style.display = ul.style.display === "none" ? "block" : "none";
if (arrow) arrow.className = ul.style.display === "none" ? "mv-arrow-right" : "mv-arrow-down-small";
};
// 计数
function mv_updateCount(opt, nodeList) {
// 当前实例下的所有 checkbox
const cbs = nodeList.querySelectorAll("input[type=checkbox]");
let checked = 0;
cbs.forEach(cb => { if(cb.checked) checked++; });
// 更新总计
const totalSpan = document.getElementById("count-" + opt);
if (totalSpan) {
totalSpan.innerHTML = "<%:Selected:%> <span style='color:red;'>" + checked + " / " + cbs.length + "</span>";
}
// 更新每个组计数
nodeList.querySelectorAll(".group-block").forEach(group => {
const gname = group.getAttribute("data-group");
const groupCbs = group.querySelectorAll("li[data-node-name] input[type=checkbox]");
let groupChecked = 0;
groupCbs.forEach(cb => { if(cb.checked) groupChecked++; });
const span = document.getElementById("group-count-" + opt + "-" + gname);
if(span) span.textContent = "(" + groupChecked + "/" + groupCbs.length + ")";
});
}
// 搜索
window["filterGroups_" + opt] = function(keyword){
keyword = keyword.toLowerCase().trim();
const groups = document.querySelectorAll("[id='" + listId + "'] .group-block");
groups.forEach(group=>{
function mv_filterGroups(keyword, opt, nodeList) {
keyword = (keyword || "").toLowerCase().trim();
nodeList.querySelectorAll(".group-block").forEach(group => {
const items = group.querySelectorAll("li[data-node-name]");
let matchCount = 0;
items.forEach(li=>{
items.forEach(li => {
const name = li.getAttribute("data-node-name");
if (!keyword || name.indexOf(keyword) !== -1) {
li.style.display = "";
@@ -187,7 +191,7 @@ end
li.style.display = "none";
}
});
// 搜索时自动展开所有
// 搜索时自动展开组
const gname = group.getAttribute("data-group");
const ul = document.getElementById("group-" + opt + "-" + gname);
const arrow = document.getElementById("arrow-" + opt + "-" + gname);
@@ -196,88 +200,71 @@ end
group.style.display = "none";
} else {
group.style.display = "";
if (keyword) {
if (keyword && ul && arrow) {
ul.style.display = "";
arrow.className = "lv-arrow-down-small";
arrow.className = "mv-arrow-down-small";
}
}
});
updateCount();
mv_updateCount(opt, nodeList);
// 清空搜索后恢复全部折叠
if (!keyword) {
const groups = document.querySelectorAll("[id='" + listId + "'] .group-block");
groups.forEach(group=>{
const gname = group.getAttribute("data-group");
const ul = document.getElementById("group-" + opt + "-" + gname);
const arrow = document.getElementById("arrow-" + opt + "-" + gname);
if (ul) ul.style.display = "none";
if (arrow) arrow.className = "lv-arrow-right";
});
mv_collapseAllGroups(opt, nodeList);
}
};
}
// 全选 / 全不选
window["selectAll_" + opt] = function(flag){
const cbs = document.querySelectorAll("[id='" + listId + "'] input[type=checkbox]");
function mv_selectAll(cbid, opt, flag) {
const nodeList = document.getElementById(cbid + ".node_list");
const cbs = nodeList.querySelectorAll("input[type=checkbox]");
cbs.forEach(cb=>{
if (cb.offsetParent !== null) cb.checked = flag;
});
updateCount();
mv_updateCount(opt, nodeList);
};
// 计数
function updateCount(){
const cbs = document.querySelectorAll("[id='" + listId + "'] input[type=checkbox]");
let checked = 0;
cbs.forEach(cb=>{ if (cb.checked) checked++; });
// 更新总计
document.getElementById("count-" + opt).innerHTML =
"<%:Selected:%> <span style='color:red;'>" + checked + " / " + cbs.length + "</span>";
// 更新每个组
const groups = document.querySelectorAll("[id='" + listId + "'] .group-block");
groups.forEach(group=>{
const gname = group.getAttribute("data-group");
const groupCbs = group.querySelectorAll("li[data-node-name] input[type=checkbox]");
let groupChecked = 0;
groupCbs.forEach(cb=>{ if(cb.checked) groupChecked++; });
const span = document.getElementById("group-count-" + opt + "-" + gname);
if(span) span.textContent = "(" + groupChecked + "/" + groupCbs.length + ")";
});
}
document.getElementById(listId)?.addEventListener("change", updateCount);
// 初始化折叠所有组和计数
const initObserver = new MutationObserver(() => {
const list = document.getElementById(listId);
if (!list) return;
if (list.offsetParent === null) return;
if (list.dataset.initDone === "1") return;
list.dataset.initDone = "1";
const groups = document.querySelectorAll("[id='" + listId + "'] .group-block");
groups.forEach(group => {
// 折叠所有组
function mv_collapseAllGroups(opt, nodeList) {
nodeList.querySelectorAll(".group-block").forEach(group => {
const gname = group.getAttribute("data-group");
const ul = document.getElementById("group-" + opt + "-" + gname);
const arrow = document.getElementById("arrow-" + opt + "-" + gname);
if (ul) ul.style.display = "none";
if (arrow) arrow.className = "lv-arrow-right";
if (arrow) arrow.className = "mv-arrow-right";
});
}
//]]>
</script>
<% end %>
updateCount();
<script type="text/javascript">
//<![CDATA[
(function(){
const cbid = "<%=cbid%>";
const opt = "<%=self.option%>";
const searchInput = document.getElementById(cbid + ".search");
const nodeList = document.getElementById(cbid + ".node_list");
nodeList.querySelectorAll(".group-title").forEach(title => {
title.addEventListener("click", function() {
const g = this.closest(".group-block")?.getAttribute("data-group");
if (g) mv_toggleGroup(opt, nodeList, searchInput, g);
});
});
initObserver.observe(document.body, {
attributes: true,
subtree: true,
attributeFilter: ["style", "class"]
searchInput.addEventListener("input", function() {
mv_filterGroups(this.value, opt, nodeList);
})
// checkbox 改变时更新计数
nodeList.addEventListener("change", () => {
mv_updateCount(opt, nodeList);
});
// 初始化折叠所有组和计数
mv_collapseAllGroups(opt, nodeList)
mv_updateCount(opt, nodeList);
})();
//]]>
</script>

View File

@@ -7,7 +7,7 @@ jobs:
stale:
runs-on: ubuntu-22.04
steps:
- uses: actions/stale@v7.0.0
- uses: actions/stale@v10
with:
stale-issue-message: "Stale Issue"
stale-pr-message: "Stale PR"

View File

@@ -62,20 +62,22 @@ jobs:
echo "version=$version" >> "$GITHUB_OUTPUT"
build:
name: Build binary
if: github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Binary'
if: false # TODO: temporarily disabled for testing
runs-on: ubuntu-latest
needs:
- calculate_version
strategy:
matrix:
include:
- { os: linux, arch: amd64, debian: amd64, rpm: x86_64, pacman: x86_64, openwrt: "x86_64" }
- { os: linux, arch: "386", go386: sse2, debian: i386, rpm: i386, openwrt: "i386_pentium4" }
# Linux with naive outbound (CGO enabled with Debian Bullseye sysroot)
- { os: linux, arch: amd64, naive: true, debian: amd64, rpm: x86_64, pacman: x86_64, openwrt: "x86_64", sysroot_sha: "36a164623d03f525e3dfb783a5e9b8a00e98e1ddd2b5cff4e449bd016dd27e50", cc_target: "x86_64-linux-gnu" }
- { os: linux, arch: arm64, naive: true, debian: arm64, rpm: aarch64, pacman: aarch64, openwrt: "aarch64_cortex-a53 aarch64_cortex-a72 aarch64_cortex-a76 aarch64_generic", sysroot_sha: "2f915d821eec27515c0c6d21b69898e23762908d8d7ccc1aa2a8f5f25e8b7e18", cc_target: "aarch64-linux-gnu", cross_pkg: "libc6-dev-arm64-cross" }
- { os: linux, arch: "386", naive: true, go386: sse2, debian: i386, rpm: i386, openwrt: "i386_pentium4", sysroot_sha: "63f0e5128b84f7b0421956a4a40affa472be8da0e58caf27e9acbc84072daee7", cc_target: "i686-linux-gnu", cross_pkg: "libc6-dev-i386-cross" }
- { os: linux, arch: arm, naive: true, goarm: "7", debian: armhf, rpm: armv7hl, pacman: armv7hl, openwrt: "arm_cortex-a5_vfpv4 arm_cortex-a7_neon-vfpv4 arm_cortex-a7_vfpv4 arm_cortex-a8_vfpv3 arm_cortex-a9_neon arm_cortex-a9_vfpv3-d16 arm_cortex-a15_neon-vfpv4", sysroot_sha: "47b3a0b161ca011b2b33d4fc1ef6ef269b8208a0b7e4c900700c345acdfd1814", cc_target: "arm-linux-gnueabihf", cross_pkg: "libc6-dev-armhf-cross", linker: "bfd" }
# Linux without naive outbound (no CGO)
- { os: linux, arch: "386", go386: softfloat, openwrt: "i386_pentium-mmx" }
- { os: linux, arch: arm64, debian: arm64, rpm: aarch64, pacman: aarch64, openwrt: "aarch64_cortex-a53 aarch64_cortex-a72 aarch64_cortex-a76 aarch64_generic" }
- { os: linux, arch: arm, goarm: "5", openwrt: "arm_arm926ej-s arm_cortex-a7 arm_cortex-a9 arm_fa526 arm_xscale" }
- { os: linux, arch: arm, goarm: "6", debian: armel, rpm: armv6hl, openwrt: "arm_arm1176jzf-s_vfp" }
- { os: linux, arch: arm, goarm: "7", debian: armhf, rpm: armv7hl, pacman: armv7hl, openwrt: "arm_cortex-a5_vfpv4 arm_cortex-a7_neon-vfpv4 arm_cortex-a7_vfpv4 arm_cortex-a8_vfpv3 arm_cortex-a9_neon arm_cortex-a9_vfpv3-d16 arm_cortex-a15_neon-vfpv4" }
- { os: linux, arch: mips, gomips: softfloat, openwrt: "mips_24kc mips_4kec mips_mips32" }
- { os: linux, arch: mipsle, gomips: hardfloat, debian: mipsel, rpm: mipsel, openwrt: "mipsel_24kc_24kf" }
- { os: linux, arch: mipsle, gomips: softfloat, openwrt: "mipsel_24kc mipsel_74kc mipsel_mips32" }
@@ -86,13 +88,10 @@ jobs:
- { os: linux, arch: ppc64le, debian: ppc64el, rpm: ppc64le }
- { os: linux, arch: riscv64, debian: riscv64, rpm: riscv64, openwrt: "riscv64_generic" }
- { os: linux, arch: loong64, debian: loongarch64, rpm: loongarch64, openwrt: "loongarch64_generic" }
- { os: windows, arch: amd64 }
# Windows 7 legacy (no naive, no CGO)
- { os: windows, arch: amd64, legacy_win7: true, legacy_name: "windows-7" }
- { os: windows, arch: "386" }
- { os: windows, arch: "386", legacy_win7: true, legacy_name: "windows-7" }
- { os: windows, arch: arm64 }
# Android (naive enabled)
- { os: android, arch: arm64, ndk: "aarch64-linux-android21" }
- { os: android, arch: arm, ndk: "armv7a-linux-androideabi21" }
- { os: android, arch: amd64, ndk: "x86_64-linux-android21" }
@@ -135,6 +134,19 @@ jobs:
with:
ndk-version: r28
local-cache: true
- name: Download sysroot (Linux naive)
if: matrix.naive
run: |
set -xeuo pipefail
wget -q "https://commondatastorage.googleapis.com/chrome-linux-sysroot/${{ matrix.sysroot_sha }}" -O sysroot.tar.xz
mkdir -p /tmp/sysroot
tar -xf sysroot.tar.xz -C /tmp/sysroot
- name: Install cross compiler (Linux naive)
if: matrix.naive
run: |
set -xeuo pipefail
sudo apt-get update
sudo apt-get install -y clang lld ${{ matrix.cross_pkg }}
- name: Set tag
run: |-
git ls-remote --exit-code --tags origin v${{ needs.calculate_version.outputs.version }} || echo "PUBLISHED=false" >> "$GITHUB_ENV"
@@ -143,12 +155,12 @@ jobs:
run: |
set -xeuo pipefail
TAGS='with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_ccm,badlinkname,tfogo_checklinkname0'
if [[ "${{ matrix.os }}" == "android" ]]; then
if [[ "${{ matrix.naive }}" == "true" ]] || [[ "${{ matrix.os }}" == "android" ]]; then
TAGS="${TAGS},with_naive_outbound"
fi
echo "BUILD_TAGS=${TAGS}" >> "${GITHUB_ENV}"
- name: Build
if: matrix.os != 'android'
if: matrix.os != 'android' && ! matrix.naive
run: |
set -xeuo pipefail
mkdir -p dist
@@ -164,6 +176,24 @@ jobs:
GOMIPS: ${{ matrix.gomips }}
GOMIPS64: ${{ matrix.gomips }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Build Linux with naive
if: matrix.naive
run: |
set -xeuo pipefail
mkdir -p dist
go build -v -trimpath -o dist/sing-box -tags "${BUILD_TAGS}" \
-ldflags "-s -buildid= -X github.com/sagernet/sing-box/constant.Version=${{ needs.calculate_version.outputs.version }} -checklinkname=0 -linkmode=external -extldflags \"-fuse-ld=${LINKER} --sysroot=/tmp/sysroot\"" \
./cmd/sing-box
env:
CGO_ENABLED: "1"
GOOS: linux
GOARCH: ${{ matrix.arch }}
GO386: ${{ matrix.go386 }}
GOARM: ${{ matrix.goarm }}
CC: clang --target=${{ matrix.cc_target }} --sysroot=/tmp/sysroot
CXX: clang++ --target=${{ matrix.cc_target }} --sysroot=/tmp/sysroot
LINKER: ${{ matrix.linker || 'lld' }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Build Android
if: matrix.os == 'android'
run: |
@@ -286,7 +316,7 @@ jobs:
path: "dist"
build_darwin:
name: Build Darwin binaries
if: github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Binary'
if: false # TODO: temporarily disabled for testing
runs-on: macos-latest
needs:
- calculate_version
@@ -318,7 +348,10 @@ jobs:
- name: Set build tags
run: |
set -xeuo pipefail
TAGS='with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_ccm,with_naive_outbound,badlinkname,tfogo_checklinkname0'
TAGS='with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_ccm,badlinkname,tfogo_checklinkname0'
if [[ "${{ matrix.legacy_go124 }}" != "true" ]]; then
TAGS="${TAGS},with_naive_outbound"
fi
echo "BUILD_TAGS=${TAGS}" >> "${GITHUB_ENV}"
- name: Build
run: |
@@ -355,25 +388,93 @@ jobs:
with:
name: binary-darwin_${{ matrix.arch }}${{ matrix.legacy_name && format('-legacy-{0}', matrix.legacy_name) }}
path: "dist"
build_naive_linux:
name: Build Linux with naive outbound
build_windows:
name: Build Windows binaries
if: github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Binary'
runs-on: windows-latest
needs:
- calculate_version
strategy:
matrix:
include:
- { arch: amd64, cc: x86_64-w64-mingw32-clang }
- { arch: "386", cc: i686-w64-mingw32-clang }
- { arch: arm64, cc: aarch64-w64-mingw32-clang }
steps:
- name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ^1.25.4
- name: Cache llvm-mingw
id: cache-llvm-mingw
uses: actions/cache@v4
with:
path: ${{ runner.temp }}/llvm-mingw
key: llvm-mingw-ucrt-x86_64
- name: Setup llvm-mingw
if: steps.cache-llvm-mingw.outputs.cache-hit != 'true'
run: |
$headers = @{ Authorization = "Bearer $env:GITHUB_TOKEN" }
$release = Invoke-RestMethod -Uri "https://api.github.com/repos/mstorsjo/llvm-mingw/releases/latest" -Headers $headers
$asset = $release.assets | Where-Object { $_.name -like "llvm-mingw-*-ucrt-x86_64.zip" }
curl -Lo llvm-mingw.zip $asset.browser_download_url
Expand-Archive llvm-mingw.zip -DestinationPath $env:RUNNER_TEMP/llvm-mingw
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Setup llvm-mingw PATH
run: |
$extractedDir = Get-ChildItem -Path $env:RUNNER_TEMP/llvm-mingw -Directory | Where-Object { $_.Name -like "llvm-mingw-*" } | Select-Object -First 1
echo "$($extractedDir.FullName)\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
- name: Set tag
run: |-
git ls-remote --exit-code --tags origin v${{ needs.calculate_version.outputs.version }} || echo "PUBLISHED=false" >> "$env:GITHUB_ENV"
git tag v${{ needs.calculate_version.outputs.version }} -f
- name: Build
run: |
mkdir -p dist
go build -v -trimpath -o dist/sing-box.exe -tags "with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_ccm,with_naive_outbound,badlinkname,tfogo_checklinkname0" `
-ldflags "-s -buildid= -X github.com/sagernet/sing-box/constant.Version=${{ needs.calculate_version.outputs.version }} -checklinkname=0" `
./cmd/sing-box
env:
CGO_ENABLED: "1"
CGO_LDFLAGS_ALLOW: "-Wl,-Xlink=.*"
GOOS: windows
GOARCH: ${{ matrix.arch }}
CC: ${{ matrix.cc }}
CXX: ${{ matrix.cc }}++
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Archive
run: |
$DIR_NAME = "sing-box-${{ needs.calculate_version.outputs.version }}-windows-${{ matrix.arch }}"
mkdir "dist/$DIR_NAME"
Copy-Item LICENSE "dist/$DIR_NAME"
Copy-Item "dist/sing-box.exe" "dist/$DIR_NAME"
Compress-Archive -Path "dist/$DIR_NAME" -DestinationPath "dist/$DIR_NAME.zip"
Remove-Item -Recurse "dist/$DIR_NAME"
- name: Cleanup
run: Remove-Item dist/sing-box.exe
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: binary-windows_${{ matrix.arch }}
path: "dist"
build_linux_musl:
name: Build Linux musl static binaries
if: false # TODO: temporarily disabled for testing
runs-on: ubuntu-latest
needs:
- calculate_version
strategy:
matrix:
include:
# Linux glibc (dynamic linking with Debian Bullseye sysroot)
- { arch: amd64, sysroot_arch: amd64, sysroot_sha: "36a164623d03f525e3dfb783a5e9b8a00e98e1ddd2b5cff4e449bd016dd27e50", cc_target: "x86_64-linux-gnu", suffix: "-naive" }
- { arch: arm64, sysroot_arch: arm64, sysroot_sha: "2f915d821eec27515c0c6d21b69898e23762908d8d7ccc1aa2a8f5f25e8b7e18", cc_target: "aarch64-linux-gnu", suffix: "-naive" }
- { arch: "386", sysroot_arch: i386, sysroot_sha: "63f0e5128b84f7b0421956a4a40affa472be8da0e58caf27e9acbc84072daee7", cc_target: "i686-linux-gnu", suffix: "-naive" }
- { arch: arm, goarm: "7", sysroot_arch: armhf, sysroot_sha: "47b3a0b161ca011b2b33d4fc1ef6ef269b8208a0b7e4c900700c345acdfd1814", cc_target: "arm-linux-gnueabihf", suffix: "-naive" }
# Linux musl (static linking)
- { arch: amd64, musl: true, cc_target: "x86_64-linux-musl", suffix: "-naive-musl" }
- { arch: arm64, musl: true, cc_target: "aarch64-linux-musl", suffix: "-naive-musl" }
- { arch: "386", musl: true, cc_target: "i686-linux-musl", suffix: "-naive-musl" }
- { arch: arm, goarm: "7", musl: true, cc_target: "arm-linux-musleabihf", suffix: "-naive-musl" }
- { arch: amd64, cc_target: "x86_64-linux-musl" }
- { arch: arm64, cc_target: "aarch64-linux-musl" }
- { arch: "386", cc_target: "i686-linux-musl" }
- { arch: arm, goarm: "7", cc_target: "arm-linux-musleabihf" }
steps:
- name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
@@ -387,62 +488,16 @@ jobs:
run: |-
git ls-remote --exit-code --tags origin v${{ needs.calculate_version.outputs.version }} || echo "PUBLISHED=false" >> "$GITHUB_ENV"
git tag v${{ needs.calculate_version.outputs.version }} -f
- name: Download sysroot (glibc)
if: ${{ ! matrix.musl }}
run: |
set -xeuo pipefail
wget -q "https://commondatastorage.googleapis.com/chrome-linux-sysroot/${{ matrix.sysroot_sha }}" -O sysroot.tar.xz
mkdir -p /tmp/sysroot
tar -xf sysroot.tar.xz -C /tmp/sysroot
- name: Install cross compiler (glibc)
if: ${{ ! matrix.musl }}
run: |
set -xeuo pipefail
sudo apt-get update
sudo apt-get install -y clang lld
if [[ "${{ matrix.arch }}" == "arm64" ]]; then
sudo apt-get install -y libc6-dev-arm64-cross
elif [[ "${{ matrix.arch }}" == "386" ]]; then
sudo apt-get install -y libc6-dev-i386-cross
elif [[ "${{ matrix.arch }}" == "arm" ]]; then
sudo apt-get install -y libc6-dev-armhf-cross
fi
- name: Install musl cross compiler
if: matrix.musl
run: |
set -xeuo pipefail
.github/setup_musl_cross.sh "${{ matrix.cc_target }}"
echo "PATH=$HOME/musl-cross/bin:$PATH" >> $GITHUB_ENV
- name: Set build tags
run: |
set -xeuo pipefail
TAGS='with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_ccm,with_naive_outbound,badlinkname,tfogo_checklinkname0'
if [[ "${{ matrix.musl }}" == "true" ]]; then
TAGS="${TAGS},with_musl"
fi
echo "BUILD_TAGS=${TAGS}" >> "${GITHUB_ENV}"
- name: Build (glibc)
if: ${{ ! matrix.musl }}
- name: Build
run: |
set -xeuo pipefail
mkdir -p dist
go build -v -trimpath -o dist/sing-box -tags "${BUILD_TAGS}" \
-ldflags '-s -buildid= -X github.com/sagernet/sing-box/constant.Version=${{ needs.calculate_version.outputs.version }} -checklinkname=0 -linkmode=external -extldflags "-fuse-ld=lld --sysroot=/tmp/sysroot"' \
./cmd/sing-box
env:
CGO_ENABLED: "1"
GOOS: linux
GOARCH: ${{ matrix.arch }}
GOARM: ${{ matrix.goarm }}
CC: "clang --target=${{ matrix.cc_target }} --sysroot=/tmp/sysroot"
CXX: "clang++ --target=${{ matrix.cc_target }} --sysroot=/tmp/sysroot"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Build (musl)
if: matrix.musl
run: |
set -xeuo pipefail
mkdir -p dist
go build -v -trimpath -o dist/sing-box -tags "${BUILD_TAGS}" \
go build -v -trimpath -o dist/sing-box -tags 'with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_ccm,with_naive_outbound,with_musl,badlinkname,tfogo_checklinkname0' \
-ldflags '-s -buildid= -X github.com/sagernet/sing-box/constant.Version=${{ needs.calculate_version.outputs.version }} -checklinkname=0 -linkmode=external -extldflags "-static"' \
./cmd/sing-box
env:
@@ -459,7 +514,7 @@ jobs:
if [[ -n "${{ matrix.goarm }}" ]]; then
DIR_NAME="${DIR_NAME}v${{ matrix.goarm }}"
fi
DIR_NAME="${DIR_NAME}${{ matrix.suffix }}"
DIR_NAME="${DIR_NAME}-musl"
echo "DIR_NAME=${DIR_NAME}" >> "${GITHUB_ENV}"
- name: Archive
run: |
@@ -475,11 +530,11 @@ jobs:
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: binary-linux_${{ matrix.arch }}${{ matrix.goarm && format('v{0}', matrix.goarm) }}${{ matrix.suffix }}
name: binary-linux_${{ matrix.arch }}${{ matrix.goarm && format('v{0}', matrix.goarm) }}-musl
path: "dist"
build_android:
name: Build Android
if: github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Android'
if: false # TODO: temporarily disabled for testing
runs-on: ubuntu-latest
needs:
- calculate_version
@@ -559,7 +614,7 @@ jobs:
path: 'dist'
publish_android:
name: Publish Android
if: github.event_name == 'workflow_dispatch' && inputs.build == 'publish-android'
if: false # TODO: temporarily disabled for testing
runs-on: ubuntu-latest
needs:
- calculate_version
@@ -806,13 +861,14 @@ jobs:
path: 'dist'
upload:
name: Upload builds
if: "!failure() && github.event_name == 'workflow_dispatch' && (inputs.build == 'All' || inputs.build == 'Binary' || inputs.build == 'Android' || inputs.build == 'Apple' || inputs.build == 'macOS-standalone')"
if: false # TODO: temporarily disabled for testing
runs-on: ubuntu-latest
needs:
- calculate_version
- build
- build_darwin
- build_naive_linux
- build_windows
- build_linux_musl
- build_android
- build_apple
steps:

View File

@@ -25,8 +25,8 @@ require (
github.com/sagernet/asc-go v0.0.0-20241217030726-d563060fe4e1
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a
github.com/sagernet/cors v1.2.1
github.com/sagernet/cronet-go v0.0.0-20251209163619-43499a42c286
github.com/sagernet/cronet-go/all v0.0.0-20251209163943-9ad85d71d2e3
github.com/sagernet/cronet-go v0.0.0-20251210132647-15dd6a9ee4bc
github.com/sagernet/cronet-go/all v0.0.0-20251210133029-b0d1058a9fcf
github.com/sagernet/fswatch v0.1.1
github.com/sagernet/gomobile v0.1.8
github.com/sagernet/gvisor v0.0.0-20250811.0-sing-box-mod.1
@@ -106,24 +106,24 @@ require (
github.com/prometheus-community/pro-bing v0.4.0 // indirect
github.com/quic-go/qpack v0.6.0 // indirect
github.com/safchain/ethtool v0.3.0 // indirect
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20251209163619-43499a42c286 // indirect
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20251209163619-43499a42c286 // indirect
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20251209163619-43499a42c286 // indirect
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20251209163619-43499a42c286 // indirect
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20251209163619-43499a42c286 // indirect
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20251209163619-43499a42c286 // indirect
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20251209163619-43499a42c286 // indirect
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20251209163619-43499a42c286 // indirect
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20251209163619-43499a42c286 // indirect
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20251209163619-43499a42c286 // indirect
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20251209163619-43499a42c286 // indirect
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20251209163619-43499a42c286 // indirect
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20251209163619-43499a42c286 // indirect
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20251209163619-43499a42c286 // indirect
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20251209163619-43499a42c286 // indirect
github.com/sagernet/cronet-go/lib/windows_386 v0.0.0-20251209163619-43499a42c286 // indirect
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20251209163619-43499a42c286 // indirect
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20251209163619-43499a42c286 // indirect
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20251210132647-15dd6a9ee4bc // indirect
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20251210132647-15dd6a9ee4bc // indirect
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20251210132647-15dd6a9ee4bc // indirect
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20251210132647-15dd6a9ee4bc // indirect
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20251210132647-15dd6a9ee4bc // indirect
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20251210132647-15dd6a9ee4bc // indirect
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20251210132647-15dd6a9ee4bc // indirect
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20251210132647-15dd6a9ee4bc // indirect
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20251210132647-15dd6a9ee4bc // indirect
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20251210132647-15dd6a9ee4bc // indirect
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20251210132647-15dd6a9ee4bc // indirect
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20251210132647-15dd6a9ee4bc // indirect
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20251210132647-15dd6a9ee4bc // indirect
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20251210132647-15dd6a9ee4bc // indirect
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20251210132647-15dd6a9ee4bc // indirect
github.com/sagernet/cronet-go/lib/windows_386 v0.0.0-20251210132647-15dd6a9ee4bc // indirect
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20251210132647-15dd6a9ee4bc // indirect
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20251210132647-15dd6a9ee4bc // indirect
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect
github.com/sagernet/nftables v0.3.0-beta.4 // indirect
github.com/spf13/pflag v1.0.6 // indirect

View File

@@ -150,46 +150,46 @@ github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkk
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM=
github.com/sagernet/cors v1.2.1 h1:Cv5Z8y9YSD6Gm+qSpNrL3LO4lD3eQVvbFYJSG7JCMHQ=
github.com/sagernet/cors v1.2.1/go.mod h1:O64VyOjjhrkLmQIjF4KGRrJO/5dVXFdpEmCW/eISRAI=
github.com/sagernet/cronet-go v0.0.0-20251209163619-43499a42c286 h1:T3l7r/FRNyf6AS1ZZfvFMYtTCozKWgm/mNXjmg/HqOw=
github.com/sagernet/cronet-go v0.0.0-20251209163619-43499a42c286/go.mod h1:l5IZJLEWpDGJbrF0qBHgxAVBPsAxKOLa1BYDh6B2sdI=
github.com/sagernet/cronet-go/all v0.0.0-20251209163943-9ad85d71d2e3 h1:a6/HHQ2bBrX4humT9jSACAD9kj4ucgal5tYWjOpxsXA=
github.com/sagernet/cronet-go/all v0.0.0-20251209163943-9ad85d71d2e3/go.mod h1:bq4r/IRzbgNUWfcWxJTyex/jKzI6WCSPfrCK3ns4O3A=
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20251209163619-43499a42c286 h1:sZFASnzhbYtPJoz+7OAx7IC85161iROwEkmHVQcaHS0=
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20251209163619-43499a42c286/go.mod h1:XXDwdjX/T8xftoeJxQmbBoYXZp8MAPFR2CwbFuTpEtw=
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20251209163619-43499a42c286 h1:XmPpSRMDde4Oi5XzYBuOqWAvzPQsNjmKQfft98OlvLg=
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20251209163619-43499a42c286/go.mod h1:iNiUGoLtnr8/JTuVNj7XJbmpOAp2C6+B81KDrPxwaZM=
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20251209163619-43499a42c286 h1:EEn7N5sCLZwnmlZjYb63Ewt2SjfYKTQwlQqEaC0zyF8=
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20251209163619-43499a42c286/go.mod h1:19ILNUOGIzRdOqa2mq+iY0JoHxuieB7/lnjYeaA2vEc=
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20251209163619-43499a42c286 h1:UA4/kKm8qA694fO7Y9EAe9csHecdBgAoKyn5CzUdAig=
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20251209163619-43499a42c286/go.mod h1:JxzGyQf94Cr6sBShKqODGDyRUlESfJK/Njcz9Lz6qMQ=
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20251209163619-43499a42c286 h1:Cz1iXs54Urg23BRtdkikDUzaifE72lNwq3D+DHZTVXE=
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20251209163619-43499a42c286/go.mod h1:KN+9T9TBycGOLzmKU4QdcHAJEj6Nlx48ifnlTvvHMvs=
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20251209163619-43499a42c286 h1:9f7dGYztdhJHqnGxAfg6e3pwiQc7gCIFfbnpYUG8+l4=
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20251209163619-43499a42c286/go.mod h1:kojvtUc29KKnk8hs2QIANynVR59921SnGWA9kXohHc0=
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20251209163619-43499a42c286 h1:cVnXsYi+qvBGxtv5i5qzx05Ol0go4/ZVhEB/nwKdZxE=
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20251209163619-43499a42c286/go.mod h1:tzVJFTOm66UxLxy6K0ZN5Ic2PC79e+sKKnt+V9puEa4=
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20251209163619-43499a42c286 h1:L/M8nypnkrbv+zSFBEzoU3E2WVYoL/+BiF7W/ZGOkcE=
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20251209163619-43499a42c286/go.mod h1:cGh5hO6eljCo6KMQ/Cel8Xgq4+etL0awZLRBDVG1EZQ=
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20251209163619-43499a42c286 h1:UcNkxALcHUpo49DBHr2epN00hTRRiijwh4qv1fdXgRQ=
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20251209163619-43499a42c286/go.mod h1:JFE0/cxaKkx0wqPMZU7MgaplQlU0zudv82dROJjClKU=
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20251209163619-43499a42c286 h1:R68J9khidtJRKka3J2dNVKVGrBq0ieevNRS3P8vijMw=
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20251209163619-43499a42c286/go.mod h1:vU8VftFeSt7fURCa3JXD6+k6ss1YAX+idQjPvHmJ2tI=
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20251209163619-43499a42c286 h1:aDxXLIVS219vxa56UN1ak9Grju6UWKhX0ULw7RGDIgs=
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20251209163619-43499a42c286/go.mod h1:vCe4OUuL+XOUge9v3MyTD45BnuAXiH+DkjN9quDXJzQ=
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20251209163619-43499a42c286 h1:r4eaHyVT7KWguRhYTudhq+RHsd0pq7HHP/xLn3v/NuI=
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20251209163619-43499a42c286/go.mod h1:w9amBWrvjtohQzBGCKJ7LCh22LhTIJs4sE7cYaKQzM0=
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20251209163619-43499a42c286 h1:TYxTK8434FqUokQKzg5Qs8xpjU8ws2VVn7J4gfL0jY0=
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20251209163619-43499a42c286/go.mod h1:TqlsFtcYS/etTeck46kHBeT8Le0Igw1Q/AV88UnMS3s=
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20251209163619-43499a42c286 h1:2dysrFpUGjR/BePrJYoGyl8UmqlEY67g8ySyI2p1cjA=
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20251209163619-43499a42c286/go.mod h1:B6Qd0vys8sv9OKVRN6J9RqDzYRGE938Fb2zrYdBDyTQ=
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20251209163619-43499a42c286 h1:edRSfV1xEloFgpdiordf0S653D5r0exHN4X85BT06nk=
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20251209163619-43499a42c286/go.mod h1:3tXMMFY7AHugOVBZ5Al7cL7JKsnFOe5bMVr0hZPk3ow=
github.com/sagernet/cronet-go/lib/windows_386 v0.0.0-20251209163619-43499a42c286 h1:CUWmGJ8PslWMJHanzgxF9+CuN4fk4NigKwxw1tjpdRY=
github.com/sagernet/cronet-go/lib/windows_386 v0.0.0-20251209163619-43499a42c286/go.mod h1:rnS7D+ULJX2PrP0Cy+05GS0mRZ2PP6+gVSroZKt8fjk=
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20251209163619-43499a42c286 h1:2/fTHNBvTGgxWALqogKGpzKw1zLgc5lSidMRchLcoqk=
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20251209163619-43499a42c286/go.mod h1:lm9w/oCCRyBiUa3G8lDQTT8x/ONUvgVR2iV9fVzUZB8=
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20251209163619-43499a42c286 h1:J1nQYpbALQGlCOuErF0/lI3SnwPd0egy/iUxhgRK76g=
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20251209163619-43499a42c286/go.mod h1:n34YyLgapgjWdKa0IoeczjAFCwD3/dxbsH5sucKw0bw=
github.com/sagernet/cronet-go v0.0.0-20251210132647-15dd6a9ee4bc h1:TeUwtjNOirI7QW6RUGmzovZHiImdyysxdXii8tj2pjE=
github.com/sagernet/cronet-go v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:l5IZJLEWpDGJbrF0qBHgxAVBPsAxKOLa1BYDh6B2sdI=
github.com/sagernet/cronet-go/all v0.0.0-20251210133029-b0d1058a9fcf h1:9HfW4vwWSXSOBcxT3s7MAyxGnAxPpcFiRHW/9ImtlFA=
github.com/sagernet/cronet-go/all v0.0.0-20251210133029-b0d1058a9fcf/go.mod h1:hljs4OQivwLEGy9ijqAQ7/bKfdfIOnudIuBKVWGpuNU=
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20251210132647-15dd6a9ee4bc h1:7RwE5fT6D/bH8g/Sp/+bFPTTgYEHk8mI3wcP9nfOkfc=
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:XXDwdjX/T8xftoeJxQmbBoYXZp8MAPFR2CwbFuTpEtw=
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20251210132647-15dd6a9ee4bc h1:5ABO0dzl0FREp4yOj8tRUil8Rnr+UxAbgHm6/1/GaUs=
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:iNiUGoLtnr8/JTuVNj7XJbmpOAp2C6+B81KDrPxwaZM=
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20251210132647-15dd6a9ee4bc h1:6RWqk2JxL/JoyxeahfV6nWj0HpRJXKM42hAZAobprLk=
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:19ILNUOGIzRdOqa2mq+iY0JoHxuieB7/lnjYeaA2vEc=
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20251210132647-15dd6a9ee4bc h1:GHUnWWlndwxHw4pEvw40ISO7xrMq+h+P+FQ3KrGlghQ=
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:JxzGyQf94Cr6sBShKqODGDyRUlESfJK/Njcz9Lz6qMQ=
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20251210132647-15dd6a9ee4bc h1:urmRC1HxIetnZuyaPkHketyrhWBhwvRr74XXEHmqgLc=
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:KN+9T9TBycGOLzmKU4QdcHAJEj6Nlx48ifnlTvvHMvs=
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20251210132647-15dd6a9ee4bc h1:EN57YqGy2cbeQexLBb6vf1IcCEjNmz6sSoMNOik8DJQ=
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:kojvtUc29KKnk8hs2QIANynVR59921SnGWA9kXohHc0=
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20251210132647-15dd6a9ee4bc h1:aRFCWKVFt5aTbcHQ7rUWLtfpxVtUbB1t1VDEgMm1LdY=
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:tzVJFTOm66UxLxy6K0ZN5Ic2PC79e+sKKnt+V9puEa4=
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20251210132647-15dd6a9ee4bc h1:txzvlKqPSL3yUVQs0DOx1bc0ONEuiWqIEoaQvMJNqdk=
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:cGh5hO6eljCo6KMQ/Cel8Xgq4+etL0awZLRBDVG1EZQ=
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20251210132647-15dd6a9ee4bc h1:DdYm5omtBr6/0DyCG5cTS4fK8hXoPXeEWiaBhDdUqac=
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:JFE0/cxaKkx0wqPMZU7MgaplQlU0zudv82dROJjClKU=
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20251210132647-15dd6a9ee4bc h1:qZ5koP16Y5Wbzi89bRA3c2C9vUlZPk7uz5ZLBAd/4h4=
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:vU8VftFeSt7fURCa3JXD6+k6ss1YAX+idQjPvHmJ2tI=
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20251210132647-15dd6a9ee4bc h1:nz3DMrICKuhS9ht7Hx1Hc1Al4LtfPADK/SbKrJ/UXKc=
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:vCe4OUuL+XOUge9v3MyTD45BnuAXiH+DkjN9quDXJzQ=
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20251210132647-15dd6a9ee4bc h1:5OLCnge+qhMLS1HBz/KY803Pd3IRC7Q9KP71GZMM+p0=
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:w9amBWrvjtohQzBGCKJ7LCh22LhTIJs4sE7cYaKQzM0=
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20251210132647-15dd6a9ee4bc h1:pg9jxoJQsiSxRBCTsFHXATGmSLMpsdvdCvVNhpMEdDA=
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:TqlsFtcYS/etTeck46kHBeT8Le0Igw1Q/AV88UnMS3s=
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20251210132647-15dd6a9ee4bc h1:gAnasnvsCH8seCtYsfFoWsHeldBZUKPvarSjt9bKIak=
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:B6Qd0vys8sv9OKVRN6J9RqDzYRGE938Fb2zrYdBDyTQ=
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20251210132647-15dd6a9ee4bc h1:YVBUW8D3w/c0F5N3F+5rnXyNPNDODFPVw1NAWfsQv2Q=
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:3tXMMFY7AHugOVBZ5Al7cL7JKsnFOe5bMVr0hZPk3ow=
github.com/sagernet/cronet-go/lib/windows_386 v0.0.0-20251210132647-15dd6a9ee4bc h1:8w1wlyIpIcH3/1LPe6NMxZxLpsTq+00FEoSrMl+o03o=
github.com/sagernet/cronet-go/lib/windows_386 v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:rnS7D+ULJX2PrP0Cy+05GS0mRZ2PP6+gVSroZKt8fjk=
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20251210132647-15dd6a9ee4bc h1:Qwof0qMpoRXycadI1OWgwj7OTaCZQqoYbwqVAKd4rrs=
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:lm9w/oCCRyBiUa3G8lDQTT8x/ONUvgVR2iV9fVzUZB8=
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20251210132647-15dd6a9ee4bc h1:/2D4fyTJjYwf5NzgnOuTElGpX6fFN2dFAf/x0L0w1pI=
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:n34YyLgapgjWdKa0IoeczjAFCwD3/dxbsH5sucKw0bw=
github.com/sagernet/fswatch v0.1.1 h1:YqID+93B7VRfqIH3PArW/XpJv5H4OLEVWDfProGoRQs=
github.com/sagernet/fswatch v0.1.1/go.mod h1:nz85laH0mkQqJfaOrqPpkwtU1znMFNVTpT/5oRsVz/o=
github.com/sagernet/gomobile v0.1.8 h1:vXgoN0pjsMONAaYCTdsKBX2T1kxuS7sbT/mZ7PElGoo=

View File

@@ -206,9 +206,9 @@ function gen_outbound(flag, node, tag, proxy_table)
local first = node.tcp_guise_http_path[1]
return (first == "" or not first) and "/" or first
end)() or "/",
headers = {
["User-Agent"] = node.tcp_guise_http_user_agent or nil
},
headers = node.tcp_guise_http_user_agent and {
["User-Agent"] = node.tcp_guise_http_user_agent
} or nil,
idle_timeout = (node.http_h2_health_check == "1") and node.http_h2_read_idle_timeout or nil,
ping_timeout = (node.http_h2_health_check == "1") and node.http_h2_health_check_timeout or nil,
}
@@ -220,9 +220,9 @@ function gen_outbound(flag, node, tag, proxy_table)
type = "http",
host = node.http_host or {},
path = node.http_path or "/",
headers = {
["User-Agent"] = node.http_user_agent or nil
},
headers = node.http_user_agent and {
["User-Agent"] = node.http_user_agent
} or nil,
idle_timeout = (node.http_h2_health_check == "1") and node.http_h2_read_idle_timeout or nil,
ping_timeout = (node.http_h2_health_check == "1") and node.http_h2_health_check_timeout or nil,
}
@@ -233,10 +233,10 @@ function gen_outbound(flag, node, tag, proxy_table)
v2ray_transport = {
type = "ws",
path = node.ws_path or "/",
headers = {
Host = node.ws_host or nil,
["User-Agent"] = node.ws_user_agent or nil
},
headers = (node.ws_host or node.ws_user_agent) and {
Host = node.ws_host,
["User-Agent"] = node.ws_user_agent
} or nil,
max_early_data = tonumber(node.ws_maxEarlyData) or nil,
early_data_header_name = (node.ws_earlyDataHeaderName) and node.ws_earlyDataHeaderName or nil --要与 Xray-core 兼容,请将其设置为 Sec-WebSocket-Protocol。它需要与服务器保持一致。
}
@@ -247,9 +247,9 @@ function gen_outbound(flag, node, tag, proxy_table)
type = "httpupgrade",
host = node.httpupgrade_host,
path = node.httpupgrade_path or "/",
headers = {
["User-Agent"] = node.httpupgrade_user_agent or nil
}
headers = node.httpupgrade_user_agent and {
["User-Agent"] = node.httpupgrade_user_agent
} or nil
}
end

View File

@@ -178,10 +178,10 @@ function gen_outbound(flag, node, tag, proxy_table)
end
return r
end)() or {"/"},
headers = {
Host = node.tcp_guise_http_host or {},
headers = (node.tcp_guise_http_host or node.tcp_guise_http_user_agent) and {
Host = node.tcp_guise_http_host,
["User-Agent"] = node.tcp_guise_http_user_agent and {node.tcp_guise_http_user_agent} or nil
}
} or nil
} or nil
}
} or nil,
@@ -201,10 +201,10 @@ function gen_outbound(flag, node, tag, proxy_table)
} or nil,
wsSettings = (node.transport == "ws") and {
path = node.ws_path or "/",
headers = {
Host = node.ws_host or nil,
["User-Agent"] = node.ws_user_agent or nil
},
headers = (node.ws_host or node.ws_user_agent) and {
Host = node.ws_host,
["User-Agent"] = node.ws_user_agent
} or nil,
maxEarlyData = tonumber(node.ws_maxEarlyData) or nil,
earlyDataHeaderName = (node.ws_earlyDataHeaderName) and node.ws_earlyDataHeaderName or nil,
heartbeatPeriod = tonumber(node.ws_heartbeatPeriod) or nil
@@ -220,9 +220,9 @@ function gen_outbound(flag, node, tag, proxy_table)
httpupgradeSettings = (node.transport == "httpupgrade") and {
path = node.httpupgrade_path or "/",
host = node.httpupgrade_host,
headers = {
["User-Agent"] = node.httpupgrade_user_agent or nil
}
headers = node.httpupgrade_user_agent and {
["User-Agent"] = node.httpupgrade_user_agent
} or nil
} or nil,
xhttpSettings = (node.transport == "xhttp") and {
mode = node.xhttp_mode or "auto",

View File

@@ -1636,9 +1636,9 @@ Si un certificat auto-signé est utilisé ou si le système contient une CA non
<value>Afficher dans le Dock de macOS (redém. requis)</value>
</data>
<data name="menuServerList2" xml:space="preserve">
<value>Configuration Item 2, Select and add from self-built</value>
<value>Élément de config 2 : choisir et ajouter depuis self-hosted</value>
</data>
<data name="AlpnMustContainHttp11ForWsTls" xml:space="preserve">
<value>ALPN must contain 'http/1.1' when using WebSocket with TLS.</value>
<value>Avec WebSocket et TLS, lALPN doit inclure http/1.1.</value>
</data>
</root>

View File

@@ -4,7 +4,6 @@ import (
"context"
"math"
"math/big"
gonet "net"
"sync"
"time"
@@ -17,7 +16,7 @@ import (
type Holder struct {
domainToIP cache.Lru
ipRange *gonet.IPNet
ipRange *net.IPNet
mu *sync.Mutex
config *FakeDnsPool
@@ -79,10 +78,10 @@ func (fkdns *Holder) initializeFromConfig() error {
}
func (fkdns *Holder) initialize(ipPoolCidr string, lruSize int) error {
var ipRange *gonet.IPNet
var ipRange *net.IPNet
var err error
if _, ipRange, err = gonet.ParseCIDR(ipPoolCidr); err != nil {
if _, ipRange, err = net.ParseCIDR(ipPoolCidr); err != nil {
return errors.New("Unable to parse CIDR for Fake DNS IP assignment").Base(err).AtError()
}

View File

@@ -1,7 +1,6 @@
package fakedns
import (
gonet "net"
"strconv"
"testing"
@@ -155,7 +154,7 @@ func TestFakeDNSMulti(t *testing.T) {
assert.True(t, inPool)
})
t.Run("ipv6", func(t *testing.T) {
ip, err := gonet.ResolveIPAddr("ip", "fddd:c5b4:ff5f:f4f0::5")
ip, err := net.ResolveIPAddr("ip", "fddd:c5b4:ff5f:f4f0::5")
assert.Nil(t, err)
inPool := fakeMulti.IsIPInIPPool(net.IPAddress(ip.IP))
assert.True(t, inPool)
@@ -165,7 +164,7 @@ func TestFakeDNSMulti(t *testing.T) {
assert.False(t, inPool)
})
t.Run("ipv6_inverse", func(t *testing.T) {
ip, err := gonet.ResolveIPAddr("ip", "fcdd:c5b4:ff5f:f4f0::5")
ip, err := net.ResolveIPAddr("ip", "fcdd:c5b4:ff5f:f4f0::5")
assert.Nil(t, err)
inPool := fakeMulti.IsIPInIPPool(net.IPAddress(ip.IP))
assert.False(t, inPool)

View File

@@ -2,7 +2,6 @@ package inbound
import (
"context"
gonet "net"
"sync"
"sync/atomic"
"time"
@@ -565,12 +564,12 @@ func (w *dsWorker) Close() error {
}
func IsLocal(ip net.IP) bool {
addrs, err := gonet.InterfaceAddrs()
addrs, err := net.InterfaceAddrs()
if err != nil {
return false
}
for _, addr := range addrs {
if ipnet, ok := addr.(*gonet.IPNet); ok {
if ipnet, ok := addr.(*net.IPNet); ok {
if ipnet.IP.Equal(ip) {
return true
}

View File

@@ -6,7 +6,6 @@ import (
goerrors "errors"
"io"
"math/big"
gonet "net"
"os"
"github.com/xtls/xray-core/common/dice"
@@ -398,7 +397,7 @@ func (h *Handler) ProxySettings() *serial.TypedMessage {
func ParseRandomIP(addr net.Address, prefix string) net.Address {
_, ipnet, _ := gonet.ParseCIDR(addr.IP().String() + "/" + prefix)
_, ipnet, _ := net.ParseCIDR(addr.IP().String() + "/" + prefix)
ones, bits := ipnet.Mask.Size()
subnetSize := new(big.Int).Lsh(big.NewInt(1), uint(bits-ones))
@@ -412,5 +411,5 @@ func ParseRandomIP(addr net.Address, prefix string) net.Address {
padded := make([]byte, len(ipnet.IP))
copy(padded[len(padded)-len(rndBytes):], rndBytes)
return net.ParseAddress(gonet.IP(padded).String())
return net.ParseAddress(net.IP(padded).String())
}

View File

@@ -12,6 +12,8 @@ var (
type ListenConfig = net.ListenConfig
type KeepAliveConfig = net.KeepAliveConfig
var (
Listen = net.Listen
ListenTCP = net.ListenTCP
@@ -26,6 +28,12 @@ var FileConn = net.FileConn
// ParseIP is an alias of net.ParseIP
var ParseIP = net.ParseIP
var ParseCIDR = net.ParseCIDR
var ResolveIPAddr = net.ResolveIPAddr
var InterfaceByName = net.InterfaceByName
var SplitHostPort = net.SplitHostPort
var CIDRMask = net.CIDRMask
@@ -51,6 +59,8 @@ type (
UnixConn = net.UnixConn
)
type IPAddr = net.IPAddr
// IP is an alias for net.IP.
type (
IP = net.IP
@@ -82,3 +92,11 @@ var (
)
type Resolver = net.Resolver
var DefaultResolver = net.DefaultResolver
var JoinHostPort = net.JoinHostPort
var InterfaceAddrs = net.InterfaceAddrs
var Interfaces = net.Interfaces

View File

@@ -21,10 +21,10 @@ require (
github.com/vishvananda/netlink v1.3.1
github.com/xtls/reality v0.0.0-20251014195629-e4eec4520535
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
golang.org/x/crypto v0.44.0
golang.org/x/net v0.47.0
golang.org/x/sync v0.18.0
golang.org/x/sys v0.38.0
golang.org/x/crypto v0.46.0
golang.org/x/net v0.48.0
golang.org/x/sync v0.19.0
golang.org/x/sys v0.39.0
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173
google.golang.org/grpc v1.77.0
google.golang.org/protobuf v1.36.10
@@ -46,10 +46,10 @@ require (
github.com/quic-go/qpack v0.6.0 // indirect
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
github.com/vishvananda/netns v0.0.5 // indirect
golang.org/x/mod v0.29.0 // indirect
golang.org/x/text v0.31.0 // indirect
golang.org/x/mod v0.30.0 // indirect
golang.org/x/text v0.32.0 // indirect
golang.org/x/time v0.12.0 // indirect
golang.org/x/tools v0.38.0 // indirect
golang.org/x/tools v0.39.0 // indirect
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect

View File

@@ -95,20 +95,20 @@ go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBs
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU=
golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc=
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk=
golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -116,21 +116,21 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@@ -3,14 +3,13 @@ package wireguard
import (
"context"
"errors"
"net"
"net/netip"
"strconv"
"sync"
"golang.zx2c4.com/wireguard/conn"
xnet "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/features/dns"
"github.com/xtls/xray-core/transport/internet"
)
@@ -51,21 +50,21 @@ func (n *netBind) ParseEndpoint(s string) (conn.Endpoint, error) {
return nil, err
}
addr := xnet.ParseAddress(ipStr)
if addr.Family() == xnet.AddressFamilyDomain {
addr := net.ParseAddress(ipStr)
if addr.Family() == net.AddressFamilyDomain {
ips, _, err := n.dns.LookupIP(addr.Domain(), n.dnsOption)
if err != nil {
return nil, err
} else if len(ips) == 0 {
return nil, dns.ErrEmptyResponse
}
addr = xnet.IPAddress(ips[0])
addr = net.IPAddress(ips[0])
}
dst := xnet.Destination{
dst := net.Destination{
Address: addr,
Port: xnet.Port(portNum),
Network: xnet.Network_UDP,
Port: net.Port(portNum),
Network: net.Network_UDP,
}
return &netEndpoint{
@@ -214,7 +213,7 @@ func (bind *netBindServer) Send(buff [][]byte, endpoint conn.Endpoint) error {
}
type netEndpoint struct {
dst xnet.Destination
dst net.Destination
conn net.Conn
}
@@ -247,7 +246,7 @@ func (e netEndpoint) SrcToString() string {
return ""
}
func toNetIpAddr(addr xnet.Address) netip.Addr {
func toNetIpAddr(addr net.Address) netip.Addr {
if addr.Family().IsIPv4() {
ip := addr.IP()
return netip.AddrFrom4([4]byte{ip[0], ip[1], ip[2], ip[3]})

View File

@@ -3,7 +3,6 @@ package wireguard
import (
"context"
"fmt"
"net"
"net/netip"
"runtime"
"strconv"
@@ -13,7 +12,7 @@ import (
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/log"
xnet "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/proxy/wireguard/gvisortun"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/adapters/gonet"
@@ -28,7 +27,7 @@ import (
type tunCreator func(localAddresses []netip.Addr, mtu int, handler promiscuousModeHandler) (Tunnel, error)
type promiscuousModeHandler func(dest xnet.Destination, conn net.Conn)
type promiscuousModeHandler func(dest net.Destination, conn net.Conn)
type Tunnel interface {
BuildDevice(ipc string, bind conn.Bind) error
@@ -169,7 +168,7 @@ func createGVisorTun(localAddresses []netip.Addr, mtu int, handler promiscuousMo
ep.SocketOptions().SetKeepAlive(true)
// local address is actually destination
handler(xnet.TCPDestination(xnet.IPAddress(id.LocalAddress.AsSlice()), xnet.Port(id.LocalPort)), gonet.NewTCPConn(&wq, ep))
handler(net.TCPDestination(net.IPAddress(id.LocalAddress.AsSlice()), net.Port(id.LocalPort)), gonet.NewTCPConn(&wq, ep))
}(r)
})
stack.SetTransportProtocolHandler(tcp.ProtocolNumber, tcpForwarder.HandlePacket)
@@ -194,7 +193,7 @@ func createGVisorTun(localAddresses []netip.Addr, mtu int, handler promiscuousMo
Timeout: 15 * time.Second,
})
handler(xnet.UDPDestination(xnet.IPAddress(id.LocalAddress.AsSlice()), xnet.Port(id.LocalPort)), gonet.NewUDPConn(&wq, ep))
handler(net.UDPDestination(net.IPAddress(id.LocalAddress.AsSlice()), net.Port(id.LocalPort)), gonet.NewUDPConn(&wq, ep))
}(r)
})
stack.SetTransportProtocolHandler(udp.ProtocolNumber, udpForwarder.HandlePacket)

View File

@@ -3,7 +3,6 @@ package internet
import (
"context"
"fmt"
gonet "net"
"strings"
"github.com/xtls/xray-core/common"
@@ -183,7 +182,7 @@ func checkAddressPortStrategy(ctx context.Context, dest net.Destination, sockopt
if len(parts) != 3 {
return nil, errors.New("invalid address format", dest.Address.String())
}
_, srvRecords, err := gonet.DefaultResolver.LookupSRV(context.Background(), parts[0][1:], parts[1][1:], parts[2])
_, srvRecords, err := net.DefaultResolver.LookupSRV(context.Background(), parts[0][1:], parts[1][1:], parts[2])
if err != nil {
return nil, errors.New("failed to lookup SRV record").Base(err)
}
@@ -198,7 +197,7 @@ func checkAddressPortStrategy(ctx context.Context, dest net.Destination, sockopt
}
if OverrideBy == "txt" {
errors.LogDebug(ctx, "query TXT record for "+dest.Address.String())
txtRecords, err := gonet.DefaultResolver.LookupTXT(ctx, dest.Address.String())
txtRecords, err := net.DefaultResolver.LookupTXT(ctx, dest.Address.String())
if err != nil {
errors.LogError(ctx, "failed to lookup SRV record: "+err.Error())
return nil, errors.New("failed to lookup SRV record").Base(err)

View File

@@ -2,7 +2,6 @@ package grpc
import (
"context"
gonet "net"
"sync"
"time"
@@ -99,7 +98,7 @@ func getGrpcClient(ctx context.Context, dest net.Destination, streamSettings *in
},
MinConnectTimeout: 5 * time.Second,
}),
grpc.WithContextDialer(func(gctx context.Context, s string) (gonet.Conn, error) {
grpc.WithContextDialer(func(gctx context.Context, s string) (net.Conn, error) {
select {
case <-gctx.Done():
return nil, gctx.Err()
@@ -180,7 +179,7 @@ func getGrpcClient(ctx context.Context, dest net.Destination, streamSettings *in
}
conn, err := grpc.Dial(
gonet.JoinHostPort(grpcDestHost, dest.Port.String()),
net.JoinHostPort(grpcDestHost, dest.Port.String()),
dialOptions...,
)
globalDialerMap[dialerConf{dest, streamSettings}] = conn

View File

@@ -3,11 +3,10 @@ package encoding
import (
"context"
"io"
"net"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/errors"
xnet "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/net/cnc"
"github.com/xtls/xray-core/common/signal/done"
"google.golang.org/grpc/metadata"
@@ -55,7 +54,7 @@ func NewHunkConn(hc HunkConn, cancel context.CancelFunc) net.Conn {
if ok {
header := md.Get("x-real-ip")
if len(header) > 0 {
realip := xnet.ParseAddress(header[0])
realip := net.ParseAddress(header[0])
if realip.Family().IsIP() {
rAddr = &net.TCPAddr{
IP: realip.IP(),

View File

@@ -2,7 +2,6 @@ package internet
import (
"context"
gonet "net"
"os"
"runtime"
"strconv"
@@ -135,7 +134,7 @@ func applyOutboundSocketOptions(network string, address string, fd uintptr, conf
}
if config.Interface != "" {
iface, err := gonet.InterfaceByName(config.Interface)
iface, err := net.InterfaceByName(config.Interface)
if err != nil {
return errors.New("failed to get interface ", config.Interface).Base(err)
@@ -226,7 +225,7 @@ func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig)
}
if config.Interface != "" {
iface, err := gonet.InterfaceByName(config.Interface)
iface, err := net.InterfaceByName(config.Interface)
if err != nil {
return errors.New("failed to get interface ", config.Interface).Base(err)

View File

@@ -3,9 +3,9 @@ package splithttp
import (
"context"
"io"
gonet "net"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/transport/internet/browser_dialer"
"github.com/xtls/xray-core/transport/internet/websocket"
)
@@ -19,13 +19,13 @@ func (c *BrowserDialerClient) IsClosed() bool {
panic("not implemented yet")
}
func (c *BrowserDialerClient) OpenStream(ctx context.Context, url string, body io.Reader, uploadOnly bool) (io.ReadCloser, gonet.Addr, gonet.Addr, error) {
func (c *BrowserDialerClient) OpenStream(ctx context.Context, url string, body io.Reader, uploadOnly bool) (io.ReadCloser, net.Addr, net.Addr, error) {
if body != nil {
return nil, nil, nil, errors.New("bidirectional streaming for browser dialer not implemented yet")
}
conn, err := browser_dialer.DialGet(url, c.transportConfig.GetRequestHeader(url))
dummyAddr := &gonet.IPAddr{}
dummyAddr := &net.IPAddr{}
if err != nil {
return nil, dummyAddr, dummyAddr, err
}

View File

@@ -5,7 +5,6 @@ import (
"context"
"fmt"
"io"
gonet "net"
"net/http"
"net/http/httptrace"
"sync"
@@ -42,7 +41,7 @@ func (c *DefaultDialerClient) IsClosed() bool {
return c.closed
}
func (c *DefaultDialerClient) OpenStream(ctx context.Context, url string, body io.Reader, uploadOnly bool) (wrc io.ReadCloser, remoteAddr, localAddr gonet.Addr, err error) {
func (c *DefaultDialerClient) OpenStream(ctx context.Context, url string, body io.Reader, uploadOnly bool) (wrc io.ReadCloser, remoteAddr, localAddr net.Addr, err error) {
// this is done when the TCP/UDP connection to the server was established,
// and we can unblock the Dial function and print correct net addresses in
// logs

View File

@@ -3,7 +3,6 @@ package internet
import (
"context"
"math/rand"
gonet "net"
"syscall"
"time"
@@ -89,7 +88,7 @@ func (d *DefaultSystemDialer) Dial(ctx context.Context, src net.Address, dest ne
}, nil
}
// Chrome defaults
keepAliveConfig := gonet.KeepAliveConfig{
keepAliveConfig := net.KeepAliveConfig{
Enable: true,
Idle: 45 * time.Second,
Interval: 45 * time.Second,

View File

@@ -2,7 +2,6 @@ package internet
import (
"context"
gonet "net"
"os"
"runtime"
"strconv"
@@ -95,7 +94,7 @@ func (dl *DefaultListener) Listen(ctx context.Context, addr net.Addr, sockopt *S
if sockopt.TcpKeepAliveIdle*sockopt.TcpKeepAliveInterval < 0 {
return nil, errors.New("invalid TcpKeepAliveIdle or TcpKeepAliveInterval value: ", sockopt.TcpKeepAliveIdle, " ", sockopt.TcpKeepAliveInterval)
}
lc.KeepAliveConfig = gonet.KeepAliveConfig{
lc.KeepAliveConfig = net.KeepAliveConfig{
Enable: false,
Idle: -1,
Interval: -1,

View File

@@ -5,7 +5,6 @@ import (
_ "embed"
"encoding/base64"
"io"
gonet "net"
"time"
"github.com/gorilla/websocket"
@@ -64,7 +63,7 @@ func dialWebSocket(ctx context.Context, dest net.Destination, streamSettings *in
tlsConfig := tConfig.GetTLSConfig(tls.WithDestination(dest), tls.WithNextProto("http/1.1"))
dialer.TLSClientConfig = tlsConfig
if fingerprint := tls.GetFingerprint(tConfig.Fingerprint); fingerprint != nil {
dialer.NetDialTLSContext = func(_ context.Context, _, addr string) (gonet.Conn, error) {
dialer.NetDialTLSContext = func(_ context.Context, _, addr string) (net.Conn, error) {
// Like the NetDial in the dialer
pconn, err := internet.DialSystem(ctx, dest, streamSettings.SocketSettings)
if err != nil {

View File

@@ -279,7 +279,7 @@ class ArchiveOrgIE(InfoExtractor):
'url': 'https://archive.org/' + track['file'].lstrip('/'),
}
metadata = self._download_json('http://archive.org/metadata/' + identifier, identifier)
metadata = self._download_json(f'https://archive.org/metadata/{identifier}', identifier)
m = metadata['metadata']
identifier = m['identifier']