mirror of
https://fastgit.cc/github.com/hicccc77/WeFlow
synced 2026-04-20 21:01:15 +08:00
111 lines
3.1 KiB
TypeScript
111 lines
3.1 KiB
TypeScript
import { existsSync } from 'fs'
|
|
import { join } from 'path'
|
|
|
|
type NativeDecryptResult = {
|
|
data: Buffer
|
|
ext: string
|
|
isWxgf?: boolean
|
|
is_wxgf?: boolean
|
|
}
|
|
|
|
type NativeAddon = {
|
|
decryptDatNative: (inputPath: string, xorKey: number, aesKey?: string) => NativeDecryptResult
|
|
}
|
|
|
|
let cachedAddon: NativeAddon | null | undefined
|
|
|
|
function shouldEnableNative(): boolean {
|
|
return process.env.WEFLOW_IMAGE_NATIVE !== '0'
|
|
}
|
|
|
|
function expandAsarCandidates(filePath: string): string[] {
|
|
if (!filePath.includes('app.asar') || filePath.includes('app.asar.unpacked')) {
|
|
return [filePath]
|
|
}
|
|
return [filePath.replace('app.asar', 'app.asar.unpacked'), filePath]
|
|
}
|
|
|
|
function getPlatformDir(): string {
|
|
if (process.platform === 'win32') return 'win32'
|
|
if (process.platform === 'darwin') return 'macos'
|
|
if (process.platform === 'linux') return 'linux'
|
|
return process.platform
|
|
}
|
|
|
|
function getArchDir(): string {
|
|
if (process.arch === 'x64') return 'x64'
|
|
if (process.arch === 'arm64') return 'arm64'
|
|
return process.arch
|
|
}
|
|
|
|
function getAddonCandidates(): string[] {
|
|
const platformDir = getPlatformDir()
|
|
const archDir = getArchDir()
|
|
const cwd = process.cwd()
|
|
const fileNames = [
|
|
`weflow-image-native-${platformDir}-${archDir}.node`
|
|
]
|
|
const roots = [
|
|
join(cwd, 'resources', 'wedecrypt', platformDir, archDir),
|
|
...(process.resourcesPath
|
|
? [
|
|
join(process.resourcesPath, 'resources', 'wedecrypt', platformDir, archDir),
|
|
join(process.resourcesPath, 'wedecrypt', platformDir, archDir)
|
|
]
|
|
: [])
|
|
]
|
|
const candidates = roots.flatMap((root) => fileNames.map((name) => join(root, name)))
|
|
return Array.from(new Set(candidates.flatMap(expandAsarCandidates)))
|
|
}
|
|
|
|
function loadAddon(): NativeAddon | null {
|
|
if (!shouldEnableNative()) return null
|
|
if (cachedAddon !== undefined) return cachedAddon
|
|
|
|
for (const candidate of getAddonCandidates()) {
|
|
if (!existsSync(candidate)) continue
|
|
try {
|
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
const addon = require(candidate) as NativeAddon
|
|
if (addon && typeof addon.decryptDatNative === 'function') {
|
|
cachedAddon = addon
|
|
return addon
|
|
}
|
|
} catch {
|
|
// try next candidate
|
|
}
|
|
}
|
|
|
|
cachedAddon = null
|
|
return null
|
|
}
|
|
|
|
export function nativeAddonLocation(): string | null {
|
|
for (const candidate of getAddonCandidates()) {
|
|
if (existsSync(candidate)) return candidate
|
|
}
|
|
return null
|
|
}
|
|
|
|
export function decryptDatViaNative(
|
|
inputPath: string,
|
|
xorKey: number,
|
|
aesKey?: string
|
|
): { data: Buffer; ext: string; isWxgf: boolean } | null {
|
|
const addon = loadAddon()
|
|
if (!addon) return null
|
|
|
|
try {
|
|
const result = addon.decryptDatNative(inputPath, xorKey, aesKey)
|
|
const isWxgf = Boolean(result?.isWxgf ?? result?.is_wxgf)
|
|
if (!result || !Buffer.isBuffer(result.data)) return null
|
|
const rawExt = typeof result.ext === 'string' && result.ext.trim()
|
|
? result.ext.trim().toLowerCase()
|
|
: ''
|
|
const ext = rawExt ? (rawExt.startsWith('.') ? rawExt : `.${rawExt}`) : ''
|
|
return { data: result.data, ext, isWxgf }
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|