Feature: support auto initial controller when host is ip

This commit is contained in:
Dreamacro 2023-04-29 18:58:02 +08:00
parent 21904d2f1f
commit 8616783b97
2 changed files with 53 additions and 1 deletions

24
src/lib/ip.ts Normal file
View File

@ -0,0 +1,24 @@
// copy from https://github.com/sindresorhus/ip-regex
const v4 = '(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}'
const v6segment = '[a-fA-F\\d]{1,4}'
const v6 = `
(?:
(?:${v6segment}:){7}(?:${v6segment}|:)| // 1:2:3:4:5:6:7:: 1:2:3:4:5:6:7:8
(?:${v6segment}:){6}(?:${v4}|:${v6segment}|:)| // 1:2:3:4:5:6:: 1:2:3:4:5:6::8 1:2:3:4:5:6::8 1:2:3:4:5:6::1.2.3.4
(?:${v6segment}:){5}(?::${v4}|(?::${v6segment}){1,2}|:)| // 1:2:3:4:5:: 1:2:3:4:5::7:8 1:2:3:4:5::8 1:2:3:4:5::7:1.2.3.4
(?:${v6segment}:){4}(?:(?::${v6segment}){0,1}:${v4}|(?::${v6segment}){1,3}|:)| // 1:2:3:4:: 1:2:3:4::6:7:8 1:2:3:4::8 1:2:3:4::6:7:1.2.3.4
(?:${v6segment}:){3}(?:(?::${v6segment}){0,2}:${v4}|(?::${v6segment}){1,4}|:)| // 1:2:3:: 1:2:3::5:6:7:8 1:2:3::8 1:2:3::5:6:7:1.2.3.4
(?:${v6segment}:){2}(?:(?::${v6segment}){0,3}:${v4}|(?::${v6segment}){1,5}|:)| // 1:2:: 1:2::4:5:6:7:8 1:2::8 1:2::4:5:6:7:1.2.3.4
(?:${v6segment}:){1}(?:(?::${v6segment}){0,4}:${v4}|(?::${v6segment}){1,6}|:)| // 1:: 1::3:4:5:6:7:8 1::8 1::3:4:5:6:7:1.2.3.4
(?::(?:(?::${v6segment}){0,5}:${v4}|(?::${v6segment}){1,7}|:)) // ::2:3:4:5:6:7:8 ::2:3:4:5:6:7:8 ::8 ::1.2.3.4
)(?:%[0-9a-zA-Z]{1,})? // %eth0 %1
`.replace(/\s*\/\/.*$/gm, '').replace(/\n/g, '').trim()
const v46Exact = new RegExp(`(?:^${v4}$)|(?:^${v6}$)`)
export function isIP (input: string): boolean {
return v46Exact.test(input)
}

View File

@ -2,6 +2,7 @@ import { atom, useAtom, useAtomValue } from 'jotai'
import { atomWithStorage } from 'jotai/utils'
import { useLocation } from 'react-router-dom'
import { isIP } from '@lib/ip'
import { isClashX, jsBridge } from '@lib/jsBridge'
import { Client } from '@lib/request'
@ -19,8 +20,35 @@ const clashxConfigAtom = atom(async () => {
}
})
function getControllerFromLocation (): string | null {
if (!isIP(location.hostname)) {
return null
}
if (location.port !== '') {
return JSON.stringify([
{
hostname: location.hostname,
port: +location.port,
secret: '',
},
])
}
const port = location.protocol === 'https:' ? 443 : 80
return JSON.stringify([
{
hostname: location.hostname,
port,
secret: '',
},
])
}
// jotai v2 use initialValue first avoid hydration warning, but we don't want that
const hostsStorageOrigin = localStorage.getItem('externalControllers') ?? '[]'
const hostsStorageOrigin = localStorage.getItem('externalControllers') ??
getControllerFromLocation() ??
'[{ "hostname": "127.0.0.1", "port": 7890, "secret": "" }]'
const hostSelectIdxStorageOrigin = localStorage.getItem('externalControllerIndex') ?? '0'
export const hostsStorageAtom = atomWithStorage<Array<{