Files
2026-07-13 13:12:33 +08:00

104 lines
3.7 KiB
JavaScript

import { strict as assert } from 'node:assert'
import { mkdir, mkdtemp, readFile, readdir, realpath, rm, symlink, writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { dirname, join, resolve } from 'node:path'
import { setTimeout as delay } from 'node:timers/promises'
import { fileURLToPath } from 'node:url'
import { _electron as electron } from 'playwright'
const scriptDir = dirname(fileURLToPath(import.meta.url))
const packageRoot = resolve(scriptDir, '..')
const repoRoot = resolve(packageRoot, '../..')
const recoveryId = '11234567-89ab-4cde-8fab-0123456789ab'
async function waitFor(check, label, timeoutMs = 60_000) {
const startedAt = Date.now()
let lastError
while (Date.now() - startedAt < timeoutMs) {
try {
const value = await check()
if (value) return value
} catch (error) {
lastError = error
}
await delay(250)
}
throw new Error(`Timed out waiting for ${label}: ${lastError?.message || lastError || ''}`)
}
const root = await realpath(await mkdtemp(join(tmpdir(), 'opensquilla-unsafe-profile-test-')))
const userData = join(root, 'user-data')
const isolatedHome = join(root, 'home')
const outside = join(root, 'outside')
const recoveryRoot = join(userData, 'recovery-profiles')
const selectedRoot = join(recoveryRoot, recoveryId)
await mkdir(recoveryRoot, { recursive: true })
await mkdir(isolatedHome, { recursive: true })
await mkdir(outside, { recursive: true })
const unsafeUpdateState = join(outside, 'opensquilla', 'state', 'desktop-update.json')
const unsafeUpdateBytes = JSON.stringify({
snoozedVersion: '0.0.1',
snoozedUntil: '2099-01-01T00:00:00.000Z',
}, null, 2)
await mkdir(dirname(unsafeUpdateState), { recursive: true })
await writeFile(unsafeUpdateState, unsafeUpdateBytes, 'utf8')
await symlink(outside, selectedRoot, process.platform === 'win32' ? 'junction' : 'dir')
await writeFile(
join(userData, 'desktop-profile-context.json'),
JSON.stringify({
schema_version: 1,
active_profile_kind: 'recovery',
active_recovery_id: recoveryId,
attention_acknowledgement: null,
updated_at: '2026-07-11T00:00:00.000Z',
}, null, 2),
'utf8',
)
let app
try {
app = await electron.launch({
args: ['--use-mock-keychain', `--user-data-dir=${userData}`, packageRoot],
env: {
...process.env,
HOME: isolatedHome,
USERPROFILE: isolatedHome,
OPENSQUILLA_DESKTOP_REPO_ROOT: repoRoot,
OPENSQUILLA_DESKTOP_SECRET_STORAGE: 'plain',
OPENSQUILLA_USER_STATE_DIR: join(isolatedHome, 'user-state'),
OPENSQUILLA_TEST_PROFILE_LOCK_ROOT: '1',
OPENSQUILLA_DESKTOP_GATEWAY_PORT: '18896',
OPENSQUILLA_DESKTOP_DISABLE_AUTO_UPDATE: '1',
OPENSQUILLA_DESKTOP_MOCK_UPDATE_VERSION: '9.9.9',
LANG: 'en_US.UTF-8',
LC_ALL: 'en_US.UTF-8',
},
})
const page = await waitFor(async () => {
for (const candidate of app.windows()) {
if (candidate.isClosed()) continue
await candidate.waitForLoadState('domcontentloaded', { timeout: 5_000 }).catch(() => {})
if (await candidate.locator('#recoveryPanel.visible').count().catch(() => 0)) return candidate
}
return null
}, 'unsafe recovery selection page')
assert.equal(
await page.locator('#recoveryCode').innerText(),
'desktop_selected_recovery_profile_unsafe',
)
await delay(1_000)
assert.deepEqual(await readdir(outside), ['opensquilla'])
assert.equal(
await readFile(unsafeUpdateState, 'utf8'),
unsafeUpdateBytes,
'updater persistence must not read or rewrite an unsafe selected recovery profile',
)
console.log(JSON.stringify({ ok: true, stableCode: 'desktop_selected_recovery_profile_unsafe' }))
} finally {
await app?.close().catch(() => {})
await rm(root, { recursive: true, force: true }).catch(() => {})
}