2023-03-05 13:08:57 +08:00

93 lines
3.7 KiB
TypeScript

import { request, generateRsaKey } from './utils'
import { getSyncAuthKey, setSyncAuthKey } from '../data'
import { SYNC_CODE } from '@/config/constant'
import log from '../log'
import { aesDecrypt, aesEncrypt, rsaDecrypt } from '../utils'
import { getDeviceName } from '@/utils/nativeModules/utils'
const hello = async(urlInfo: LX.Sync.UrlInfo) => request(`${urlInfo.httpProtocol}//${urlInfo.hostPath}/hello`)
.then(({ text }) => text == SYNC_CODE.helloMsg)
.catch((err: any) => {
log.error('[auth] hello', err.message)
console.log(err)
return false
})
const getServerId = async(urlInfo: LX.Sync.UrlInfo) => request(`${urlInfo.httpProtocol}//${urlInfo.hostPath}/id`)
.then(({ text }) => {
if (!text.startsWith(SYNC_CODE.idPrefix)) return ''
return text.replace(SYNC_CODE.idPrefix, '')
})
.catch((err: any) => {
log.error('[auth] getServerId', err.message)
console.log(err)
throw err
})
const codeAuth = async(urlInfo: LX.Sync.UrlInfo, serverId: string, authCode: string) => {
let key = ''.padStart(16, Buffer.from(authCode).toString('hex'))
// const iv = Buffer.from(key.split('').reverse().join('')).toString('base64')
key = Buffer.from(key).toString('base64')
let { publicKey, privateKey } = await generateRsaKey()
publicKey = publicKey.replace(/\n/g, '')
.replace('-----BEGIN PUBLIC KEY-----', '')
.replace('-----END PUBLIC KEY-----', '')
const msg = aesEncrypt(`${SYNC_CODE.authMsg}\n${publicKey}\n${await getDeviceName()}\nlx_music_mobile`, key)
// console.log(msg, key)
return request(`${urlInfo.httpProtocol}//${urlInfo.hostPath}/ah`, { headers: { m: msg } }).then(async({ text, code }) => {
// console.log(text)
switch (text) {
case SYNC_CODE.msgBlockedIp:
throw new Error(SYNC_CODE.msgBlockedIp)
case SYNC_CODE.authFailed:
throw new Error(SYNC_CODE.authFailed)
default:
if (code != 200) throw new Error(SYNC_CODE.authFailed)
}
let msg
try {
msg = rsaDecrypt(Buffer.from(text, 'base64'), privateKey).toString()
} catch (err: any) {
log.error('[auth] codeAuth decryptMsg error', err.message)
throw new Error(SYNC_CODE.authFailed)
}
// console.log(msg)
if (!msg) return Promise.reject(new Error(SYNC_CODE.authFailed))
const info = JSON.parse(msg) as LX.Sync.KeyInfo
void setSyncAuthKey(serverId, info)
return info
})
}
const keyAuth = async(urlInfo: LX.Sync.UrlInfo, keyInfo: LX.Sync.KeyInfo) => {
const msg = aesEncrypt(SYNC_CODE.authMsg + await getDeviceName(), keyInfo.key)
return request(`${urlInfo.httpProtocol}//${urlInfo.hostPath}/ah`, { headers: { i: keyInfo.clientId, m: msg } }).then(async({ text, code }) => {
if (code != 200) throw new Error(SYNC_CODE.authFailed)
let msg
try {
msg = aesDecrypt(text, keyInfo.key)
} catch (err: any) {
log.error('[auth] keyAuth decryptMsg error', err.message)
throw new Error(SYNC_CODE.authFailed)
}
if (msg != SYNC_CODE.helloMsg) return Promise.reject(new Error(SYNC_CODE.authFailed))
})
}
const auth = async(urlInfo: LX.Sync.UrlInfo, serverId: string, authCode?: string) => {
if (authCode) return codeAuth(urlInfo, serverId, authCode)
const keyInfo = await getSyncAuthKey(serverId)
if (!keyInfo) throw new Error(SYNC_CODE.missingAuthCode)
await keyAuth(urlInfo, keyInfo)
return keyInfo
}
export default async(urlInfo: LX.Sync.UrlInfo, authCode?: string) => {
console.log('connect: ', urlInfo.href, authCode)
if (!await hello(urlInfo)) throw new Error(SYNC_CODE.connectServiceFailed)
const serverId = await getServerId(urlInfo)
if (!serverId) throw new Error(SYNC_CODE.getServiceIdFailed)
return auth(urlInfo, serverId, authCode)
}