mirror of
https://github.com/bolucat/Archive.git
synced 2025-09-27 04:30:12 +08:00
Update On Thu Aug 21 20:41:19 CEST 2025
This commit is contained in:
1
.github/update.log
vendored
1
.github/update.log
vendored
@@ -1096,3 +1096,4 @@ Update On Sun Aug 17 20:39:03 CEST 2025
|
||||
Update On Mon Aug 18 20:42:30 CEST 2025
|
||||
Update On Tue Aug 19 20:36:45 CEST 2025
|
||||
Update On Wed Aug 20 20:53:01 CEST 2025
|
||||
Update On Thu Aug 21 20:41:11 CEST 2025
|
||||
|
BIN
brook/docs/images/user-system.png
Normal file
BIN
brook/docs/images/user-system.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 286 KiB |
@@ -149,6 +149,10 @@ func (c *Conn) ReaderReplaceable() bool {
|
||||
return c.disablePipe.Load() || c.deadline.Load().IsZero()
|
||||
}
|
||||
|
||||
func (c *Conn) WriterReplaceable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *Conn) Upstream() any {
|
||||
return c.ExtendedConn
|
||||
}
|
||||
|
@@ -1,97 +0,0 @@
|
||||
// Copy from https://github.com/WireGuard/wgctrl-go/blob/a9ab2273dd1075ea74b88c76f8757f8b4003fcbf/wgtypes/types.go#L71-L155
|
||||
|
||||
package generater
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/crypto/curve25519"
|
||||
)
|
||||
|
||||
// KeyLen is the expected key length for a WireGuard key.
|
||||
const KeyLen = 32 // wgh.KeyLen
|
||||
|
||||
// A Key is a public, private, or pre-shared secret key. The Key constructor
|
||||
// functions in this package can be used to create Keys suitable for each of
|
||||
// these applications.
|
||||
type Key [KeyLen]byte
|
||||
|
||||
// GenerateKey generates a Key suitable for use as a pre-shared secret key from
|
||||
// a cryptographically safe source.
|
||||
//
|
||||
// The output Key should not be used as a private key; use GeneratePrivateKey
|
||||
// instead.
|
||||
func GenerateKey() (Key, error) {
|
||||
b := make([]byte, KeyLen)
|
||||
if _, err := rand.Read(b); err != nil {
|
||||
return Key{}, fmt.Errorf("wgtypes: failed to read random bytes: %v", err)
|
||||
}
|
||||
|
||||
return NewKey(b)
|
||||
}
|
||||
|
||||
// GeneratePrivateKey generates a Key suitable for use as a private key from a
|
||||
// cryptographically safe source.
|
||||
func GeneratePrivateKey() (Key, error) {
|
||||
key, err := GenerateKey()
|
||||
if err != nil {
|
||||
return Key{}, err
|
||||
}
|
||||
|
||||
// Modify random bytes using algorithm described at:
|
||||
// https://cr.yp.to/ecdh.html.
|
||||
key[0] &= 248
|
||||
key[31] &= 127
|
||||
key[31] |= 64
|
||||
|
||||
return key, nil
|
||||
}
|
||||
|
||||
// NewKey creates a Key from an existing byte slice. The byte slice must be
|
||||
// exactly 32 bytes in length.
|
||||
func NewKey(b []byte) (Key, error) {
|
||||
if len(b) != KeyLen {
|
||||
return Key{}, fmt.Errorf("wgtypes: incorrect key size: %d", len(b))
|
||||
}
|
||||
|
||||
var k Key
|
||||
copy(k[:], b)
|
||||
|
||||
return k, nil
|
||||
}
|
||||
|
||||
// ParseKey parses a Key from a base64-encoded string, as produced by the
|
||||
// Key.String method.
|
||||
func ParseKey(s string) (Key, error) {
|
||||
b, err := base64.StdEncoding.DecodeString(s)
|
||||
if err != nil {
|
||||
return Key{}, fmt.Errorf("wgtypes: failed to parse base64-encoded key: %v", err)
|
||||
}
|
||||
|
||||
return NewKey(b)
|
||||
}
|
||||
|
||||
// PublicKey computes a public key from the private key k.
|
||||
//
|
||||
// PublicKey should only be called when k is a private key.
|
||||
func (k Key) PublicKey() Key {
|
||||
var (
|
||||
pub [KeyLen]byte
|
||||
priv = [KeyLen]byte(k)
|
||||
)
|
||||
|
||||
// ScalarBaseMult uses the correct base value per https://cr.yp.to/ecdh.html,
|
||||
// so no need to specify it.
|
||||
curve25519.ScalarBaseMult(&pub, &priv)
|
||||
|
||||
return Key(pub)
|
||||
}
|
||||
|
||||
// String returns the base64-encoded string representation of a Key.
|
||||
//
|
||||
// ParseKey can be used to produce a new Key from this string.
|
||||
func (k Key) String() string {
|
||||
return base64.StdEncoding.EncodeToString(k[:])
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
package generater
|
||||
package generator
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
func Main(args []string) {
|
||||
if len(args) < 1 {
|
||||
panic("Using: generate uuid/reality-keypair/wg-keypair/ech-keypair/vless-mlkem768")
|
||||
panic("Using: generate uuid/reality-keypair/wg-keypair/ech-keypair/vless-mlkem768/vless-x25519")
|
||||
}
|
||||
switch args[0] {
|
||||
case "uuid":
|
||||
@@ -22,20 +22,19 @@ func Main(args []string) {
|
||||
}
|
||||
fmt.Println(newUUID.String())
|
||||
case "reality-keypair":
|
||||
privateKey, err := GeneratePrivateKey()
|
||||
privateKey, err := GenX25519PrivateKey()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
publicKey := privateKey.PublicKey()
|
||||
fmt.Println("PrivateKey: " + base64.RawURLEncoding.EncodeToString(privateKey[:]))
|
||||
fmt.Println("PublicKey: " + base64.RawURLEncoding.EncodeToString(publicKey[:]))
|
||||
fmt.Println("PrivateKey: " + base64.RawURLEncoding.EncodeToString(privateKey.Bytes()))
|
||||
fmt.Println("PublicKey: " + base64.RawURLEncoding.EncodeToString(privateKey.PublicKey().Bytes()))
|
||||
case "wg-keypair":
|
||||
privateKey, err := GeneratePrivateKey()
|
||||
privateKey, err := GenX25519PrivateKey()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println("PrivateKey: " + privateKey.String())
|
||||
fmt.Println("PublicKey: " + privateKey.PublicKey().String())
|
||||
fmt.Println("PrivateKey: " + base64.StdEncoding.EncodeToString(privateKey.Bytes()))
|
||||
fmt.Println("PublicKey: " + base64.StdEncoding.EncodeToString(privateKey.PublicKey().Bytes()))
|
||||
case "ech-keypair":
|
||||
if len(args) < 2 {
|
||||
panic("Using: generate ech-keypair <plain_server_name>")
|
||||
@@ -51,11 +50,23 @@ func Main(args []string) {
|
||||
if len(args) > 1 {
|
||||
seed = args[1]
|
||||
}
|
||||
seedBase64, clientBase64, err := encryption.GenMLKEM768(seed)
|
||||
seedBase64, clientBase64, hash11Base64, err := encryption.GenMLKEM768(seed)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println("Seed: " + seedBase64)
|
||||
fmt.Println("Client: " + clientBase64)
|
||||
fmt.Println("Hash11: " + hash11Base64)
|
||||
case "vless-x25519":
|
||||
var privateKey string
|
||||
if len(args) > 1 {
|
||||
privateKey = args[1]
|
||||
}
|
||||
privateKeyBase64, passwordBase64, err := encryption.GenX25519(privateKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println("PrivateKey: " + privateKeyBase64)
|
||||
fmt.Println("Password: " + passwordBase64)
|
||||
}
|
||||
}
|
27
clash-meta/component/generator/x25519.go
Normal file
27
clash-meta/component/generator/x25519.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"crypto/ecdh"
|
||||
"crypto/rand"
|
||||
)
|
||||
|
||||
const X25519KeySize = 32
|
||||
|
||||
func GenX25519PrivateKey() (*ecdh.PrivateKey, error) {
|
||||
var privateKey [X25519KeySize]byte
|
||||
_, err := rand.Read(privateKey[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Avoid generating equivalent X25519 private keys
|
||||
// https://github.com/XTLS/Xray-core/pull/1747
|
||||
//
|
||||
// Modify random bytes using algorithm described at:
|
||||
// https://cr.yp.to/ecdh.html.
|
||||
privateKey[0] &= 248
|
||||
privateKey[31] &= 127
|
||||
privateKey[31] |= 64
|
||||
|
||||
return ecdh.X25519().NewPrivateKey(privateKey[:])
|
||||
}
|
@@ -638,8 +638,12 @@ proxies: # socks5
|
||||
port: 443
|
||||
uuid: uuid
|
||||
network: tcp
|
||||
encryption: "8min-vless-mlkem768client-bas64RawURLEncoding" # 复用八分钟后协商新的 sharedKey,需小于服务端的值
|
||||
# encryption: "8min-xored-mlkem768client-bas64RawURLEncoding"
|
||||
# -------------------------
|
||||
# vless encryption客户端配置:
|
||||
# (只使用 1-RTT 模式 / 复用八分钟后协商新的 baseKey,周期需小于服务端的值)
|
||||
# / 是只能选一个,后面是 base64RawURLEncoding,使用 mihomo generate vless-x25519 和 mihomo generate vless-mlkem768 生成,替换值时需去掉括号
|
||||
# -------------------------
|
||||
encryption: "1rtt/8min.native/divide/random.mlkem768Client.(X25519 Password).(ML-KEM-768 Client)"
|
||||
tls: false #可以不开启tls
|
||||
udp: true
|
||||
|
||||
@@ -1359,8 +1363,12 @@ listeners:
|
||||
flow: xtls-rprx-vision
|
||||
# ws-path: "/" # 如果不为空则开启 websocket 传输层
|
||||
# grpc-service-name: "GunService" # 如果不为空则开启 grpc 传输层
|
||||
# decryption: "10min-vless-mlkem768seed-bas64RawURLEncoding" # 同时允许 1-RTT 模式与十分钟复用的 0-RTT 模式, 后面base64字符串可由可由 mihomo generate vless-mlkem768 命令生成
|
||||
# decryption: "10min-xored-mlkem768seed-bas64RawURLEncoding"
|
||||
# -------------------------
|
||||
# vless encryption服务端配置:
|
||||
# (只允许 1-RTT 模式 / 同时允许 1-RTT 模式与十分钟复用的 0-RTT 模式;原生外观 / ECH 式 XOR / 全随机数)
|
||||
# / 是只能选一个,后面是 base64RawURLEncoding,使用 mihomo generate vless-x25519 和 mihomo generate vless-mlkem768 生成,替换值时需去掉括号
|
||||
# -------------------------
|
||||
# decryption: "1rtt/10min.native/divide/random.mlkem768Seed.(X25519 PrivateKey).(ML-KEM-768 Seed)"
|
||||
# 下面两项如果填写则开启 tls(需要同时填写)
|
||||
# certificate: ./server.crt
|
||||
# private-key: ./server.key
|
||||
|
@@ -31,7 +31,7 @@ require (
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.6
|
||||
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2
|
||||
github.com/metacubex/sing-tun v0.4.7
|
||||
github.com/metacubex/sing-vmess v0.2.4-0.20250819151326-51d195aac5db
|
||||
github.com/metacubex/sing-vmess v0.2.4-0.20250821024956-97839f31a65d
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f
|
||||
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee
|
||||
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4
|
||||
|
@@ -131,8 +131,8 @@ github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2 h1:gXU+MY
|
||||
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2/go.mod h1:mbfboaXauKJNIHJYxQRa+NJs4JU9NZfkA+I33dS2+9E=
|
||||
github.com/metacubex/sing-tun v0.4.7 h1:ZDY/W+1c7PeWWKeKRyUo18fySF/TWjB0i5ui81Ar778=
|
||||
github.com/metacubex/sing-tun v0.4.7/go.mod h1:xHecZRwBnKWe6zG9amAK9cXf91lF6blgjBqm+VvOrmU=
|
||||
github.com/metacubex/sing-vmess v0.2.4-0.20250819151326-51d195aac5db h1:W7VKxR0r5IR+56Lblx2iyrEaykx0esdQwTQbkSrSaek=
|
||||
github.com/metacubex/sing-vmess v0.2.4-0.20250819151326-51d195aac5db/go.mod h1:21R5R1u90uUvBQF0owoooEu96/SAYYD56nDrwm6nFaM=
|
||||
github.com/metacubex/sing-vmess v0.2.4-0.20250821024956-97839f31a65d h1:jchYEho5+kTmok4aTMflqJyTRnqVPTOVeC1RFXxuw9A=
|
||||
github.com/metacubex/sing-vmess v0.2.4-0.20250821024956-97839f31a65d/go.mod h1:21R5R1u90uUvBQF0owoooEu96/SAYYD56nDrwm6nFaM=
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f h1:Sr/DYKYofKHKc4GF3qkRGNuj6XA6c0eqPgEDN+VAsYU=
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f/go.mod h1:jpAkVLPnCpGSfNyVmj6Cq4YbuZsFepm/Dc+9BAOcR80=
|
||||
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee h1:lp6hJ+4wCLZu113awp7P6odM2okB5s60HUyF0FMqKmo=
|
||||
|
@@ -21,7 +21,7 @@ import (
|
||||
"github.com/metacubex/mihomo/component/ca"
|
||||
"github.com/metacubex/mihomo/component/dialer"
|
||||
"github.com/metacubex/mihomo/component/ech"
|
||||
"github.com/metacubex/mihomo/component/generater"
|
||||
"github.com/metacubex/mihomo/component/generator"
|
||||
tlsC "github.com/metacubex/mihomo/component/tls"
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
|
||||
@@ -48,13 +48,12 @@ var echConfigBase64, echKeyPem, _ = ech.GenECHConfig(echPublicSni)
|
||||
|
||||
func init() {
|
||||
rand.Read(httpData)
|
||||
privateKey, err := generater.GeneratePrivateKey()
|
||||
privateKey, err := generator.GenX25519PrivateKey()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
publicKey := privateKey.PublicKey()
|
||||
realityPrivateKey = base64.RawURLEncoding.EncodeToString(privateKey[:])
|
||||
realityPublickey = base64.RawURLEncoding.EncodeToString(publicKey[:])
|
||||
realityPrivateKey = base64.RawURLEncoding.EncodeToString(privateKey.Bytes())
|
||||
realityPublickey = base64.RawURLEncoding.EncodeToString(privateKey.PublicKey().Bytes())
|
||||
}
|
||||
|
||||
type TestTunnel struct {
|
||||
|
@@ -89,17 +89,29 @@ func TestInboundVless_TLS(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestInboundVless_Encryption(t *testing.T) {
|
||||
seedBase64, clientBase64, err := encryption.GenMLKEM768("")
|
||||
seedBase64, clientBase64, _, err := encryption.GenMLKEM768("")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
return
|
||||
}
|
||||
t.Run("-vless-", func(t *testing.T) {
|
||||
privateKeyBase64, passwordBase64, err := encryption.GenX25519("")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
return
|
||||
}
|
||||
var modes = []string{
|
||||
"native",
|
||||
"divide",
|
||||
"random",
|
||||
}
|
||||
for i := range modes {
|
||||
mode := modes[i]
|
||||
t.Run(mode, func(t *testing.T) {
|
||||
inboundOptions := inbound.VlessOption{
|
||||
Decryption: "10min-vless-mlkem768seed-" + seedBase64,
|
||||
Decryption: "10min." + mode + ".mlkem768Seed." + privateKeyBase64 + "." + seedBase64,
|
||||
}
|
||||
outboundOptions := outbound.VlessOption{
|
||||
Encryption: "8min-vless-mlkem768client-" + clientBase64,
|
||||
Encryption: "8min." + mode + ".mlkem768Client." + passwordBase64 + "." + clientBase64,
|
||||
}
|
||||
testInboundVless(t, inboundOptions, outboundOptions)
|
||||
t.Run("xtls-rprx-vision", func(t *testing.T) {
|
||||
@@ -108,20 +120,7 @@ func TestInboundVless_Encryption(t *testing.T) {
|
||||
testInboundVless(t, inboundOptions, outboundOptions)
|
||||
})
|
||||
})
|
||||
t.Run("-xored-", func(t *testing.T) {
|
||||
inboundOptions := inbound.VlessOption{
|
||||
Decryption: "10min-xored-mlkem768seed-" + seedBase64,
|
||||
}
|
||||
outboundOptions := outbound.VlessOption{
|
||||
Encryption: "8min-xored-mlkem768client-" + clientBase64,
|
||||
}
|
||||
testInboundVless(t, inboundOptions, outboundOptions)
|
||||
t.Run("xtls-rprx-vision", func(t *testing.T) {
|
||||
outboundOptions := outboundOptions
|
||||
outboundOptions.Flow = "xtls-rprx-vision"
|
||||
testInboundVless(t, inboundOptions, outboundOptions)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestInboundVless_Wss1(t *testing.T) {
|
||||
|
@@ -14,7 +14,7 @@ import (
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/metacubex/mihomo/component/generater"
|
||||
"github.com/metacubex/mihomo/component/generator"
|
||||
"github.com/metacubex/mihomo/component/geodata"
|
||||
"github.com/metacubex/mihomo/component/updater"
|
||||
"github.com/metacubex/mihomo/config"
|
||||
@@ -73,7 +73,7 @@ func main() {
|
||||
}
|
||||
|
||||
if len(os.Args) > 1 && os.Args[1] == "generate" {
|
||||
generater.Main(os.Args[2:])
|
||||
generator.Main(os.Args[2:])
|
||||
return
|
||||
}
|
||||
|
||||
|
@@ -3,6 +3,7 @@ package encryption
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/cipher"
|
||||
"crypto/ecdh"
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -40,7 +41,8 @@ type ClientInstance struct {
|
||||
sync.RWMutex
|
||||
nfsEKey *mlkem.EncapsulationKey768
|
||||
hash11 [11]byte // no more capacity
|
||||
xorKey []byte
|
||||
xorMode uint32
|
||||
xorPKey *ecdh.PublicKey
|
||||
minutes time.Duration
|
||||
expire time.Time
|
||||
baseKey []byte
|
||||
@@ -60,22 +62,23 @@ type ClientConn struct {
|
||||
input bytes.Reader // peerCache
|
||||
}
|
||||
|
||||
func (i *ClientInstance) Init(nfsEKeyBytes []byte, xor uint32, minutes time.Duration) (err error) {
|
||||
func (i *ClientInstance) Init(nfsEKeyBytes, xorPKeyBytes []byte, xorMode, minutes uint32) (err error) {
|
||||
if i.nfsEKey != nil {
|
||||
err = errors.New("already initialized")
|
||||
return
|
||||
}
|
||||
i.nfsEKey, err = mlkem.NewEncapsulationKey768(nfsEKeyBytes)
|
||||
if err != nil {
|
||||
if i.nfsEKey, err = mlkem.NewEncapsulationKey768(nfsEKeyBytes); err != nil {
|
||||
return
|
||||
}
|
||||
hash32 := sha3.Sum256(nfsEKeyBytes)
|
||||
copy(i.hash11[:], hash32[:])
|
||||
if xor > 0 {
|
||||
xorKey := sha3.Sum256(nfsEKeyBytes)
|
||||
i.xorKey = xorKey[:]
|
||||
if xorMode > 0 {
|
||||
i.xorMode = xorMode
|
||||
if i.xorPKey, err = ecdh.X25519().NewPublicKey(xorPKeyBytes); err != nil {
|
||||
return
|
||||
}
|
||||
i.minutes = minutes
|
||||
}
|
||||
i.minutes = time.Duration(minutes) * time.Minute
|
||||
return
|
||||
}
|
||||
|
||||
@@ -83,8 +86,8 @@ func (i *ClientInstance) Handshake(conn net.Conn) (*ClientConn, error) {
|
||||
if i.nfsEKey == nil {
|
||||
return nil, errors.New("uninitialized")
|
||||
}
|
||||
if i.xorKey != nil {
|
||||
conn = NewXorConn(conn, i.xorKey)
|
||||
if i.xorMode > 0 {
|
||||
conn, _ = NewXorConn(conn, i.xorMode, i.xorPKey, nil)
|
||||
}
|
||||
c := &ClientConn{Conn: conn}
|
||||
|
||||
@@ -145,7 +148,7 @@ func (i *ClientInstance) Handshake(conn net.Conn) (*ClientConn, error) {
|
||||
}
|
||||
c.baseKey = append(pfsKey, nfsKey...)
|
||||
|
||||
VLESS, _ := NewAead(ClientCipher, c.baseKey, encapsulatedPfsKey, encapsulatedNfsKey).Open(nil, append(i.hash11[:], ClientCipher), c.ticket[11:], pfsEKeyBytes)
|
||||
VLESS, _ := NewAEAD(ClientCipher, c.baseKey, encapsulatedPfsKey, encapsulatedNfsKey).Open(nil, append(i.hash11[:], ClientCipher), c.ticket[11:], pfsEKeyBytes)
|
||||
if !bytes.Equal(VLESS, []byte("VLESS")) {
|
||||
return nil, errors.New("invalid server")
|
||||
}
|
||||
@@ -180,7 +183,7 @@ func (c *ClientConn) Write(b []byte) (int, error) {
|
||||
rand.Read(c.random)
|
||||
copy(data[5+32:], c.random)
|
||||
EncodeHeader(data[5+32+32:], 23, len(b)+16)
|
||||
c.aead = NewAead(ClientCipher, c.baseKey, c.random, c.ticket)
|
||||
c.aead = NewAEAD(ClientCipher, c.baseKey, c.random, c.ticket)
|
||||
c.nonce = make([]byte, 12)
|
||||
c.aead.Seal(data[:5+32+32+5], c.nonce, b, data[5+32+32:5+32+32+5])
|
||||
} else {
|
||||
@@ -188,7 +191,7 @@ func (c *ClientConn) Write(b []byte) (int, error) {
|
||||
EncodeHeader(data, 23, len(b)+16)
|
||||
c.aead.Seal(data[:5], c.nonce, b, data[:5])
|
||||
if bytes.Equal(c.nonce, MaxNonce) {
|
||||
c.aead = NewAead(ClientCipher, c.baseKey, data[5:], data[:5])
|
||||
c.aead = NewAEAD(ClientCipher, c.baseKey, data[5:], data[:5])
|
||||
}
|
||||
}
|
||||
IncreaseNonce(c.nonce)
|
||||
@@ -229,7 +232,7 @@ func (c *ClientConn) Read(b []byte) (int, error) {
|
||||
if c.random == nil {
|
||||
return 0, errors.New("empty c.random")
|
||||
}
|
||||
c.peerAead = NewAead(ClientCipher, c.baseKey, peerRandomHello, c.random)
|
||||
c.peerAead = NewAEAD(ClientCipher, c.baseKey, peerRandomHello, c.random)
|
||||
c.peerNonce = make([]byte, 12)
|
||||
}
|
||||
if c.input.Len() > 0 {
|
||||
@@ -252,7 +255,7 @@ func (c *ClientConn) Read(b []byte) (int, error) {
|
||||
}
|
||||
var peerAead cipher.AEAD
|
||||
if bytes.Equal(c.peerNonce, MaxNonce) {
|
||||
peerAead = NewAead(ClientCipher, c.baseKey, peerData, h)
|
||||
peerAead = NewAEAD(ClientCipher, c.baseKey, peerData, h)
|
||||
}
|
||||
_, err = c.peerAead.Open(dst[:0], c.peerNonce, peerData, h)
|
||||
if peerAead != nil {
|
||||
|
@@ -73,7 +73,7 @@ func ReadAndDiscardPaddings(conn net.Conn) (h []byte, t byte, l int, err error)
|
||||
}
|
||||
}
|
||||
|
||||
func NewAead(c byte, secret, salt, info []byte) (aead cipher.AEAD) {
|
||||
func NewAEAD(c byte, secret, salt, info []byte) (aead cipher.AEAD) {
|
||||
key := make([]byte, 32)
|
||||
hkdf.New(sha3.New256, secret, salt, info).Read(key)
|
||||
if c&1 == 1 {
|
||||
|
@@ -14,4 +14,5 @@
|
||||
// https://github.com/XTLS/Xray-core/commit/d1fb48521271251a8c74bd64fcc2fc8700717a3b
|
||||
// https://github.com/XTLS/Xray-core/commit/49580705f6029648399304b816a2737f991582a8
|
||||
// https://github.com/XTLS/Xray-core/commit/84835bec7d0d8555d0dd30953ed26a272de814c4
|
||||
// https://github.com/XTLS/Xray-core/commit/373558ed7abdbac3de41745cf30ec04c9adde604
|
||||
package encryption
|
||||
|
@@ -5,7 +5,6 @@ import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// NewClient new client from encryption string
|
||||
@@ -15,7 +14,7 @@ func NewClient(encryption string) (*ClientInstance, error) {
|
||||
case "", "none": // We will not reject empty string like xray-core does, because we need to ensure compatibility
|
||||
return nil, nil
|
||||
}
|
||||
if s := strings.SplitN(encryption, "-", 4); len(s) == 4 && s[2] == "mlkem768client" {
|
||||
if s := strings.Split(encryption, "."); len(s) == 5 && s[2] == "mlkem768Client" {
|
||||
var minutes uint32
|
||||
if s[0] != "1rtt" {
|
||||
t := strings.TrimSuffix(s[0], "min")
|
||||
@@ -28,27 +27,35 @@ func NewClient(encryption string) (*ClientInstance, error) {
|
||||
}
|
||||
minutes = uint32(i)
|
||||
}
|
||||
var xor uint32
|
||||
var xorMode uint32
|
||||
switch s[1] {
|
||||
case "vless":
|
||||
case "xored":
|
||||
xor = 1
|
||||
case "native":
|
||||
case "divide":
|
||||
xorMode = 1
|
||||
case "random":
|
||||
xorMode = 2
|
||||
default:
|
||||
return nil, fmt.Errorf("invaild vless encryption value: %s", encryption)
|
||||
}
|
||||
b, err := base64.RawURLEncoding.DecodeString(s[3])
|
||||
xorPKeyBytes, err := base64.RawURLEncoding.DecodeString(s[3])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invaild vless encryption value: %s", encryption)
|
||||
}
|
||||
if len(b) == MLKEM768ClientLength {
|
||||
if len(xorPKeyBytes) != X25519PasswordSize {
|
||||
return nil, fmt.Errorf("invaild vless encryption value: %s", encryption)
|
||||
}
|
||||
nfsEKeyBytes, err := base64.RawURLEncoding.DecodeString(s[4])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invaild vless encryption value: %s", encryption)
|
||||
}
|
||||
if len(nfsEKeyBytes) != MLKEM768ClientLength {
|
||||
return nil, fmt.Errorf("invaild vless encryption value: %s", encryption)
|
||||
}
|
||||
client := &ClientInstance{}
|
||||
if err = client.Init(b, xor, time.Duration(minutes)*time.Minute); err != nil {
|
||||
if err = client.Init(nfsEKeyBytes, xorPKeyBytes, xorMode, minutes); err != nil {
|
||||
return nil, fmt.Errorf("failed to use mlkem768seed: %w", err)
|
||||
}
|
||||
return client, nil
|
||||
} else {
|
||||
return nil, fmt.Errorf("invaild vless encryption value: %s", encryption)
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("invaild vless encryption value: %s", encryption)
|
||||
}
|
||||
@@ -60,7 +67,7 @@ func NewServer(decryption string) (*ServerInstance, error) {
|
||||
case "", "none": // We will not reject empty string like xray-core does, because we need to ensure compatibility
|
||||
return nil, nil
|
||||
}
|
||||
if s := strings.SplitN(decryption, "-", 4); len(s) == 4 && s[2] == "mlkem768seed" {
|
||||
if s := strings.Split(decryption, "."); len(s) == 5 && s[2] == "mlkem768Seed" {
|
||||
var minutes uint32
|
||||
if s[0] != "1rtt" {
|
||||
t := strings.TrimSuffix(s[0], "min")
|
||||
@@ -73,27 +80,35 @@ func NewServer(decryption string) (*ServerInstance, error) {
|
||||
}
|
||||
minutes = uint32(i)
|
||||
}
|
||||
var xor uint32
|
||||
var xorMode uint32
|
||||
switch s[1] {
|
||||
case "vless":
|
||||
case "xored":
|
||||
xor = 1
|
||||
case "native":
|
||||
case "divide":
|
||||
xorMode = 1
|
||||
case "random":
|
||||
xorMode = 2
|
||||
default:
|
||||
return nil, fmt.Errorf("invaild vless decryption value: %s", decryption)
|
||||
}
|
||||
b, err := base64.RawURLEncoding.DecodeString(s[3])
|
||||
xorSKeyBytes, err := base64.RawURLEncoding.DecodeString(s[3])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invaild vless decryption value: %s", decryption)
|
||||
}
|
||||
if len(b) == MLKEM768SeedLength {
|
||||
if len(xorSKeyBytes) != X25519PrivateKeySize {
|
||||
return nil, fmt.Errorf("invaild vless decryption value: %s", decryption)
|
||||
}
|
||||
nfsDKeySeed, err := base64.RawURLEncoding.DecodeString(s[4])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invaild vless decryption value: %s", decryption)
|
||||
}
|
||||
if len(nfsDKeySeed) != MLKEM768SeedLength {
|
||||
return nil, fmt.Errorf("invaild vless decryption value: %s", decryption)
|
||||
}
|
||||
server := &ServerInstance{}
|
||||
if err = server.Init(b, xor, time.Duration(minutes)*time.Minute); err != nil {
|
||||
if err = server.Init(nfsDKeySeed, xorSKeyBytes, xorMode, minutes); err != nil {
|
||||
return nil, fmt.Errorf("failed to use mlkem768seed: %w", err)
|
||||
}
|
||||
return server, nil
|
||||
} else {
|
||||
return nil, fmt.Errorf("invaild vless decryption value: %s", decryption)
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("invaild vless decryption value: %s", decryption)
|
||||
}
|
||||
|
@@ -1,25 +1,29 @@
|
||||
package encryption
|
||||
|
||||
import (
|
||||
"crypto/ecdh"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
|
||||
"github.com/metacubex/utls/mlkem"
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
const MLKEM768SeedLength = mlkem.SeedSize
|
||||
const MLKEM768ClientLength = mlkem.EncapsulationKeySize768
|
||||
const X25519PasswordSize = 32
|
||||
const X25519PrivateKeySize = 32
|
||||
|
||||
func GenMLKEM768(seedStr string) (seedBase64, clientBase64 string, err error) {
|
||||
var seed [64]byte
|
||||
func GenMLKEM768(seedStr string) (seedBase64, clientBase64, hash11Base64 string, err error) {
|
||||
var seed [MLKEM768SeedLength]byte
|
||||
if len(seedStr) > 0 {
|
||||
s, _ := base64.RawURLEncoding.DecodeString(seedStr)
|
||||
if len(s) != 64 {
|
||||
if len(s) != MLKEM768SeedLength {
|
||||
err = fmt.Errorf("invalid length of ML-KEM-768 seed: %s", seedStr)
|
||||
return
|
||||
}
|
||||
seed = [64]byte(s)
|
||||
seed = [MLKEM768SeedLength]byte(s)
|
||||
} else {
|
||||
_, err = rand.Read(seed[:])
|
||||
if err != nil {
|
||||
@@ -28,8 +32,45 @@ func GenMLKEM768(seedStr string) (seedBase64, clientBase64 string, err error) {
|
||||
}
|
||||
|
||||
key, _ := mlkem.NewDecapsulationKey768(seed[:])
|
||||
pub := key.EncapsulationKey()
|
||||
client := key.EncapsulationKey().Bytes()
|
||||
hash32 := sha3.Sum256(client)
|
||||
seedBase64 = base64.RawURLEncoding.EncodeToString(seed[:])
|
||||
clientBase64 = base64.RawURLEncoding.EncodeToString(pub.Bytes())
|
||||
clientBase64 = base64.RawURLEncoding.EncodeToString(client)
|
||||
hash11Base64 = base64.RawURLEncoding.EncodeToString(hash32[:11])
|
||||
return
|
||||
}
|
||||
|
||||
func GenX25519(privateKeyStr string) (privateKeyBase64, passwordBase64 string, err error) {
|
||||
var privateKey [X25519PrivateKeySize]byte
|
||||
if len(privateKeyStr) > 0 {
|
||||
s, _ := base64.RawURLEncoding.DecodeString(privateKeyStr)
|
||||
if len(s) != X25519PrivateKeySize {
|
||||
err = fmt.Errorf("invalid length of X25519 private key: %s", privateKeyStr)
|
||||
return
|
||||
}
|
||||
privateKey = [X25519PrivateKeySize]byte(s)
|
||||
} else {
|
||||
_, err = rand.Read(privateKey[:])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Avoid generating equivalent X25519 private keys
|
||||
// https://github.com/XTLS/Xray-core/pull/1747
|
||||
//
|
||||
// Modify random bytes using algorithm described at:
|
||||
// https://cr.yp.to/ecdh.html.
|
||||
privateKey[0] &= 248
|
||||
privateKey[31] &= 127
|
||||
privateKey[31] |= 64
|
||||
|
||||
key, err := ecdh.X25519().NewPrivateKey(privateKey[:])
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
privateKeyBase64 = base64.RawURLEncoding.EncodeToString(privateKey[:])
|
||||
passwordBase64 = base64.RawURLEncoding.EncodeToString(key.PublicKey().Bytes())
|
||||
return
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package encryption
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/cipher"
|
||||
"crypto/ecdh"
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -26,7 +27,8 @@ type ServerInstance struct {
|
||||
sync.RWMutex
|
||||
nfsDKey *mlkem.DecapsulationKey768
|
||||
hash11 [11]byte // no more capacity
|
||||
xorKey []byte
|
||||
xorMode uint32
|
||||
xorSKey *ecdh.PrivateKey
|
||||
minutes time.Duration
|
||||
sessions map[[32]byte]*ServerSession
|
||||
closed bool
|
||||
@@ -45,23 +47,24 @@ type ServerConn struct {
|
||||
nonce []byte
|
||||
}
|
||||
|
||||
func (i *ServerInstance) Init(nfsDKeySeed []byte, xor uint32, minutes time.Duration) (err error) {
|
||||
func (i *ServerInstance) Init(nfsDKeySeed, xorSKeyBytes []byte, xorMode, minutes uint32) (err error) {
|
||||
if i.nfsDKey != nil {
|
||||
err = errors.New("already initialized")
|
||||
return
|
||||
}
|
||||
i.nfsDKey, err = mlkem.NewDecapsulationKey768(nfsDKeySeed)
|
||||
if err != nil {
|
||||
if i.nfsDKey, err = mlkem.NewDecapsulationKey768(nfsDKeySeed); err != nil {
|
||||
return
|
||||
}
|
||||
hash32 := sha3.Sum256(i.nfsDKey.EncapsulationKey().Bytes())
|
||||
copy(i.hash11[:], hash32[:])
|
||||
if xor > 0 {
|
||||
xorKey := sha3.Sum256(i.nfsDKey.EncapsulationKey().Bytes())
|
||||
i.xorKey = xorKey[:]
|
||||
if xorMode > 0 {
|
||||
i.xorMode = xorMode
|
||||
if i.xorSKey, err = ecdh.X25519().NewPrivateKey(xorSKeyBytes); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
if minutes > 0 {
|
||||
i.minutes = minutes
|
||||
i.minutes = time.Duration(minutes) * time.Minute
|
||||
i.sessions = make(map[[32]byte]*ServerSession)
|
||||
go func() {
|
||||
for {
|
||||
@@ -95,8 +98,11 @@ func (i *ServerInstance) Handshake(conn net.Conn) (*ServerConn, error) {
|
||||
if i.nfsDKey == nil {
|
||||
return nil, errors.New("uninitialized")
|
||||
}
|
||||
if i.xorKey != nil {
|
||||
conn = NewXorConn(conn, i.xorKey)
|
||||
if i.xorMode > 0 {
|
||||
var err error
|
||||
if conn, err = NewXorConn(conn, i.xorMode, nil, i.xorSKey); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
c := &ServerConn{Conn: conn}
|
||||
|
||||
@@ -167,7 +173,7 @@ func (i *ServerInstance) Handshake(conn net.Conn) (*ServerConn, error) {
|
||||
pfsKey, encapsulatedPfsKey := pfsEKey.Encapsulate()
|
||||
c.baseKey = append(pfsKey, nfsKey...)
|
||||
|
||||
c.ticket = append(i.hash11[:], NewAead(c.cipher, c.baseKey, encapsulatedPfsKey, encapsulatedNfsKey).Seal(nil, peerClientHello[:12], []byte("VLESS"), pfsEKeyBytes)...)
|
||||
c.ticket = append(i.hash11[:], NewAEAD(c.cipher, c.baseKey, encapsulatedPfsKey, encapsulatedNfsKey).Seal(nil, peerClientHello[:12], []byte("VLESS"), pfsEKeyBytes)...)
|
||||
|
||||
paddingLen := randBetween(100, 1000)
|
||||
|
||||
@@ -221,7 +227,7 @@ func (c *ServerConn) Read(b []byte) (int, error) {
|
||||
}
|
||||
c.peerRandom = peerTicketHello[32:]
|
||||
}
|
||||
c.peerAead = NewAead(c.cipher, c.baseKey, c.peerRandom, c.ticket)
|
||||
c.peerAead = NewAEAD(c.cipher, c.baseKey, c.peerRandom, c.ticket)
|
||||
c.peerNonce = make([]byte, 12)
|
||||
}
|
||||
if c.input.Len() > 0 {
|
||||
@@ -244,7 +250,7 @@ func (c *ServerConn) Read(b []byte) (int, error) {
|
||||
}
|
||||
var peerAead cipher.AEAD
|
||||
if bytes.Equal(c.peerNonce, MaxNonce) {
|
||||
peerAead = NewAead(c.cipher, c.baseKey, peerData, h)
|
||||
peerAead = NewAEAD(c.cipher, c.baseKey, peerData, h)
|
||||
}
|
||||
_, err = c.peerAead.Open(dst[:0], c.peerNonce, peerData, h)
|
||||
if peerAead != nil {
|
||||
@@ -280,7 +286,7 @@ func (c *ServerConn) Write(b []byte) (int, error) {
|
||||
EncodeHeader(data, 0, 32)
|
||||
rand.Read(data[5 : 5+32])
|
||||
EncodeHeader(data[5+32:], 23, len(b)+16)
|
||||
c.aead = NewAead(c.cipher, c.baseKey, data[5:5+32], c.peerRandom)
|
||||
c.aead = NewAEAD(c.cipher, c.baseKey, data[5:5+32], c.peerRandom)
|
||||
c.nonce = make([]byte, 12)
|
||||
c.aead.Seal(data[:5+32+5], c.nonce, b, data[5+32:5+32+5])
|
||||
} else {
|
||||
@@ -288,7 +294,7 @@ func (c *ServerConn) Write(b []byte) (int, error) {
|
||||
EncodeHeader(data, 23, len(b)+16)
|
||||
c.aead.Seal(data[:5], c.nonce, b, data[:5])
|
||||
if bytes.Equal(c.nonce, MaxNonce) {
|
||||
c.aead = NewAead(c.cipher, c.baseKey, data[5:], data[:5])
|
||||
c.aead = NewAEAD(c.cipher, c.baseKey, data[5:], data[:5])
|
||||
}
|
||||
}
|
||||
IncreaseNonce(c.nonce)
|
||||
|
@@ -3,13 +3,21 @@ package encryption
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/ecdh"
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
|
||||
"golang.org/x/crypto/hkdf"
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
type XorConn struct {
|
||||
net.Conn
|
||||
Divide bool
|
||||
|
||||
head []byte
|
||||
key []byte
|
||||
ctr cipher.Stream
|
||||
peerCtr cipher.Stream
|
||||
@@ -25,8 +33,55 @@ type XorConn struct {
|
||||
in_skip int
|
||||
}
|
||||
|
||||
func NewXorConn(conn net.Conn, key []byte) *XorConn {
|
||||
return &XorConn{Conn: conn, key: key}
|
||||
func NewCTR(key, iv []byte, isServer bool) cipher.Stream {
|
||||
info := "CLIENT"
|
||||
if isServer {
|
||||
info = "SERVER" // avoids attackers sending traffic back to the client, though the encryption layer has its own protection
|
||||
}
|
||||
hkdf.New(sha3.New256, key, iv, []byte(info)).Read(key) // avoids using pKey directly if attackers sent the basepoint, or whaterver they like
|
||||
block, _ := aes.NewCipher(key)
|
||||
return cipher.NewCTR(block, iv)
|
||||
}
|
||||
|
||||
func NewXorConn(conn net.Conn, mode uint32, pKey *ecdh.PublicKey, sKey *ecdh.PrivateKey) (*XorConn, error) {
|
||||
if mode == 0 || (pKey == nil && sKey == nil) || (pKey != nil && sKey != nil) {
|
||||
return nil, errors.New("invalid parameters")
|
||||
}
|
||||
c := &XorConn{
|
||||
Conn: conn,
|
||||
Divide: mode == 1,
|
||||
isHeader: true,
|
||||
out_header: make([]byte, 0, 5), // important
|
||||
in_header: make([]byte, 0, 5), // important
|
||||
}
|
||||
if pKey != nil {
|
||||
c.head = make([]byte, 16+32)
|
||||
rand.Read(c.head)
|
||||
eSKey, _ := ecdh.X25519().GenerateKey(rand.Reader)
|
||||
NewCTR(pKey.Bytes(), c.head[:16], false).XORKeyStream(c.head[16:], eSKey.PublicKey().Bytes()) // make X25519 public key distinguishable from random bytes
|
||||
c.key, _ = eSKey.ECDH(pKey)
|
||||
c.ctr = NewCTR(c.key, c.head[:16], false)
|
||||
}
|
||||
if sKey != nil {
|
||||
peerHead := make([]byte, 16+32)
|
||||
if _, err := io.ReadFull(c.Conn, peerHead); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
NewCTR(sKey.PublicKey().Bytes(), peerHead[:16], false).XORKeyStream(peerHead[16:], peerHead[16:]) // we don't use buggy elligator, because we have PSK :)
|
||||
ePKey, err := ecdh.X25519().NewPublicKey(peerHead[16:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
key, err := sKey.ECDH(ePKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.peerCtr = NewCTR(key, peerHead[:16], false)
|
||||
c.head = make([]byte, 16)
|
||||
rand.Read(c.head) // make sure the server always replies random bytes even when received replays, though it is not important
|
||||
c.ctr = NewCTR(key, c.head, true) // the same key links the upload & download, though the encryption layer has its own link
|
||||
}
|
||||
return c, nil
|
||||
//chacha20.NewUnauthenticatedCipher()
|
||||
}
|
||||
|
||||
@@ -35,13 +90,6 @@ func (c *XorConn) Write(b []byte) (int, error) { // whole one/two records
|
||||
return 0, nil
|
||||
}
|
||||
if !c.out_after0 {
|
||||
var iv []byte
|
||||
if c.ctr == nil {
|
||||
block, _ := aes.NewCipher(c.key)
|
||||
iv = make([]byte, 16)
|
||||
rand.Read(iv)
|
||||
c.ctr = cipher.NewCTR(block, iv)
|
||||
}
|
||||
t, l, _ := DecodeHeader(b)
|
||||
if t == 23 { // single 23
|
||||
l = 5
|
||||
@@ -49,20 +97,24 @@ func (c *XorConn) Write(b []byte) (int, error) { // whole one/two records
|
||||
l += 10
|
||||
if t == 0 {
|
||||
c.out_after0 = true
|
||||
c.out_header = make([]byte, 0, 5) // important
|
||||
if c.Divide {
|
||||
l -= 5
|
||||
}
|
||||
}
|
||||
}
|
||||
c.ctr.XORKeyStream(b[:l], b[:l]) // caller MUST discard b
|
||||
if iv != nil {
|
||||
b = append(iv, b...)
|
||||
l = len(b)
|
||||
if c.head != nil {
|
||||
b = append(c.head, b...)
|
||||
c.head = nil
|
||||
}
|
||||
if _, err := c.Conn.Write(b); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if iv != nil {
|
||||
b = b[16:] // for len(b)
|
||||
return l, nil
|
||||
}
|
||||
return len(b), nil
|
||||
if c.Divide {
|
||||
return c.Conn.Write(b)
|
||||
}
|
||||
for p := b; ; { // for XTLS
|
||||
if len(p) <= c.out_skip {
|
||||
@@ -93,14 +145,12 @@ func (c *XorConn) Read(b []byte) (int, error) { // 5-bytes, data, 5-bytes...
|
||||
return 0, nil
|
||||
}
|
||||
if !c.in_after0 || !c.isHeader {
|
||||
if c.peerCtr == nil {
|
||||
if c.peerCtr == nil { // for client
|
||||
peerIv := make([]byte, 16)
|
||||
if _, err := io.ReadFull(c.Conn, peerIv); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
block, _ := aes.NewCipher(c.key)
|
||||
c.peerCtr = cipher.NewCTR(block, peerIv)
|
||||
c.isHeader = true
|
||||
c.peerCtr = NewCTR(c.key, peerIv, true)
|
||||
}
|
||||
if _, err := io.ReadFull(c.Conn, b); err != nil {
|
||||
return 0, err
|
||||
@@ -117,7 +167,6 @@ func (c *XorConn) Read(b []byte) (int, error) { // 5-bytes, data, 5-bytes...
|
||||
c.isHeader = false
|
||||
if t == 0 {
|
||||
c.in_after0 = true
|
||||
c.in_header = make([]byte, 0, 5) // important
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -125,6 +174,9 @@ func (c *XorConn) Read(b []byte) (int, error) { // 5-bytes, data, 5-bytes...
|
||||
}
|
||||
return len(b), nil
|
||||
}
|
||||
if c.Divide {
|
||||
return c.Conn.Read(b)
|
||||
}
|
||||
n, err := c.Conn.Read(b)
|
||||
for p := b[:n]; ; { // for XTLS
|
||||
if len(p) <= c.in_skip {
|
||||
@@ -146,3 +198,27 @@ func (c *XorConn) Read(b []byte) (int, error) { // 5-bytes, data, 5-bytes...
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (c *XorConn) WriterReplaceable() bool {
|
||||
if !c.Divide { // never replaceable
|
||||
return false
|
||||
}
|
||||
if !c.out_after0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *XorConn) ReaderReplaceable() bool {
|
||||
if !c.Divide { // never replaceable
|
||||
return false
|
||||
}
|
||||
if !c.in_after0 || !c.isHeader {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *XorConn) Upstream() any {
|
||||
return c.Conn
|
||||
}
|
||||
|
@@ -19,7 +19,7 @@
|
||||
"@mui/icons-material": "7.3.1",
|
||||
"@mui/lab": "7.0.0-beta.16",
|
||||
"@mui/material": "7.3.1",
|
||||
"@mui/x-date-pickers": "8.10.0",
|
||||
"@mui/x-date-pickers": "8.10.2",
|
||||
"@nyanpasu/interface": "workspace:^",
|
||||
"@nyanpasu/ui": "workspace:^",
|
||||
"@tailwindcss/postcss": "4.1.12",
|
||||
@@ -78,7 +78,7 @@
|
||||
"@vitejs/plugin-react-swc": "4.0.1",
|
||||
"change-case": "5.4.4",
|
||||
"clsx": "2.1.1",
|
||||
"core-js": "3.45.0",
|
||||
"core-js": "3.45.1",
|
||||
"filesize": "11.0.2",
|
||||
"meta-json-schema": "1.19.12",
|
||||
"monaco-yaml": "5.4.0",
|
||||
|
@@ -2,7 +2,7 @@
|
||||
"manifest_version": 1,
|
||||
"latest": {
|
||||
"mihomo": "v1.19.12",
|
||||
"mihomo_alpha": "alpha-2790481",
|
||||
"mihomo_alpha": "alpha-5f09db2",
|
||||
"clash_rs": "v0.9.0",
|
||||
"clash_premium": "2023-09-05-gdcc8d87",
|
||||
"clash_rs_alpha": "0.9.0-alpha+sha.51d55ef"
|
||||
@@ -69,5 +69,5 @@
|
||||
"linux-armv7hf": "clash-armv7-unknown-linux-gnueabihf"
|
||||
}
|
||||
},
|
||||
"updated_at": "2025-08-19T22:21:14.276Z"
|
||||
"updated_at": "2025-08-20T22:21:19.472Z"
|
||||
}
|
||||
|
@@ -67,8 +67,8 @@
|
||||
"@types/fs-extra": "11.0.4",
|
||||
"@types/lodash-es": "4.17.12",
|
||||
"@types/node": "22.17.2",
|
||||
"@typescript-eslint/eslint-plugin": "8.39.1",
|
||||
"@typescript-eslint/parser": "8.39.1",
|
||||
"@typescript-eslint/eslint-plugin": "8.40.0",
|
||||
"@typescript-eslint/parser": "8.40.0",
|
||||
"autoprefixer": "10.4.21",
|
||||
"conventional-changelog-conventionalcommits": "9.1.0",
|
||||
"cross-env": "10.0.0",
|
||||
@@ -107,7 +107,7 @@
|
||||
"tailwindcss": "4.1.12",
|
||||
"tsx": "4.20.4",
|
||||
"typescript": "5.9.2",
|
||||
"typescript-eslint": "8.39.1"
|
||||
"typescript-eslint": "8.40.0"
|
||||
},
|
||||
"packageManager": "pnpm@10.14.0",
|
||||
"engines": {
|
||||
|
258
clash-nyanpasu/pnpm-lock.yaml
generated
258
clash-nyanpasu/pnpm-lock.yaml
generated
@@ -50,11 +50,11 @@ importers:
|
||||
specifier: 22.17.2
|
||||
version: 22.17.2
|
||||
'@typescript-eslint/eslint-plugin':
|
||||
specifier: 8.39.1
|
||||
version: 8.39.1(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)
|
||||
specifier: 8.40.0
|
||||
version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)
|
||||
'@typescript-eslint/parser':
|
||||
specifier: 8.39.1
|
||||
version: 8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)
|
||||
specifier: 8.40.0
|
||||
version: 8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)
|
||||
autoprefixer:
|
||||
specifier: 10.4.21
|
||||
version: 10.4.21(postcss@8.5.6)
|
||||
@@ -75,13 +75,13 @@ importers:
|
||||
version: 10.1.8(eslint@9.33.0(jiti@2.5.1))
|
||||
eslint-import-resolver-alias:
|
||||
specifier: 1.1.2
|
||||
version: 1.1.2(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1)))
|
||||
version: 1.1.2(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1)))
|
||||
eslint-plugin-html:
|
||||
specifier: 8.1.3
|
||||
version: 8.1.3
|
||||
eslint-plugin-import:
|
||||
specifier: 2.32.0
|
||||
version: 2.32.0(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1))
|
||||
version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1))
|
||||
eslint-plugin-n:
|
||||
specifier: 17.21.3
|
||||
version: 17.21.3(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)
|
||||
@@ -111,7 +111,7 @@ importers:
|
||||
version: 16.1.5
|
||||
neostandard:
|
||||
specifier: 0.12.2
|
||||
version: 0.12.2(@typescript-eslint/utils@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)
|
||||
version: 0.12.2(@typescript-eslint/utils@8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)
|
||||
npm-run-all2:
|
||||
specifier: 8.0.4
|
||||
version: 8.0.4
|
||||
@@ -170,8 +170,8 @@ importers:
|
||||
specifier: 5.9.2
|
||||
version: 5.9.2
|
||||
typescript-eslint:
|
||||
specifier: 8.39.1
|
||||
version: 8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)
|
||||
specifier: 8.40.0
|
||||
version: 8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)
|
||||
|
||||
frontend/interface:
|
||||
dependencies:
|
||||
@@ -237,8 +237,8 @@ importers:
|
||||
specifier: 7.3.1
|
||||
version: 7.3.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@mui/x-date-pickers':
|
||||
specifier: 8.10.0
|
||||
version: 8.10.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@mui/material@7.3.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@mui/system@7.3.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(dayjs@1.11.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
specifier: 8.10.2
|
||||
version: 8.10.2(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@mui/material@7.3.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@mui/system@7.3.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(dayjs@1.11.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@nyanpasu/interface':
|
||||
specifier: workspace:^
|
||||
version: link:../interface
|
||||
@@ -286,7 +286,7 @@ importers:
|
||||
version: 0.4.0
|
||||
material-react-table:
|
||||
specifier: npm:@greenhat616/material-react-table@4.0.0
|
||||
version: '@greenhat616/material-react-table@4.0.0(098023d060c5c1c6a96afb3bdaa051b0)'
|
||||
version: '@greenhat616/material-react-table@4.0.0(d0e09da0dd57ee89e64ea69924c8dcff)'
|
||||
monaco-editor:
|
||||
specifier: 0.52.2
|
||||
version: 0.52.2
|
||||
@@ -307,7 +307,7 @@ importers:
|
||||
version: 1.6.5(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
react-hook-form-mui:
|
||||
specifier: 7.6.2
|
||||
version: 7.6.2(aea177882beb7723aeada5c99e57089b)
|
||||
version: 7.6.2(8d03dcd7938824115d8443966a6d9038)
|
||||
react-i18next:
|
||||
specifier: 15.6.1
|
||||
version: 15.6.1(i18next@25.3.6(typescript@5.9.2))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.9.2)
|
||||
@@ -409,8 +409,8 @@ importers:
|
||||
specifier: 2.1.1
|
||||
version: 2.1.1
|
||||
core-js:
|
||||
specifier: 3.45.0
|
||||
version: 3.45.0
|
||||
specifier: 3.45.1
|
||||
version: 3.45.1
|
||||
filesize:
|
||||
specifier: 11.0.2
|
||||
version: 11.0.2
|
||||
@@ -1970,8 +1970,8 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@mui/x-date-pickers@8.10.0':
|
||||
resolution: {integrity: sha512-3nY+SS2/JtqcptQodECIyWKsTvPBDAcXKkyW65R4rQUCrnV6tuzriSrzy/FEYqTK0hyXYPIGJhQ6A0FbtQ9AkQ==}
|
||||
'@mui/x-date-pickers@8.10.2':
|
||||
resolution: {integrity: sha512-eS5t1jUojN/jL2FeJ8gtpCBxIEswUp9kLjM64aJ5LUKrNgM7X9dwsEHyplS+x07kWLiEAhO3nX3mepnS3Z43qg==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
'@emotion/react': ^11.9.0
|
||||
@@ -2007,8 +2007,8 @@ packages:
|
||||
moment-jalaali:
|
||||
optional: true
|
||||
|
||||
'@mui/x-internals@8.10.0':
|
||||
resolution: {integrity: sha512-stYhWBeCKfV2/ltAWShZ3ZJ51otbqpMpC+krWWoIsxM8TuvGzwXw5YMU9L2fTb8hRstsiOCQfEzIn12Ii7+N0Q==}
|
||||
'@mui/x-internals@8.10.2':
|
||||
resolution: {integrity: sha512-dlC0BQRRBdiWtqn1yDppaHYRUjU3OuPWTxy0UtqxDaJjJf4pfR8ALr243nbxgJAFqvQyWPWyO4A6p9x9eJMJEQ==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
@@ -3427,16 +3427,16 @@ packages:
|
||||
'@types/yauzl@2.10.3':
|
||||
resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==}
|
||||
|
||||
'@typescript-eslint/eslint-plugin@8.39.1':
|
||||
resolution: {integrity: sha512-yYegZ5n3Yr6eOcqgj2nJH8cH/ZZgF+l0YIdKILSDjYFRjgYQMgv/lRjV5Z7Up04b9VYUondt8EPMqg7kTWgJ2g==}
|
||||
'@typescript-eslint/eslint-plugin@8.40.0':
|
||||
resolution: {integrity: sha512-w/EboPlBwnmOBtRbiOvzjD+wdiZdgFeo17lkltrtn7X37vagKKWJABvyfsJXTlHe6XBzugmYgd4A4nW+k8Mixw==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
'@typescript-eslint/parser': ^8.39.1
|
||||
'@typescript-eslint/parser': ^8.40.0
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: '>=4.8.4 <6.0.0'
|
||||
|
||||
'@typescript-eslint/parser@8.39.1':
|
||||
resolution: {integrity: sha512-pUXGCuHnnKw6PyYq93lLRiZm3vjuslIy7tus1lIQTYVK9bL8XBgJnCWm8a0KcTtHC84Yya1Q6rtll+duSMj0dg==}
|
||||
'@typescript-eslint/parser@8.40.0':
|
||||
resolution: {integrity: sha512-jCNyAuXx8dr5KJMkecGmZ8KI61KBUhkCob+SD+C+I5+Y1FWI2Y3QmY4/cxMCC5WAsZqoEtEETVhUiUMIGCf6Bw==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
@@ -3448,8 +3448,8 @@ packages:
|
||||
peerDependencies:
|
||||
typescript: '>=4.8.4 <5.9.0'
|
||||
|
||||
'@typescript-eslint/project-service@8.39.1':
|
||||
resolution: {integrity: sha512-8fZxek3ONTwBu9ptw5nCKqZOSkXshZB7uAxuFF0J/wTMkKydjXCzqqga7MlFMpHi9DoG4BadhmTkITBcg8Aybw==}
|
||||
'@typescript-eslint/project-service@8.40.0':
|
||||
resolution: {integrity: sha512-/A89vz7Wf5DEXsGVvcGdYKbVM9F7DyFXj52lNYUDS1L9yJfqjW/fIp5PgMuEJL/KeqVTe2QSbXAGUZljDUpArw==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
typescript: '>=4.8.4 <6.0.0'
|
||||
@@ -3458,8 +3458,8 @@ packages:
|
||||
resolution: {integrity: sha512-WJw3AVlFFcdT9Ri1xs/lg8LwDqgekWXWhH3iAF+1ZM+QPd7oxQ6jvtW/JPwzAScxitILUIFs0/AnQ/UWHzbATQ==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@typescript-eslint/scope-manager@8.39.1':
|
||||
resolution: {integrity: sha512-RkBKGBrjgskFGWuyUGz/EtD8AF/GW49S21J8dvMzpJitOF1slLEbbHnNEtAHtnDAnx8qDEdRrULRnWVx27wGBw==}
|
||||
'@typescript-eslint/scope-manager@8.40.0':
|
||||
resolution: {integrity: sha512-y9ObStCcdCiZKzwqsE8CcpyuVMwRouJbbSrNuThDpv16dFAj429IkM6LNb1dZ2m7hK5fHyzNcErZf7CEeKXR4w==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@typescript-eslint/tsconfig-utils@8.38.0':
|
||||
@@ -3468,20 +3468,20 @@ packages:
|
||||
peerDependencies:
|
||||
typescript: '>=4.8.4 <5.9.0'
|
||||
|
||||
'@typescript-eslint/tsconfig-utils@8.39.0':
|
||||
resolution: {integrity: sha512-Fd3/QjmFV2sKmvv3Mrj8r6N8CryYiCS8Wdb/6/rgOXAWGcFuc+VkQuG28uk/4kVNVZBQuuDHEDUpo/pQ32zsIQ==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
typescript: '>=4.8.4 <6.0.0'
|
||||
|
||||
'@typescript-eslint/tsconfig-utils@8.39.1':
|
||||
resolution: {integrity: sha512-ePUPGVtTMR8XMU2Hee8kD0Pu4NDE1CN9Q1sxGSGd/mbOtGZDM7pnhXNJnzW63zk/q+Z54zVzj44HtwXln5CvHA==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
typescript: '>=4.8.4 <6.0.0'
|
||||
|
||||
'@typescript-eslint/type-utils@8.39.1':
|
||||
resolution: {integrity: sha512-gu9/ahyatyAdQbKeHnhT4R+y3YLtqqHyvkfDxaBYk97EcbfChSJXyaJnIL3ygUv7OuZatePHmQvuH5ru0lnVeA==}
|
||||
'@typescript-eslint/tsconfig-utils@8.40.0':
|
||||
resolution: {integrity: sha512-jtMytmUaG9d/9kqSl/W3E3xaWESo4hFDxAIHGVW/WKKtQhesnRIJSAJO6XckluuJ6KDB5woD1EiqknriCtAmcw==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
typescript: '>=4.8.4 <6.0.0'
|
||||
|
||||
'@typescript-eslint/type-utils@8.40.0':
|
||||
resolution: {integrity: sha512-eE60cK4KzAc6ZrzlJnflXdrMqOBaugeukWICO2rB0KNvwdIMaEaYiywwHMzA1qFpTxrLhN9Lp4E/00EgWcD3Ow==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
@@ -3495,22 +3495,22 @@ packages:
|
||||
resolution: {integrity: sha512-wzkUfX3plUqij4YwWaJyqhiPE5UCRVlFpKn1oCRn2O1bJ592XxWJj8ROQ3JD5MYXLORW84063z3tZTb/cs4Tyw==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@typescript-eslint/types@8.39.0':
|
||||
resolution: {integrity: sha512-ArDdaOllnCj3yn/lzKn9s0pBQYmmyme/v1HbGIGB0GB/knFI3fWMHloC+oYTJW46tVbYnGKTMDK4ah1sC2v0Kg==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@typescript-eslint/types@8.39.1':
|
||||
resolution: {integrity: sha512-7sPDKQQp+S11laqTrhHqeAbsCfMkwJMrV7oTDvtDds4mEofJYir414bYKUEb8YPUm9QL3U+8f6L6YExSoAGdQw==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@typescript-eslint/types@8.40.0':
|
||||
resolution: {integrity: sha512-ETdbFlgbAmXHyFPwqUIYrfc12ArvpBhEVgGAxVYSwli26dn8Ko+lIo4Su9vI9ykTZdJn+vJprs/0eZU0YMAEQg==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@typescript-eslint/typescript-estree@8.38.0':
|
||||
resolution: {integrity: sha512-fooELKcAKzxux6fA6pxOflpNS0jc+nOQEEOipXFNjSlBS6fqrJOVY/whSn70SScHrcJ2LDsxWrneFoWYSVfqhQ==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
typescript: '>=4.8.4 <5.9.0'
|
||||
|
||||
'@typescript-eslint/typescript-estree@8.39.1':
|
||||
resolution: {integrity: sha512-EKkpcPuIux48dddVDXyQBlKdeTPMmALqBUbEk38McWv0qVEZwOpVJBi7ugK5qVNgeuYjGNQxrrnoM/5+TI/BPw==}
|
||||
'@typescript-eslint/typescript-estree@8.40.0':
|
||||
resolution: {integrity: sha512-k1z9+GJReVVOkc1WfVKs1vBrR5MIKKbdAjDTPvIK3L8De6KbFfPFt6BKpdkdk7rZS2GtC/m6yI5MYX+UsuvVYQ==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
typescript: '>=4.8.4 <6.0.0'
|
||||
@@ -3522,8 +3522,8 @@ packages:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: '>=4.8.4 <5.9.0'
|
||||
|
||||
'@typescript-eslint/utils@8.39.1':
|
||||
resolution: {integrity: sha512-VF5tZ2XnUSTuiqZFXCZfZs1cgkdd3O/sSYmdo2EpSyDlC86UM/8YytTmKnehOW3TGAlivqTDT6bS87B/GQ/jyg==}
|
||||
'@typescript-eslint/utils@8.40.0':
|
||||
resolution: {integrity: sha512-Cgzi2MXSZyAUOY+BFwGs17s7ad/7L+gKt6Y8rAVVWS+7o6wrjeFN4nVfTpbE25MNcxyJ+iYUXflbs2xR9h4UBg==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
@@ -3533,8 +3533,8 @@ packages:
|
||||
resolution: {integrity: sha512-pWrTcoFNWuwHlA9CvlfSsGWs14JxfN1TH25zM5L7o0pRLhsoZkDnTsXfQRJBEWJoV5DL0jf+Z+sxiud+K0mq1g==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@typescript-eslint/visitor-keys@8.39.1':
|
||||
resolution: {integrity: sha512-W8FQi6kEh2e8zVhQ0eeRnxdvIoOkAp/CPAahcNio6nO9dsIwb9b34z90KOlheoyuVf6LSOEdjlkxSkapNEc+4A==}
|
||||
'@typescript-eslint/visitor-keys@8.40.0':
|
||||
resolution: {integrity: sha512-8CZ47QwalyRjsypfwnbI3hKy5gJDPmrkLjkgMxhi0+DZZ2QNx2naS6/hWoVYUHU7LU2zleF68V9miaVZvhFfTA==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@ungap/structured-clone@1.2.0':
|
||||
@@ -4253,8 +4253,8 @@ packages:
|
||||
core-js-compat@3.44.0:
|
||||
resolution: {integrity: sha512-JepmAj2zfl6ogy34qfWtcE7nHKAJnKsQFRn++scjVS2bZFllwptzw61BZcZFYBPpUznLfAvh0LGhxKppk04ClA==}
|
||||
|
||||
core-js@3.45.0:
|
||||
resolution: {integrity: sha512-c2KZL9lP4DjkN3hk/an4pWn5b5ZefhRJnAc42n6LJ19kSnbeRbdQZE5dSeE2LBol1OwJD3X1BQvFTAsa8ReeDA==}
|
||||
core-js@3.45.1:
|
||||
resolution: {integrity: sha512-L4NPsJlCfZsPeXukyzHFlg/i7IIVwHSItR0wg0FLNqYClJ4MQYTYLbC7EkjKYRLZF2iof2MUgN0EGy7MdQFChg==}
|
||||
|
||||
cosmiconfig-typescript-loader@6.1.0:
|
||||
resolution: {integrity: sha512-tJ1w35ZRUiM5FeTzT7DtYWAFFv37ZLqSRkGi2oeCK1gPhvaWjkAtfXvLmvE1pRfxxp9aQo6ba/Pvg1dKj05D4g==}
|
||||
@@ -8133,8 +8133,8 @@ packages:
|
||||
typedarray-to-buffer@3.1.5:
|
||||
resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==}
|
||||
|
||||
typescript-eslint@8.39.1:
|
||||
resolution: {integrity: sha512-GDUv6/NDYngUlNvwaHM1RamYftxf782IyEDbdj3SeaIHHv8fNQVRC++fITT7kUJV/5rIA/tkoRSSskt6osEfqg==}
|
||||
typescript-eslint@8.40.0:
|
||||
resolution: {integrity: sha512-Xvd2l+ZmFDPEt4oj1QEXzA4A2uUK6opvKu3eGN9aGjB8au02lIVcLyi375w94hHyejTOmzIU77L8ol2sRg9n7Q==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
@@ -8765,7 +8765,7 @@ snapshots:
|
||||
|
||||
'@babel/generator@7.17.7':
|
||||
dependencies:
|
||||
'@babel/types': 7.28.1
|
||||
'@babel/types': 7.28.2
|
||||
jsesc: 2.5.2
|
||||
source-map: 0.5.7
|
||||
optional: true
|
||||
@@ -8856,20 +8856,20 @@ snapshots:
|
||||
|
||||
'@babel/helper-environment-visitor@7.24.7':
|
||||
dependencies:
|
||||
'@babel/types': 7.28.1
|
||||
'@babel/types': 7.28.2
|
||||
optional: true
|
||||
|
||||
'@babel/helper-function-name@7.24.7':
|
||||
dependencies:
|
||||
'@babel/template': 7.27.2
|
||||
'@babel/types': 7.28.1
|
||||
'@babel/types': 7.28.2
|
||||
optional: true
|
||||
|
||||
'@babel/helper-globals@7.28.0': {}
|
||||
|
||||
'@babel/helper-hoist-variables@7.24.7':
|
||||
dependencies:
|
||||
'@babel/types': 7.28.1
|
||||
'@babel/types': 7.28.2
|
||||
optional: true
|
||||
|
||||
'@babel/helper-member-expression-to-functions@7.25.9':
|
||||
@@ -8982,7 +8982,7 @@ snapshots:
|
||||
|
||||
'@babel/helper-split-export-declaration@7.24.7':
|
||||
dependencies:
|
||||
'@babel/types': 7.28.1
|
||||
'@babel/types': 7.28.2
|
||||
optional: true
|
||||
|
||||
'@babel/helper-string-parser@7.27.1': {}
|
||||
@@ -9574,13 +9574,13 @@ snapshots:
|
||||
'@babel/traverse@7.23.2':
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.27.1
|
||||
'@babel/generator': 7.28.0
|
||||
'@babel/generator': 7.28.3
|
||||
'@babel/helper-environment-visitor': 7.24.7
|
||||
'@babel/helper-function-name': 7.24.7
|
||||
'@babel/helper-hoist-variables': 7.24.7
|
||||
'@babel/helper-split-export-declaration': 7.24.7
|
||||
'@babel/parser': 7.28.0
|
||||
'@babel/types': 7.28.1
|
||||
'@babel/parser': 7.28.3
|
||||
'@babel/types': 7.28.2
|
||||
debug: 4.4.1
|
||||
globals: 11.12.0
|
||||
transitivePeerDependencies:
|
||||
@@ -10032,13 +10032,13 @@ snapshots:
|
||||
|
||||
'@fastify/busboy@2.1.1': {}
|
||||
|
||||
'@greenhat616/material-react-table@4.0.0(098023d060c5c1c6a96afb3bdaa051b0)':
|
||||
'@greenhat616/material-react-table@4.0.0(d0e09da0dd57ee89e64ea69924c8dcff)':
|
||||
dependencies:
|
||||
'@emotion/react': 11.14.0(@types/react@19.1.10)(react@19.1.1)
|
||||
'@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)
|
||||
'@mui/icons-material': 7.3.1(@mui/material@7.3.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)
|
||||
'@mui/material': 7.3.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@mui/x-date-pickers': 8.10.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@mui/material@7.3.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@mui/system@7.3.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(dayjs@1.11.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@mui/x-date-pickers': 8.10.2(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@mui/material@7.3.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@mui/system@7.3.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(dayjs@1.11.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@tanstack/match-sorter-utils': 8.19.4
|
||||
'@tanstack/react-table': 8.21.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@tanstack/react-virtual': 3.13.9(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
@@ -10286,13 +10286,13 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@types/react': 19.1.10
|
||||
|
||||
'@mui/x-date-pickers@8.10.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@mui/material@7.3.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@mui/system@7.3.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(dayjs@1.11.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
|
||||
'@mui/x-date-pickers@8.10.2(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@mui/material@7.3.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@mui/system@7.3.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(dayjs@1.11.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.28.2
|
||||
'@mui/material': 7.3.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@mui/system': 7.3.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)
|
||||
'@mui/utils': 7.3.1(@types/react@19.1.10)(react@19.1.1)
|
||||
'@mui/x-internals': 8.10.0(@types/react@19.1.10)(react@19.1.1)
|
||||
'@mui/x-internals': 8.10.2(@types/react@19.1.10)(react@19.1.1)
|
||||
'@types/react-transition-group': 4.4.12(@types/react@19.1.10)
|
||||
clsx: 2.1.1
|
||||
prop-types: 15.8.1
|
||||
@@ -10306,7 +10306,7 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- '@types/react'
|
||||
|
||||
'@mui/x-internals@8.10.0(@types/react@19.1.10)(react@19.1.1)':
|
||||
'@mui/x-internals@8.10.2(@types/react@19.1.10)(react@19.1.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.28.2
|
||||
'@mui/utils': 7.3.1(@types/react@19.1.10)(react@19.1.1)
|
||||
@@ -11377,7 +11377,7 @@ snapshots:
|
||||
'@trivago/prettier-plugin-sort-imports@4.3.0(prettier@3.6.2)':
|
||||
dependencies:
|
||||
'@babel/generator': 7.17.7
|
||||
'@babel/parser': 7.28.0
|
||||
'@babel/parser': 7.28.3
|
||||
'@babel/traverse': 7.23.2
|
||||
'@babel/types': 7.17.0
|
||||
javascript-natural-sort: 0.7.1
|
||||
@@ -11657,14 +11657,14 @@ snapshots:
|
||||
'@types/node': 22.17.2
|
||||
optional: true
|
||||
|
||||
'@typescript-eslint/eslint-plugin@8.39.1(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)':
|
||||
'@typescript-eslint/eslint-plugin@8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)':
|
||||
dependencies:
|
||||
'@eslint-community/regexpp': 4.12.1
|
||||
'@typescript-eslint/parser': 8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)
|
||||
'@typescript-eslint/scope-manager': 8.39.1
|
||||
'@typescript-eslint/type-utils': 8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)
|
||||
'@typescript-eslint/utils': 8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)
|
||||
'@typescript-eslint/visitor-keys': 8.39.1
|
||||
'@typescript-eslint/parser': 8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)
|
||||
'@typescript-eslint/scope-manager': 8.40.0
|
||||
'@typescript-eslint/type-utils': 8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)
|
||||
'@typescript-eslint/utils': 8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)
|
||||
'@typescript-eslint/visitor-keys': 8.40.0
|
||||
eslint: 9.33.0(jiti@2.5.1)
|
||||
graphemer: 1.4.0
|
||||
ignore: 7.0.5
|
||||
@@ -11674,12 +11674,12 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)':
|
||||
'@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)':
|
||||
dependencies:
|
||||
'@typescript-eslint/scope-manager': 8.39.1
|
||||
'@typescript-eslint/types': 8.39.1
|
||||
'@typescript-eslint/typescript-estree': 8.39.1(typescript@5.9.2)
|
||||
'@typescript-eslint/visitor-keys': 8.39.1
|
||||
'@typescript-eslint/scope-manager': 8.40.0
|
||||
'@typescript-eslint/types': 8.40.0
|
||||
'@typescript-eslint/typescript-estree': 8.40.0(typescript@5.9.2)
|
||||
'@typescript-eslint/visitor-keys': 8.40.0
|
||||
debug: 4.4.1
|
||||
eslint: 9.33.0(jiti@2.5.1)
|
||||
typescript: 5.9.2
|
||||
@@ -11688,17 +11688,17 @@ snapshots:
|
||||
|
||||
'@typescript-eslint/project-service@8.38.0(typescript@5.9.2)':
|
||||
dependencies:
|
||||
'@typescript-eslint/tsconfig-utils': 8.39.0(typescript@5.9.2)
|
||||
'@typescript-eslint/types': 8.39.0
|
||||
'@typescript-eslint/tsconfig-utils': 8.39.1(typescript@5.9.2)
|
||||
'@typescript-eslint/types': 8.39.1
|
||||
debug: 4.4.1
|
||||
typescript: 5.9.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/project-service@8.39.1(typescript@5.9.2)':
|
||||
'@typescript-eslint/project-service@8.40.0(typescript@5.9.2)':
|
||||
dependencies:
|
||||
'@typescript-eslint/tsconfig-utils': 8.39.1(typescript@5.9.2)
|
||||
'@typescript-eslint/types': 8.39.1
|
||||
'@typescript-eslint/tsconfig-utils': 8.40.0(typescript@5.9.2)
|
||||
'@typescript-eslint/types': 8.40.0
|
||||
debug: 4.4.1
|
||||
typescript: 5.9.2
|
||||
transitivePeerDependencies:
|
||||
@@ -11709,28 +11709,28 @@ snapshots:
|
||||
'@typescript-eslint/types': 8.38.0
|
||||
'@typescript-eslint/visitor-keys': 8.38.0
|
||||
|
||||
'@typescript-eslint/scope-manager@8.39.1':
|
||||
'@typescript-eslint/scope-manager@8.40.0':
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.39.1
|
||||
'@typescript-eslint/visitor-keys': 8.39.1
|
||||
'@typescript-eslint/types': 8.40.0
|
||||
'@typescript-eslint/visitor-keys': 8.40.0
|
||||
|
||||
'@typescript-eslint/tsconfig-utils@8.38.0(typescript@5.9.2)':
|
||||
dependencies:
|
||||
typescript: 5.9.2
|
||||
|
||||
'@typescript-eslint/tsconfig-utils@8.39.0(typescript@5.9.2)':
|
||||
dependencies:
|
||||
typescript: 5.9.2
|
||||
|
||||
'@typescript-eslint/tsconfig-utils@8.39.1(typescript@5.9.2)':
|
||||
dependencies:
|
||||
typescript: 5.9.2
|
||||
|
||||
'@typescript-eslint/type-utils@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)':
|
||||
'@typescript-eslint/tsconfig-utils@8.40.0(typescript@5.9.2)':
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.39.1
|
||||
'@typescript-eslint/typescript-estree': 8.39.1(typescript@5.9.2)
|
||||
'@typescript-eslint/utils': 8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)
|
||||
typescript: 5.9.2
|
||||
|
||||
'@typescript-eslint/type-utils@8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)':
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.40.0
|
||||
'@typescript-eslint/typescript-estree': 8.40.0(typescript@5.9.2)
|
||||
'@typescript-eslint/utils': 8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)
|
||||
debug: 4.4.1
|
||||
eslint: 9.33.0(jiti@2.5.1)
|
||||
ts-api-utils: 2.1.0(typescript@5.9.2)
|
||||
@@ -11742,10 +11742,10 @@ snapshots:
|
||||
|
||||
'@typescript-eslint/types@8.38.0': {}
|
||||
|
||||
'@typescript-eslint/types@8.39.0': {}
|
||||
|
||||
'@typescript-eslint/types@8.39.1': {}
|
||||
|
||||
'@typescript-eslint/types@8.40.0': {}
|
||||
|
||||
'@typescript-eslint/typescript-estree@8.38.0(typescript@5.9.2)':
|
||||
dependencies:
|
||||
'@typescript-eslint/project-service': 8.38.0(typescript@5.9.2)
|
||||
@@ -11762,12 +11762,12 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/typescript-estree@8.39.1(typescript@5.9.2)':
|
||||
'@typescript-eslint/typescript-estree@8.40.0(typescript@5.9.2)':
|
||||
dependencies:
|
||||
'@typescript-eslint/project-service': 8.39.1(typescript@5.9.2)
|
||||
'@typescript-eslint/tsconfig-utils': 8.39.1(typescript@5.9.2)
|
||||
'@typescript-eslint/types': 8.39.1
|
||||
'@typescript-eslint/visitor-keys': 8.39.1
|
||||
'@typescript-eslint/project-service': 8.40.0(typescript@5.9.2)
|
||||
'@typescript-eslint/tsconfig-utils': 8.40.0(typescript@5.9.2)
|
||||
'@typescript-eslint/types': 8.40.0
|
||||
'@typescript-eslint/visitor-keys': 8.40.0
|
||||
debug: 4.4.1
|
||||
fast-glob: 3.3.3
|
||||
is-glob: 4.0.3
|
||||
@@ -11789,12 +11789,12 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/utils@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)':
|
||||
'@typescript-eslint/utils@8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)':
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.7.0(eslint@9.33.0(jiti@2.5.1))
|
||||
'@typescript-eslint/scope-manager': 8.39.1
|
||||
'@typescript-eslint/types': 8.39.1
|
||||
'@typescript-eslint/typescript-estree': 8.39.1(typescript@5.9.2)
|
||||
'@typescript-eslint/scope-manager': 8.40.0
|
||||
'@typescript-eslint/types': 8.40.0
|
||||
'@typescript-eslint/typescript-estree': 8.40.0(typescript@5.9.2)
|
||||
eslint: 9.33.0(jiti@2.5.1)
|
||||
typescript: 5.9.2
|
||||
transitivePeerDependencies:
|
||||
@@ -11805,9 +11805,9 @@ snapshots:
|
||||
'@typescript-eslint/types': 8.38.0
|
||||
eslint-visitor-keys: 4.2.1
|
||||
|
||||
'@typescript-eslint/visitor-keys@8.39.1':
|
||||
'@typescript-eslint/visitor-keys@8.40.0':
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.39.1
|
||||
'@typescript-eslint/types': 8.40.0
|
||||
eslint-visitor-keys: 4.2.1
|
||||
|
||||
'@ungap/structured-clone@1.2.0': {}
|
||||
@@ -11881,7 +11881,7 @@ snapshots:
|
||||
babel-plugin-polyfill-regenerator: 0.6.5(@babel/core@7.28.0)
|
||||
browserslist: 4.25.1
|
||||
browserslist-to-esbuild: 2.1.1(browserslist@4.25.1)
|
||||
core-js: 3.45.0
|
||||
core-js: 3.45.1
|
||||
magic-string: 0.30.17
|
||||
regenerator-runtime: 0.14.1
|
||||
systemjs: 6.15.1
|
||||
@@ -12584,7 +12584,7 @@ snapshots:
|
||||
dependencies:
|
||||
browserslist: 4.25.1
|
||||
|
||||
core-js@3.45.0: {}
|
||||
core-js@3.45.1: {}
|
||||
|
||||
cosmiconfig-typescript-loader@6.1.0(@types/node@22.17.2)(cosmiconfig@9.0.0(typescript@5.9.2))(typescript@5.9.2):
|
||||
dependencies:
|
||||
@@ -13397,9 +13397,9 @@ snapshots:
|
||||
optionalDependencies:
|
||||
unrs-resolver: 1.10.1
|
||||
|
||||
eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1))):
|
||||
eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1))):
|
||||
dependencies:
|
||||
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1))
|
||||
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1))
|
||||
|
||||
eslint-import-resolver-node@0.3.9:
|
||||
dependencies:
|
||||
@@ -13409,7 +13409,7 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-import-resolver-typescript@3.10.1(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.33.0(jiti@2.5.1)))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1)):
|
||||
eslint-import-resolver-typescript@3.10.1(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.33.0(jiti@2.5.1)))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1)):
|
||||
dependencies:
|
||||
'@nolyfill/is-core-module': 1.0.39
|
||||
debug: 4.4.1
|
||||
@@ -13420,16 +13420,16 @@ snapshots:
|
||||
tinyglobby: 0.2.14
|
||||
unrs-resolver: 1.10.1
|
||||
optionalDependencies:
|
||||
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1))
|
||||
eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.33.0(jiti@2.5.1))
|
||||
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1))
|
||||
eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.33.0(jiti@2.5.1))
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-module-utils@2.12.1(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.33.0(jiti@2.5.1)):
|
||||
eslint-module-utils@2.12.1(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.33.0(jiti@2.5.1)):
|
||||
dependencies:
|
||||
debug: 3.2.7
|
||||
optionalDependencies:
|
||||
'@typescript-eslint/parser': 8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)
|
||||
'@typescript-eslint/parser': 8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)
|
||||
eslint: 9.33.0(jiti@2.5.1)
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
transitivePeerDependencies:
|
||||
@@ -13446,7 +13446,7 @@ snapshots:
|
||||
dependencies:
|
||||
htmlparser2: 10.0.0
|
||||
|
||||
eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.33.0(jiti@2.5.1)):
|
||||
eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.33.0(jiti@2.5.1)):
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.35.1
|
||||
comment-parser: 1.4.1
|
||||
@@ -13459,12 +13459,12 @@ snapshots:
|
||||
stable-hash-x: 0.2.0
|
||||
unrs-resolver: 1.10.1
|
||||
optionalDependencies:
|
||||
'@typescript-eslint/utils': 8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)
|
||||
'@typescript-eslint/utils': 8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1)):
|
||||
eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1)):
|
||||
dependencies:
|
||||
'@rtsao/scc': 1.1.0
|
||||
array-includes: 3.1.9
|
||||
@@ -13475,7 +13475,7 @@ snapshots:
|
||||
doctrine: 2.1.0
|
||||
eslint: 9.33.0(jiti@2.5.1)
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.33.0(jiti@2.5.1))
|
||||
eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.33.0(jiti@2.5.1))
|
||||
hasown: 2.0.2
|
||||
is-core-module: 2.16.1
|
||||
is-glob: 4.0.3
|
||||
@@ -13487,7 +13487,7 @@ snapshots:
|
||||
string.prototype.trimend: 1.0.9
|
||||
tsconfig-paths: 3.15.0
|
||||
optionalDependencies:
|
||||
'@typescript-eslint/parser': 8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)
|
||||
'@typescript-eslint/parser': 8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)
|
||||
transitivePeerDependencies:
|
||||
- eslint-import-resolver-typescript
|
||||
- eslint-import-resolver-webpack
|
||||
@@ -15286,20 +15286,20 @@ snapshots:
|
||||
sax: 1.3.0
|
||||
optional: true
|
||||
|
||||
neostandard@0.12.2(@typescript-eslint/utils@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2):
|
||||
neostandard@0.12.2(@typescript-eslint/utils@8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2):
|
||||
dependencies:
|
||||
'@humanwhocodes/gitignore-to-minimatch': 1.0.2
|
||||
'@stylistic/eslint-plugin': 2.11.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)
|
||||
eslint: 9.33.0(jiti@2.5.1)
|
||||
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.33.0(jiti@2.5.1)))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1))
|
||||
eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.33.0(jiti@2.5.1))
|
||||
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.33.0(jiti@2.5.1)))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1))
|
||||
eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.33.0(jiti@2.5.1))
|
||||
eslint-plugin-n: 17.21.3(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)
|
||||
eslint-plugin-promise: 7.2.1(eslint@9.33.0(jiti@2.5.1))
|
||||
eslint-plugin-react: 7.37.5(eslint@9.33.0(jiti@2.5.1))
|
||||
find-up: 5.0.0
|
||||
globals: 15.15.0
|
||||
peowly: 1.3.2
|
||||
typescript-eslint: 8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)
|
||||
typescript-eslint: 8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)
|
||||
transitivePeerDependencies:
|
||||
- '@typescript-eslint/utils'
|
||||
- eslint-import-resolver-node
|
||||
@@ -15847,14 +15847,14 @@ snapshots:
|
||||
react: 19.1.1
|
||||
react-dom: 19.1.1(react@19.1.1)
|
||||
|
||||
react-hook-form-mui@7.6.2(aea177882beb7723aeada5c99e57089b):
|
||||
react-hook-form-mui@7.6.2(8d03dcd7938824115d8443966a6d9038):
|
||||
dependencies:
|
||||
'@mui/material': 7.3.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
react: 19.1.1
|
||||
react-hook-form: 7.52.1(react@19.1.1)
|
||||
optionalDependencies:
|
||||
'@mui/icons-material': 7.3.1(@mui/material@7.3.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)
|
||||
'@mui/x-date-pickers': 8.10.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@mui/material@7.3.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@mui/system@7.3.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(dayjs@1.11.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@mui/x-date-pickers': 8.10.2(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@mui/material@7.3.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@mui/system@7.3.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(dayjs@1.11.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
|
||||
react-hook-form@7.52.1(react@19.1.1):
|
||||
dependencies:
|
||||
@@ -17000,12 +17000,12 @@ snapshots:
|
||||
dependencies:
|
||||
is-typedarray: 1.0.0
|
||||
|
||||
typescript-eslint@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2):
|
||||
typescript-eslint@8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2):
|
||||
dependencies:
|
||||
'@typescript-eslint/eslint-plugin': 8.39.1(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)
|
||||
'@typescript-eslint/parser': 8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)
|
||||
'@typescript-eslint/typescript-estree': 8.39.1(typescript@5.9.2)
|
||||
'@typescript-eslint/utils': 8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)
|
||||
'@typescript-eslint/eslint-plugin': 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)
|
||||
'@typescript-eslint/parser': 8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)
|
||||
'@typescript-eslint/typescript-estree': 8.40.0(typescript@5.9.2)
|
||||
'@typescript-eslint/utils': 8.40.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)
|
||||
eslint: 9.33.0(jiti@2.5.1)
|
||||
typescript: 5.9.2
|
||||
transitivePeerDependencies:
|
||||
|
@@ -91,6 +91,12 @@ define U-Boot/Bananapro
|
||||
BUILD_DEVICES:=lemaker_bananapro
|
||||
endef
|
||||
|
||||
define U-Boot/beelink_x2
|
||||
BUILD_SUBTARGET:=cortexa7
|
||||
NAME:=Beelink X2 (H3)
|
||||
BUILD_DEVICES:=roofull_beelink-x2
|
||||
endef
|
||||
|
||||
define U-Boot/Cubieboard
|
||||
BUILD_SUBTARGET:=cortexa8
|
||||
NAME:=Cubieboard
|
||||
@@ -112,6 +118,7 @@ endef
|
||||
define U-Boot/Hummingbird_A31
|
||||
BUILD_SUBTARGET:=cortexa7
|
||||
NAME:=Hummingbird A31 board
|
||||
BUILD_DEVICES:=merrii_hummingbird
|
||||
endef
|
||||
|
||||
define U-Boot/Marsboard_A10
|
||||
@@ -138,6 +145,12 @@ define U-Boot/Linksprite_pcDuino
|
||||
BUILD_DEVICES:=linksprite_a10-pcduino
|
||||
endef
|
||||
|
||||
define U-Boot/LicheePi_Zero
|
||||
BUILD_SUBTARGET:=cortexa7
|
||||
NAME:=Lichee Pi Zero V3s
|
||||
BUILD_DEVICES:=licheepi_licheepi-zero-dock
|
||||
endef
|
||||
|
||||
define U-Boot/Linksprite_pcDuino3
|
||||
BUILD_SUBTARGET:=cortexa7
|
||||
NAME:=Linksprite pcDuino3
|
||||
@@ -337,6 +350,15 @@ define U-Boot/orangepi_zero2
|
||||
ATF:=h616
|
||||
endef
|
||||
|
||||
define U-Boot/orangepi_zero2w
|
||||
BUILD_SUBTARGET:=cortexa53
|
||||
NAME:=Xunlong Orange Pi Zero2W
|
||||
BUILD_DEVICES:=xunlong_orangepi-zero2w
|
||||
DEPENDS:=+PACKAGE_u-boot-orangepi_zero2w:trusted-firmware-a-sunxi-h616
|
||||
UENV:=h616
|
||||
ATF:=h616
|
||||
endef
|
||||
|
||||
define U-Boot/orangepi_zero3
|
||||
BUILD_SUBTARGET:=cortexa53
|
||||
NAME:=Xunlong Orange Pi Zero3
|
||||
@@ -380,6 +402,7 @@ UBOOT_TARGETS := \
|
||||
bananapi_p2_zero \
|
||||
Bananapi_M2_Ultra \
|
||||
Bananapro \
|
||||
beelink_x2 \
|
||||
Cubieboard \
|
||||
Cubieboard2 \
|
||||
Cubietruck \
|
||||
@@ -387,6 +410,7 @@ UBOOT_TARGETS := \
|
||||
Marsboard_A10 \
|
||||
Mele_M9 \
|
||||
OLIMEX_A13_SOM \
|
||||
LicheePi_Zero \
|
||||
Linksprite_pcDuino \
|
||||
Linksprite_pcDuino3 \
|
||||
Linksprite_pcDuino3_Nano \
|
||||
@@ -409,6 +433,7 @@ UBOOT_TARGETS := \
|
||||
orangepi_2 \
|
||||
orangepi_pc2 \
|
||||
orangepi_zero2 \
|
||||
orangepi_zero2w \
|
||||
orangepi_zero3 \
|
||||
pangolin \
|
||||
pine64_plus \
|
||||
|
@@ -1,7 +1,6 @@
|
||||
setenv mmc_rootpart 2
|
||||
part uuid mmc ${mmc_bootdev}:${mmc_rootpart} uuid
|
||||
setenv loadkernel fatload mmc \$mmc_bootdev \$kernel_addr_r uImage
|
||||
setenv loaddtb fatload mmc \$mmc_bootdev \$fdt_addr_r dtb
|
||||
setenv loadkernel fatload mmc \$mmc_bootdev \$kernel_comp_addr_r uImage
|
||||
setenv bootargs console=ttyS0,115200 earlyprintk root=PARTUUID=${uuid} rootwait earlycon=uart,mmio32,0x01c28000
|
||||
setenv uenvcmd run loadkernel \&\& run loaddtb \&\& booti \$kernel_addr_r - \$fdt_addr_r
|
||||
setenv uenvcmd run loadkernel \&\& bootm \$kernel_comp_addr_r
|
||||
run uenvcmd
|
||||
|
@@ -1,8 +1,6 @@
|
||||
setenv fdt_high ffffffff
|
||||
setenv mmc_rootpart 2
|
||||
part uuid mmc ${mmc_bootdev}:${mmc_rootpart} uuid
|
||||
setenv loadkernel fatload mmc \$mmc_bootdev \$kernel_addr_r uImage
|
||||
setenv loaddtb fatload mmc \$mmc_bootdev \$fdt_addr_r dtb
|
||||
setenv bootargs console=ttyS0,115200 earlyprintk root=PARTUUID=${uuid} rootwait
|
||||
setenv uenvcmd run loadkernel \&\& run loaddtb \&\& bootm \$kernel_addr_r - \$fdt_addr_r
|
||||
setenv uenvcmd run loadkernel \&\& bootm \$kernel_addr_r
|
||||
run uenvcmd
|
||||
|
@@ -1,7 +1,6 @@
|
||||
setenv mmc_rootpart 2
|
||||
part uuid mmc ${mmc_bootdev}:${mmc_rootpart} uuid
|
||||
setenv loadkernel fatload mmc \$mmc_bootdev \$kernel_addr_r uImage
|
||||
setenv loaddtb fatload mmc \$mmc_bootdev \$fdt_addr_r dtb
|
||||
setenv loadkernel fatload mmc \$mmc_bootdev \$kernel_comp_addr_r uImage
|
||||
setenv bootargs console=ttyS0,115200 earlyprintk root=PARTUUID=${uuid} rootwait
|
||||
setenv uenvcmd run loadkernel \&\& run loaddtb \&\& booti \$kernel_addr_r - \$fdt_addr_r
|
||||
setenv uenvcmd run loadkernel \&\& bootm \$kernel_comp_addr_r
|
||||
run uenvcmd
|
||||
|
@@ -1,7 +1,6 @@
|
||||
setenv mmc_rootpart 2
|
||||
part uuid mmc ${mmc_bootdev}:${mmc_rootpart} uuid
|
||||
setenv loadkernel fatload mmc \$mmc_bootdev \$kernel_addr_r uImage
|
||||
setenv loaddtb fatload mmc \$mmc_bootdev \$fdt_addr_r dtb
|
||||
setenv loadkernel fatload mmc \$mmc_bootdev \$kernel_comp_addr_r uImage
|
||||
setenv bootargs console=ttyS0,115200 earlyprintk root=PARTUUID=${uuid} rootwait
|
||||
setenv uenvcmd run loadkernel \&\& run loaddtb \&\& booti \$kernel_addr_r - \$fdt_addr_r
|
||||
setenv uenvcmd run loadkernel \&\& bootm \$kernel_comp_addr_r
|
||||
run uenvcmd
|
||||
|
@@ -1,6 +1,4 @@
|
||||
setenv fdt_high ffffffff
|
||||
setenv loadkernel fatload mmc 0 \$kernel_addr_r uImage
|
||||
setenv loaddtb fatload mmc 0 \$fdt_addr_r dtb
|
||||
setenv bootargs console=ttyS2,115200 earlyprintk root=/dev/mmcblk0p2 rootwait
|
||||
setenv uenvcmd run loadkernel \&\& run loaddtb \&\& bootm \$kernel_addr_r - \$fdt_addr_r
|
||||
setenv uenvcmd run loadkernel \&\& run loaddtb \&\& bootm \$kernel_addr_r
|
||||
run uenvcmd
|
||||
|
@@ -16,6 +16,7 @@ CONFIG_NET_DSA=y
|
||||
CONFIG_NET_DSA_TAG_BRCM=y
|
||||
CONFIG_NET_DSA_TAG_BRCM_COMMON=y
|
||||
CONFIG_NET_DSA_TAG_BRCM_LEGACY=y
|
||||
CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS=y
|
||||
CONFIG_NET_DSA_TAG_BRCM_PREPEND=y
|
||||
CONFIG_NET_SWITCHDEV=y
|
||||
CONFIG_NOP_USB_XCEIV=y
|
||||
|
@@ -16,7 +16,6 @@ define Build/sunxi-sdcard
|
||||
mkfs.fat $@.boot -C $(FAT32_BLOCKS)
|
||||
|
||||
mcopy -i $@.boot $(STAGING_DIR_IMAGE)/$(DEVICE_NAME)-boot.scr ::boot.scr
|
||||
mcopy -i $@.boot $(DTS_DIR)/$(SUNXI_DTS).dtb ::dtb
|
||||
mcopy -i $@.boot $(IMAGE_KERNEL) ::uImage
|
||||
./gen_sunxi_sdcard_img.sh $@ \
|
||||
$@.boot \
|
||||
@@ -34,10 +33,18 @@ define Device/Default
|
||||
KERNEL := kernel-bin | uImage none
|
||||
IMAGES := sdcard.img.gz
|
||||
IMAGE/sdcard.img.gz := sunxi-sdcard | append-metadata | gzip
|
||||
SUNXI_DTS_DIR :=allwinner/
|
||||
SUNXI_DTS_DIR := allwinner/
|
||||
SUNXI_DTS = $$(SUNXI_DTS_DIR)$$(SOC)-$(lastword $(subst _, ,$(1)))
|
||||
endef
|
||||
|
||||
define Device/FitImageLzma
|
||||
KERNEL = kernel-bin | lzma | fit lzma $$(DTS_DIR)/$$(SUNXI_DTS).dtb
|
||||
endef
|
||||
|
||||
define Device/FitImageGzip
|
||||
KERNEL = kernel-bin | gzip | fit gzip $$(DTS_DIR)/$$(SUNXI_DTS).dtb
|
||||
endef
|
||||
|
||||
include $(SUBTARGET).mk
|
||||
|
||||
$(eval $(call BuildImage))
|
||||
|
@@ -3,12 +3,12 @@
|
||||
# Copyright (C) 2013-2016 OpenWrt.org
|
||||
# Copyright (C) 2016 Yousong Zhou
|
||||
|
||||
KERNEL_LOADADDR:=0x40008000
|
||||
KERNEL_LOADADDR:=0x40080000
|
||||
|
||||
define Device/sun50i
|
||||
$(call Device/FitImageLzma)
|
||||
SUNXI_DTS_DIR := allwinner/
|
||||
KERNEL_NAME := Image
|
||||
KERNEL := kernel-bin
|
||||
endef
|
||||
|
||||
define Device/sun50i-a64
|
||||
@@ -127,6 +127,13 @@ define Device/xunlong_orangepi-zero2
|
||||
endef
|
||||
TARGET_DEVICES += xunlong_orangepi-zero2
|
||||
|
||||
define Device/xunlong_orangepi-zero2w
|
||||
DEVICE_VENDOR := Xunlong
|
||||
DEVICE_MODEL := Orange Pi Zero 2W
|
||||
$(Device/sun50i-h618)
|
||||
endef
|
||||
TARGET_DEVICES += xunlong_orangepi-zero2w
|
||||
|
||||
define Device/xunlong_orangepi-zero3
|
||||
DEVICE_VENDOR := Xunlong
|
||||
DEVICE_MODEL := Orange Pi Zero 3
|
||||
|
@@ -6,6 +6,7 @@
|
||||
KERNEL_LOADADDR:=0x40008000
|
||||
|
||||
define Device/cubietech_cubieboard2
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := Cubietech
|
||||
DEVICE_MODEL := Cubieboard2
|
||||
DEVICE_PACKAGES:=kmod-ata-sunxi kmod-sun4i-emac kmod-rtc-sunxi
|
||||
@@ -14,6 +15,7 @@ endef
|
||||
TARGET_DEVICES += cubietech_cubieboard2
|
||||
|
||||
define Device/cubietech_cubietruck
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := Cubietech
|
||||
DEVICE_MODEL := Cubietruck
|
||||
DEVICE_PACKAGES:=kmod-ata-sunxi kmod-rtc-sunxi kmod-brcmfmac
|
||||
@@ -22,6 +24,7 @@ endef
|
||||
TARGET_DEVICES += cubietech_cubietruck
|
||||
|
||||
define Device/friendlyarm_nanopi-m1-plus
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := FriendlyARM
|
||||
DEVICE_MODEL := NanoPi M1 Plus
|
||||
DEVICE_PACKAGES:=kmod-leds-gpio kmod-brcmfmac \
|
||||
@@ -31,6 +34,7 @@ endef
|
||||
TARGET_DEVICES += friendlyarm_nanopi-m1-plus
|
||||
|
||||
define Device/friendlyarm_nanopi-neo
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := FriendlyARM
|
||||
DEVICE_MODEL := NanoPi NEO
|
||||
SOC := sun8i-h3
|
||||
@@ -38,6 +42,7 @@ endef
|
||||
TARGET_DEVICES += friendlyarm_nanopi-neo
|
||||
|
||||
define Device/friendlyarm_nanopi-neo-air
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := FriendlyARM
|
||||
DEVICE_MODEL := NanoPi NEO Air
|
||||
DEVICE_PACKAGES := kmod-leds-gpio kmod-brcmfmac \
|
||||
@@ -47,6 +52,7 @@ endef
|
||||
TARGET_DEVICES += friendlyarm_nanopi-neo-air
|
||||
|
||||
define Device/friendlyarm_nanopi-r1
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := FriendlyARM
|
||||
DEVICE_MODEL := NanoPi R1
|
||||
DEVICE_PACKAGES := kmod-usb-net-rtl8152 kmod-leds-gpio \
|
||||
@@ -56,6 +62,7 @@ endef
|
||||
TARGET_DEVICES += friendlyarm_nanopi-r1
|
||||
|
||||
define Device/friendlyarm_zeropi
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := FriendlyARM
|
||||
DEVICE_MODEL := ZeroPi
|
||||
DEVICE_PACKAGES := kmod-rtc-sunxi
|
||||
@@ -64,6 +71,7 @@ endef
|
||||
TARGET_DEVICES += friendlyarm_zeropi
|
||||
|
||||
define Device/lamobo_lamobo-r1
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := Lamobo
|
||||
DEVICE_MODEL := Lamobo R1
|
||||
DEVICE_ALT0_VENDOR := Bananapi
|
||||
@@ -76,6 +84,7 @@ endef
|
||||
TARGET_DEVICES += lamobo_lamobo-r1
|
||||
|
||||
define Device/lemaker_bananapi
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := LeMaker
|
||||
DEVICE_MODEL := Banana Pi
|
||||
DEVICE_PACKAGES:=kmod-rtc-sunxi kmod-ata-sunxi
|
||||
@@ -84,6 +93,7 @@ endef
|
||||
TARGET_DEVICES += lemaker_bananapi
|
||||
|
||||
define Device/sinovoip_bananapi-m2-berry
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := Sinovoip
|
||||
DEVICE_MODEL := Banana Pi M2 Berry
|
||||
DEVICE_PACKAGES:=kmod-ata-sunxi kmod-brcmfmac \
|
||||
@@ -94,6 +104,7 @@ endef
|
||||
TARGET_DEVICES += sinovoip_bananapi-m2-berry
|
||||
|
||||
define Device/sinovoip_bananapi-m2-ultra
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := Sinovoip
|
||||
DEVICE_MODEL := Banana Pi M2 Ultra
|
||||
DEVICE_PACKAGES:=kmod-ata-sunxi kmod-brcmfmac \
|
||||
@@ -104,6 +115,7 @@ endef
|
||||
TARGET_DEVICES += sinovoip_bananapi-m2-ultra
|
||||
|
||||
define Device/lemaker_bananapro
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := LeMaker
|
||||
DEVICE_MODEL := Banana Pro
|
||||
DEVICE_PACKAGES:=kmod-rtc-sunxi kmod-ata-sunxi kmod-brcmfmac \
|
||||
@@ -112,7 +124,17 @@ define Device/lemaker_bananapro
|
||||
endef
|
||||
TARGET_DEVICES += lemaker_bananapro
|
||||
|
||||
define Device/licheepi_licheepi-zero-dock
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := LicheePi
|
||||
DEVICE_MODEL := Zero with Dock (V3s)
|
||||
DEVICE_PACKAGES:=kmod-rtc-sunxi
|
||||
SOC := sun8i-v3s
|
||||
endef
|
||||
TARGET_DEVICES += licheepi_licheepi-zero-dock
|
||||
|
||||
define Device/linksprite_pcduino3
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := LinkSprite
|
||||
DEVICE_MODEL := pcDuino3
|
||||
DEVICE_PACKAGES:=kmod-sun4i-emac kmod-rtc-sunxi kmod-ata-sunxi kmod-rtl8xxxu \
|
||||
@@ -122,6 +144,7 @@ endef
|
||||
TARGET_DEVICES += linksprite_pcduino3
|
||||
|
||||
define Device/linksprite_pcduino3-nano
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := LinkSprite
|
||||
DEVICE_MODEL := pcDuino3 Nano
|
||||
DEVICE_PACKAGES:=kmod-rtc-sunxi kmod-ata-sunxi
|
||||
@@ -130,6 +153,7 @@ endef
|
||||
TARGET_DEVICES += linksprite_pcduino3-nano
|
||||
|
||||
define Device/mele_m9
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := Mele
|
||||
DEVICE_MODEL := M9
|
||||
DEVICE_PACKAGES:=kmod-sun4i-emac kmod-rtl8192cu
|
||||
@@ -137,7 +161,17 @@ define Device/mele_m9
|
||||
endef
|
||||
TARGET_DEVICES += mele_m9
|
||||
|
||||
define Device/merrii_hummingbird
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := Merrii
|
||||
DEVICE_MODEL := Hummingbird
|
||||
DEVICE_PACKAGES:=kmod-brcmfmac cypress-firmware-43362-sdio wpad-basic-mbedtls
|
||||
SOC := sun6i-a31
|
||||
endef
|
||||
TARGET_DEVICES += merrii_hummingbird
|
||||
|
||||
define Device/olimex_a20-olinuxino-lime
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := Olimex
|
||||
DEVICE_MODEL := A20-OLinuXino-LIME
|
||||
DEVICE_PACKAGES:=kmod-ata-sunxi kmod-rtc-sunxi
|
||||
@@ -146,6 +180,7 @@ endef
|
||||
TARGET_DEVICES += olimex_a20-olinuxino-lime
|
||||
|
||||
define Device/olimex_a20-olinuxino-lime2
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := Olimex
|
||||
DEVICE_MODEL := A20-OLinuXino-LIME2
|
||||
DEVICE_PACKAGES:=kmod-ata-sunxi kmod-rtc-sunxi kmod-usb-hid
|
||||
@@ -154,6 +189,7 @@ endef
|
||||
TARGET_DEVICES += olimex_a20-olinuxino-lime2
|
||||
|
||||
define Device/olimex_a20-olinuxino-lime2-emmc
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := Olimex
|
||||
DEVICE_MODEL := A20-OLinuXino-LIME2
|
||||
DEVICE_VARIANT := eMMC
|
||||
@@ -163,6 +199,7 @@ endef
|
||||
TARGET_DEVICES += olimex_a20-olinuxino-lime2-emmc
|
||||
|
||||
define Device/olimex_a20-olinuxino-micro
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := Olimex
|
||||
DEVICE_MODEL := A20-OLinuXino-MICRO
|
||||
DEVICE_PACKAGES:=kmod-ata-sunxi kmod-sun4i-emac kmod-rtc-sunxi
|
||||
@@ -170,7 +207,18 @@ define Device/olimex_a20-olinuxino-micro
|
||||
endef
|
||||
TARGET_DEVICES += olimex_a20-olinuxino-micro
|
||||
|
||||
define Device/roofull_beelink-x2
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := Roofull
|
||||
DEVICE_MODEL := Beelink-X2
|
||||
DEVICE_PACKAGES:=kmod-leds-gpio kmod-gpio-button-hotplug \
|
||||
kmod-brcmfmac cypress-firmware-43430-sdio wpad-basic-mbedtls
|
||||
SOC := sun8i-h3
|
||||
endef
|
||||
TARGET_DEVICES += roofull_beelink-x2
|
||||
|
||||
define Device/sinovoip_bananapi-m2-plus
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := Sinovoip
|
||||
DEVICE_MODEL := Banana Pi M2+
|
||||
DEVICE_PACKAGES:=kmod-leds-gpio kmod-brcmfmac \
|
||||
@@ -180,6 +228,7 @@ endef
|
||||
TARGET_DEVICES += sinovoip_bananapi-m2-plus
|
||||
|
||||
define Device/sinovoip_bananapi-m3
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := Sinovoip
|
||||
DEVICE_MODEL := Banana Pi M3
|
||||
DEVICE_PACKAGES:=kmod-rtc-sunxi kmod-leds-gpio kmod-rtc-ac100 \
|
||||
@@ -189,6 +238,7 @@ endef
|
||||
TARGET_DEVICES += sinovoip_bananapi-m3
|
||||
|
||||
define Device/sinovoip_bananapi-p2-zero
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := Sinovoip
|
||||
DEVICE_MODEL := Banana Pi P2 Zero
|
||||
DEVICE_PACKAGES:=kmod-leds-gpio kmod-brcmfmac \
|
||||
@@ -198,6 +248,7 @@ endef
|
||||
TARGET_DEVICES += sinovoip_bananapi-p2-zero
|
||||
|
||||
define Device/xunlong_orangepi-one
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := Xunlong
|
||||
DEVICE_MODEL := Orange Pi One
|
||||
DEVICE_PACKAGES:=kmod-rtc-sunxi
|
||||
@@ -206,6 +257,7 @@ endef
|
||||
TARGET_DEVICES += xunlong_orangepi-one
|
||||
|
||||
define Device/xunlong_orangepi-pc
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := Xunlong
|
||||
DEVICE_MODEL := Orange Pi PC
|
||||
DEVICE_PACKAGES:=kmod-gpio-button-hotplug
|
||||
@@ -214,6 +266,7 @@ endef
|
||||
TARGET_DEVICES += xunlong_orangepi-pc
|
||||
|
||||
define Device/xunlong_orangepi-pc-plus
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := Xunlong
|
||||
DEVICE_MODEL := Orange Pi PC Plus
|
||||
DEVICE_PACKAGES:=kmod-gpio-button-hotplug
|
||||
@@ -222,6 +275,7 @@ endef
|
||||
TARGET_DEVICES += xunlong_orangepi-pc-plus
|
||||
|
||||
define Device/xunlong_orangepi-plus
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := Xunlong
|
||||
DEVICE_MODEL := Orange Pi Plus
|
||||
DEVICE_PACKAGES:=kmod-rtc-sunxi
|
||||
@@ -230,6 +284,7 @@ endef
|
||||
TARGET_DEVICES += xunlong_orangepi-plus
|
||||
|
||||
define Device/xunlong_orangepi-r1
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := Xunlong
|
||||
DEVICE_MODEL := Orange Pi R1
|
||||
DEVICE_PACKAGES:=kmod-usb-net-rtl8152
|
||||
@@ -238,6 +293,7 @@ endef
|
||||
TARGET_DEVICES += xunlong_orangepi-r1
|
||||
|
||||
define Device/xunlong_orangepi-zero
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := Xunlong
|
||||
DEVICE_MODEL := Orange Pi Zero
|
||||
DEVICE_PACKAGES:=kmod-rtc-sunxi
|
||||
@@ -246,6 +302,7 @@ endef
|
||||
TARGET_DEVICES += xunlong_orangepi-zero
|
||||
|
||||
define Device/xunlong_orangepi-2
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := Xunlong
|
||||
DEVICE_MODEL := Orange Pi 2
|
||||
DEVICE_PACKAGES:=kmod-rtc-sunxi
|
||||
|
@@ -6,6 +6,7 @@
|
||||
KERNEL_LOADADDR:=0x40008000
|
||||
|
||||
define Device/cubietech_a10-cubieboard
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := Cubietech
|
||||
DEVICE_MODEL := Cubieboard
|
||||
DEVICE_PACKAGES:=kmod-ata-sunxi kmod-sun4i-emac kmod-rtc-sunxi
|
||||
@@ -14,6 +15,7 @@ endef
|
||||
TARGET_DEVICES += cubietech_a10-cubieboard
|
||||
|
||||
define Device/haoyu_a10-marsboard
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := HAOYU Electronics
|
||||
DEVICE_MODEL := MarsBoard A10
|
||||
DEVICE_PACKAGES:=kmod-ata-core kmod-ata-sunxi kmod-sun4i-emac \
|
||||
@@ -24,6 +26,7 @@ endef
|
||||
TARGET_DEVICES += haoyu_a10-marsboard
|
||||
|
||||
define Device/linksprite_a10-pcduino
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := LinkSprite
|
||||
DEVICE_MODEL := pcDuino
|
||||
DEVICE_PACKAGES:=kmod-sun4i-emac kmod-rtc-sunxi kmod-rtl8192cu
|
||||
@@ -32,6 +35,7 @@ endef
|
||||
TARGET_DEVICES += linksprite_a10-pcduino
|
||||
|
||||
define Device/olimex_a10-olinuxino-lime
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := Olimex
|
||||
DEVICE_MODEL := A10-OLinuXino-LIME
|
||||
DEVICE_PACKAGES:=kmod-ata-sunxi kmod-sun4i-emac kmod-rtc-sunxi
|
||||
@@ -40,6 +44,7 @@ endef
|
||||
TARGET_DEVICES += olimex_a10-olinuxino-lime
|
||||
|
||||
define Device/olimex_a13-olimex-som
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := Olimex
|
||||
DEVICE_MODEL := A13-SOM
|
||||
DEVICE_PACKAGES:=kmod-rtl8192cu
|
||||
@@ -50,6 +55,7 @@ endef
|
||||
TARGET_DEVICES += olimex_a13-olimex-som
|
||||
|
||||
define Device/olimex_a13-olinuxino
|
||||
$(call Device/FitImageGzip)
|
||||
DEVICE_VENDOR := Olimex
|
||||
DEVICE_MODEL := A13-OLinuXino
|
||||
DEVICE_PACKAGES:=kmod-rtl8192cu
|
||||
|
@@ -149,6 +149,10 @@ func (c *Conn) ReaderReplaceable() bool {
|
||||
return c.disablePipe.Load() || c.deadline.Load().IsZero()
|
||||
}
|
||||
|
||||
func (c *Conn) WriterReplaceable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *Conn) Upstream() any {
|
||||
return c.ExtendedConn
|
||||
}
|
||||
|
@@ -1,97 +0,0 @@
|
||||
// Copy from https://github.com/WireGuard/wgctrl-go/blob/a9ab2273dd1075ea74b88c76f8757f8b4003fcbf/wgtypes/types.go#L71-L155
|
||||
|
||||
package generater
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/crypto/curve25519"
|
||||
)
|
||||
|
||||
// KeyLen is the expected key length for a WireGuard key.
|
||||
const KeyLen = 32 // wgh.KeyLen
|
||||
|
||||
// A Key is a public, private, or pre-shared secret key. The Key constructor
|
||||
// functions in this package can be used to create Keys suitable for each of
|
||||
// these applications.
|
||||
type Key [KeyLen]byte
|
||||
|
||||
// GenerateKey generates a Key suitable for use as a pre-shared secret key from
|
||||
// a cryptographically safe source.
|
||||
//
|
||||
// The output Key should not be used as a private key; use GeneratePrivateKey
|
||||
// instead.
|
||||
func GenerateKey() (Key, error) {
|
||||
b := make([]byte, KeyLen)
|
||||
if _, err := rand.Read(b); err != nil {
|
||||
return Key{}, fmt.Errorf("wgtypes: failed to read random bytes: %v", err)
|
||||
}
|
||||
|
||||
return NewKey(b)
|
||||
}
|
||||
|
||||
// GeneratePrivateKey generates a Key suitable for use as a private key from a
|
||||
// cryptographically safe source.
|
||||
func GeneratePrivateKey() (Key, error) {
|
||||
key, err := GenerateKey()
|
||||
if err != nil {
|
||||
return Key{}, err
|
||||
}
|
||||
|
||||
// Modify random bytes using algorithm described at:
|
||||
// https://cr.yp.to/ecdh.html.
|
||||
key[0] &= 248
|
||||
key[31] &= 127
|
||||
key[31] |= 64
|
||||
|
||||
return key, nil
|
||||
}
|
||||
|
||||
// NewKey creates a Key from an existing byte slice. The byte slice must be
|
||||
// exactly 32 bytes in length.
|
||||
func NewKey(b []byte) (Key, error) {
|
||||
if len(b) != KeyLen {
|
||||
return Key{}, fmt.Errorf("wgtypes: incorrect key size: %d", len(b))
|
||||
}
|
||||
|
||||
var k Key
|
||||
copy(k[:], b)
|
||||
|
||||
return k, nil
|
||||
}
|
||||
|
||||
// ParseKey parses a Key from a base64-encoded string, as produced by the
|
||||
// Key.String method.
|
||||
func ParseKey(s string) (Key, error) {
|
||||
b, err := base64.StdEncoding.DecodeString(s)
|
||||
if err != nil {
|
||||
return Key{}, fmt.Errorf("wgtypes: failed to parse base64-encoded key: %v", err)
|
||||
}
|
||||
|
||||
return NewKey(b)
|
||||
}
|
||||
|
||||
// PublicKey computes a public key from the private key k.
|
||||
//
|
||||
// PublicKey should only be called when k is a private key.
|
||||
func (k Key) PublicKey() Key {
|
||||
var (
|
||||
pub [KeyLen]byte
|
||||
priv = [KeyLen]byte(k)
|
||||
)
|
||||
|
||||
// ScalarBaseMult uses the correct base value per https://cr.yp.to/ecdh.html,
|
||||
// so no need to specify it.
|
||||
curve25519.ScalarBaseMult(&pub, &priv)
|
||||
|
||||
return Key(pub)
|
||||
}
|
||||
|
||||
// String returns the base64-encoded string representation of a Key.
|
||||
//
|
||||
// ParseKey can be used to produce a new Key from this string.
|
||||
func (k Key) String() string {
|
||||
return base64.StdEncoding.EncodeToString(k[:])
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
package generater
|
||||
package generator
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
func Main(args []string) {
|
||||
if len(args) < 1 {
|
||||
panic("Using: generate uuid/reality-keypair/wg-keypair/ech-keypair/vless-mlkem768")
|
||||
panic("Using: generate uuid/reality-keypair/wg-keypair/ech-keypair/vless-mlkem768/vless-x25519")
|
||||
}
|
||||
switch args[0] {
|
||||
case "uuid":
|
||||
@@ -22,20 +22,19 @@ func Main(args []string) {
|
||||
}
|
||||
fmt.Println(newUUID.String())
|
||||
case "reality-keypair":
|
||||
privateKey, err := GeneratePrivateKey()
|
||||
privateKey, err := GenX25519PrivateKey()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
publicKey := privateKey.PublicKey()
|
||||
fmt.Println("PrivateKey: " + base64.RawURLEncoding.EncodeToString(privateKey[:]))
|
||||
fmt.Println("PublicKey: " + base64.RawURLEncoding.EncodeToString(publicKey[:]))
|
||||
fmt.Println("PrivateKey: " + base64.RawURLEncoding.EncodeToString(privateKey.Bytes()))
|
||||
fmt.Println("PublicKey: " + base64.RawURLEncoding.EncodeToString(privateKey.PublicKey().Bytes()))
|
||||
case "wg-keypair":
|
||||
privateKey, err := GeneratePrivateKey()
|
||||
privateKey, err := GenX25519PrivateKey()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println("PrivateKey: " + privateKey.String())
|
||||
fmt.Println("PublicKey: " + privateKey.PublicKey().String())
|
||||
fmt.Println("PrivateKey: " + base64.StdEncoding.EncodeToString(privateKey.Bytes()))
|
||||
fmt.Println("PublicKey: " + base64.StdEncoding.EncodeToString(privateKey.PublicKey().Bytes()))
|
||||
case "ech-keypair":
|
||||
if len(args) < 2 {
|
||||
panic("Using: generate ech-keypair <plain_server_name>")
|
||||
@@ -51,11 +50,23 @@ func Main(args []string) {
|
||||
if len(args) > 1 {
|
||||
seed = args[1]
|
||||
}
|
||||
seedBase64, clientBase64, err := encryption.GenMLKEM768(seed)
|
||||
seedBase64, clientBase64, hash11Base64, err := encryption.GenMLKEM768(seed)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println("Seed: " + seedBase64)
|
||||
fmt.Println("Client: " + clientBase64)
|
||||
fmt.Println("Hash11: " + hash11Base64)
|
||||
case "vless-x25519":
|
||||
var privateKey string
|
||||
if len(args) > 1 {
|
||||
privateKey = args[1]
|
||||
}
|
||||
privateKeyBase64, passwordBase64, err := encryption.GenX25519(privateKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println("PrivateKey: " + privateKeyBase64)
|
||||
fmt.Println("Password: " + passwordBase64)
|
||||
}
|
||||
}
|
27
mihomo/component/generator/x25519.go
Normal file
27
mihomo/component/generator/x25519.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"crypto/ecdh"
|
||||
"crypto/rand"
|
||||
)
|
||||
|
||||
const X25519KeySize = 32
|
||||
|
||||
func GenX25519PrivateKey() (*ecdh.PrivateKey, error) {
|
||||
var privateKey [X25519KeySize]byte
|
||||
_, err := rand.Read(privateKey[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Avoid generating equivalent X25519 private keys
|
||||
// https://github.com/XTLS/Xray-core/pull/1747
|
||||
//
|
||||
// Modify random bytes using algorithm described at:
|
||||
// https://cr.yp.to/ecdh.html.
|
||||
privateKey[0] &= 248
|
||||
privateKey[31] &= 127
|
||||
privateKey[31] |= 64
|
||||
|
||||
return ecdh.X25519().NewPrivateKey(privateKey[:])
|
||||
}
|
@@ -638,8 +638,12 @@ proxies: # socks5
|
||||
port: 443
|
||||
uuid: uuid
|
||||
network: tcp
|
||||
encryption: "8min-vless-mlkem768client-bas64RawURLEncoding" # 复用八分钟后协商新的 sharedKey,需小于服务端的值
|
||||
# encryption: "8min-xored-mlkem768client-bas64RawURLEncoding"
|
||||
# -------------------------
|
||||
# vless encryption客户端配置:
|
||||
# (只使用 1-RTT 模式 / 复用八分钟后协商新的 baseKey,周期需小于服务端的值)
|
||||
# / 是只能选一个,后面是 base64RawURLEncoding,使用 mihomo generate vless-x25519 和 mihomo generate vless-mlkem768 生成,替换值时需去掉括号
|
||||
# -------------------------
|
||||
encryption: "1rtt/8min.native/divide/random.mlkem768Client.(X25519 Password).(ML-KEM-768 Client)"
|
||||
tls: false #可以不开启tls
|
||||
udp: true
|
||||
|
||||
@@ -1359,8 +1363,12 @@ listeners:
|
||||
flow: xtls-rprx-vision
|
||||
# ws-path: "/" # 如果不为空则开启 websocket 传输层
|
||||
# grpc-service-name: "GunService" # 如果不为空则开启 grpc 传输层
|
||||
# decryption: "10min-vless-mlkem768seed-bas64RawURLEncoding" # 同时允许 1-RTT 模式与十分钟复用的 0-RTT 模式, 后面base64字符串可由可由 mihomo generate vless-mlkem768 命令生成
|
||||
# decryption: "10min-xored-mlkem768seed-bas64RawURLEncoding"
|
||||
# -------------------------
|
||||
# vless encryption服务端配置:
|
||||
# (只允许 1-RTT 模式 / 同时允许 1-RTT 模式与十分钟复用的 0-RTT 模式;原生外观 / ECH 式 XOR / 全随机数)
|
||||
# / 是只能选一个,后面是 base64RawURLEncoding,使用 mihomo generate vless-x25519 和 mihomo generate vless-mlkem768 生成,替换值时需去掉括号
|
||||
# -------------------------
|
||||
# decryption: "1rtt/10min.native/divide/random.mlkem768Seed.(X25519 PrivateKey).(ML-KEM-768 Seed)"
|
||||
# 下面两项如果填写则开启 tls(需要同时填写)
|
||||
# certificate: ./server.crt
|
||||
# private-key: ./server.key
|
||||
|
@@ -31,7 +31,7 @@ require (
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.6
|
||||
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2
|
||||
github.com/metacubex/sing-tun v0.4.7
|
||||
github.com/metacubex/sing-vmess v0.2.4-0.20250819151326-51d195aac5db
|
||||
github.com/metacubex/sing-vmess v0.2.4-0.20250821024956-97839f31a65d
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f
|
||||
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee
|
||||
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4
|
||||
|
@@ -131,8 +131,8 @@ github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2 h1:gXU+MY
|
||||
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2/go.mod h1:mbfboaXauKJNIHJYxQRa+NJs4JU9NZfkA+I33dS2+9E=
|
||||
github.com/metacubex/sing-tun v0.4.7 h1:ZDY/W+1c7PeWWKeKRyUo18fySF/TWjB0i5ui81Ar778=
|
||||
github.com/metacubex/sing-tun v0.4.7/go.mod h1:xHecZRwBnKWe6zG9amAK9cXf91lF6blgjBqm+VvOrmU=
|
||||
github.com/metacubex/sing-vmess v0.2.4-0.20250819151326-51d195aac5db h1:W7VKxR0r5IR+56Lblx2iyrEaykx0esdQwTQbkSrSaek=
|
||||
github.com/metacubex/sing-vmess v0.2.4-0.20250819151326-51d195aac5db/go.mod h1:21R5R1u90uUvBQF0owoooEu96/SAYYD56nDrwm6nFaM=
|
||||
github.com/metacubex/sing-vmess v0.2.4-0.20250821024956-97839f31a65d h1:jchYEho5+kTmok4aTMflqJyTRnqVPTOVeC1RFXxuw9A=
|
||||
github.com/metacubex/sing-vmess v0.2.4-0.20250821024956-97839f31a65d/go.mod h1:21R5R1u90uUvBQF0owoooEu96/SAYYD56nDrwm6nFaM=
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f h1:Sr/DYKYofKHKc4GF3qkRGNuj6XA6c0eqPgEDN+VAsYU=
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f/go.mod h1:jpAkVLPnCpGSfNyVmj6Cq4YbuZsFepm/Dc+9BAOcR80=
|
||||
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee h1:lp6hJ+4wCLZu113awp7P6odM2okB5s60HUyF0FMqKmo=
|
||||
|
@@ -21,7 +21,7 @@ import (
|
||||
"github.com/metacubex/mihomo/component/ca"
|
||||
"github.com/metacubex/mihomo/component/dialer"
|
||||
"github.com/metacubex/mihomo/component/ech"
|
||||
"github.com/metacubex/mihomo/component/generater"
|
||||
"github.com/metacubex/mihomo/component/generator"
|
||||
tlsC "github.com/metacubex/mihomo/component/tls"
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
|
||||
@@ -48,13 +48,12 @@ var echConfigBase64, echKeyPem, _ = ech.GenECHConfig(echPublicSni)
|
||||
|
||||
func init() {
|
||||
rand.Read(httpData)
|
||||
privateKey, err := generater.GeneratePrivateKey()
|
||||
privateKey, err := generator.GenX25519PrivateKey()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
publicKey := privateKey.PublicKey()
|
||||
realityPrivateKey = base64.RawURLEncoding.EncodeToString(privateKey[:])
|
||||
realityPublickey = base64.RawURLEncoding.EncodeToString(publicKey[:])
|
||||
realityPrivateKey = base64.RawURLEncoding.EncodeToString(privateKey.Bytes())
|
||||
realityPublickey = base64.RawURLEncoding.EncodeToString(privateKey.PublicKey().Bytes())
|
||||
}
|
||||
|
||||
type TestTunnel struct {
|
||||
|
@@ -89,17 +89,29 @@ func TestInboundVless_TLS(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestInboundVless_Encryption(t *testing.T) {
|
||||
seedBase64, clientBase64, err := encryption.GenMLKEM768("")
|
||||
seedBase64, clientBase64, _, err := encryption.GenMLKEM768("")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
return
|
||||
}
|
||||
t.Run("-vless-", func(t *testing.T) {
|
||||
privateKeyBase64, passwordBase64, err := encryption.GenX25519("")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
return
|
||||
}
|
||||
var modes = []string{
|
||||
"native",
|
||||
"divide",
|
||||
"random",
|
||||
}
|
||||
for i := range modes {
|
||||
mode := modes[i]
|
||||
t.Run(mode, func(t *testing.T) {
|
||||
inboundOptions := inbound.VlessOption{
|
||||
Decryption: "10min-vless-mlkem768seed-" + seedBase64,
|
||||
Decryption: "10min." + mode + ".mlkem768Seed." + privateKeyBase64 + "." + seedBase64,
|
||||
}
|
||||
outboundOptions := outbound.VlessOption{
|
||||
Encryption: "8min-vless-mlkem768client-" + clientBase64,
|
||||
Encryption: "8min." + mode + ".mlkem768Client." + passwordBase64 + "." + clientBase64,
|
||||
}
|
||||
testInboundVless(t, inboundOptions, outboundOptions)
|
||||
t.Run("xtls-rprx-vision", func(t *testing.T) {
|
||||
@@ -108,20 +120,7 @@ func TestInboundVless_Encryption(t *testing.T) {
|
||||
testInboundVless(t, inboundOptions, outboundOptions)
|
||||
})
|
||||
})
|
||||
t.Run("-xored-", func(t *testing.T) {
|
||||
inboundOptions := inbound.VlessOption{
|
||||
Decryption: "10min-xored-mlkem768seed-" + seedBase64,
|
||||
}
|
||||
outboundOptions := outbound.VlessOption{
|
||||
Encryption: "8min-xored-mlkem768client-" + clientBase64,
|
||||
}
|
||||
testInboundVless(t, inboundOptions, outboundOptions)
|
||||
t.Run("xtls-rprx-vision", func(t *testing.T) {
|
||||
outboundOptions := outboundOptions
|
||||
outboundOptions.Flow = "xtls-rprx-vision"
|
||||
testInboundVless(t, inboundOptions, outboundOptions)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestInboundVless_Wss1(t *testing.T) {
|
||||
|
@@ -14,7 +14,7 @@ import (
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/metacubex/mihomo/component/generater"
|
||||
"github.com/metacubex/mihomo/component/generator"
|
||||
"github.com/metacubex/mihomo/component/geodata"
|
||||
"github.com/metacubex/mihomo/component/updater"
|
||||
"github.com/metacubex/mihomo/config"
|
||||
@@ -73,7 +73,7 @@ func main() {
|
||||
}
|
||||
|
||||
if len(os.Args) > 1 && os.Args[1] == "generate" {
|
||||
generater.Main(os.Args[2:])
|
||||
generator.Main(os.Args[2:])
|
||||
return
|
||||
}
|
||||
|
||||
|
@@ -3,6 +3,7 @@ package encryption
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/cipher"
|
||||
"crypto/ecdh"
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -40,7 +41,8 @@ type ClientInstance struct {
|
||||
sync.RWMutex
|
||||
nfsEKey *mlkem.EncapsulationKey768
|
||||
hash11 [11]byte // no more capacity
|
||||
xorKey []byte
|
||||
xorMode uint32
|
||||
xorPKey *ecdh.PublicKey
|
||||
minutes time.Duration
|
||||
expire time.Time
|
||||
baseKey []byte
|
||||
@@ -60,22 +62,23 @@ type ClientConn struct {
|
||||
input bytes.Reader // peerCache
|
||||
}
|
||||
|
||||
func (i *ClientInstance) Init(nfsEKeyBytes []byte, xor uint32, minutes time.Duration) (err error) {
|
||||
func (i *ClientInstance) Init(nfsEKeyBytes, xorPKeyBytes []byte, xorMode, minutes uint32) (err error) {
|
||||
if i.nfsEKey != nil {
|
||||
err = errors.New("already initialized")
|
||||
return
|
||||
}
|
||||
i.nfsEKey, err = mlkem.NewEncapsulationKey768(nfsEKeyBytes)
|
||||
if err != nil {
|
||||
if i.nfsEKey, err = mlkem.NewEncapsulationKey768(nfsEKeyBytes); err != nil {
|
||||
return
|
||||
}
|
||||
hash32 := sha3.Sum256(nfsEKeyBytes)
|
||||
copy(i.hash11[:], hash32[:])
|
||||
if xor > 0 {
|
||||
xorKey := sha3.Sum256(nfsEKeyBytes)
|
||||
i.xorKey = xorKey[:]
|
||||
if xorMode > 0 {
|
||||
i.xorMode = xorMode
|
||||
if i.xorPKey, err = ecdh.X25519().NewPublicKey(xorPKeyBytes); err != nil {
|
||||
return
|
||||
}
|
||||
i.minutes = minutes
|
||||
}
|
||||
i.minutes = time.Duration(minutes) * time.Minute
|
||||
return
|
||||
}
|
||||
|
||||
@@ -83,8 +86,8 @@ func (i *ClientInstance) Handshake(conn net.Conn) (*ClientConn, error) {
|
||||
if i.nfsEKey == nil {
|
||||
return nil, errors.New("uninitialized")
|
||||
}
|
||||
if i.xorKey != nil {
|
||||
conn = NewXorConn(conn, i.xorKey)
|
||||
if i.xorMode > 0 {
|
||||
conn, _ = NewXorConn(conn, i.xorMode, i.xorPKey, nil)
|
||||
}
|
||||
c := &ClientConn{Conn: conn}
|
||||
|
||||
@@ -145,7 +148,7 @@ func (i *ClientInstance) Handshake(conn net.Conn) (*ClientConn, error) {
|
||||
}
|
||||
c.baseKey = append(pfsKey, nfsKey...)
|
||||
|
||||
VLESS, _ := NewAead(ClientCipher, c.baseKey, encapsulatedPfsKey, encapsulatedNfsKey).Open(nil, append(i.hash11[:], ClientCipher), c.ticket[11:], pfsEKeyBytes)
|
||||
VLESS, _ := NewAEAD(ClientCipher, c.baseKey, encapsulatedPfsKey, encapsulatedNfsKey).Open(nil, append(i.hash11[:], ClientCipher), c.ticket[11:], pfsEKeyBytes)
|
||||
if !bytes.Equal(VLESS, []byte("VLESS")) {
|
||||
return nil, errors.New("invalid server")
|
||||
}
|
||||
@@ -180,7 +183,7 @@ func (c *ClientConn) Write(b []byte) (int, error) {
|
||||
rand.Read(c.random)
|
||||
copy(data[5+32:], c.random)
|
||||
EncodeHeader(data[5+32+32:], 23, len(b)+16)
|
||||
c.aead = NewAead(ClientCipher, c.baseKey, c.random, c.ticket)
|
||||
c.aead = NewAEAD(ClientCipher, c.baseKey, c.random, c.ticket)
|
||||
c.nonce = make([]byte, 12)
|
||||
c.aead.Seal(data[:5+32+32+5], c.nonce, b, data[5+32+32:5+32+32+5])
|
||||
} else {
|
||||
@@ -188,7 +191,7 @@ func (c *ClientConn) Write(b []byte) (int, error) {
|
||||
EncodeHeader(data, 23, len(b)+16)
|
||||
c.aead.Seal(data[:5], c.nonce, b, data[:5])
|
||||
if bytes.Equal(c.nonce, MaxNonce) {
|
||||
c.aead = NewAead(ClientCipher, c.baseKey, data[5:], data[:5])
|
||||
c.aead = NewAEAD(ClientCipher, c.baseKey, data[5:], data[:5])
|
||||
}
|
||||
}
|
||||
IncreaseNonce(c.nonce)
|
||||
@@ -229,7 +232,7 @@ func (c *ClientConn) Read(b []byte) (int, error) {
|
||||
if c.random == nil {
|
||||
return 0, errors.New("empty c.random")
|
||||
}
|
||||
c.peerAead = NewAead(ClientCipher, c.baseKey, peerRandomHello, c.random)
|
||||
c.peerAead = NewAEAD(ClientCipher, c.baseKey, peerRandomHello, c.random)
|
||||
c.peerNonce = make([]byte, 12)
|
||||
}
|
||||
if c.input.Len() > 0 {
|
||||
@@ -252,7 +255,7 @@ func (c *ClientConn) Read(b []byte) (int, error) {
|
||||
}
|
||||
var peerAead cipher.AEAD
|
||||
if bytes.Equal(c.peerNonce, MaxNonce) {
|
||||
peerAead = NewAead(ClientCipher, c.baseKey, peerData, h)
|
||||
peerAead = NewAEAD(ClientCipher, c.baseKey, peerData, h)
|
||||
}
|
||||
_, err = c.peerAead.Open(dst[:0], c.peerNonce, peerData, h)
|
||||
if peerAead != nil {
|
||||
|
@@ -73,7 +73,7 @@ func ReadAndDiscardPaddings(conn net.Conn) (h []byte, t byte, l int, err error)
|
||||
}
|
||||
}
|
||||
|
||||
func NewAead(c byte, secret, salt, info []byte) (aead cipher.AEAD) {
|
||||
func NewAEAD(c byte, secret, salt, info []byte) (aead cipher.AEAD) {
|
||||
key := make([]byte, 32)
|
||||
hkdf.New(sha3.New256, secret, salt, info).Read(key)
|
||||
if c&1 == 1 {
|
||||
|
@@ -14,4 +14,5 @@
|
||||
// https://github.com/XTLS/Xray-core/commit/d1fb48521271251a8c74bd64fcc2fc8700717a3b
|
||||
// https://github.com/XTLS/Xray-core/commit/49580705f6029648399304b816a2737f991582a8
|
||||
// https://github.com/XTLS/Xray-core/commit/84835bec7d0d8555d0dd30953ed26a272de814c4
|
||||
// https://github.com/XTLS/Xray-core/commit/373558ed7abdbac3de41745cf30ec04c9adde604
|
||||
package encryption
|
||||
|
@@ -5,7 +5,6 @@ import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// NewClient new client from encryption string
|
||||
@@ -15,7 +14,7 @@ func NewClient(encryption string) (*ClientInstance, error) {
|
||||
case "", "none": // We will not reject empty string like xray-core does, because we need to ensure compatibility
|
||||
return nil, nil
|
||||
}
|
||||
if s := strings.SplitN(encryption, "-", 4); len(s) == 4 && s[2] == "mlkem768client" {
|
||||
if s := strings.Split(encryption, "."); len(s) == 5 && s[2] == "mlkem768Client" {
|
||||
var minutes uint32
|
||||
if s[0] != "1rtt" {
|
||||
t := strings.TrimSuffix(s[0], "min")
|
||||
@@ -28,27 +27,35 @@ func NewClient(encryption string) (*ClientInstance, error) {
|
||||
}
|
||||
minutes = uint32(i)
|
||||
}
|
||||
var xor uint32
|
||||
var xorMode uint32
|
||||
switch s[1] {
|
||||
case "vless":
|
||||
case "xored":
|
||||
xor = 1
|
||||
case "native":
|
||||
case "divide":
|
||||
xorMode = 1
|
||||
case "random":
|
||||
xorMode = 2
|
||||
default:
|
||||
return nil, fmt.Errorf("invaild vless encryption value: %s", encryption)
|
||||
}
|
||||
b, err := base64.RawURLEncoding.DecodeString(s[3])
|
||||
xorPKeyBytes, err := base64.RawURLEncoding.DecodeString(s[3])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invaild vless encryption value: %s", encryption)
|
||||
}
|
||||
if len(b) == MLKEM768ClientLength {
|
||||
if len(xorPKeyBytes) != X25519PasswordSize {
|
||||
return nil, fmt.Errorf("invaild vless encryption value: %s", encryption)
|
||||
}
|
||||
nfsEKeyBytes, err := base64.RawURLEncoding.DecodeString(s[4])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invaild vless encryption value: %s", encryption)
|
||||
}
|
||||
if len(nfsEKeyBytes) != MLKEM768ClientLength {
|
||||
return nil, fmt.Errorf("invaild vless encryption value: %s", encryption)
|
||||
}
|
||||
client := &ClientInstance{}
|
||||
if err = client.Init(b, xor, time.Duration(minutes)*time.Minute); err != nil {
|
||||
if err = client.Init(nfsEKeyBytes, xorPKeyBytes, xorMode, minutes); err != nil {
|
||||
return nil, fmt.Errorf("failed to use mlkem768seed: %w", err)
|
||||
}
|
||||
return client, nil
|
||||
} else {
|
||||
return nil, fmt.Errorf("invaild vless encryption value: %s", encryption)
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("invaild vless encryption value: %s", encryption)
|
||||
}
|
||||
@@ -60,7 +67,7 @@ func NewServer(decryption string) (*ServerInstance, error) {
|
||||
case "", "none": // We will not reject empty string like xray-core does, because we need to ensure compatibility
|
||||
return nil, nil
|
||||
}
|
||||
if s := strings.SplitN(decryption, "-", 4); len(s) == 4 && s[2] == "mlkem768seed" {
|
||||
if s := strings.Split(decryption, "."); len(s) == 5 && s[2] == "mlkem768Seed" {
|
||||
var minutes uint32
|
||||
if s[0] != "1rtt" {
|
||||
t := strings.TrimSuffix(s[0], "min")
|
||||
@@ -73,27 +80,35 @@ func NewServer(decryption string) (*ServerInstance, error) {
|
||||
}
|
||||
minutes = uint32(i)
|
||||
}
|
||||
var xor uint32
|
||||
var xorMode uint32
|
||||
switch s[1] {
|
||||
case "vless":
|
||||
case "xored":
|
||||
xor = 1
|
||||
case "native":
|
||||
case "divide":
|
||||
xorMode = 1
|
||||
case "random":
|
||||
xorMode = 2
|
||||
default:
|
||||
return nil, fmt.Errorf("invaild vless decryption value: %s", decryption)
|
||||
}
|
||||
b, err := base64.RawURLEncoding.DecodeString(s[3])
|
||||
xorSKeyBytes, err := base64.RawURLEncoding.DecodeString(s[3])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invaild vless decryption value: %s", decryption)
|
||||
}
|
||||
if len(b) == MLKEM768SeedLength {
|
||||
if len(xorSKeyBytes) != X25519PrivateKeySize {
|
||||
return nil, fmt.Errorf("invaild vless decryption value: %s", decryption)
|
||||
}
|
||||
nfsDKeySeed, err := base64.RawURLEncoding.DecodeString(s[4])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invaild vless decryption value: %s", decryption)
|
||||
}
|
||||
if len(nfsDKeySeed) != MLKEM768SeedLength {
|
||||
return nil, fmt.Errorf("invaild vless decryption value: %s", decryption)
|
||||
}
|
||||
server := &ServerInstance{}
|
||||
if err = server.Init(b, xor, time.Duration(minutes)*time.Minute); err != nil {
|
||||
if err = server.Init(nfsDKeySeed, xorSKeyBytes, xorMode, minutes); err != nil {
|
||||
return nil, fmt.Errorf("failed to use mlkem768seed: %w", err)
|
||||
}
|
||||
return server, nil
|
||||
} else {
|
||||
return nil, fmt.Errorf("invaild vless decryption value: %s", decryption)
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("invaild vless decryption value: %s", decryption)
|
||||
}
|
||||
|
@@ -1,25 +1,29 @@
|
||||
package encryption
|
||||
|
||||
import (
|
||||
"crypto/ecdh"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
|
||||
"github.com/metacubex/utls/mlkem"
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
const MLKEM768SeedLength = mlkem.SeedSize
|
||||
const MLKEM768ClientLength = mlkem.EncapsulationKeySize768
|
||||
const X25519PasswordSize = 32
|
||||
const X25519PrivateKeySize = 32
|
||||
|
||||
func GenMLKEM768(seedStr string) (seedBase64, clientBase64 string, err error) {
|
||||
var seed [64]byte
|
||||
func GenMLKEM768(seedStr string) (seedBase64, clientBase64, hash11Base64 string, err error) {
|
||||
var seed [MLKEM768SeedLength]byte
|
||||
if len(seedStr) > 0 {
|
||||
s, _ := base64.RawURLEncoding.DecodeString(seedStr)
|
||||
if len(s) != 64 {
|
||||
if len(s) != MLKEM768SeedLength {
|
||||
err = fmt.Errorf("invalid length of ML-KEM-768 seed: %s", seedStr)
|
||||
return
|
||||
}
|
||||
seed = [64]byte(s)
|
||||
seed = [MLKEM768SeedLength]byte(s)
|
||||
} else {
|
||||
_, err = rand.Read(seed[:])
|
||||
if err != nil {
|
||||
@@ -28,8 +32,45 @@ func GenMLKEM768(seedStr string) (seedBase64, clientBase64 string, err error) {
|
||||
}
|
||||
|
||||
key, _ := mlkem.NewDecapsulationKey768(seed[:])
|
||||
pub := key.EncapsulationKey()
|
||||
client := key.EncapsulationKey().Bytes()
|
||||
hash32 := sha3.Sum256(client)
|
||||
seedBase64 = base64.RawURLEncoding.EncodeToString(seed[:])
|
||||
clientBase64 = base64.RawURLEncoding.EncodeToString(pub.Bytes())
|
||||
clientBase64 = base64.RawURLEncoding.EncodeToString(client)
|
||||
hash11Base64 = base64.RawURLEncoding.EncodeToString(hash32[:11])
|
||||
return
|
||||
}
|
||||
|
||||
func GenX25519(privateKeyStr string) (privateKeyBase64, passwordBase64 string, err error) {
|
||||
var privateKey [X25519PrivateKeySize]byte
|
||||
if len(privateKeyStr) > 0 {
|
||||
s, _ := base64.RawURLEncoding.DecodeString(privateKeyStr)
|
||||
if len(s) != X25519PrivateKeySize {
|
||||
err = fmt.Errorf("invalid length of X25519 private key: %s", privateKeyStr)
|
||||
return
|
||||
}
|
||||
privateKey = [X25519PrivateKeySize]byte(s)
|
||||
} else {
|
||||
_, err = rand.Read(privateKey[:])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Avoid generating equivalent X25519 private keys
|
||||
// https://github.com/XTLS/Xray-core/pull/1747
|
||||
//
|
||||
// Modify random bytes using algorithm described at:
|
||||
// https://cr.yp.to/ecdh.html.
|
||||
privateKey[0] &= 248
|
||||
privateKey[31] &= 127
|
||||
privateKey[31] |= 64
|
||||
|
||||
key, err := ecdh.X25519().NewPrivateKey(privateKey[:])
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
privateKeyBase64 = base64.RawURLEncoding.EncodeToString(privateKey[:])
|
||||
passwordBase64 = base64.RawURLEncoding.EncodeToString(key.PublicKey().Bytes())
|
||||
return
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package encryption
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/cipher"
|
||||
"crypto/ecdh"
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -26,7 +27,8 @@ type ServerInstance struct {
|
||||
sync.RWMutex
|
||||
nfsDKey *mlkem.DecapsulationKey768
|
||||
hash11 [11]byte // no more capacity
|
||||
xorKey []byte
|
||||
xorMode uint32
|
||||
xorSKey *ecdh.PrivateKey
|
||||
minutes time.Duration
|
||||
sessions map[[32]byte]*ServerSession
|
||||
closed bool
|
||||
@@ -45,23 +47,24 @@ type ServerConn struct {
|
||||
nonce []byte
|
||||
}
|
||||
|
||||
func (i *ServerInstance) Init(nfsDKeySeed []byte, xor uint32, minutes time.Duration) (err error) {
|
||||
func (i *ServerInstance) Init(nfsDKeySeed, xorSKeyBytes []byte, xorMode, minutes uint32) (err error) {
|
||||
if i.nfsDKey != nil {
|
||||
err = errors.New("already initialized")
|
||||
return
|
||||
}
|
||||
i.nfsDKey, err = mlkem.NewDecapsulationKey768(nfsDKeySeed)
|
||||
if err != nil {
|
||||
if i.nfsDKey, err = mlkem.NewDecapsulationKey768(nfsDKeySeed); err != nil {
|
||||
return
|
||||
}
|
||||
hash32 := sha3.Sum256(i.nfsDKey.EncapsulationKey().Bytes())
|
||||
copy(i.hash11[:], hash32[:])
|
||||
if xor > 0 {
|
||||
xorKey := sha3.Sum256(i.nfsDKey.EncapsulationKey().Bytes())
|
||||
i.xorKey = xorKey[:]
|
||||
if xorMode > 0 {
|
||||
i.xorMode = xorMode
|
||||
if i.xorSKey, err = ecdh.X25519().NewPrivateKey(xorSKeyBytes); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
if minutes > 0 {
|
||||
i.minutes = minutes
|
||||
i.minutes = time.Duration(minutes) * time.Minute
|
||||
i.sessions = make(map[[32]byte]*ServerSession)
|
||||
go func() {
|
||||
for {
|
||||
@@ -95,8 +98,11 @@ func (i *ServerInstance) Handshake(conn net.Conn) (*ServerConn, error) {
|
||||
if i.nfsDKey == nil {
|
||||
return nil, errors.New("uninitialized")
|
||||
}
|
||||
if i.xorKey != nil {
|
||||
conn = NewXorConn(conn, i.xorKey)
|
||||
if i.xorMode > 0 {
|
||||
var err error
|
||||
if conn, err = NewXorConn(conn, i.xorMode, nil, i.xorSKey); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
c := &ServerConn{Conn: conn}
|
||||
|
||||
@@ -167,7 +173,7 @@ func (i *ServerInstance) Handshake(conn net.Conn) (*ServerConn, error) {
|
||||
pfsKey, encapsulatedPfsKey := pfsEKey.Encapsulate()
|
||||
c.baseKey = append(pfsKey, nfsKey...)
|
||||
|
||||
c.ticket = append(i.hash11[:], NewAead(c.cipher, c.baseKey, encapsulatedPfsKey, encapsulatedNfsKey).Seal(nil, peerClientHello[:12], []byte("VLESS"), pfsEKeyBytes)...)
|
||||
c.ticket = append(i.hash11[:], NewAEAD(c.cipher, c.baseKey, encapsulatedPfsKey, encapsulatedNfsKey).Seal(nil, peerClientHello[:12], []byte("VLESS"), pfsEKeyBytes)...)
|
||||
|
||||
paddingLen := randBetween(100, 1000)
|
||||
|
||||
@@ -221,7 +227,7 @@ func (c *ServerConn) Read(b []byte) (int, error) {
|
||||
}
|
||||
c.peerRandom = peerTicketHello[32:]
|
||||
}
|
||||
c.peerAead = NewAead(c.cipher, c.baseKey, c.peerRandom, c.ticket)
|
||||
c.peerAead = NewAEAD(c.cipher, c.baseKey, c.peerRandom, c.ticket)
|
||||
c.peerNonce = make([]byte, 12)
|
||||
}
|
||||
if c.input.Len() > 0 {
|
||||
@@ -244,7 +250,7 @@ func (c *ServerConn) Read(b []byte) (int, error) {
|
||||
}
|
||||
var peerAead cipher.AEAD
|
||||
if bytes.Equal(c.peerNonce, MaxNonce) {
|
||||
peerAead = NewAead(c.cipher, c.baseKey, peerData, h)
|
||||
peerAead = NewAEAD(c.cipher, c.baseKey, peerData, h)
|
||||
}
|
||||
_, err = c.peerAead.Open(dst[:0], c.peerNonce, peerData, h)
|
||||
if peerAead != nil {
|
||||
@@ -280,7 +286,7 @@ func (c *ServerConn) Write(b []byte) (int, error) {
|
||||
EncodeHeader(data, 0, 32)
|
||||
rand.Read(data[5 : 5+32])
|
||||
EncodeHeader(data[5+32:], 23, len(b)+16)
|
||||
c.aead = NewAead(c.cipher, c.baseKey, data[5:5+32], c.peerRandom)
|
||||
c.aead = NewAEAD(c.cipher, c.baseKey, data[5:5+32], c.peerRandom)
|
||||
c.nonce = make([]byte, 12)
|
||||
c.aead.Seal(data[:5+32+5], c.nonce, b, data[5+32:5+32+5])
|
||||
} else {
|
||||
@@ -288,7 +294,7 @@ func (c *ServerConn) Write(b []byte) (int, error) {
|
||||
EncodeHeader(data, 23, len(b)+16)
|
||||
c.aead.Seal(data[:5], c.nonce, b, data[:5])
|
||||
if bytes.Equal(c.nonce, MaxNonce) {
|
||||
c.aead = NewAead(c.cipher, c.baseKey, data[5:], data[:5])
|
||||
c.aead = NewAEAD(c.cipher, c.baseKey, data[5:], data[:5])
|
||||
}
|
||||
}
|
||||
IncreaseNonce(c.nonce)
|
||||
|
@@ -3,13 +3,21 @@ package encryption
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/ecdh"
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
|
||||
"golang.org/x/crypto/hkdf"
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
type XorConn struct {
|
||||
net.Conn
|
||||
Divide bool
|
||||
|
||||
head []byte
|
||||
key []byte
|
||||
ctr cipher.Stream
|
||||
peerCtr cipher.Stream
|
||||
@@ -25,8 +33,55 @@ type XorConn struct {
|
||||
in_skip int
|
||||
}
|
||||
|
||||
func NewXorConn(conn net.Conn, key []byte) *XorConn {
|
||||
return &XorConn{Conn: conn, key: key}
|
||||
func NewCTR(key, iv []byte, isServer bool) cipher.Stream {
|
||||
info := "CLIENT"
|
||||
if isServer {
|
||||
info = "SERVER" // avoids attackers sending traffic back to the client, though the encryption layer has its own protection
|
||||
}
|
||||
hkdf.New(sha3.New256, key, iv, []byte(info)).Read(key) // avoids using pKey directly if attackers sent the basepoint, or whaterver they like
|
||||
block, _ := aes.NewCipher(key)
|
||||
return cipher.NewCTR(block, iv)
|
||||
}
|
||||
|
||||
func NewXorConn(conn net.Conn, mode uint32, pKey *ecdh.PublicKey, sKey *ecdh.PrivateKey) (*XorConn, error) {
|
||||
if mode == 0 || (pKey == nil && sKey == nil) || (pKey != nil && sKey != nil) {
|
||||
return nil, errors.New("invalid parameters")
|
||||
}
|
||||
c := &XorConn{
|
||||
Conn: conn,
|
||||
Divide: mode == 1,
|
||||
isHeader: true,
|
||||
out_header: make([]byte, 0, 5), // important
|
||||
in_header: make([]byte, 0, 5), // important
|
||||
}
|
||||
if pKey != nil {
|
||||
c.head = make([]byte, 16+32)
|
||||
rand.Read(c.head)
|
||||
eSKey, _ := ecdh.X25519().GenerateKey(rand.Reader)
|
||||
NewCTR(pKey.Bytes(), c.head[:16], false).XORKeyStream(c.head[16:], eSKey.PublicKey().Bytes()) // make X25519 public key distinguishable from random bytes
|
||||
c.key, _ = eSKey.ECDH(pKey)
|
||||
c.ctr = NewCTR(c.key, c.head[:16], false)
|
||||
}
|
||||
if sKey != nil {
|
||||
peerHead := make([]byte, 16+32)
|
||||
if _, err := io.ReadFull(c.Conn, peerHead); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
NewCTR(sKey.PublicKey().Bytes(), peerHead[:16], false).XORKeyStream(peerHead[16:], peerHead[16:]) // we don't use buggy elligator, because we have PSK :)
|
||||
ePKey, err := ecdh.X25519().NewPublicKey(peerHead[16:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
key, err := sKey.ECDH(ePKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.peerCtr = NewCTR(key, peerHead[:16], false)
|
||||
c.head = make([]byte, 16)
|
||||
rand.Read(c.head) // make sure the server always replies random bytes even when received replays, though it is not important
|
||||
c.ctr = NewCTR(key, c.head, true) // the same key links the upload & download, though the encryption layer has its own link
|
||||
}
|
||||
return c, nil
|
||||
//chacha20.NewUnauthenticatedCipher()
|
||||
}
|
||||
|
||||
@@ -35,13 +90,6 @@ func (c *XorConn) Write(b []byte) (int, error) { // whole one/two records
|
||||
return 0, nil
|
||||
}
|
||||
if !c.out_after0 {
|
||||
var iv []byte
|
||||
if c.ctr == nil {
|
||||
block, _ := aes.NewCipher(c.key)
|
||||
iv = make([]byte, 16)
|
||||
rand.Read(iv)
|
||||
c.ctr = cipher.NewCTR(block, iv)
|
||||
}
|
||||
t, l, _ := DecodeHeader(b)
|
||||
if t == 23 { // single 23
|
||||
l = 5
|
||||
@@ -49,20 +97,24 @@ func (c *XorConn) Write(b []byte) (int, error) { // whole one/two records
|
||||
l += 10
|
||||
if t == 0 {
|
||||
c.out_after0 = true
|
||||
c.out_header = make([]byte, 0, 5) // important
|
||||
if c.Divide {
|
||||
l -= 5
|
||||
}
|
||||
}
|
||||
}
|
||||
c.ctr.XORKeyStream(b[:l], b[:l]) // caller MUST discard b
|
||||
if iv != nil {
|
||||
b = append(iv, b...)
|
||||
l = len(b)
|
||||
if c.head != nil {
|
||||
b = append(c.head, b...)
|
||||
c.head = nil
|
||||
}
|
||||
if _, err := c.Conn.Write(b); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if iv != nil {
|
||||
b = b[16:] // for len(b)
|
||||
return l, nil
|
||||
}
|
||||
return len(b), nil
|
||||
if c.Divide {
|
||||
return c.Conn.Write(b)
|
||||
}
|
||||
for p := b; ; { // for XTLS
|
||||
if len(p) <= c.out_skip {
|
||||
@@ -93,14 +145,12 @@ func (c *XorConn) Read(b []byte) (int, error) { // 5-bytes, data, 5-bytes...
|
||||
return 0, nil
|
||||
}
|
||||
if !c.in_after0 || !c.isHeader {
|
||||
if c.peerCtr == nil {
|
||||
if c.peerCtr == nil { // for client
|
||||
peerIv := make([]byte, 16)
|
||||
if _, err := io.ReadFull(c.Conn, peerIv); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
block, _ := aes.NewCipher(c.key)
|
||||
c.peerCtr = cipher.NewCTR(block, peerIv)
|
||||
c.isHeader = true
|
||||
c.peerCtr = NewCTR(c.key, peerIv, true)
|
||||
}
|
||||
if _, err := io.ReadFull(c.Conn, b); err != nil {
|
||||
return 0, err
|
||||
@@ -117,7 +167,6 @@ func (c *XorConn) Read(b []byte) (int, error) { // 5-bytes, data, 5-bytes...
|
||||
c.isHeader = false
|
||||
if t == 0 {
|
||||
c.in_after0 = true
|
||||
c.in_header = make([]byte, 0, 5) // important
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -125,6 +174,9 @@ func (c *XorConn) Read(b []byte) (int, error) { // 5-bytes, data, 5-bytes...
|
||||
}
|
||||
return len(b), nil
|
||||
}
|
||||
if c.Divide {
|
||||
return c.Conn.Read(b)
|
||||
}
|
||||
n, err := c.Conn.Read(b)
|
||||
for p := b[:n]; ; { // for XTLS
|
||||
if len(p) <= c.in_skip {
|
||||
@@ -146,3 +198,27 @@ func (c *XorConn) Read(b []byte) (int, error) { // 5-bytes, data, 5-bytes...
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (c *XorConn) WriterReplaceable() bool {
|
||||
if !c.Divide { // never replaceable
|
||||
return false
|
||||
}
|
||||
if !c.out_after0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *XorConn) ReaderReplaceable() bool {
|
||||
if !c.Divide { // never replaceable
|
||||
return false
|
||||
}
|
||||
if !c.in_after0 || !c.isHeader {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *XorConn) Upstream() any {
|
||||
return c.Conn
|
||||
}
|
||||
|
@@ -6,12 +6,12 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=adguardhome
|
||||
PKG_VERSION:=0.107.64
|
||||
PKG_VERSION:=0.107.65
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=https://codeload.github.com/AdguardTeam/AdGuardHome/tar.gz/v$(PKG_VERSION)?
|
||||
PKG_HASH:=a6b61d3c102fa47072a7230382d438f3d408f74ffae3aff7d330adad90ed169c
|
||||
PKG_HASH:=b770007696de88ab4de0008502002a4966a30aca88c9b030c142183a1c2a5830
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/AdGuardHome-$(PKG_VERSION)
|
||||
|
||||
PKG_LICENSE:=GPL-3.0-only
|
||||
@@ -58,7 +58,7 @@ define Download/adguardhome-frontend
|
||||
URL:=https://github.com/AdguardTeam/AdGuardHome/releases/download/v$(PKG_VERSION)/
|
||||
URL_FILE:=AdGuardHome_frontend.tar.gz
|
||||
FILE:=$(FRONTEND_FILE)
|
||||
HASH:=f0c1e4d6e673d4d26d52947cdb220682aa554158d331fa044576d1794b82e325
|
||||
HASH:=e838234d8391a23f86b32a26a5c68112a975c7ee83b79646f0597c001f6cab3f
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
|
@@ -8,12 +8,12 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=ddns-go
|
||||
PKG_VERSION:=6.12.2
|
||||
PKG_VERSION:=6.12.4
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=https://codeload.github.com/jeessy2/ddns-go/tar.gz/v$(PKG_VERSION)?
|
||||
PKG_HASH:=a3ea99ad74212fc3bd1380e5ad444a1c5fe6bb1bb656624a441551034a17edaa
|
||||
PKG_HASH:=04f65f7f1ccc18b23dd108f915810146e8b655cd19e7d8ee488cf557222c3fee
|
||||
|
||||
PKG_LICENSE:=MIT
|
||||
PKG_LICENSE_FILES:=LICENSE
|
||||
|
@@ -10,11 +10,11 @@ include $(TOPDIR)/rules.mk
|
||||
PKG_ARCH_quickstart:=$(ARCH)
|
||||
|
||||
PKG_NAME:=quickstart
|
||||
PKG_VERSION:=0.11.2
|
||||
PKG_VERSION:=0.11.3
|
||||
PKG_RELEASE:=1
|
||||
PKG_SOURCE:=$(PKG_NAME)-binary-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=https://github.com/linkease/istore-packages/releases/download/prebuilt/
|
||||
PKG_HASH:=b22f430f08fb12739179e4b983133afb84a37be1e702d5b4e9fb30b1e701824d
|
||||
PKG_HASH:=fee17158398f7867eb20bf187fbfb2d12d46e44d2f9e882376173392a8979d14
|
||||
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-binary-$(PKG_VERSION)
|
||||
|
||||
|
@@ -58,7 +58,8 @@ for k, e in ipairs(api.get_valid_nodes()) do
|
||||
nodes_table[#nodes_table + 1] = {
|
||||
id = e[".name"],
|
||||
remark = e["remark"],
|
||||
type = e["type"]
|
||||
type = e["type"],
|
||||
chain_proxy = e["chain_proxy"]
|
||||
}
|
||||
end
|
||||
if e.protocol == "_balancing" then
|
||||
@@ -696,7 +697,7 @@ o = s:option(ListValue, _n("to_node"), translate("Landing Node"), translate("Onl
|
||||
o:depends({ [_n("chain_proxy")] = "2" })
|
||||
|
||||
for k, v in pairs(nodes_table) do
|
||||
if v.type == "Xray" and v.id ~= arg[1] then
|
||||
if v.type == "Xray" and v.id ~= arg[1] and (not v.chain_proxy or v.chain_proxy == "") then
|
||||
s.fields[_n("preproxy_node")]:value(v.id, v.remark)
|
||||
s.fields[_n("to_node")]:value(v.id, v.remark)
|
||||
end
|
||||
|
@@ -75,7 +75,8 @@ for k, e in ipairs(api.get_valid_nodes()) do
|
||||
nodes_table[#nodes_table + 1] = {
|
||||
id = e[".name"],
|
||||
remark = e["remark"],
|
||||
type = e["type"]
|
||||
type = e["type"],
|
||||
chain_proxy = e["chain_proxy"]
|
||||
}
|
||||
end
|
||||
if e.protocol == "_iface" then
|
||||
@@ -753,7 +754,7 @@ o = s:option(ListValue, _n("to_node"), translate("Landing Node"), translate("Onl
|
||||
o:depends({ [_n("chain_proxy")] = "2" })
|
||||
|
||||
for k, v in pairs(nodes_table) do
|
||||
if v.type == "sing-box" and v.id ~= arg[1] then
|
||||
if v.type == "sing-box" and v.id ~= arg[1] and (not v.chain_proxy or v.chain_proxy == "") then
|
||||
s.fields[_n("preproxy_node")]:value(v.id, v.remark)
|
||||
s.fields[_n("to_node")]:value(v.id, v.remark)
|
||||
end
|
||||
|
@@ -1,3 +1,3 @@
|
||||
VERSION_CODE=554
|
||||
VERSION_NAME=1.12.2
|
||||
VERSION_CODE=556
|
||||
VERSION_NAME=1.12.3
|
||||
GO_VERSION=go1.25.0
|
||||
|
@@ -7,7 +7,6 @@ import (
|
||||
"errors"
|
||||
"net"
|
||||
|
||||
mDNS "github.com/miekg/dns"
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/dns"
|
||||
@@ -20,6 +19,8 @@ import (
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
"github.com/sagernet/sing/service"
|
||||
|
||||
mDNS "github.com/miekg/dns"
|
||||
)
|
||||
|
||||
func RegisterTransport(registry *dns.TransportRegistry) {
|
||||
|
@@ -2,15 +2,19 @@ package local
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/service/resolved"
|
||||
"github.com/sagernet/sing-tun"
|
||||
"github.com/sagernet/sing/common/atomic"
|
||||
"github.com/sagernet/sing/common/control"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
"github.com/sagernet/sing/common/x/list"
|
||||
"github.com/sagernet/sing/service"
|
||||
|
||||
"github.com/godbus/dbus/v5"
|
||||
@@ -18,13 +22,20 @@ import (
|
||||
)
|
||||
|
||||
type DBusResolvedResolver struct {
|
||||
ctx context.Context
|
||||
logger logger.ContextLogger
|
||||
interfaceMonitor tun.DefaultInterfaceMonitor
|
||||
interfaceCallback *list.Element[tun.DefaultInterfaceUpdateCallback]
|
||||
systemBus *dbus.Conn
|
||||
resoledObject atomic.TypedValue[dbus.BusObject]
|
||||
resoledObject atomic.Pointer[ResolvedObject]
|
||||
closeOnce sync.Once
|
||||
}
|
||||
|
||||
type ResolvedObject struct {
|
||||
dbus.BusObject
|
||||
InterfaceIndex int32
|
||||
}
|
||||
|
||||
func NewResolvedResolver(ctx context.Context, logger logger.ContextLogger) (ResolvedResolver, error) {
|
||||
interfaceMonitor := service.FromContext[adapter.NetworkManager](ctx).InterfaceMonitor()
|
||||
if interfaceMonitor == nil {
|
||||
@@ -35,6 +46,7 @@ func NewResolvedResolver(ctx context.Context, logger logger.ContextLogger) (Reso
|
||||
return nil, err
|
||||
}
|
||||
return &DBusResolvedResolver{
|
||||
ctx: ctx,
|
||||
logger: logger,
|
||||
interfaceMonitor: interfaceMonitor,
|
||||
systemBus: systemBus,
|
||||
@@ -43,6 +55,7 @@ func NewResolvedResolver(ctx context.Context, logger logger.ContextLogger) (Reso
|
||||
|
||||
func (t *DBusResolvedResolver) Start() error {
|
||||
t.updateStatus()
|
||||
t.interfaceCallback = t.interfaceMonitor.RegisterCallback(t.updateDefaultInterface)
|
||||
err := t.systemBus.BusObject().AddMatchSignal(
|
||||
"org.freedesktop.DBus",
|
||||
"NameOwnerChanged",
|
||||
@@ -58,6 +71,9 @@ func (t *DBusResolvedResolver) Start() error {
|
||||
|
||||
func (t *DBusResolvedResolver) Close() error {
|
||||
t.closeOnce.Do(func() {
|
||||
if t.interfaceCallback != nil {
|
||||
t.interfaceMonitor.UnregisterCallback(t.interfaceCallback)
|
||||
}
|
||||
if t.systemBus != nil {
|
||||
_ = t.systemBus.Close()
|
||||
}
|
||||
@@ -70,22 +86,23 @@ func (t *DBusResolvedResolver) Object() any {
|
||||
}
|
||||
|
||||
func (t *DBusResolvedResolver) Exchange(object any, ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
||||
defaultInterface := t.interfaceMonitor.DefaultInterface()
|
||||
if defaultInterface == nil {
|
||||
return nil, E.New("missing default interface")
|
||||
}
|
||||
question := message.Question[0]
|
||||
call := object.(*dbus.Object).CallWithContext(
|
||||
resolvedObject := object.(*ResolvedObject)
|
||||
call := resolvedObject.CallWithContext(
|
||||
ctx,
|
||||
"org.freedesktop.resolve1.Manager.ResolveRecord",
|
||||
0,
|
||||
int32(defaultInterface.Index),
|
||||
resolvedObject.InterfaceIndex,
|
||||
question.Name,
|
||||
question.Qclass,
|
||||
question.Qtype,
|
||||
uint64(0),
|
||||
)
|
||||
if call.Err != nil {
|
||||
var dbusError dbus.Error
|
||||
if errors.As(call.Err, &dbusError) && dbusError.Name == "org.freedesktop.resolve1.NoNameServers" {
|
||||
t.updateStatus()
|
||||
}
|
||||
return nil, E.Cause(call.Err, " resolve record via resolved")
|
||||
}
|
||||
var (
|
||||
@@ -137,14 +154,76 @@ func (t *DBusResolvedResolver) loopUpdateStatus() {
|
||||
}
|
||||
|
||||
func (t *DBusResolvedResolver) updateStatus() {
|
||||
dbusObject := t.systemBus.Object("org.freedesktop.resolve1", "/org/freedesktop/resolve1")
|
||||
err := dbusObject.Call("org.freedesktop.DBus.Peer.Ping", 0).Err
|
||||
dbusObject, err := t.checkResolved(context.Background())
|
||||
oldValue := t.resoledObject.Swap(dbusObject)
|
||||
if err != nil {
|
||||
if t.resoledObject.Swap(nil) != nil {
|
||||
var dbusErr dbus.Error
|
||||
if !errors.As(err, &dbusErr) || dbusErr.Name != "org.freedesktop.DBus.Error.NameHasNoOwnerCould" {
|
||||
t.logger.Debug(E.Cause(err, "systemd-resolved service unavailable"))
|
||||
}
|
||||
if oldValue != nil {
|
||||
t.logger.Debug("systemd-resolved service is gone")
|
||||
}
|
||||
return
|
||||
}
|
||||
t.resoledObject.Store(dbusObject)
|
||||
} else if oldValue == nil {
|
||||
t.logger.Debug("using systemd-resolved service as resolver")
|
||||
}
|
||||
}
|
||||
|
||||
func (t *DBusResolvedResolver) checkResolved(ctx context.Context) (*ResolvedObject, error) {
|
||||
dbusObject := t.systemBus.Object("org.freedesktop.resolve1", "/org/freedesktop/resolve1")
|
||||
err := dbusObject.Call("org.freedesktop.DBus.Peer.Ping", 0).Err
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defaultInterface := t.interfaceMonitor.DefaultInterface()
|
||||
if defaultInterface == nil {
|
||||
return nil, E.New("missing default interface")
|
||||
}
|
||||
call := dbusObject.(*dbus.Object).CallWithContext(
|
||||
ctx,
|
||||
"org.freedesktop.resolve1.Manager.GetLink",
|
||||
0,
|
||||
int32(defaultInterface.Index),
|
||||
)
|
||||
if call.Err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var linkPath dbus.ObjectPath
|
||||
err = call.Store(&linkPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
linkObject := t.systemBus.Object("org.freedesktop.resolve1", linkPath)
|
||||
if linkObject == nil {
|
||||
return nil, E.New("missing link object for default interface")
|
||||
}
|
||||
dnsProp, err := linkObject.GetProperty("org.freedesktop.resolve1.Link.DNS")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var linkDNS []resolved.LinkDNS
|
||||
err = dnsProp.Store(&linkDNS)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(linkDNS) == 0 {
|
||||
for _, inbound := range service.FromContext[adapter.InboundManager](t.ctx).Inbounds() {
|
||||
if inbound.Type() == C.TypeTun {
|
||||
return nil, E.New("No appropriate name servers or networks for name found")
|
||||
}
|
||||
}
|
||||
return &ResolvedObject{
|
||||
BusObject: dbusObject,
|
||||
}, nil
|
||||
} else {
|
||||
return &ResolvedObject{
|
||||
BusObject: dbusObject,
|
||||
InterfaceIndex: int32(defaultInterface.Index),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (t *DBusResolvedResolver) updateDefaultInterface(defaultInterface *control.Interface, flags int) {
|
||||
t.updateStatus()
|
||||
}
|
||||
|
@@ -6,6 +6,14 @@ icon: material/alert-decagram
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.12.3
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.13.0-alpha.4
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.12.2
|
||||
|
||||
* Fixes and improvements
|
||||
|
@@ -861,8 +861,8 @@ return view.extend({
|
||||
|
||||
so = ss.taboption('direct_list', hm.TextValue, 'direct_list.yaml', null);
|
||||
so.rows = 20;
|
||||
so.default = 'FQDN:\nIPCIDR:\nIPCIDR6:\n';
|
||||
so.placeholder = "FQDN:\n- mask.icloud.com\n- mask-h2.icloud.com\n- mask.apple-dns.net\nIPCIDR:\n- '223.0.0.0/12'\nIPCIDR6:\n- '2400:3200::/32'\n";
|
||||
so.default = 'DOMAIN:\nIPCIDR:\nIPCIDR6:\n';
|
||||
so.placeholder = "DOMAIN:\n- mask.icloud.com\n- mask-h2.icloud.com\n- mask.apple-dns.net\nIPCIDR:\n- '223.0.0.0/12'\nIPCIDR6:\n- '2400:3200::/32'\n";
|
||||
so.load = function(section_id) {
|
||||
return L.resolveDefault(hm.readFile('resources', this.option), '');
|
||||
}
|
||||
@@ -879,8 +879,8 @@ return view.extend({
|
||||
|
||||
so = ss.taboption('proxy_list', hm.TextValue, 'proxy_list.yaml', null);
|
||||
so.rows = 20;
|
||||
so.default = 'FQDN:\nIPCIDR:\nIPCIDR6:\n';
|
||||
so.placeholder = "FQDN:\n- www.google.com\nIPCIDR:\n- '91.105.192.0/23'\nIPCIDR6:\n- '2001:67c:4e8::/48'\n";
|
||||
so.default = 'DOMAIN:\nIPCIDR:\nIPCIDR6:\n';
|
||||
so.placeholder = "DOMAIN:\n- www.google.com\n- '.googlevideo.com'\n- google.com\nIPCIDR:\n- '91.105.192.0/23'\nIPCIDR6:\n- '2001:67c:4e8::/48'\n";
|
||||
so.load = function(section_id) {
|
||||
return L.resolveDefault(hm.readFile('resources', this.option), '');
|
||||
}
|
||||
|
@@ -186,7 +186,7 @@ start_service() {
|
||||
local yaml="$5"
|
||||
|
||||
if [ -n "$yaml" ]; then
|
||||
yq '.[] |= with(select(. == null); . = []) | .FQDN[]' "$src" | \
|
||||
yq '.[] |= with(select(. == null); . = []) | .DOMAIN[]' "$src" | \
|
||||
sed "s|^|nftset=/|;s|$|/${family}#inet#fchomo#${set_name}|" > "$dst"
|
||||
else
|
||||
sed "s|^|nftset=/|;s|$|/${family}#inet#fchomo#${set_name}|" "$src" > "$dst"
|
||||
|
@@ -14,7 +14,7 @@ fi
|
||||
# Initialize the default direct list
|
||||
if [ ! -s "/etc/fchomo/resources/direct_list.yaml" ]; then
|
||||
cat <<- EOF > "/etc/fchomo/resources/direct_list.yaml"
|
||||
FQDN:
|
||||
DOMAIN:
|
||||
IPCIDR:
|
||||
- '223.0.0.0/12'
|
||||
IPCIDR6:
|
||||
@@ -25,8 +25,10 @@ fi
|
||||
# Initialize the default proxy list
|
||||
if [ ! -s "/etc/fchomo/resources/proxy_list.yaml" ]; then
|
||||
cat <<- EOF > "/etc/fchomo/resources/proxy_list.yaml"
|
||||
FQDN:
|
||||
DOMAIN:
|
||||
- www.google.com
|
||||
- '.googlevideo.com'
|
||||
- google.com
|
||||
IPCIDR:
|
||||
- '91.105.192.0/23'
|
||||
- '91.108.4.0/22'
|
||||
|
@@ -1,5 +1,8 @@
|
||||
#!/bin/sh
|
||||
|
||||
sed -i 's|^FQDN:$|DOMAIN:|' "/etc/fchomo/resources/direct_list.yaml"
|
||||
sed -i 's|^FQDN:$|DOMAIN:|' "/etc/fchomo/resources/proxy_list.yaml"
|
||||
|
||||
default_proxy=$(uci -q get fchomo.routing.default_proxy)
|
||||
if [ -n "$default_proxy" ]; then
|
||||
uci -q batch <<-EOF >"/dev/null"
|
||||
|
@@ -107,6 +107,9 @@ return baseclass.extend({
|
||||
const profile = await callNikkiProfile({ 'external-controller': null, 'secret': null });
|
||||
const apiListen = profile['external-controller'];
|
||||
const apiSecret = profile['secret'] ?? '';
|
||||
if (!apiListen) {
|
||||
return Promise.reject('API has not been configured');
|
||||
}
|
||||
const apiPort = apiListen.substring(apiListen.lastIndexOf(':') + 1);
|
||||
const url = `http://${window.location.hostname}:${apiPort}${path}`;
|
||||
return request.request(url, {
|
||||
@@ -114,7 +117,7 @@ return baseclass.extend({
|
||||
headers: { 'Authorization': `Bearer ${apiSecret}` },
|
||||
query: query,
|
||||
content: body
|
||||
})
|
||||
});
|
||||
},
|
||||
|
||||
openDashboard: async function () {
|
||||
@@ -122,6 +125,9 @@ return baseclass.extend({
|
||||
const uiName = profile['external-ui-name'];
|
||||
const apiListen = profile['external-controller'];
|
||||
const apiSecret = profile['secret'] ?? '';
|
||||
if (!apiListen) {
|
||||
return Promise.reject('API has not been configured');
|
||||
}
|
||||
const apiPort = apiListen.substring(apiListen.lastIndexOf(':') + 1);
|
||||
const params = {
|
||||
host: window.location.hostname,
|
||||
@@ -137,6 +143,7 @@ return baseclass.extend({
|
||||
url = `http://${window.location.hostname}:${apiPort}/ui/?${query}`;
|
||||
}
|
||||
setTimeout(function () { window.open(url, '_blank') }, 0);
|
||||
return Promise.resolve();
|
||||
},
|
||||
|
||||
updateDashboard: function () {
|
||||
|
@@ -58,7 +58,8 @@ for k, e in ipairs(api.get_valid_nodes()) do
|
||||
nodes_table[#nodes_table + 1] = {
|
||||
id = e[".name"],
|
||||
remark = e["remark"],
|
||||
type = e["type"]
|
||||
type = e["type"],
|
||||
chain_proxy = e["chain_proxy"]
|
||||
}
|
||||
end
|
||||
if e.protocol == "_balancing" then
|
||||
@@ -696,7 +697,7 @@ o = s:option(ListValue, _n("to_node"), translate("Landing Node"), translate("Onl
|
||||
o:depends({ [_n("chain_proxy")] = "2" })
|
||||
|
||||
for k, v in pairs(nodes_table) do
|
||||
if v.type == "Xray" and v.id ~= arg[1] then
|
||||
if v.type == "Xray" and v.id ~= arg[1] and (not v.chain_proxy or v.chain_proxy == "") then
|
||||
s.fields[_n("preproxy_node")]:value(v.id, v.remark)
|
||||
s.fields[_n("to_node")]:value(v.id, v.remark)
|
||||
end
|
||||
|
@@ -75,7 +75,8 @@ for k, e in ipairs(api.get_valid_nodes()) do
|
||||
nodes_table[#nodes_table + 1] = {
|
||||
id = e[".name"],
|
||||
remark = e["remark"],
|
||||
type = e["type"]
|
||||
type = e["type"],
|
||||
chain_proxy = e["chain_proxy"]
|
||||
}
|
||||
end
|
||||
if e.protocol == "_iface" then
|
||||
@@ -753,7 +754,7 @@ o = s:option(ListValue, _n("to_node"), translate("Landing Node"), translate("Onl
|
||||
o:depends({ [_n("chain_proxy")] = "2" })
|
||||
|
||||
for k, v in pairs(nodes_table) do
|
||||
if v.type == "sing-box" and v.id ~= arg[1] then
|
||||
if v.type == "sing-box" and v.id ~= arg[1] and (not v.chain_proxy or v.chain_proxy == "") then
|
||||
s.fields[_n("preproxy_node")]:value(v.id, v.remark)
|
||||
s.fields[_n("to_node")]:value(v.id, v.remark)
|
||||
end
|
||||
|
@@ -38,11 +38,13 @@ config mixin 'mixin'
|
||||
option 'redir_port' '7891'
|
||||
option 'tproxy_port' '7892'
|
||||
option 'authentication' '1'
|
||||
option 'tun_enabled' '1'
|
||||
option 'tun_device' 'nikki'
|
||||
option 'tun_stack' 'mixed'
|
||||
option 'tun_dns_hijack' '0'
|
||||
list 'tun_dns_hijacks' 'tcp://any:53'
|
||||
list 'tun_dns_hijacks' 'udp://any:53'
|
||||
option 'dns_enabled' '1'
|
||||
option 'dns_listen' '[::]:1053'
|
||||
option 'dns_ipv6' '1'
|
||||
option 'dns_mode' 'fake-ip'
|
||||
|
@@ -6,12 +6,12 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=sing-box
|
||||
PKG_VERSION:=1.12.2
|
||||
PKG_VERSION:=1.12.3
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=https://codeload.github.com/SagerNet/sing-box/tar.gz/v$(PKG_VERSION)?
|
||||
PKG_HASH:=95d902c008ed0b414ab29408dc565310fffe435a15753e02d10ca5c8e6837ce5
|
||||
PKG_HASH:=3dce8ee383655908451f7f193714f0c8f90b8fd4baecb8e7e3948d263d766359
|
||||
|
||||
PKG_LICENSE:=GPL-3.0-or-later
|
||||
PKG_LICENSE_FILES:=LICENSE
|
||||
|
@@ -21,13 +21,13 @@ define Download/geoip
|
||||
HASH:=54761d8691a5756fdb08d2cd4d0a9c889dbaab786e1cf758592e09fb00377f53
|
||||
endef
|
||||
|
||||
GEOSITE_VER:=20250820044243
|
||||
GEOSITE_VER:=20250821075639
|
||||
GEOSITE_FILE:=dlc.dat.$(GEOSITE_VER)
|
||||
define Download/geosite
|
||||
URL:=https://github.com/v2fly/domain-list-community/releases/download/$(GEOSITE_VER)/
|
||||
URL_FILE:=dlc.dat
|
||||
FILE:=$(GEOSITE_FILE)
|
||||
HASH:=08eaf7b6e93ff4422eac2919673ec53f5840643ab318e891981e0f3bd51100f9
|
||||
HASH:=b35fcc137b86b4db2ef23919a05c7f90267dc4783186b4e416ff10213cc62ff5
|
||||
endef
|
||||
|
||||
GEOSITE_IRAN_VER:=202508180044
|
||||
|
34
v2rayn/.github/workflows/build-linux.yml
vendored
34
v2rayn/.github/workflows/build-linux.yml
vendored
@@ -99,3 +99,37 @@ jobs:
|
||||
tag: ${{ github.event.inputs.release_tag }}
|
||||
file_glob: true
|
||||
prerelease: true
|
||||
|
||||
# release RHEL package
|
||||
- name: Package RPM (RHEL-family)
|
||||
if: github.event.inputs.release_tag != ''
|
||||
run: |
|
||||
chmod 755 package-rhel.sh
|
||||
# Build for both x86_64 and aarch64 in one go (explicit version passed; no --buildfrom)
|
||||
./package-rhel.sh "${{ github.event.inputs.release_tag }}" --arch all
|
||||
|
||||
- name: Collect RPMs into workspace
|
||||
if: github.event.inputs.release_tag != ''
|
||||
run: |
|
||||
mkdir -p "${{ github.workspace }}/dist/rpm"
|
||||
rsync -av "$HOME/rpmbuild/RPMS/" "${{ github.workspace }}/dist/rpm/"
|
||||
# Rename to requested filenames
|
||||
find "${{ github.workspace }}/dist/rpm" -name "v2rayN-*-1.x86_64.rpm" -exec mv {} "${{ github.workspace }}/dist/rpm/v2rayN-linux-rhel-x64.rpm" \; || true
|
||||
find "${{ github.workspace }}/dist/rpm" -name "v2rayN-*-1.aarch64.rpm" -exec mv {} "${{ github.workspace }}/dist/rpm/v2rayN-linux-rhel-arm64.rpm" \; || true
|
||||
|
||||
- name: Upload RPM artifacts
|
||||
if: github.event.inputs.release_tag != ''
|
||||
uses: actions/upload-artifact@v4.6.2
|
||||
with:
|
||||
name: v2rayN-rpm
|
||||
path: |
|
||||
${{ github.workspace }}/dist/rpm/**/*.rpm
|
||||
|
||||
- name: Upload RPMs to release
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
if: github.event.inputs.release_tag != ''
|
||||
with:
|
||||
file: ${{ github.workspace }}/dist/rpm/**/*.rpm
|
||||
tag: ${{ github.event.inputs.release_tag }}
|
||||
file_glob: true
|
||||
prerelease: true
|
||||
|
@@ -332,6 +332,7 @@ download_xray() {
|
||||
# Download Xray core and install to outdir/xray
|
||||
local outdir="$1" ver="${XRAY_VER:-}" url tmp zipname="xray.zip"
|
||||
mkdir -p "$outdir"
|
||||
if [[ -n "${XRAY_VER:-}" ]]; then ver="${XRAY_VER}"; fi
|
||||
if [[ -z "$ver" ]]; then
|
||||
ver="$(curl -fsSL https://api.github.com/repos/XTLS/Xray-core/releases/latest \
|
||||
| grep -Eo '"tag_name":\s*"v[^"]+"' | sed -E 's/.*"v([^"]+)".*/\1/' | head -n1)" || true
|
||||
@@ -353,6 +354,7 @@ download_singbox() {
|
||||
# Download sing-box core and install to outdir/sing-box
|
||||
local outdir="$1" ver="${SING_VER:-}" url tmp tarname="singbox.tar.gz" bin
|
||||
mkdir -p "$outdir"
|
||||
if [[ -n "${SING_VER:-}" ]]; then ver="${SING_VER}"; fi
|
||||
if [[ -z "$ver" ]]; then
|
||||
ver="$(curl -fsSL https://api.github.com/repos/SagerNet/sing-box/releases/latest \
|
||||
| grep -Eo '"tag_name":\s*"v[^"]+"' | sed -E 's/.*"v([^"]+)".*/\1/' | head -n1)" || true
|
||||
@@ -372,6 +374,22 @@ download_singbox() {
|
||||
install -Dm755 "$bin" "$outdir/sing-box"
|
||||
}
|
||||
|
||||
# ---- NEW: download_mihomo (REQUIRED in --netcore mode) ----
|
||||
download_mihomo() {
|
||||
# Download mihomo into outroot/bin/mihomo/mihomo
|
||||
local outroot="$1"
|
||||
local url=""
|
||||
if [[ "$RID_DIR" == "linux-arm64" ]]; then
|
||||
url="https://raw.githubusercontent.com/2dust/v2rayN-core-bin/refs/heads/master/v2rayN-linux-arm64/bin/mihomo/mihomo"
|
||||
else
|
||||
url="https://raw.githubusercontent.com/2dust/v2rayN-core-bin/refs/heads/master/v2rayN-linux-64/bin/mihomo/mihomo"
|
||||
fi
|
||||
echo "[+] Download mihomo: $url"
|
||||
mkdir -p "$outroot/bin/mihomo"
|
||||
curl -fL "$url" -o "$outroot/bin/mihomo/mihomo"
|
||||
chmod +x "$outroot/bin/mihomo/mihomo" || true
|
||||
}
|
||||
|
||||
# Move geo files to a unified path: outroot/bin/xray/
|
||||
unify_geo_layout() {
|
||||
local outroot="$1"
|
||||
@@ -451,7 +469,8 @@ download_v2rayn_bundle() {
|
||||
fi
|
||||
|
||||
rm -f "$outroot/v2rayn.zip" 2>/dev/null || true
|
||||
find "$outroot" -type d -name "mihomo" -prune -exec rm -rf {} + 2>/dev/null || true
|
||||
# keep mihomo
|
||||
# find "$outroot" -type d -name "mihomo" -prune -exec rm -rf {} + 2>/dev/null || true
|
||||
|
||||
local nested_dir
|
||||
nested_dir="$(find "$outroot" -maxdepth 1 -type d -name 'v2rayN-linux-*' | head -n1 || true)"
|
||||
@@ -561,6 +580,8 @@ build_for_arch() {
|
||||
download_singbox "$WORKDIR/$PKGROOT/bin/sing_box" || echo "[!] sing-box download failed (skipped)"
|
||||
fi
|
||||
download_geo_assets "$WORKDIR/$PKGROOT" || echo "[!] Geo rules download failed (skipped)"
|
||||
# ---- REQUIRED: always fetch mihomo in netcore mode, per-arch ----
|
||||
download_mihomo "$WORKDIR/$PKGROOT" || echo "[!] mihomo download failed (skipped)"
|
||||
fi
|
||||
|
||||
# Tarball
|
||||
@@ -583,6 +604,7 @@ Release: 1%{?dist}
|
||||
Summary: v2rayN (Avalonia) GUI client for Linux (x86_64/aarch64)
|
||||
License: GPL-3.0-only
|
||||
URL: https://github.com/2dust/v2rayN
|
||||
BugURL: https://github.com/2dust/v2rayN/issues
|
||||
ExclusiveArch: aarch64 x86_64
|
||||
Source0: __PKGROOT__.tar.gz
|
||||
|
||||
@@ -591,10 +613,11 @@ Requires: libX11, libXrandr, libXcursor, libXi, libXext, libxcb, libXrende
|
||||
Requires: fontconfig, freetype, cairo, pango, mesa-libEGL, mesa-libGL
|
||||
|
||||
%description
|
||||
v2rayN GUI client built with Avalonia.
|
||||
Installs self-contained publish under /opt/v2rayN and a launcher 'v2rayn'.
|
||||
Cores (if bundled): /opt/v2rayN/bin/xray, /opt/v2rayN/bin/sing_box.
|
||||
Geo files for Xray are placed at /opt/v2rayN/bin/xray; launcher will symlink them into user's XDG data dir on first run.
|
||||
v2rayN Linux for Red Hat Enterprise Linux
|
||||
Support vless / vmess / Trojan / http / socks / Anytls / Hysteria2 / Shadowsocks / tuic / WireGuard
|
||||
Support Red Hat Enterprise Linux / Fedora Linux / Rocky Linux / AlmaLinux / CentOS
|
||||
For more information, Please visit our website
|
||||
https://github.com/2dust/v2rayN
|
||||
|
||||
%prep
|
||||
%setup -q -n __PKGROOT__
|
||||
@@ -645,7 +668,7 @@ cat > %{buildroot}%{_datadir}/applications/v2rayn.desktop << 'EOF'
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=v2rayN
|
||||
Comment=GUI client for Xray / sing-box
|
||||
Comment=v2rayN for Red Hat Enterprise Linux
|
||||
Exec=v2rayn
|
||||
Icon=v2rayn
|
||||
Terminal=false
|
||||
|
@@ -10,6 +10,7 @@
|
||||
|
||||
<x:Double x:Key="IconButtonWidth">32</x:Double>
|
||||
<x:Double x:Key="IconButtonHeight">32</x:Double>
|
||||
<x:Double x:Key="MenuFlyoutMaxHeight">1000</x:Double>
|
||||
|
||||
<Thickness x:Key="Margin2">2</Thickness>
|
||||
<Thickness x:Key="MarginLr4">4,0</Thickness>
|
||||
|
@@ -27,7 +27,7 @@ require (
|
||||
golang.org/x/sys v0.35.0
|
||||
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173
|
||||
google.golang.org/grpc v1.75.0
|
||||
google.golang.org/protobuf v1.36.7
|
||||
google.golang.org/protobuf v1.36.8
|
||||
gvisor.dev/gvisor v0.0.0-20250428193742-2d800c3129d5
|
||||
h12.io/socks v1.0.3
|
||||
lukechampine.com/blake3 v1.4.1
|
||||
|
@@ -145,8 +145,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4=
|
||||
google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
|
||||
google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A=
|
||||
google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
|
@@ -306,7 +306,8 @@ INNERTUBE_CLIENTS = {
|
||||
'client': {
|
||||
'clientName': 'TVHTML5',
|
||||
'clientVersion': '7.20250312.16.00',
|
||||
'userAgent': 'Mozilla/5.0 (ChromiumStylePlatform) Cobalt/Version',
|
||||
# See: https://github.com/youtube/cobalt/blob/main/cobalt/browser/user_agent/user_agent_platform_info.cc#L506
|
||||
'userAgent': 'Mozilla/5.0 (ChromiumStylePlatform) Cobalt/25.lts.30.1034943-gold (unlike Gecko), Unknown_TV_Unknown_0/Unknown (Unknown, Unknown)',
|
||||
},
|
||||
},
|
||||
'INNERTUBE_CONTEXT_CLIENT_NAME': 7,
|
||||
|
Reference in New Issue
Block a user