@@ -26,6 +26,7 @@ export default function Egern_Producer() {
2626 'wireguard' ,
2727 'anytls' ,
2828 'ssh' ,
29+ 'snell' ,
2930 ] . includes ( proxy . type ) ||
3031 ( proxy . type === 'ss' &&
3132 ( ( proxy . plugin === 'obfs' &&
@@ -63,16 +64,20 @@ export default function Egern_Producer() {
6364 '2022-blake3-aes-256-gcm' ,
6465 ] . includes ( proxy . cipher ) ) ) ||
6566 ( proxy . type === 'vmess' &&
66- ! [ 'h2' , 'http' , 'ws' , 'tcp' ] . includes ( proxy . network ) &&
67- proxy . network ) ||
67+ ( ( ! [ 'h2' , 'http' , 'ws' , 'tcp' , 'grpc' ] . includes (
68+ proxy . network ,
69+ ) &&
70+ proxy . network ) ||
71+ ! isEgernGrpcGun ( proxy ) ) ) ||
6872 ( proxy . type === 'trojan' &&
6973 ! [ 'http' , 'ws' , 'tcp' ] . includes ( proxy . network ) &&
7074 proxy . network ) ||
7175 ( proxy . type === 'vless' &&
72- ( ( ! [ 'h2' , 'http' , 'ws' , 'tcp' ] . includes (
76+ ( ( ! [ 'h2' , 'http' , 'ws' , 'tcp' , 'grpc' ] . includes (
7377 proxy . network ,
7478 ) &&
7579 proxy . network ) ||
80+ ! isEgernGrpcGun ( proxy ) ||
7681 ( typeof proxy . flow !== 'undefined' &&
7782 ! [ 'xtls-rprx-vision' , '' ] . includes (
7883 proxy . flow ,
@@ -82,12 +87,15 @@ export default function Egern_Producer() {
8287 proxy . token . length !== 0 )
8388 ) {
8489 return false ;
90+ } else if (
91+ proxy . type === 'snell' &&
92+ normalizeSnellVersion ( proxy . version ) === null
93+ ) {
94+ return false ;
8595 } else if (
8696 [ 'anytls' ] . includes ( proxy . type ) &&
8797 proxy . network &&
88- ( ! [ 'tcp' ] . includes ( proxy . network ) ||
89- ( [ 'tcp' ] . includes ( proxy . network ) &&
90- proxy [ 'reality-opts' ] ) )
98+ ! [ 'tcp' ] . includes ( proxy . network )
9199 ) {
92100 return false ;
93101 } else if (
@@ -126,12 +134,13 @@ export default function Egern_Producer() {
126134 headers : proxy . headers ,
127135 }
128136 : { } ) ,
129- tfo : proxy . tfo || proxy [ 'fast-open' ] ,
137+ tfo : getTfo ( proxy ) ,
130138 ...( proxy . tls
131139 ? {
132140 sni : proxy . sni ,
133141 skip_tls_verify :
134142 proxy [ 'skip-cert-verify' ] ,
143+ reality : getReality ( proxy ) ,
135144 }
136145 : { } ) ,
137146 } ;
@@ -148,21 +157,29 @@ export default function Egern_Producer() {
148157 headers : proxy . headers ,
149158 }
150159 : { } ) ,
151- tfo : proxy . tfo || proxy [ 'fast-open' ] ,
160+ tfo : getTfo ( proxy ) ,
152161 sni : proxy . sni ,
153162 skip_tls_verify : proxy [ 'skip-cert-verify' ] ,
163+ reality : getReality ( proxy ) ,
154164 } ;
155165 } else if ( proxy . type === 'socks5' ) {
156166 proxy = {
157- type : 'socks5' ,
167+ type : proxy . tls ? 'socks5_tls' : 'socks5' ,
158168 name : proxy . name ,
159169 server : proxy . server ,
160170 port : proxy . port ,
161171 username : proxy . username ,
162172 password : proxy . password ,
163- tfo : proxy . tfo || proxy [ 'fast-open' ] ,
164- udp_relay :
165- proxy . udp || proxy . udp_relay || proxy . udp_relay ,
173+ tfo : getTfo ( proxy ) ,
174+ udp_relay : getUdpRelay ( proxy ) ,
175+ ...( proxy . tls
176+ ? {
177+ sni : proxy . sni ,
178+ skip_tls_verify :
179+ proxy [ 'skip-cert-verify' ] ,
180+ reality : getReality ( proxy ) ,
181+ }
182+ : { } ) ,
166183 } ;
167184 } else if ( proxy . type === 'ss' ) {
168185 proxy = {
@@ -175,9 +192,8 @@ export default function Egern_Producer() {
175192 server : proxy . server ,
176193 port : proxy . port ,
177194 password : proxy . password ,
178- tfo : proxy . tfo || proxy [ 'fast-open' ] ,
179- udp_relay :
180- proxy . udp || proxy . udp_relay || proxy . udp_relay ,
195+ tfo : getTfo ( proxy ) ,
196+ udp_relay : getUdpRelay ( proxy ) ,
181197 } ;
182198 if ( isPresent ( original , 'plugin' ) ) {
183199 if ( original . plugin === 'obfs' ) {
@@ -207,9 +223,8 @@ export default function Egern_Producer() {
207223 ) ,
208224 }
209225 : { } ) ,
210- tfo : proxy . tfo || proxy [ 'fast-open' ] ,
211- udp_relay :
212- proxy . udp || proxy . udp_relay || proxy . udp_relay ,
226+ tfo : getTfo ( proxy ) ,
227+ udp_relay : getUdpRelay ( proxy ) ,
213228 sni : proxy . sni ,
214229 skip_tls_verify : proxy [ 'skip-cert-verify' ] ,
215230 port_hopping : proxy . ports ,
@@ -251,11 +266,11 @@ export default function Egern_Producer() {
251266 server : proxy . server ,
252267 port : proxy . port ,
253268 password : proxy . password ,
254- tfo : proxy . tfo || proxy [ 'fast-open' ] ,
255- udp_relay :
256- proxy . udp || proxy . udp_relay || proxy . udp_relay ,
269+ tfo : getTfo ( proxy ) ,
270+ udp_relay : getUdpRelay ( proxy ) ,
257271 sni : proxy . sni ,
258272 skip_tls_verify : proxy [ 'skip-cert-verify' ] ,
273+ reality : getReality ( proxy ) ,
259274 websocket : proxy . websocket ,
260275 } ;
261276 } else if ( proxy . type === 'anytls' ) {
@@ -265,11 +280,11 @@ export default function Egern_Producer() {
265280 server : proxy . server ,
266281 port : proxy . port ,
267282 password : proxy . password ,
268- tfo : proxy . tfo || proxy [ 'fast-open' ] ,
269- udp_relay :
270- proxy . udp || proxy . udp_relay || proxy . udp_relay ,
283+ tfo : getTfo ( proxy ) ,
284+ udp_relay : getUdpRelay ( proxy ) ,
271285 sni : proxy . sni ,
272286 skip_tls_verify : proxy [ 'skip-cert-verify' ] ,
287+ reality : getReality ( proxy ) ,
273288 } ;
274289 } else if ( proxy . type === 'vmess' ) {
275290 // Egern:传输层,支持 ws/wss/http1/http2/tls,不配置则为 tcp
@@ -319,6 +334,8 @@ export default function Egern_Producer() {
319334 skip_tls_verify : proxy [ 'skip-cert-verify' ] ,
320335 } ,
321336 } ;
337+ } else if ( proxy . network === 'grpc' ) {
338+ proxy . transport = getGrpcTransport ( proxy ) ;
322339 } else if (
323340 ( proxy . network === 'tcp' || ! proxy . network ) &&
324341 proxy . tls
@@ -332,10 +349,13 @@ export default function Egern_Producer() {
332349 } ,
333350 } ;
334351 }
335- let legacy ;
352+ let legacy = false ;
336353 if ( isPresent ( proxy , 'aead' ) && ! proxy . aead ) {
337354 legacy = true ;
338- } else if ( proxy . alterId !== 0 ) {
355+ } else if (
356+ isPresent ( proxy , 'alterId' ) &&
357+ proxy . alterId !== 0
358+ ) {
339359 legacy = true ;
340360 }
341361 proxy = {
@@ -345,10 +365,9 @@ export default function Egern_Producer() {
345365 port : proxy . port ,
346366 user_id : proxy . uuid ,
347367 security,
348- tfo : proxy . tfo || proxy [ 'fast-open' ] ,
368+ tfo : getTfo ( proxy ) ,
349369 legacy,
350- udp_relay :
351- proxy . udp || proxy . udp_relay || proxy . udp_relay ,
370+ udp_relay : getUdpRelay ( proxy ) ,
352371 transport : proxy . transport ,
353372 } ;
354373 } else if ( proxy . type === 'vless' ) {
@@ -401,25 +420,16 @@ export default function Egern_Producer() {
401420 skip_tls_verify : proxy [ 'skip-cert-verify' ] ,
402421 } ,
403422 } ;
423+ } else if ( proxy . network === 'grpc' ) {
424+ proxy . transport = getGrpcTransport ( proxy ) ;
404425 } else if ( proxy . network === 'tcp' || ! proxy . network ) {
405- let reality ;
406- if (
407- proxy [ 'reality-opts' ] ?. [ 'short-id' ] ||
408- proxy [ 'reality-opts' ] ?. [ 'public-key' ]
409- ) {
410- reality = {
411- short_id : proxy [ 'reality-opts' ] [ 'short-id' ] ,
412- public_key :
413- proxy [ 'reality-opts' ] [ 'public-key' ] ,
414- } ;
415- }
416426 proxy . transport = {
417427 [ proxy . tls ? 'tls' : 'tcp' ] : {
418428 sni : proxy . tls ? proxy . sni : undefined ,
419429 skip_tls_verify : proxy . tls
420430 ? proxy [ 'skip-cert-verify' ]
421431 : undefined ,
422- reality,
432+ reality : getReality ( proxy ) ,
423433 } ,
424434 } ;
425435 flow = proxy . flow ;
@@ -432,9 +442,8 @@ export default function Egern_Producer() {
432442 port : proxy . port ,
433443 user_id : proxy . uuid ,
434444 security : proxy . cipher ,
435- tfo : proxy . tfo || proxy [ 'fast-open' ] ,
436- udp_relay :
437- proxy . udp || proxy . udp_relay || proxy . udp_relay ,
445+ tfo : getTfo ( proxy ) ,
446+ udp_relay : getUdpRelay ( proxy ) ,
438447 transport : proxy . transport ,
439448 flow,
440449 } ;
@@ -500,7 +509,31 @@ export default function Egern_Producer() {
500509 private_key : proxy [ 'private-key' ] ,
501510 // private_key_passphrase: proxy['private-key-passphrase'],
502511 host_keys : proxy [ 'host-key' ] ,
503- tfo : proxy . tfo || proxy [ 'fast-open' ] ,
512+ tfo : getTfo ( proxy ) ,
513+ } ;
514+ } else if ( proxy . type === 'snell' ) {
515+ const snellVersion = normalizeSnellVersion (
516+ proxy . version ,
517+ ) ;
518+ proxy = {
519+ type : 'snell' ,
520+ name : proxy . name ,
521+ server : proxy . server ,
522+ port : proxy . port ,
523+ psk : proxy . psk ,
524+ version : snellVersion ,
525+ ...( snellVersion == null || snellVersion >= 3
526+ ? {
527+ udp_relay : getUdpRelay ( proxy ) ,
528+ }
529+ : { } ) ,
530+ reuse : proxy . reuse ,
531+ obfs : proxy [ 'obfs-opts' ] ?. mode || proxy . obfs ,
532+ obfs_host :
533+ proxy [ 'obfs-opts' ] ?. host ||
534+ proxy [ 'obfs-host' ] ||
535+ proxy . obfs_host ,
536+ tfo : getTfo ( proxy ) ,
504537 } ;
505538 }
506539 if (
@@ -561,6 +594,7 @@ export default function Egern_Producer() {
561594 'hysteria2' ,
562595 'anytls' ,
563596 'ssh' ,
597+ 'snell' ,
564598 ] . includes ( original . type )
565599 ) {
566600 if (
@@ -595,11 +629,12 @@ export default function Egern_Producer() {
595629 if ( proxy . transport ) {
596630 for ( const key in proxy . transport ) {
597631 if (
598- Object . keys ( proxy . transport [ key ] ) . length ===
632+ key !== 'grpc' &&
633+ ( Object . keys ( proxy . transport [ key ] ) . length ===
599634 0 ||
600- Object . values ( proxy . transport [ key ] ) . every (
601- ( value ) => value == null ,
602- )
635+ Object . values ( proxy . transport [ key ] ) . every (
636+ ( value ) => value == null ,
637+ ) )
603638 ) {
604639 delete proxy . transport [ key ] ;
605640 }
@@ -644,6 +679,62 @@ function hasHeaders(proxy) {
644679 ) ;
645680}
646681
682+ function getTfo ( proxy ) {
683+ return proxy . tfo ?? proxy [ 'fast-open' ] ;
684+ }
685+
686+ function getUdpRelay ( proxy ) {
687+ return proxy . udp ?? proxy . udp_relay ;
688+ }
689+
690+ function getNonEmptyValue ( value ) {
691+ if ( value == null ) return undefined ;
692+ if ( typeof value === 'string' && value . length === 0 ) return undefined ;
693+ return value ;
694+ }
695+
696+ function getReality ( proxy ) {
697+ const realityOpts = proxy ?. [ 'reality-opts' ] ;
698+ if ( ! realityOpts ) return undefined ;
699+
700+ const reality = { } ;
701+ const publicKey = getNonEmptyValue ( realityOpts [ 'public-key' ] ) ;
702+ const shortId = getNonEmptyValue ( realityOpts [ 'short-id' ] ) ;
703+ if ( publicKey != null ) reality . public_key = publicKey ;
704+ if ( shortId != null ) reality . short_id = shortId ;
705+
706+ return Object . keys ( reality ) . length > 0 ? reality : undefined ;
707+ }
708+
709+ function getGrpcTransport ( proxy ) {
710+ return {
711+ grpc : {
712+ service_name : proxy [ 'grpc-opts' ] ?. [ 'grpc-service-name' ] ,
713+ sni : proxy . sni ,
714+ reality : getReality ( proxy ) ,
715+ skip_tls_verify : proxy [ 'skip-cert-verify' ] ,
716+ } ,
717+ } ;
718+ }
719+
720+ function isEgernGrpcGun ( proxy ) {
721+ if ( proxy . network !== 'grpc' ) return true ;
722+
723+ const grpcType = proxy [ 'grpc-opts' ] ?. [ '_grpc-type' ] ;
724+ if ( grpcType == null ) return true ;
725+
726+ return `${ grpcType } ` . trim ( ) . toLowerCase ( ) === 'gun' ;
727+ }
728+
729+ function normalizeSnellVersion ( version ) {
730+ if ( version == null ) return undefined ;
731+
732+ const normalized = `${ version } ` . trim ( ) ;
733+ if ( ! / ^ [ 1 - 5 ] $ / . test ( normalized ) ) return null ;
734+
735+ return parseInt ( normalized , 10 ) ;
736+ }
737+
647738function getFirstHeaderValue ( headers , ...keys ) {
648739 for ( const key of keys ) {
649740 const value = getFirstValue ( headers ?. [ key ] ) ;
@@ -699,14 +790,15 @@ function supportsRootFingerprintSha256(original, proxy) {
699790 [ 'anytls' , 'https' , 'hysteria2' , 'trojan' , 'tuic' ] . includes (
700791 original . type ,
701792 ) ||
793+ ( original . type === 'socks5' && proxy . type === 'socks5_tls' ) ||
702794 ( original . type === 'http' && proxy . type === 'https' )
703795 ) ;
704796}
705797
706798function addTransportFingerprintSha256 ( transport , fingerprintSha256 ) {
707799 if ( ! transport ) return ;
708800
709- for ( const key of [ 'http2' , 'tls' , 'wss' ] ) {
801+ for ( const key of [ 'grpc' , ' http2', 'tls' , 'wss' ] ) {
710802 if ( transport [ key ] ) {
711803 transport [ key ] . fingerprint_sha256 = fingerprintSha256 ;
712804 }
0 commit comments