mirror of
https://wget.la/https://github.com/Wxw-Gu/WechatExplorer
synced 2026-08-21 21:47:00 +08:00
93 lines
3.5 KiB
TypeScript
93 lines
3.5 KiB
TypeScript
import { mkdtempSync, readFileSync, rmSync } from 'fs'
|
|
import { tmpdir } from 'os'
|
|
import { join, resolve } from 'path'
|
|
import { afterAll, describe, expect, it, vi } from 'vitest'
|
|
import { classifyStickerHttpFailure } from '../../src/shared/sticker'
|
|
|
|
const logs = mkdtempSync(join(tmpdir(), 'wxe-log-test-'))
|
|
vi.mock('electron', () => ({
|
|
app: { getPath: () => logs, isPackaged: true },
|
|
shell: { showItemInFolder: vi.fn() }
|
|
}))
|
|
|
|
import { AppLogger } from '../../src/main/app-logger'
|
|
|
|
describe('sensitive logging', () => {
|
|
afterAll(() => rmSync(logs, { recursive: true, force: true }))
|
|
|
|
it('does not persist database keys, API keys or bearer tokens', () => {
|
|
const databaseKey = 'a'.repeat(64)
|
|
const logger = new AppLogger()
|
|
logger.write({
|
|
level: 'error',
|
|
scope: 'fixture',
|
|
message: `database open failed key=${databaseKey}`,
|
|
details: {
|
|
databaseKey,
|
|
apiKey: 'sk-fixture-secret-value',
|
|
authorization: 'Bearer fixture-token-value'
|
|
}
|
|
})
|
|
const persisted = readFileSync(logger.logPath, 'utf8')
|
|
expect(persisted).not.toContain(databaseKey)
|
|
expect(persisted).not.toContain('sk-fixture-secret-value')
|
|
expect(persisted).not.toContain('fixture-token-value')
|
|
expect(persisted).toContain('***')
|
|
})
|
|
})
|
|
|
|
describe('sticker HTTP failures', () => {
|
|
it('distinguishes expired, unauthorized, removed and rate-limited resources', () => {
|
|
expect(classifyStickerHttpFailure(403, 'https://fixture.invalid/a?expires=1', 2_000).code).toBe(
|
|
'link_expired'
|
|
)
|
|
expect(classifyStickerHttpFailure(403, 'https://fixture.invalid/a').code).toBe('access_denied')
|
|
expect(classifyStickerHttpFailure(401, 'https://fixture.invalid/a').code).toBe(
|
|
'authentication_required'
|
|
)
|
|
expect(classifyStickerHttpFailure(410, 'https://fixture.invalid/a').code).toBe(
|
|
'resource_removed'
|
|
)
|
|
expect(classifyStickerHttpFailure(429, 'https://fixture.invalid/a').code).toBe('rate_limited')
|
|
})
|
|
})
|
|
|
|
describe('personal WeChat runtime security invariants', () => {
|
|
it('waits for sender termination during application shutdown', () => {
|
|
const mainSource = readFileSync(resolve('src/main/index.ts'), 'utf8')
|
|
const shutdownStart = mainSource.indexOf("app.on('before-quit'")
|
|
const shutdownEnd = mainSource.indexOf('function showMainWindow', shutdownStart)
|
|
const shutdownSource = mainSource.slice(shutdownStart, shutdownEnd)
|
|
|
|
expect(shutdownStart).toBeGreaterThanOrEqual(0)
|
|
expect(shutdownEnd).toBeGreaterThan(shutdownStart)
|
|
expect(shutdownSource).toContain('await Promise.all([')
|
|
expect(shutdownSource).toContain('personalWechatSendService.terminate()')
|
|
expect(shutdownSource).not.toContain('personalWechatSendService.stop()')
|
|
|
|
const senderSource = readFileSync(
|
|
resolve('src/main/services/personal-wechat-send-service.ts'),
|
|
'utf8'
|
|
)
|
|
expect(senderSource).toContain("process.kill(pid, 'SIGTERM')")
|
|
expect(senderSource).toContain("process.kill(pid, 'SIGKILL')")
|
|
expect(senderSource).toContain('const trackedPid = this.child?.pid')
|
|
})
|
|
|
|
it('does not install Python packages while preparing the sender runtime', () => {
|
|
const runtimeManagerSource = readFileSync(
|
|
resolve('src/main/services/personal-wechat-runtime-manager.ts'),
|
|
'utf8'
|
|
)
|
|
const preparationScriptSource = readFileSync(
|
|
resolve('scripts/prepare-wechat-chatter-runtime.cjs'),
|
|
'utf8'
|
|
)
|
|
|
|
for (const source of [runtimeManagerSource, preparationScriptSource]) {
|
|
expect(source).not.toContain('pilk==')
|
|
expect(source).not.toMatch(/['"]pip['"]/)
|
|
}
|
|
})
|
|
})
|