Skip to content

Commit

Permalink
fix: shadowsock SIP002URI parse fail
Browse files Browse the repository at this point in the history
  • Loading branch information
SharerMax committed Jul 8, 2023
1 parent bf69dce commit 57fe4a2
Show file tree
Hide file tree
Showing 9 changed files with 59 additions and 32 deletions.
2 changes: 1 addition & 1 deletion .vscode/.debug.script.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ fs.writeFileSync(path.join(__dirname, '.debug.env'), envContent.join('\n'))

// bootstrap
spawn(
process.platform === 'win32' ? 'npm.cmd' : 'npm',
process.platform === 'win32' ? 'pnpm' : 'pnpm',
['run', 'debug',],
{ stdio: 'inherit', env: {...process.env, NODE_ENV: 'development'}},
)
9 changes: 5 additions & 4 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,16 @@
"name": "Debug Main Process",
"type": "node",
"request": "launch",
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
"windows": {
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron.cmd"
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd"
},
"runtimeArgs": [
"--remote-debugging-port=9229",
"${workspaceRoot}/dist/electron/main/index.js"
"${workspaceFolder}/dist/electron/main/index.js"
],
"envFile": "${workspaceFolder}/.vscode/.debug.env"
"envFile": "${workspaceFolder}/.vscode/.debug.env",
"outputCapture": "std"
},
{
"name": "Debug Renderer Process",
Expand Down
17 changes: 9 additions & 8 deletions electron/main/clash.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// import { spawn } from 'node:child_process'
import process from 'process'
import path from 'path'
import type { ChildProcess } from 'child_process'
import { spawn } from 'child_process'
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs'
import process from 'node:process'
import path from 'node:path'
import type { ChildProcess } from 'node:child_process'
import { spawn } from 'node:child_process'
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
import { app, net } from 'electron'
import yaml from 'js-yaml'
import getPort, { portNumbers } from 'get-port'
Expand Down Expand Up @@ -121,7 +121,7 @@ function cancelAllProxySubscribeJob() {
}

function checkProxySubTask() {
const subscribe = store.get('subscribe', null)
const subscribe = store.get('subscribe')
if (subscribe) {
const updateTime = subscribe.updateTime
if (updateTime) {
Expand All @@ -144,7 +144,7 @@ function checkProxySubTask() {
}

function updateProxySub() {
const subscribe = store.get('subscribe', null)
const subscribe = store.get('subscribe')
const subscribeUrl = subscribe?.url
if (!subscribeUrl) {
return
Expand All @@ -171,7 +171,8 @@ function updateProxySub() {
store.set('subscribe', subscribe)

const configFilePath = getClashDefaultConfigPath()
const configYaml = (yaml.load(readFileSync(configFilePath, 'utf-8')) as any) as ClashConfig
const configYaml = (yaml.load(readFileSync(configFilePath, 'utf-8')) as any)

let needUpdateConfigFile = false
if (configYaml && typeof configYaml === 'object') {
if (!('proxy-providers' in configYaml)) {
Expand Down
2 changes: 1 addition & 1 deletion electron/main/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ async function createWindow() {
// https://github.com/vitejs/vite/issues/3229; will be fix in vite 3.x

console.log('process.env', process.env)
const url = `${process.env.VITE_DEV_SERVER_URL}`
const url = `http://${process.env.VITE_DEV_SERVER_HOST}:${process.env.VITE_DEV_SERVER_PORT}`
console.log(`render server on: ${url}\n`)
win.loadURL(url)
}
Expand Down
2 changes: 1 addition & 1 deletion packages/share/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
],
"scripts": {
"test": "vitest",
"dev": "tsup --watch",
"dev": "tsup --watch --sourcemap inline",
"build": "tsup"
},
"devDependencies": {
Expand Down
41 changes: 31 additions & 10 deletions packages/share/src/utils/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import URL from 'url-parse'
import { toUnicode } from 'punycode-esm'
import type { ClashProxy, HttpProxy, ShadowSocks, ShadowSocksCipher, ShadowSocksRProxy, ShadowSocksWithObfs, ShadowSocksWithV2ray, ShadowsocksRObfs, ShadowsocksRProtocol, SocksProxy, TrojanProxy, VmessProxy } from '../type'
import { parse as parseJson } from './json-helper'

export type ProxySubType = 'plain' | 'base64' | 'sip008' | 'clash'

export function parseProxySubContent(type: ProxySubType, content: string): ClashProxy[] | null {
Expand All @@ -21,10 +22,10 @@ function parsePlainProxyContent(content: string): ClashProxy[] | null {
const clashProxyList: ClashProxy[] = []
for (const uri of uriList) {
const clashProxy = parseUri(uri.trim())
console.log('============')
console.log(`raw: ${uri}`)
// console.log('============')
// console.log(`raw: ${uri}`)
console.log(`clash: ${JSON.stringify(clashProxy)}`)
console.log('============')
// console.log('============')
if (clashProxy) {
clashProxyList.push(clashProxy)
}
Expand Down Expand Up @@ -74,7 +75,7 @@ export function parseUri(uri: string): ClashProxy | null {
export function parseShadowsocksUri(uri: string): ShadowSocks | null {
if (uri) {
if (uri.includes('@')) {
return parseShadowsocksUri(uri)
return parseShadowsocksSIP002URI(uri)
}
else {
return parseShadowsocksLegacyUri(uri)
Expand Down Expand Up @@ -112,29 +113,36 @@ export function parseShadowsocksLegacyUri(uri: string): ShadowSocks | null {
const userInfo = decodeInfo.slice(0, serveSplitIndex)
const serverInfo = decodeInfo.slice(serveSplitIndex + 1)
const [cipher, password] = userInfo.split(':')
if (!isSupportedShadowsocksCipher(cipher)) {
return null
}
const [server, port] = serverInfo.split(':')
return {
type: 'ss',
name,
server,
cipher: cipher as ShadowSocks['cipher'],
password,
port: parseInt(port),
port: Number.parseInt(port),
}
}

// https://github.com/shadowsocks/shadowsocks-org/wiki/SIP002-URI-Scheme
// https://shadowsocks.org/guide/sip002.html
// https://shadowsocks.org/doc/sip002.html

export function parseShadowsocksSIP002URI(uri: string): ClashProxy | null {
export function parseShadowsocksSIP002URI(uri: string): ShadowSocks | null {
if (uri) {
// ss://cmM0LW1kNTpwYXNzd2Q@us.proxy.com:8888/?plugin=obfs-local%3Bobfs%3Dhttp#Example2
// const regex = /ss:\/\/(\S+)@(\S+):(\d+)(?:\/\?plugin=(\S+))?#(\S+)/
// const [userInfo, host, port, pluginArgs, name] = uri.match(regex) ?? []
const ssUrl = new URL(decodeURIComponent(uri))
const [cipher, password] = decodeBase64(ssUrl.username).split(':')
const decodedUserInfo = isBase64Valid(ssUrl.username) ? decodeBase64(ssUrl.username) : ssUrl.username
const [cipher, password] = decodedUserInfo.split(':')
if (!isSupportedShadowsocksCipher(cipher)) {
return null
}
const host = ssUrl.hostname
const port = parseInt(ssUrl.port)
const port = Number.parseInt(ssUrl.port)
const pluginInfo = new URLSearchParams(ssUrl.query).get('plugin') || ''
const name = ssUrl.hash.slice(1)
// console.log(cipher, password, host, port, pluginInfo, name)
Expand All @@ -144,7 +152,7 @@ export function parseShadowsocksSIP002URI(uri: string): ClashProxy | null {
name,
server: host,
cipher: cipher as ShadowSocks['cipher'],
password: decodeURIComponent(password),
password,
port,
}
if (pluginInfo) {
Expand Down Expand Up @@ -188,6 +196,19 @@ export function parseShadowsocksSIP002URI(uri: string): ClashProxy | null {
return null
}

// https://dreamacro.github.io/clash/configuration/configuration-reference.html
const SUPPORTED_CIPHERS = [
'aes-128-gcm', 'aes-192-gcm', 'aes-256-gcm',
'aes-128-cfb', 'aes-192-cfb', 'aes-256-cfb',
'aes-128-ctr', 'aes-192-ctr', 'aes-256-ctr',
'rc4-md5', 'chacha20-ietf', 'xchacha20',
'chacha20-ietf-poly1305', 'xchacha20-ietf-poly1305',
]

export function isSupportedShadowsocksCipher(cipher: string): boolean {
return SUPPORTED_CIPHERS.includes(cipher)
}

export function parseHttpUri(uri: string): HttpProxy | null {
if (uri) {
const parsed = new URL(uri)
Expand Down
16 changes: 9 additions & 7 deletions packages/share/tests/utils/parse.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,23 @@ import { parseHttpUri, parseShadowsocksLegacyUri, parseShadowsocksRUri, parseSha
import type { OrdinaryTrojanProxy, OrdinaryVmessProxy, ShadowSocksRProxy, TrojanWebsocketProxy, VmessGrpcProxy, VmessH2Proxy, VmessHttpProxy, VmessWebsocketProxy } from '../../src/type'

describe('utils:parse', () => {
test('parseShadowsocksSIP002UR', () => {
const result = parseShadowsocksSIP002URI('ss://cmM0LW1kNTpwYXNzd2Q@us.proxy.com:8888#Example2')
test('parseShadowsocksSIP002URI', () => {
const result = parseShadowsocksSIP002URI('ss://YWVzLTEyOC1nY206ODNYdlg0Vm8lKjNh@us.proxy.com:8888#Example2')
expect(result).toEqual({
type: 'ss',
name: 'Example2',
server: 'us.proxy.com',
cipher: 'rc4-md5',
password: 'passwd',
cipher: 'aes-128-gcm',
password: '83XvX4Vo%*3a',
port: 8888,
})
const withV2rayResult = parseShadowsocksSIP002URI('ss://MjAyMi1ibGFrZTMtYWVzLTI1Ni1nY206WWN0UFo2VTd4UFBjVSUyQmdwM3UlMkIwdHglMkZ0Uml6Sk45Szh5JTJCdUtsVzJxamxJJTNE@192.168.100.1:8888/?plugin=v2ray-plugin%3Btls%3Bhost%3Dcn.bing.com#Example3')
const withV2rayResult = parseShadowsocksSIP002URI('ss://cmM0LW1kNTpwYXNzd2Q@192.168.100.1:8888/?plugin=v2ray-plugin%3Btls%3Bhost%3Dcn.bing.com#Example3')
expect(withV2rayResult).toEqual({
'type': 'ss',
'name': 'Example3',
'server': '192.168.100.1',
'cipher': '2022-blake3-aes-256-gcm',
'password': 'YctPZ6U7xPPcU+gp3u+0tx/tRizJN9K8y+uKlW2qjlI=',
'cipher': 'rc4-md5',
'password': 'passwd',
'port': 8888,
'plugin': 'v2ray-plugin',
'plugin-opt': {
Expand All @@ -43,6 +43,8 @@ describe('utils:parse', () => {
host: '',
},
})
const withUnsupportedCipherResult = parseShadowsocksSIP002URI('ss://MjAyMi1ibGFrZTMtYWVzLTI1Ni1nY206WWN0UFo2VTd4UFBjVSUyQmdwM3UlMkIwdHglMkZ0Uml6Sk45Szh5JTJCdUtsVzJxamxJJTNE@us.proxy.com:8888/?plugin=obfs-local%3Bobfs%3Dhttp#Example2')
expect(withUnsupportedCipherResult).toBeNull()
})
test('parseShadowsocksLegacyUri', () => {
const result = parseShadowsocksLegacyUri('ss://cmM0LW1kNTp0ZXN0LyFAIzpAMTkyLjE2OC4xMDAuMTo4ODg4#Example1')
Expand Down
1 change: 1 addition & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'

// import './samples/node-api'
import 'uno.css'
import 'vfonts/FiraCode.css'
Expand Down
1 change: 1 addition & 0 deletions vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import VueDevTools from 'vite-plugin-vue-devtools'
import Unocss from 'unocss/vite'
import { env } from './package.json'

Object.assign(process.env, { VITE_DEV_SERVER_HOST: env.VITE_DEV_SERVER_HOST, VITE_DEV_SERVER_PORT: env.VITE_DEV_SERVER_PORT })
// https://vitejs.dev/config/
export default defineConfig(({ mode }) => {
if (mode !== 'debug') {
Expand Down

0 comments on commit 57fe4a2

Please sign in to comment.