@@ -1727,6 +1727,140 @@ echo ""`
17271727 await this . installNwWatchdog ( )
17281728 }
17291729 }
1730+ parseProfileURI ( uri ) {
1731+ // ssr://dnBzLmljeW1pbmQuY29tOjk5OTk6YXV0aF9hZXMxMjhfbWQ1OmNoYWNoYTIwOnRsczEuMl90aWNrZXRfYXV0aDphR0Z3Y0hramMzTnlJekl3TVRjLz9vYmZzcGFyYW09JnByb3RvcGFyYW09TXpJJnJlbWFya3M9UVc1a2NtOXBaQ0JUVTFJZ1JHVm1ZWFZzZEEmZ3JvdXA9ZG5Ceg
1732+
1733+ // ss://Y2hhY2hhMjA6aGFwcHkjc3MjMjAxNw@vps .icymind.com:7979?plugin=kcptun%3Bnocomp%3Dtrue%3Bmode%3Dfast%3Bkey%3Dhappy%23kt%232017%3Bcrypt%3Dnone#kcptun
1734+
1735+ // ss://Y2hhY2hhMjA6aGFwcHkjc3MjMjAxNw@vps .icymind.com:8989#%E6%98%8E%E6%98%8E%E6%98%8E
1736+ let profile = {
1737+ 'name' : '配置xx' ,
1738+ 'action' : 'new' ,
1739+ 'mode' : 'whitelist' ,
1740+ 'proxies' : 'ss' ,
1741+ 'relayUDP' : false ,
1742+ 'enableTunnelDns' : true ,
1743+ 'selectedBL' : { 'gfwDomains' : true , 'extraBlackList' : true } ,
1744+ 'selectedWL' : { 'chinaIPs' : true , 'lanNetworks' : true , 'extraWhiteList' : true } ,
1745+ 'shadowsocks' : {
1746+ 'address' : '123.123.123.123' ,
1747+ 'port' : '8989' ,
1748+ 'password' : 'demo-paswd' ,
1749+ 'timeout' : 300 ,
1750+ 'method' : 'chacha20' ,
1751+ 'fastopen' : false
1752+ } ,
1753+ 'shadowsocksr' : {
1754+ 'address' : '123.123.123.123' ,
1755+ 'port' : '9999' ,
1756+ 'password' : 'demo-paswd' ,
1757+ 'timeout' : 300 ,
1758+ 'method' : 'chacha20' ,
1759+ 'protocol' : 'auth_aes128_md5' ,
1760+ 'protocol_param' : '32' ,
1761+ 'obfs' : 'tls1.2_ticket_auth' ,
1762+ 'obfs_param' : '' ,
1763+ 'others' : '' ,
1764+ 'fastopen' : false
1765+ } ,
1766+ 'kcptun' : {
1767+ 'address' : '' ,
1768+ 'port' : '' ,
1769+ 'key' : 'demo-secret' ,
1770+ 'crypt' : 'aes-128' ,
1771+ 'mode' : 'fast2' ,
1772+ 'others' : 'sndwnd=256;rcvwnd=2048;nocomp=true'
1773+ }
1774+ }
1775+ let type = uri . substr ( 0 , uri . indexOf ( ':' ) )
1776+ if ( type === 'ssr' ) {
1777+ profile . proxies = 'ssr'
1778+ let decode = Buffer . from ( uri . substr ( 6 ) , 'base64' ) . toString ( )
1779+ const separatorIndex = decode . indexOf ( '/?' )
1780+ let config = decode . substr ( 0 , separatorIndex ) . split ( ':' )
1781+ config [ config . length - 1 ] = Buffer . from ( config [ config . length - 1 ] , 'base64' ) . toString ( )
1782+ ; [ profile . shadowsocksr . address , profile . shadowsocksr . port , profile . shadowsocksr . protocol , profile . shadowsocksr . method , profile . shadowsocksr . obfs , profile . shadowsocksr . password ] = config
1783+
1784+ config = decode . substr ( separatorIndex + 2 ) . split ( '&' )
1785+ config . forEach ( ( pair ) => {
1786+ let [ key , value ] = pair . split ( '=' )
1787+ value = Buffer . from ( value , 'base64' ) . toString ( )
1788+ switch ( key ) {
1789+ case 'obfsparam' :
1790+ profile . shadowsocksr . obfs_param = value
1791+ break
1792+ case 'protoparam' :
1793+ profile . shadowsocksr . protocol_param = value
1794+ break
1795+ case 'remarks' :
1796+ profile . name = value
1797+ break
1798+ case 'group' :
1799+ break
1800+ default :
1801+ profile . shadowsocksr . others += `${ key } =${ value } ;`
1802+ }
1803+ } )
1804+ } else if ( type === 'ss' ) {
1805+ profile . proxies = 'ss'
1806+ const nameIndex = uri . lastIndexOf ( '#' )
1807+ if ( nameIndex >= 0 ) {
1808+ profile . name = decodeURIComponent ( uri . substr ( nameIndex + 1 ) )
1809+ }
1810+ const separatorIndex = uri . indexOf ( '@' )
1811+ if ( separatorIndex > 0 ) {
1812+ // https://shadowsocks.org/en/spec/SIP002-URI-Scheme.html
1813+ // ss://[email protected] :8888/?plugin=url-encoded-plugin-argument-value&unsupported-arguments=should-be-ignored#Dummy+profile+name 1814+ let decode = Buffer . from ( uri . substr ( 5 , separatorIndex - 5 ) , 'base64' ) . toString ( )
1815+ ; [ profile . shadowsocks . method , profile . shadowsocks . password ] = decode . split ( ':' )
1816+
1817+ const pluginIndex = uri . indexOf ( '?plugin' )
1818+ if ( pluginIndex < 0 ) {
1819+ // without plugin
1820+ decode = uri . substr ( separatorIndex + 1 , nameIndex < 0 ? undefined : nameIndex - separatorIndex - 1 )
1821+ ; [ profile . shadowsocks . address , profile . shadowsocks . port ] = decode . split ( ':' )
1822+ } else {
1823+ // with plugin
1824+ decode = uri . substr ( separatorIndex + 1 , pluginIndex - separatorIndex - 1 )
1825+ ; [ profile . shadowsocks . address , profile . shadowsocks . port ] = decode . split ( ':' )
1826+
1827+ let plugin = uri . substr ( pluginIndex + '?plugin' . length + 1 , nameIndex - 1 - pluginIndex - '?plugin' . length )
1828+ let config = decodeURIComponent ( plugin ) . split ( ';' )
1829+ if ( config [ 0 ] !== 'kcptun' ) {
1830+ throw Error ( `unsupported plugin: ${ config [ 0 ] } ` )
1831+ } else {
1832+ profile . proxies = 'ssKt'
1833+ let others = ''
1834+ config . slice ( 1 ) . forEach ( ( pair ) => {
1835+ let [ key , value ] = pair . split ( '=' )
1836+ switch ( key ) {
1837+ case 'mode' :
1838+ case 'key' :
1839+ case 'crypt' :
1840+ profile . kcptun [ key ] = value
1841+ break
1842+ default :
1843+ others += `${ pair } ;`
1844+ }
1845+ } )
1846+ profile . kcptun . address = profile . kcptun . address || profile . shadowsocks . address
1847+ profile . kcptun . port = profile . kcptun . port || profile . shadowsocks . port
1848+ profile . kcptun . others = others === '' ? profile . kcptun . others : others
1849+ }
1850+ }
1851+ } else {
1852+ // https://shadowsocks.org/en/config/quick-guide.html
1853+ // ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xMDAuMTo4ODg4Cg#example-server
1854+ let index = uri . indexOf ( '#' )
1855+ let decode = Buffer . from ( uri . substr ( 5 , index < 0 ? undefined : nameIndex - 5 ) , 'base64' ) . toString ( )
1856+ let config = decode . split ( '@' )
1857+ ; [ profile . shadowsocks . address , profile . shadowsocks . port , profile . shadowsocks . method , profile . shadowsocks . password ] = [ ...config [ 1 ] . split ( ':' ) , ...config [ 0 ] . split ( ':' ) ]
1858+ }
1859+ } else {
1860+ throw Error ( 'unsupported URI' )
1861+ }
1862+ return profile
1863+ }
17301864 async copyTemplate ( fileName ) {
17311865 const template = path . join ( __dirname , '..' , 'config' , fileName )
17321866 const dest = path . join ( this . config . host . configDir , fileName )
0 commit comments