Files
go_bt/tests/database_raw_account_line.test.js
T

125 lines
6.0 KiB
JavaScript

const assert = require('assert');
const fs = require('fs');
const os = require('os');
const path = require('path');
const Sqlite = require('better-sqlite3');
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'raw-account-line-'));
const dbPath = path.join(tempDir, 'accounts.db');
// 模拟升级前的 accounts 表,验证 initDB 会为旧库补列。
const legacyDb = new Sqlite(dbPath);
legacyDb.exec(`
CREATE TABLE accounts (
email TEXT PRIMARY KEY,
password TEXT,
recovery_email TEXT,
secret_key TEXT,
browser_id TEXT,
country TEXT,
sheerid_link TEXT,
status TEXT DEFAULT '未登录',
message TEXT,
status_reason TEXT,
proxy_ip TEXT,
is_exported INTEGER DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`);
legacyDb.close();
const Config = require('../src/core/config');
Config.DATA_DIR = tempDir;
Config.DB_PATH = dbPath;
const database = require('../src/core/database');
try {
database.initDB();
const columns = database.getDb().pragma('table_info(accounts)').map(row => row.name);
assert(columns.includes('raw_account_line'), '旧数据库应自动增加 raw_account_line');
assert(columns.includes('password_changed_at'), '旧数据库应自动增加改密时间字段');
const firstRaw = ' test@example.com----OldPass#1----helper@example.com----ABCDEF234567 ';
const result = database.importAccountsFromText(`# 注释\r\n${firstRaw}\r\n\r\n`);
assert.strictEqual(result.successCount, 1);
assert.strictEqual(result.errorCount, 0);
let account = database.getAccount('test@example.com');
assert.strictEqual(account.raw_account_line, firstRaw, '应原样保留有效账号整行');
assert.strictEqual(account.secret_key, 'abcdef234567', '字段解析仍可执行既有的 2FA 小写转换');
database.updateAccountPassword(account.email, 'ChangedPassword');
database.updateAccount2faKey(account.email, 'changed2fa');
account = database.getAccount(account.email);
assert.strictEqual(account.raw_account_line, firstRaw, '任务更新密码/2FA 不应改写导入原文');
assert.strictEqual(account.password_changed, 1, '成功保存新密码时应同步标记已改密');
assert.strictEqual(account.secret_key, 'changed2fa', '成功保存新2FA时应回填新密钥');
assert.strictEqual(account.fa_changed, 1, '新2FA密钥和已改2FA标记必须同时写入');
assert(account.password_changed_at, '成功保存新密码时应记录改密时间');
const securityDates = JSON.parse(account.security_dates);
assert(securityDates.passwordMonth && securityDates.passwordDay, '成功改密后应立即写入今天的密码日期');
database.updateAccountStatusReason(account.email, ' totp_code_wrong ');
account = database.getAccount(account.email);
assert.strictEqual(account.status_reason, 'TOTP_CODE_WRONG', '失败原因码应标准化后持久化');
database.updateAccountStatusReason(account.email, null);
account = database.getAccount(account.email);
assert.strictEqual(account.status_reason, null, '登录成功后应能清除旧失败原因');
assert.strictEqual(account.raw_account_line, firstRaw, '原因码更新不应改写导入原文');
const latestRaw = 'test@example.com----LatestPass----LATEST234567';
database.importAccountsFromText(latestRaw);
account = database.getAccount(account.email);
assert.strictEqual(account.raw_account_line, latestRaw, '重复导入应保存最新一次原文');
const beforeSkippedImport = { ...account };
const skipped = database.importAccountsFromText(
'TEST@example.com----MustNotReplace----SKIPPED234567',
'----',
'待检查',
null,
'新客户',
true,
);
account = database.getAccount(account.email);
assert.strictEqual(skipped.successCount, 0, '勾选跳过重复后不应把重复邮箱计为导入成功');
assert.strictEqual(skipped.skippedCount, 1, '邮箱大小写不同时也应识别为重复');
assert.deepStrictEqual(account, beforeSkippedImport, '跳过重复邮箱后账号全部字段都应保持不变');
assert.deepStrictEqual(skipped.importedEmails, [], '跳过的邮箱不应进入导入后的自动初始化名单');
const sameBatch = database.importAccountsFromText(
'new@example.com----FirstPassword\nNEW@example.com----SecondPassword',
'----',
'未登录',
null,
null,
true,
);
assert.strictEqual(sameBatch.successCount, 1, '同一批次首次出现的邮箱应正常导入');
assert.strictEqual(sameBatch.skippedCount, 1, '同一批次后续重复邮箱应跳过');
assert.strictEqual(database.getAccount('new@example.com').password, 'FirstPassword', '同批重复行不应覆盖首次导入内容');
database.updateAccountTag(account.email, '家庭组母号');
database.updateAccount2faKey(account.email, 'familychanged2fa');
account = database.getAccount(account.email);
assert.strictEqual(account.secret_key, 'familychanged2fa', '家庭组母号的任务2FA回写也不得被导入保护跳过');
assert.strictEqual(account.fa_changed, 1, '家庭组母号应正常保留已改2FA标记');
const protectedRaw = 'test@example.com----MustNotReplace----PROTECTED234';
database.importAccountsFromText(protectedRaw);
account = database.getAccount(account.email);
assert.strictEqual(account.raw_account_line, latestRaw, '家庭组母号重复导入时仍应整体跳过');
database.updateAccountStatus(account.email, '登录成功');
database.updateAccountMessage(account.email, '✅ 登录成功');
account = database.getAccount(account.email);
assert.strictEqual(account.status, '登录成功', '家庭组母号的任务状态不应被导入保护拦截');
assert.strictEqual(account.message, '✅ 登录成功', '家庭组母号的任务消息不应保留旧错误');
assert.strictEqual(account.raw_account_line, latestRaw, '任务状态/消息更新不应改写导入原文');
console.log('database_raw_account_line.test.js: PASS');
} finally {
try { database.getDb().close(); } catch (_) {}
fs.rmSync(tempDir, { recursive: true, force: true });
}