mirror of
https://github.com/shuaiplus/nodewarden.git
synced 2026-06-20 21:00:41 +00:00
fix: add support for trusted two-factor device tokens in backup import and export
This commit is contained in:
@@ -68,6 +68,7 @@ export interface BackupPayload {
|
||||
ciphers: SqlRow[];
|
||||
attachments: SqlRow[];
|
||||
webauthn_credentials?: SqlRow[];
|
||||
trusted_two_factor_device_tokens?: SqlRow[];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -302,6 +303,7 @@ export function validateBackupPayloadContents(
|
||||
const cipherRows = ensureRowArray(payload.db.ciphers, 'ciphers');
|
||||
const attachmentRows = ensureRowArray(payload.db.attachments, 'attachments');
|
||||
const accountPasskeyRows = ensureRowArray(payload.db.webauthn_credentials || [], 'webauthn_credentials');
|
||||
const trustedTwoFactorTokenRows = ensureRowArray(payload.db.trusted_two_factor_device_tokens || [], 'trusted_two_factor_device_tokens');
|
||||
const externalAttachmentKeys = new Set<string>(
|
||||
options.allowExternalAttachmentBlobs
|
||||
? (payload.manifest.attachmentBlobs || []).map((item) => `attachments/${String(item.cipherId || '').trim()}/${String(item.attachmentId || '').trim()}.bin`)
|
||||
@@ -390,6 +392,21 @@ export function validateBackupPayloadContents(
|
||||
accountPasskeyIds.add(id);
|
||||
accountPasskeyCredentialIds.add(credentialId);
|
||||
}
|
||||
|
||||
const trustedTwoFactorTokens = new Set<string>();
|
||||
for (const row of trustedTwoFactorTokenRows) {
|
||||
const token = String(row.token || '').trim();
|
||||
const userId = String(row.user_id || '').trim();
|
||||
const deviceIdentifier = String(row.device_identifier || '').trim();
|
||||
const expiresAt = Number(row.expires_at || 0);
|
||||
if (!token || !userIds.has(userId) || !deviceIdentifier || !Number.isFinite(expiresAt) || expiresAt <= 0) {
|
||||
throw new Error('Backup archive contains an invalid trusted two-factor device token row');
|
||||
}
|
||||
if (trustedTwoFactorTokens.has(token)) {
|
||||
throw new Error(`Backup archive contains duplicate trusted two-factor device token: ${token}`);
|
||||
}
|
||||
trustedTwoFactorTokens.add(token);
|
||||
}
|
||||
}
|
||||
|
||||
export async function buildBackupArchive(
|
||||
@@ -408,7 +425,7 @@ export async function buildBackupArchive(
|
||||
includeAttachments,
|
||||
});
|
||||
const encoder = new TextEncoder();
|
||||
const [configRows, userRows, domainSettingsRows, revisionRows, folderRows, cipherRows, attachmentRows, accountPasskeyRows] = await Promise.all([
|
||||
const [configRows, userRows, domainSettingsRows, revisionRows, folderRows, cipherRows, attachmentRows, accountPasskeyRows, trustedTwoFactorTokenRows] = await Promise.all([
|
||||
queryRows(env.DB, 'SELECT key, value FROM config ORDER BY key ASC'),
|
||||
queryRows(env.DB, 'SELECT id, email, name, master_password_hint, master_password_hash, key, private_key, public_key, kdf_type, kdf_iterations, kdf_memory, kdf_parallelism, security_stamp, role, status, verify_devices, totp_secret, totp_recovery_code, created_at, updated_at FROM users ORDER BY created_at ASC'),
|
||||
queryRows(env.DB, 'SELECT user_id, equivalent_domains, custom_equivalent_domains, excluded_global_equivalent_domains, updated_at FROM domain_settings ORDER BY user_id ASC'),
|
||||
@@ -417,6 +434,7 @@ export async function buildBackupArchive(
|
||||
queryRows(env.DB, 'SELECT id, user_id, type, folder_id, name, notes, favorite, data, reprompt, key, created_at, updated_at, archived_at, deleted_at FROM ciphers ORDER BY created_at ASC'),
|
||||
queryRows(env.DB, 'SELECT id, cipher_id, file_name, size, size_name, key FROM attachments ORDER BY cipher_id ASC, id ASC'),
|
||||
queryRows(env.DB, 'SELECT id, user_id, name, public_key, credential_id, counter, type, aa_guid, transports, encrypted_user_key, encrypted_public_key, encrypted_private_key, supports_prf, created_at, updated_at FROM webauthn_credentials ORDER BY created_at ASC'),
|
||||
queryRows(env.DB, 'SELECT token, user_id, device_identifier, expires_at FROM trusted_two_factor_device_tokens WHERE expires_at >= ? ORDER BY user_id ASC, device_identifier ASC, expires_at DESC', date.getTime()),
|
||||
]);
|
||||
const exportedConfigRows = sanitizeConfigRowsForExport(configRows);
|
||||
const exportedAttachmentRows = includeAttachments ? attachmentRows : [];
|
||||
@@ -445,6 +463,7 @@ export async function buildBackupArchive(
|
||||
ciphers: cipherRows.length,
|
||||
attachments: exportedAttachmentRows.length,
|
||||
webauthn_credentials: accountPasskeyRows.length,
|
||||
trusted_two_factor_device_tokens: trustedTwoFactorTokenRows.length,
|
||||
},
|
||||
includes: {
|
||||
attachments: includeAttachments,
|
||||
@@ -468,6 +487,7 @@ export async function buildBackupArchive(
|
||||
ciphers: cipherRows,
|
||||
attachments: exportedAttachmentRows,
|
||||
webauthn_credentials: accountPasskeyRows,
|
||||
trusted_two_factor_device_tokens: trustedTwoFactorTokenRows,
|
||||
}, null, BACKUP_JSON_INDENT)),
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user