feat: 修改UI,保持风格统一

This commit is contained in:
nap0o committed 2026-03-16 21:07:15 +08:00
1 parent 6ce7b828e0
commit 552ceb378b
16 files changed
+85 -87

No files matched your search

@@ -237,19 +237,13 @@
.migration-ms-tip code {
display: block;
margin-top: 6px;
padding: 6px 10px;
background: rgba(0, 0, 0, 0.05);
border-radius: 4px;
font-family: var(--el-font-family-mono);
font-size: 11px;
word-break: break-all;
color: var(--el-text-color-regular);
border: 1px solid rgba(0, 0, 0, 0.05);
}
html.dark .migration-ms-tip code {
background: rgba(255, 255, 255, 0.05);
border-color: rgba(255, 255, 255, 0.1);
color: var(--el-text-color-secondary);
}
@@ -129,6 +129,10 @@ export function useDataExport() {
mimeType = 'text/csv'
filename = `2fauth-worker-export-csv-${date}.csv`
break
case 'bitwarden_auth_csv':
mimeType = 'text/csv'
filename = `2fauth-worker-export-bitwarden-auth-${date}.csv`
break
case 'bitwarden_auth_json':
mimeType = 'application/json'
filename = `2fauth-worker-export-bitwarden-auth-${date}.json`
@@ -182,7 +182,7 @@ export function useDataImport(emitFn) {
}
}
if (detectedType === '2fauth_encrypted' || detectedType === 'aegis_encrypted' || detectedType === 'proton_auth_encrypted' || detectedType === 'proton_pass_pgp' || detectedType === '2fas_encrypted' || detectedType === 'ente_encrypted' || detectedType === 'bitwarden_vault_encrypted') {
if (detectedType === '2fauth_encrypted' || detectedType === 'aegis_encrypted' || detectedType === 'proton_auth_encrypted' || detectedType === 'proton_pass_pgp' || detectedType === '2fas_encrypted' || detectedType === 'ente_encrypted' || detectedType === 'bitwarden_pass_encrypted') {
importPassword.value = ''
isDialogHandled.value = false
showDecryptDialog.value = true
@@ -35,7 +35,7 @@ export const dataMigrationService = {
* 智能识别导入内容或文件的类型
* @param {string|ArrayBuffer|Uint8Array} content - 文件文本内容或二进制数据
* @param {string} filename - 文件名
* @returns {'bitwarden_vault_csv'|'bitwarden_auth_csv'|'generic_csv'|'generic_text'|'bitwarden_vault_json'|'bitwarden_auth_json'|'bitwarden_vault_encrypted'|'2fauth_encrypted'|'2fauth_json'|'2fas'|'2fas_encrypted'|'aegis'|'aegis_encrypted'|'phonefactor'|'1password_pux'|'lastpass_auth_json'|'unknown'} 返回类型标识
* @returns {'bitwarden_pass_csv'|'bitwarden_auth_csv'|'generic_csv'|'generic_text'|'bitwarden_pass_json'|'bitwarden_auth_json'|'bitwarden_pass_encrypted'|'2fauth_encrypted'|'2fauth_json'|'2fas'|'2fas_encrypted'|'aegis'|'aegis_encrypted'|'phonefactor'|'1password_pux'|'lastpass_auth_json'|'unknown'} 返回类型标识
*/
detectFileType(content, filename) {
// 如果是二进制数据,尝试用更宽容的方式判断 PhoneFactor
@@ -74,7 +74,7 @@ export const dataMigrationService = {
if (filename && filename.toLowerCase().endsWith('.csv')) {
const firstLine = typeof textContent === 'string' ? textContent.split('\n')[0].toLowerCase() : ''
if (firstLine.includes('login_totp')) return 'bitwarden_vault_csv'
if (firstLine.includes('login_totp')) return 'bitwarden_pass_csv'
if (firstLine.includes('title') && firstLine.includes('otpauth')) return '1password_csv'
if (firstLine.includes('otpauth')) return 'bitwarden_auth_csv'
if (firstLine.includes('totp') && firstLine.includes('vault') && firstLine.includes('createtime')) return 'proton_pass_csv'
@@ -89,8 +89,8 @@ export const dataMigrationService = {
if (typeof textContent === 'string') {
const json = tryParseJSON(textContent)
if (json) {
// 如果包含 folders 字段,通常是 Bitwarden Vault (密码管理器)
if (Array.isArray(json.items) && Array.isArray(json.folders)) return 'bitwarden_vault_json'
// 如果包含 folders 字段,通常是 Bitwarden Pass (密码管理器)
if (Array.isArray(json.items) && Array.isArray(json.folders)) return 'bitwarden_pass_json'
// 如果只包含 items 且是明文,归类为 bitwarden_auth_json (之前测试过的独立 App 路径)
if (Array.isArray(json.items) && (json.encrypted === false || !('encrypted' in json))) return 'bitwarden_auth_json'
if (json.encrypted === true && json.app === '2fauth') return '2fauth_encrypted'
@@ -105,8 +105,8 @@ export const dataMigrationService = {
if (json.version === 1 && typeof json.salt === 'string' && typeof json.content === 'string') return 'proton_auth_encrypted'
// Ente Auth 加密导出:同时包含 kdfParams 和 encryptedData 两个关键字段
if (json.kdfParams && typeof json.encryptedData === 'string') return 'ente_encrypted'
// Bitwarden password-protected export (Vault)
if (json.encrypted === true && json.passwordProtected === true && json.encKeyValidation_DO_NOT_EDIT) return 'bitwarden_vault_encrypted'
// Bitwarden Password password-protected export
if (json.encrypted === true && json.passwordProtected === true && json.encKeyValidation_DO_NOT_EDIT) return 'bitwarden_pass_encrypted'
}
}
@@ -249,18 +249,19 @@ export const dataMigrationService = {
}).join('\n')
}
if (type === 'bitwarden_auth_csv') {
let csv = 'name,secret,totp,favorite,folder\n'
vault.forEach(acc => {
const name = `"${acc.service}${acc.account ? ':' + acc.account : ''}"`
const label = encodeURIComponent(`${acc.service}:${acc.account}`)
const issuer = encodeURIComponent(acc.service)
const totp = `"otpauth://totp/${label}?secret=${acc.secret}&issuer=${issuer}&digits=${acc.digits}&period=${acc.period}"`
csv += `${name},${acc.secret},${totp},0,\n`
})
return csv
}
if (type === 'generic_csv') {
if (variant === 'bitwarden_auth') {
let csv = 'name,secret,totp,favorite,folder\n'
vault.forEach(acc => {
const name = `"${acc.service}${acc.account ? ':' + acc.account : ''}"`
const label = encodeURIComponent(`${acc.service}:${acc.account}`)
const issuer = encodeURIComponent(acc.service)
const totp = `"otpauth://totp/${label}?secret=${acc.secret}&issuer=${issuer}&digits=${acc.digits}&period=${acc.period}"`
csv += `${name},${acc.secret},${totp},0,\n`
})
return csv
}
// generic csv
let csv = 'name,issuer,secret,algorithm,digits,period,type\n'
vault.forEach(acc => {
@@ -653,7 +654,7 @@ export const dataMigrationService = {
* @param {Object} json
* @returns {Promise<Object>} 解密后的 JSON 对象
*/
async decryptBitwardenVaultEncrypted(password, json) {
async decryptBitwardenPassEncrypted(password, json) {
try {
const saltStr = json.salt;
const iterations = json.kdfIterations;
@@ -666,7 +667,7 @@ export const dataMigrationService = {
// 1. 衍生主密钥: 关键是直接使用 salt 字符串作为 UTF-8 字节输入
const saltBytes = new TextEncoder().encode(saltStr);
const passwordBytes = new TextEncoder().encode(password);
const keyMaterialHandle = await crypto.subtle.importKey(
'raw', passwordBytes, { name: 'PBKDF2' }, false, ['deriveBits']
);
@@ -1146,14 +1147,14 @@ export const dataMigrationService = {
}
// 处理 Bitwarden 加密导出 (Password-protected Vault)
if (type === 'bitwarden_vault_encrypted') {
if (type === 'bitwarden_pass_encrypted') {
if (!password) throw new migrationError('导入 Bitwarden 加密文件需要密码', 'MISSING_PASSWORD')
try {
const bitwardenJson = typeof content === 'string' ? JSON.parse(content) : content
const decrypted = await this.decryptBitwardenVaultEncrypted(password, bitwardenJson)
// 解密后的格式就是普通的 bitwarden_vault_json 结构(有 items 数组)
const decrypted = await this.decryptBitwardenPassEncrypted(password, bitwardenJson)
// 解密后的格式就是普通的 bitwarden_pass_json 结构(有 items 数组)
content = JSON.stringify(decrypted)
type = 'bitwarden_vault_json'
type = 'bitwarden_pass_json'
password = undefined
} catch (e) {
if (e instanceof migrationError) throw e
@@ -1225,7 +1226,7 @@ export const dataMigrationService = {
})
}
}
else if (type === 'bitwarden_vault_json' || type === 'bitwarden_auth_json') {
else if (type === 'bitwarden_pass_json' || type === 'bitwarden_auth_json') {
const json = typeof content === 'string' ? JSON.parse(content) : content
if (Array.isArray(json.items)) {
json.items.forEach(item => {
@@ -1288,7 +1289,7 @@ export const dataMigrationService = {
}))
}
}
else if (type === 'bitwarden_vault_csv' || type === 'bitwarden_auth_csv' || type === '1password_csv' || type === 'proton_pass_csv' || type === 'dashlane_csv' || type === 'generic_csv') rawVault = csvStrategy.parseCsv(content)
else if (type === 'bitwarden_pass_csv' || type === 'bitwarden_auth_csv' || type === '1password_csv' || type === 'proton_pass_csv' || type === 'dashlane_csv' || type === 'generic_csv') rawVault = csvStrategy.parseCsv(content)
return rawVault.map(acc => {
if (typeof acc.account === 'string' && acc.account.includes(':')) {
@@ -1357,15 +1358,15 @@ export const dataMigrationService = {
const bytes = content instanceof Uint8Array ? content : new Uint8Array(content)
const unzipped = unzipSync(bytes)
const dataFileContent = unzipped['export.data']
if (!dataFileContent) throw new Error('未能在 .1pux 文件中找到 export.data')
const text = new TextDecoder().decode(dataFileContent)
const data = JSON.parse(text)
const rawVault = []
const accounts = data.accounts || []
accounts.forEach(account => {
const vaults = account.vaults || []
vaults.forEach(vault => {
@@ -1373,7 +1374,7 @@ export const dataMigrationService = {
items.forEach(item => {
const title = item.overview?.title || 'Unknown'
const subtitle = item.overview?.subtitle || ''
// 1PUX 的 TOTP 字段路径通常在 sections[].fields 或是 loginFields 中
const checkFields = (fields) => {
if (!Array.isArray(fields)) return
@@ -1390,7 +1391,7 @@ export const dataMigrationService = {
}
})
}
checkFields(item.details?.loginFields)
if (Array.isArray(item.details?.sections)) {
item.details.sections.forEach(section => checkFields(section.fields))
@@ -1398,7 +1399,7 @@ export const dataMigrationService = {
})
})
})
return rawVault
} catch (e) {
throw new migrationError('解析 1Password 备份失败: ' + (e.message || String(e)), 'ONEPASSWORD_PARSE_FAILED', e)
@@ -41,7 +41,7 @@
<el-icon><iconGoogleAuth /></el-icon> {{ $t('migration.migrate_ga') }}
</el-button>
<el-button plain @click="openWarningDialog('bitwarden_auth_json')" class="migration-button-with-icon">
<el-icon><iconBitwarden /></el-icon> Bitwarden Auth (.json)
<el-icon><iconBitwardenAuth /></el-icon> Bitwarden Auth (.json)
</el-button>
</div>
</div>
@@ -177,7 +177,7 @@ import {
import icon2FAS from '@/shared/components/icons/icon2FAS.vue'
import iconAegis from '@/shared/components/icons/iconAegis.vue'
import iconGoogleAuth from '@/shared/components/icons/iconGoogleAuth.vue'
import iconBitwarden from '@/shared/components/icons/iconBitwarden.vue'
import iconBitwardenAuth from '@/shared/components/icons/iconBitwardenAuth.vue'
import { useLayoutStore } from '@/shared/stores/layoutStore'
import { useDataExport } from '@/features/migration/composables/useDataExport'
import { i18n } from '@/locales'
@@ -60,7 +60,7 @@
{{ $t('migration.password_manager_format') }}
</h4>
<div class="ecosystem-grid">
<el-button plain class="migration-button-with-icon" @click="triggerUpload"><el-icon><iconBitwarden /></el-icon> Bitwarden Vault (.json/.csv)</el-button>
<el-button plain class="migration-button-with-icon" @click="triggerUpload"><el-icon><iconBitwardenPass /></el-icon> Bitwarden Pass (.json/.csv)</el-button>
<el-button plain class="migration-button-with-icon" @click="triggerUpload"><el-icon><icon1Password /></el-icon> 1Password (.1pux/.csv)</el-button>
<el-button plain class="migration-button-with-icon" @click="triggerUpload"><el-icon><iconProtonPass /></el-icon> Proton Pass (.pgp/.csv)</el-button>
<el-button plain class="migration-button-with-icon" @click="triggerUpload"><el-icon><iconDashlanePass /></el-icon> Dashlane (.csv)</el-button>
@@ -76,7 +76,7 @@
<div class="ecosystem-grid">
<el-button plain class="migration-button-with-icon" @click="triggerUpload"><el-icon><icon2FAS /></el-icon> 2FAS (.2fas)</el-button>
<el-button plain class="migration-button-with-icon" @click="triggerUpload"><el-icon><iconAegis /></el-icon> Aegis (.json/.txt)</el-button>
<el-button plain class="migration-button-with-icon" @click="triggerUpload"><el-icon><iconBitwarden /></el-icon> Bitwarden Auth (.json/.csv)</el-button>
<el-button plain class="migration-button-with-icon" @click="triggerUpload"><el-icon><iconBitwardenAuth /></el-icon> Bitwarden Auth (.json/.csv)</el-button>
<el-button plain class="migration-button-with-icon" @click="triggerUpload"><el-icon><iconProtonAuth /></el-icon> Proton Auth(.json)</el-button>
<el-button plain class="migration-button-with-icon" @click="triggerUpload"><el-icon><iconEnte /></el-icon> Ente Auth(.txt)</el-button>
<el-button plain class="migration-button-with-icon" @click="triggerUpload"><el-icon><iconGoogleAuth /></el-icon> Google Auth (.png/.jpg)</el-button>
@@ -111,7 +111,7 @@
</div>
<div class="migration-ms-tip">
<span><el-icon><iconMicrosoftAuth /></el-icon> {{ $t('migration.ms_auth_desc') }}</span>
<p>{{ $t('migration.ms_auth_detail') }}:</p>
<p>{{ $t('migration.ms_auth_detail') }}</p>
<div class="code-block-wrapper">
<code>/data/data/com.azure.authenticator/databases/PhoneFactor</code>
<code>/data/data/com.azure.authenticator/databases/PhoneFactor-wal</code>
@@ -155,7 +155,7 @@
<el-alert v-else-if="currentImportType === 'proton_pass_pgp'" :title="$t('migration.detect_proton_pass')" type="warning" :closable="false" class="mb-15" />
<el-alert v-else-if="currentImportType === '2fas_encrypted'" :title="$t('migration.detect_2fas')" type="warning" :closable="false" class="mb-15" />
<el-alert v-else-if="currentImportType === 'ente_encrypted'" :title="$t('migration.detect_ente')" type="warning" :closable="false" class="mb-15" />
<el-alert v-else-if="currentImportType === 'bitwarden_vault_encrypted'" :title="$t('migration.detect_bitwarden_vault')" type="warning" :closable="false" class="mb-15" />
<el-alert v-else-if="currentImportType === 'bitwarden_pass_encrypted'" :title="$t('migration.detect_bitwarden_pass')" type="warning" :closable="false" class="mb-15" />
<el-alert v-else :title="$t('migration.detect_system')" type="success" :closable="false" class="mb-15" />
<el-form label-position="top">
<el-form-item :label="$t('migration.input_decrypt_pwd_label')">
@@ -188,7 +188,8 @@ const triggerUpload = () => {
import icon2FAS from '@/shared/components/icons/icon2FAS.vue'
import iconAegis from '@/shared/components/icons/iconAegis.vue'
import iconGoogleAuth from '@/shared/components/icons/iconGoogleAuth.vue'
import iconBitwarden from '@/shared/components/icons/iconBitwarden.vue'
import iconBitwardenPass from '@/shared/components/icons/iconBitwardenPass.vue'
import iconBitwardenAuth from '@/shared/components/icons/iconBitwardenAuth.vue'
import iconMicrosoftAuth from '@/shared/components/icons/iconMicrosoftAuth.vue'
import iconDashlanePass from '@/shared/components/icons/iconDashlanePass.vue'
import iconProtonAuth from '@/shared/components/icons/iconProtonAuth.vue'
@@ -110,12 +110,12 @@ import Icon2FAS from '@/shared/components/icons/icon2FAS.vue'
import IconAegis from '@/shared/components/icons/iconAegis.vue'
import IconEnte from '@/shared/components/icons/iconEnte.vue'
import IconProtonAuth from '@/shared/components/icons/iconProtonAuth.vue'
import IconBitwarden from '@/shared/components/icons/iconBitwarden.vue'
import IconBitwardenAuth from '@/shared/components/icons/iconBitwardenAuth.vue'
import IconMicrosoftAuth from '@/shared/components/icons/iconMicrosoftAuth.vue'
import IconGoogleAuth from '@/shared/components/icons/iconGoogleAuth.vue'
import IconFreeOTP from '@/shared/components/icons/iconFreeOTP.vue'
import IconAuthy from '@/shared/components/icons/iconAuthy.vue'
import IconLastPass from '@/shared/components/icons/iconLastPass.vue'
import iconLastPassAuth from '@/shared/components/icons/iconLastPassAuth.vue'
import IconRaivo from '@/shared/components/icons/iconRaivo.vue'
const appList = [
@@ -123,12 +123,12 @@ const appList = [
{ id: 'ente', name: 'Ente Auth', rating: 4.8, icon: IconEnte, link: 'https://ente.io/auth/', recommended: true, securityIssue: false, downloads: { ios: 'https://apps.apple.com/app/ente-authenticator/id6444101188', android: 'https://play.google.com/store/apps/details?id=io.ente.auth', fdroid: 'https://f-droid.org/packages/io.ente.auth', github: 'https://github.com/ente-io/ente/releases', desktop: 'https://ente.io/download/auth/desktop' } },
{ id: 'aegis', name: 'Aegis Authenticator', rating: 4.8, icon: IconAegis, link: 'https://getaegis.app/', recommended: true, securityIssue: false, downloads: { android: 'https://play.google.com/store/apps/details?id=com.beemdevelopment.aegis', fdroid: 'https://f-droid.org/packages/com.beemdevelopment.aegis/', github: 'https://github.com/beemdevelopment/Aegis/releases' } },
{ id: 'proton', name: 'Proton Authenticator', rating: 4.5, icon: IconProtonAuth, link: 'https://proton.me/pass', recommended: false, securityIssue: false, downloads: { ios: 'https://apps.apple.com/us/app/proton-pass-password-manager/id6443490729', android: 'https://play.google.com/store/apps/details?id=me.proton.android.pass', extension: 'https://chrome.google.com/webstore/detail/proton-pass-free-password/ghmbeldphafepmbegfdlkmapnddhbheg' } },
{ id: 'bitwarden', name: 'Bitwarden Authenticator', rating: 4.2, icon: IconBitwarden, link: 'https://bitwarden.com/products/authenticator/', recommended: false, securityIssue: false, downloads: { ios: 'https://apps.apple.com/us/app/bitwarden-authenticator/id6475654992', android: 'https://play.google.com/store/apps/details?id=com.bitwarden.authenticator', github: 'https://github.com/bitwarden/authenticator/releases' } },
{ id: 'bitwarden', name: 'Bitwarden Authenticator', rating: 4.2, icon: IconBitwardenAuth, link: 'https://bitwarden.com/products/authenticator/', recommended: false, securityIssue: false, downloads: { ios: 'https://apps.apple.com/us/app/bitwarden-authenticator/id6475654992', android: 'https://play.google.com/store/apps/details?id=com.bitwarden.authenticator', github: 'https://github.com/bitwarden/authenticator/releases' } },
{ id: 'google', name: 'Google Authenticator', rating: 4.0, icon: IconGoogleAuth, link: 'https://safety.google/authentication/', recommended: false, securityIssue: false, downloads: { ios: 'https://apps.apple.com/us/app/google-authenticator/id388497605', android: 'https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2' } },
{ id: 'freeotp', name: 'FreeOTP', rating: 3.0, icon: IconFreeOTP, link: 'https://freeotp.github.io/', recommended: false, securityIssue: false, downloads: { ios: 'https://apps.apple.com/us/app/freeotp-authenticator/id872559395', android: 'https://play.google.com/store/apps/details?id=org.fedorahosted.freeotp', fdroid: 'https://f-droid.org/en/packages/org.fedorahosted.freeotp/' } },
{ id: 'microsoft', name: 'Microsoft Authenticator', rating: 2.0, icon: IconMicrosoftAuth, link: 'https://www.microsoft.com/en-us/security/mobile-authenticator-app', recommended: false, securityIssue: true, downloads: { ios: 'https://apps.apple.com/us/app/microsoft-authenticator/id983156458', android: 'https://play.google.com/store/apps/details?id=com.azure.authenticator' } },
{ id: 'authy', name: 'Authy', rating: 1.5, icon: IconAuthy, link: 'https://authy.com/', recommended: false, securityIssue: true, downloads: { ios: 'https://apps.apple.com/us/app/twilio-authy/id494168017', android: 'https://play.google.com/store/apps/details?id=com.authy.authy' } },
{ id: 'lastpass', name: 'LastPass Auth', rating: 1.5, icon: IconLastPass, link: 'https://www.lastpass.com/auth', recommended: false, securityIssue: true, downloads: { ios: 'https://apps.apple.com/us/app/lastpass-authenticator/id1079110004', android: 'https://play.google.com/store/apps/details?id=com.lastpass.authenticator' } },
{ id: 'lastpass', name: 'LastPass Auth', rating: 1.5, icon: iconLastPassAuth, link: 'https://www.lastpass.com/auth', recommended: false, securityIssue: true, downloads: { ios: 'https://apps.apple.com/us/app/lastpass-authenticator/id1079110004', android: 'https://play.google.com/store/apps/details?id=com.lastpass.authenticator' } },
{ id: 'raivo', name: 'Raivo OTP', rating: 1.0, icon: IconRaivo, link: 'https://raivo-otp.com/', recommended: false, securityIssue: true, downloads: { ios: 'https://apps.apple.com/us/app/raivo-otp/id1459042137' } }
]
</script>
+5 -5
View File
@@ -372,10 +372,10 @@
"center_desc": "Support restoring data from various 2FA apps or system backups.",
"auto_identify_tip": "💡 Automatically recognize file types",
"drag_drop_tip": "Drag backup files or migration QR screenshots here, or <em>click to upload</em>",
"support_desc": "Supported List",
"support_desc": "Support List",
"ga_auth_desc": "Export 'Transfer QR code' in the App and upload the screenshot (.png / .jpg)",
"ms_auth_desc": "Microsoft Authenticator (Android Only)",
"ms_auth_detail": "Export the following 3 files from Android and upload them together",
"ms_auth_desc": "Microsoft Authenticator",
"ms_auth_detail": "Only support Android, export the following 3 files and upload them together",
"import_guide": "Import Guide",
"batch_import_processing": "📦 Batch Import Processing",
"batch_progress": "{processed} / {total} tasks completed",
@@ -385,13 +385,13 @@
"detect_proton_pass": "Proton Pass encrypted backup detected (.pgp)",
"detect_2fas": "2FAS Auth encrypted backup detected",
"detect_ente": "Ente Auth encrypted backup detected",
"detect_bitwarden_vault": "Bitwarden Vault encrypted backup detected",
"detect_bitwarden_pass": "Bitwarden Pass encrypted backup detected",
"detect_system": "System encrypted backup detected",
"input_decrypt_pwd_label": "Please enter the decryption password:",
"input_decrypt_pwd_placeholder": "Enter the password set during export",
"confirm_decrypt_import": "Confirm Decrypt & Import",
"system_backup_format": "System Backup",
"password_manager_format": "Password Manager (Vault)",
"password_manager_format": "Password Manager",
"encrypted_backup_json": "Encrypted Backup (.json)",
"plaintext_backup_json": "Plaintext Backup (.json)",
"mobile_app_format": "Mobile 2FA Apps",
+4 -4
View File
@@ -374,8 +374,8 @@
"drag_drop_tip": "将备份文件或迁移二维码截图拖到此处,或 <em>点击上传</em>",
"support_desc": "支持列表",
"ga_auth_desc": "请在 App 内导出\"迁移二维码\",将截图直接上传 (.png / .jpg)",
"ms_auth_desc": "Microsoft Authenticator (仅支持 Android)",
"ms_auth_detail": "Android 手机导出以下3个文件后,同时选中上传即可导入",
"ms_auth_desc": "Microsoft Authenticator",
"ms_auth_detail": "仅支持 Android 手机,导出以下3个文件后,同时选中上传即可导入",
"import_guide": "导入指南",
"batch_import_processing": "📦 批量导入处理中",
"batch_progress": "{processed} / {total} 任务已完成",
@@ -385,13 +385,13 @@
"detect_proton_pass": "检测到 Proton Pass 加密备份 (.pgp)",
"detect_2fas": "检测到 2FAS Auth 加密备份",
"detect_ente": "检测到 Ente Auth 加密备份",
"detect_bitwarden_vault": "检测到 Bitwarden Vault 加密备份",
"detect_bitwarden_pass": "检测到 Bitwarden Pass 加密备份",
"detect_system": "检测到本系统加密备份",
"input_decrypt_pwd_label": "请输入该备份的解密密码:",
"input_decrypt_pwd_placeholder": "输入当时设置的导出密码",
"confirm_decrypt_import": "确认解密并导入",
"system_backup_format": "本系统备份",
"password_manager_format": "密码管理器 (Vault)",
"password_manager_format": "密码管理器",
"encrypted_backup_json": "加密备份 (.json)",
"plaintext_backup_json": "明文备份 (.json)",
"mobile_app_format": "移动端 2FA App",
@@ -0,0 +1,12 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="4 4 40 40">
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin:round; stroke-width="3" d="M24,34.7977c4.7152-2.5049,7.7884-5.8753,7.7884-8.6581v-11.1835h-7.7761l-.0123,19.8417Z"/>
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin:round; stroke-width="3" d="M23.3973,38.3619c.3782.1842.8271.1842,1.2053,0,6.0876-2.9643,10.6295-7.5417,10.6295-12.2221v-13.2574c0-.7635-.6189-1.3824-1.3824-1.3824h-9.8497,0-9.8497c-.7635,0-1.3824.6189-1.3824,1.3824v13.2574c0,4.6804,4.5419,9.2578,10.6295,12.2221Z"/><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin:round; stroke-width="3" d="M16,5.5h-6.5c-2.2091,0-4,1.7909-4,4v6.5"/>
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin:round; stroke-width="3" d="M42.5,16v-6.5c0-2.2091-1.7909-4-4-4h-6.5"/>
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin:round; stroke-width="3" d="M5.5,32v6.5c0,2.2091,1.7909,4,4,4h6.5"/>
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin:round; stroke-width="3" d="M32,42.5h6.5c2.2091,0,4-1.7909,4-4v-6.5"/>
</svg>
</template>
<script>
export default { name: 'iconBitwardenAuth' }
</script>
@@ -4,5 +4,5 @@
</svg>
</template>
<script>
export default { name: 'iconBitwarden' }
export default { name: 'iconBitwardenPass' }
</script>
@@ -1,10 +1,7 @@
<template>
<svg width="1em" height="1em" viewBox="0 0 454 468" xmlns="http://www.w3.org/2000/svg" fill="none">
<g fill="none">
<path fill="#606266" d="M124.721 124.711h204.043v247.898H124.721z"/>
<path d="M231.893 4.782c22.837 0 45.232 3.271 66.559 9.733 19.11 5.504 37.435 14.01 54.464 25.27 16.479 10.895 31.477 24.18 44.583 39.487a220.5 220.5 0 0 1 32.269 50.016h-.001c8.574 18.34 14.46 37.552 17.483 57.106l.192 1.229c1.937 12.703 2.013 25.205.2 37.17-1.904 12.564-5.848 24.284-11.747 34.811-6.1 10.881-14.132 20.212-23.87 27.705l-.001-.001c-8.2 6.311-17.45 11.189-27.55 14.562 11.375 9.056 19.43 21.427 23.342 35.782 3.843 12.629 4.776 24.886 2.619 36.382-2.022 10.773-6.74 20.83-13.94 29.881-12.835 16.136-31.665 26.895-47.787 35.076l-.011.006-.176.088-.025.012-.14.066.002.001c-32.527 15.734-65.021 26.327-108.9 24.201-51.681-.009-101.245-15.172-139.578-42.863-23.531-16.13-43.386-37.091-59.03-62.269v-.001c-14.876-23.947-25.302-50.624-31.003-79.267-5.638-28.338-6.344-57.025-2.09-85.255 4.404-29.227 13.92-56.432 28.304-80.831 19.258-33.56 48.323-61.333 84.019-80.365 34.037-18.149 72.7-27.732 111.813-27.732Zm1.872 303.849c-14.221 0-30.265.004-46.556.031 4.284 2.079 9.138 3.788 14.376 5.137 10.413 2.682 21.975 3.849 32.748 3.849 14.302 0 28.488-1.952 38.878-5.254l.007-.002.008-.002.396-.125c5.32-1.678 8.303-2.625 10.914-3.634-4.41.001-8.693.005-12.804.005l-18.98-.003zm-3.015-159.163c-21.936 0-40.748 7.911-52.012 20.655l4.825.008 4.287.006v.002c18.074.03 38.117.061 57.359.061 14.692 0 27.31-.02 38.159-.056-12.385-14.39-32.161-20.3-48.148-20.601l-.864-.011h-.29l-.085-.003-.231-.008v-.001q-1.5-.052-3-.052Z" stroke="#606266" stroke-width="8.584" fill="#606266" />
<path d="M168.883 288.253c53.36-.153 108.51.004 161.633-.125 14.068-.058 28.41-.109 42.01-4.033 41.462-10.707 61.786-49.764 54.53-94.496-11.023-71.552-64.42-135.37-134.367-155.465-87.93-26.72-192.407 7.776-238.96 89.042-53.35 90.405-29.486 220.858 57.92 280.601 63.819 46.237 157.469 51.004 227.81 16.981 31.953-16.217 61.253-36.825 48.708-77.458-7.142-26.754-33.907-41.473-59.177-32.829-8.374 2.502-16.03 6.821-23.675 10.844-11.421 6.022-13.471 6.645-25.903 10.567-35.94 11.425-108.641 10.036-127.256-29.492-2.597-11.349 7.654-14.147 16.692-14.137h.037zm-11.421-98.904c-3.965-1.465-6.606-5.292-6.405-9.519.104-3.66 1.745-7.217 3.45-10.437 14.77-27.747 47.468-41.443 79.984-40.308 30.405.189 62.265 15.363 75.182 44.89.985 2.49 1.604 5.08 1.276 7.598-.921 6.622-6.973 8.956-12.912 8.956-37.695.226-94.344.078-133.51.023-2.266-.072-4.777-.302-7.023-1.184l-.042-.016z" fill="#eeeeee"/>
</g>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="2 2 44 44">
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M25.8709,14.0934c2.9838,0,5.5018,1.3454,7.1206,3.5599.6876.9406.0103,2.2655-1.1548,2.2655h-12.5302c-1.1972,0-1.8737-1.3963-1.1123-2.3202,1.787-2.1683,4.5133-3.5052,7.6766-3.5052ZM15.56,7.05c2.98-1.79,6.51-2.81,10.31-2.81,5.3,0,10.17,2.1,13.69,5.93,2.39,2.59,4.02,5.81,4.77,9.34,1.03,4.88-2.73,9.47-7.72,9.47h-17.27c-1.04,0-1.56,1.24-.84,1.99,1.9,2,4.64,2.94,7.37,2.94,2.79,0,5.43-.74,7.43-2.09,2.27-1.53,5.37-.91,6.87,1.39,1.51,2.29.72,5.42-1.57,6.92-3.58,2.35-8.09,3.63-12.73,3.63-5.29,0-10.21-1.89-13.84-5.34-3.82-3.63-5.92-8.75-5.92-14.42,0-3.16.71-6.13,1.97-8.75"/>
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M15.8791,7.9625c-.3682-1.8321-2.152-3.0187-3.984-2.6505-1.2062.2424-2.129,1.0999-2.5161,2.1792-.8843-.9663-2.3014-1.3955-3.678-.8924-1.2709.4645-2.1481,1.687-2.1985,3.0391-.0276.739.1779,1.3948.5244,1.9416,1.3187,2.2356,4.8441,4.2132,6.4486,5.0284.4814.2446,1.0652.1272,1.4147-.2844,1.1649-1.3719,3.6524-4.558,4.005-7.1295.0674-.3974.0681-.8127-.016-1.2316h0Z"/>
</svg>
</template>
<script>
@@ -1,10 +1,6 @@
<template>
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" height="24" width="24" fill="none">
<path d="M21 6C20.4477 6 20 6.44771 20 7V17C20 17.5523 20.4477 18 21 18C21.5523 18 22 17.5523 22 17V7C22 6.44772 21.5523 6 21 6Z" fill="currentColor" />
<path d="M4 14C5.10457 14 6 13.1046 6 12C6 10.8954 5.10457 10 4 10C2.89543 10 2 10.8954 2 12C2 13.1046 2.89543 14 4 14Z" fill="currentColor"
/>
<path d="M12 12C12 13.1046 11.1046 14 10 14C8.89543 14 8 13.1046 8 12C8 10.8954 8.89543 10 10 10C11.1046 10 12 10.8954 12 12Z" fill="currentColor" />
<path d="M16 14C17.1046 14 18 13.1046 18 12C18 10.8954 17.1046 10 16 10C14.8954 10 14 10.8954 14 12C14 13.1046 14.8954 14 16 14Z" fill="currentColor" />
<svg xmlns="http://www.w3.org/2000/svg" viewBox="4 4 40 40">
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M24,4.5a.75.75,0,0,1,.26,0L40.34,9.32a.93.93,0,0,1,.66.88V26a15,15,0,0,1-4.87,11.2c-3,2.84-7.17,4.83-11.87,6.22a.86.86,0,0,1-.52,0c-4.7-1.39-8.85-3.38-11.87-6.22A15,15,0,0,1,7,26V10.2a.93.93,0,0,1,.66-.88L23.74,4.54a.75.75,0,0,1,.26,0ZM15.09,19.7a2.87,2.87,0,1,1-2.87,2.87A2.87,2.87,0,0,1,15.09,19.7Zm7.3,0a2.87,2.87,0,1,1-2.87,2.87A2.88,2.88,0,0,1,22.39,19.7Zm7.29,0a2.87,2.87,0,1,1-2.87,2.87A2.87,2.87,0,0,1,29.68,19.7Zm5.44-4.6v15"/>
</svg>
</template>
<script>
@@ -1,14 +1,7 @@
<template>
<svg fill="none" width="1em" height="1em" viewBox="0 0 482 482" xmlns="http://www.w3.org/2000/svg">
<path fill="currentColor" d="M282.973 219.186c0 16.827-9.934 31.28-24.2 37.973v29.894c0 9.8-7.934 17.733-17.774 17.733-9.826 0-17.72-7.933-17.72-17.733v-29.894c-14.306-6.693-24.186-21.146-24.186-37.973 0-23.186 18.773-41.96 41.906-41.96 23.147 0 41.974 18.774 41.974 41.96m76.267 72.054c3.892-9.227 6.706-18.774 8.372-28.467-1.626 9.733-4.426 19.24-8.373 28.466zm10.266-50.28c0 1.426-.04 2.893-.094 4.32-.093 3.893-.426 7.8-.946 11.64.48-3.947.8-7.84.906-11.787a61 61 0 0 0 .134-4.174z"></path>
<path fill="currentColor" d="M296.8 56.8c0 1.04-.054 2.04-.107 3.093 0 .52-.04 1.04-.134 1.56-.053 1.094-.2 2.147-.333 3.24a38 38 0 0 1-.573 3.32c0 .387-.147.72-.24 1a32 32 0 0 1-.707 2.853c-.333 1.374-.813 2.707-1.293 3.987-.28.907-.654 1.76-.987 2.613-.2.48-.387.907-.573 1.294-.48 1.04-.947 2.04-1.48 2.986-.52 1-1.094 2-1.654 2.947a80 80 0 0 1-3 4.427 57 57 0 0 1-4.04 4.8c-.853.893-1.706 1.8-2.613 2.613-.947.853-1.853 1.707-2.853 2.467a56 56 0 0 1-9.36 6.226h-.054c-14.68-9.413-30.12-17.013-46.146-22.906a250 250 0 0 0-16.107-5.28c-2.76-.8-5.466-1.52-8.213-2.187-37.84-9.453-77.52-9.546-115.44-.373-3.093.76-6.227 1.613-9.32 2.466A296 296 0 0 0 62.36 80.8a206 206 0 0 1 8.933-9.507c1.613-1.573 3.173-3.093 4.747-4.613 2.906-2.747 5.8-5.413 8.84-7.933 1.573-1.374 3.133-2.654 4.706-3.987a202 202 0 0 1 9.027-6.987c.187-.146.333-.24.48-.386 1.667-1.134 3.28-2.374 4.893-3.467 11.12-7.747 22.76-14.493 34.787-20.147 3.427-1.613 6.893-3.093 10.413-4.56 1.8-.76 3.654-1.48 5.507-2.186 1.76-.72 3.56-1.334 5.32-2 1.813-.614 3.667-1.24 5.467-1.854 1.813-.613 3.666-1.186 5.426-1.76 1.8-.52 3.654-1.04 5.454-1.573a246 246 0 0 1 22.24-5.08c1.866-.333 3.72-.613 5.613-.907 11.213-1.76 22.533-2.653 33.893-2.8.987 0 1.947-.053 2.893-.053.947 0 1.947.053 2.894.053C273.413 2.52 296.839 26.907 296.8 56.8"></path>
<path fill="currentColor" d="M296.8 56.8c0 1.04-.054 2.04-.107 3.093a9 9 0 0 1-.133 1.56c-.054 1.094-.2 2.147-.334 3.24a38 38 0 0 1-.573 3.32c0 .387-.147.72-.24 1a32 32 0 0 1-.707 2.853 35 35 0 0 1-1.293 3.987c-.28.907-.653 1.76-.987 2.613a42 42 0 0 1-2.053 4.28c-.52 1-1.093 2-1.653 2.947a57.4 57.4 0 0 1-7.04 9.227c-.854.893-1.707 1.8-2.614 2.613-.946.853-1.853 1.707-2.853 2.467a56 56 0 0 1-9.36 6.226h-.053a236.5 236.5 0 0 0-70.467-30.373 242 242 0 0 0-124.76 2.093A296 296 0 0 0 62.36 80.8a206 206 0 0 1 13.68-14.12c2.907-2.747 5.8-5.413 8.84-7.933 1.574-1.374 3.134-2.654 4.707-3.987a202 202 0 0 1 9.027-6.987c.186-.146.333-.24.48-.386 1.666-1.134 3.28-2.374 4.893-3.467a238 238 0 0 1 34.786-20.147 251 251 0 0 1 15.92-6.746c1.76-.72 3.56-1.334 5.32-2l5.467-1.854c1.813-.613 3.667-1.186 5.427-1.76 1.8-.52 3.653-1.04 5.453-1.573a246 246 0 0 1 22.24-5.08c1.867-.333 3.72-.613 5.613-.907 11.214-1.76 22.534-2.653 33.894-2.8.986 0 1.946-.053 2.893-.053s1.947.053 2.893.053C273.576 2.547 296.859 27.08 296.8 56.8Z" stroke="currentColor"></path>
<path fill="currentColor" d="M480.999 238.106v5.8c-.147 11.36-1.04 22.667-2.8 33.88-.24 1.907-.574 3.76-.907 5.613-1.333 7.454-3 14.867-5.08 22.24-.533 1.8-1 3.654-1.573 5.467-.574 1.76-1.147 3.613-1.76 5.413-.574 1.854-1.24 3.667-1.853 5.467-.667 1.76-1.28 3.56-2 5.32q-1.048 2.778-2.187 5.52a206 206 0 0 1-4.56 10.4 234.6 234.6 0 0 1-20.147 34.786c-1.093 1.627-2.28 3.24-3.466 4.907-.147.133-.24.28-.334.467-2.28 3-4.613 6.08-7.04 9.026-1.333 1.574-2.613 3.147-3.946 4.707-2.56 3.04-5.227 5.947-7.974 8.84-1.52 1.573-3.053 3.133-4.613 4.76-27.373 27.373-59.787 46.813-94.2 58.16 56.133-62.44 73.76-147.226 52.893-223.6 0-.04-.04-.093-.04-.146.094-1.374.147-2.747.147-4.174 0-30.8 24.947-55.746 55.747-55.746 29.84-.053 54.213 23.386 55.693 52.893"></path>
<path fill="currentColor" stroke="currentColor" d="M480.999 238.106v5.8c-.146 11.36-1.04 22.667-2.8 33.88-.24 1.907-.573 3.76-.906 5.613-1.334 7.454-3 14.867-5.08 22.24-.534 1.8-1 3.654-1.574 5.467-.573 1.76-1.146 3.613-1.76 5.413-.573 1.854-1.24 3.667-1.853 5.467-.667 1.76-1.28 3.56-2 5.32a183 183 0 0 1-2.187 5.52 234.6 234.6 0 0 1-24.706 45.186c-1.094 1.627-2.28 3.24-3.467 4.907q-.211.201-.333.467c-2.28 3-4.614 6.08-7.04 9.026-1.334 1.574-2.614 3.147-3.947 4.707-2.56 3.04-5.227 5.947-7.973 8.84l-4.614 4.76a238.85 238.85 0 0 1-94.2 58.16c56.134-62.44 73.76-147.226 52.894-223.6 0-.04-.04-.093-.04-.146.093-1.374.147-2.747.147-4.174a55.733 55.733 0 0 1 55.746-55.746c29.7-.044 54.207 23.23 55.693 52.893Z"></path>
<path fill="currentColor" d="M316.52 468.879c-83.414 27.52-178.88 8.133-245.227-58.16-90.626-90.64-93.626-235.72-8.933-329.92 3.04-1 6.133-1.946 9.213-2.853 3.093-.853 6.227-1.706 9.32-2.466 37.92-9.227 77.6-9.133 115.44.373 2.747.667 5.466 1.387 8.213 2.187a250 250 0 0 1 16.12 5.28c16.013 5.893 31.453 13.493 46.147 22.906-.96.52-1.96 1-2.947 1.467-1 .387-2 .813-3 1.187-1 .386-2.04.773-3.093 1.093-.04 0-.094 0-.134.053a56.6 56.6 0 0 1-13.12 2.374 74 74 0 0 1-3.466.093c-32.894 0-65.773 12.547-90.867 37.64-50.146 50.187-50.186 131.506 0 181.693 50.187 50.186 131.547 50.133 181.68 0 1.573-1.573 3.093-3.133 4.56-4.8 2.76-3.04 5.333-6.187 7.746-9.453a275 275 0 0 0 3.574-5.04c1.133-1.667 2.226-3.427 3.28-5.134 1.04-1.76 2.04-3.52 2.986-5.28 1-1.8 1.907-3.613 2.76-5.413.854-1.813 1.707-3.613 2.467-5.467a129 129 0 0 0 8.373-28.466c.32-1.947.614-3.894.854-5.854.466-3.933.8-7.84.893-11.773 0 .04.053.093.053.133 20.867 76.374 3.227 161.16-52.893 223.6z"></path>
<path stroke="currentColor" d="M316.52 468.879c-83.413 27.52-178.88 8.133-245.226-58.16-90.627-90.64-93.627-235.72-8.934-329.92 3.04-1 6.134-1.946 9.214-2.853a240.64 240.64 0 0 1 149.092 5.374 237.3 237.3 0 0 1 46.146 22.906 61 61 0 0 1-2.947 1.467c-1 .387-2 .813-3 1.187a45 45 0 0 1-3.093 1.093c-.04 0-.093 0-.133.053a56.6 56.6 0 0 1-16.587 2.467 128.1 128.1 0 0 0-90.866 37.64c-50.147 50.187-50.187 131.506 0 181.693 50.186 50.186 131.546 50.133 181.68 0a121 121 0 0 0 12.306-14.253 139 139 0 0 0 6.853-10.174 151 151 0 0 0 5.747-10.693c.853-1.813 1.707-3.613 2.467-5.467a129 129 0 0 0 9.226-34.32c.467-3.933.8-7.84.894-11.773 0 .04.053.093.053.133 20.867 76.374 3.227 161.16-52.893 223.6Z"></path>
<path stroke="currentColor" d="M282.973 219.186c0 16.827-9.934 31.28-24.2 37.973v29.894c0 9.8-7.934 17.733-17.774 17.733-9.826 0-17.72-7.933-17.72-17.733v-29.894c-14.306-6.693-24.186-21.146-24.186-37.973 0-23.186 18.773-41.96 41.906-41.96 23.147 0 41.974 18.774 41.974 41.96Z"></path>
<path stroke="currentColor" d="M282.973 219.186c0 16.827-9.934 31.28-24.2 37.973v29.894c0 9.8-7.934 17.733-17.774 17.733-9.826 0-17.72-7.933-17.72-17.733v-29.894c-14.306-6.693-24.186-21.146-24.186-37.973 0-23.186 18.773-41.96 41.906-41.96 23.147 0 41.974 18.774 41.974 41.96Z"></path>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="4 4 40 40">
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M27.0582,22.2034c0-1.689-1.3692-3.0582-3.0582-3.0582s-3.0582,1.3692-3.0582,3.0582c0,1.2178.7172,2.2606,1.7475,2.7526v2.759c0,.7239.5869,1.3107,1.3107,1.3107s1.3108-.5869,1.3108-1.3107v-2.759c1.0303-.4919,1.7474-1.5347,1.7474-2.7526Z"/>
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M24,5.3481c2.4853,0,4.5,2.0147,4.5,4.5s-2.0147,4.5-4.5,4.5c-5.3306,0-9.6519,4.3213-9.6519,9.6519s4.3213,9.6519,9.6519,9.6519,9.6519-4.3213,9.6519-9.6519c0-2.4853,2.0147-4.5,4.5-4.5s4.5,2.0147,4.5,4.5c0,10.3011-8.3507,18.6519-18.6519,18.6519S5.3481,34.3011,5.3481,24,13.6989,5.3481,24,5.3481Z"/>
</svg>
</template>
<script>
@@ -1,5 +1,5 @@
<template>
<svg width="1em" height="1em" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
<svg width="1em" height="1em" viewBox="2 2 42 42" xmlns="http://www.w3.org/2000/svg">
<rect fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="3px" x="8.379" y="8.379" width="31.242" height="31.242" rx="4" ry="4" transform="translate(24 -9.9411) rotate(45)"/>
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="3px" d="m10.1332,11.3867h18.2265c2.2077,0,4,1.7923,4,4v18.2265c0,1.6557-1.3443,3-3,3H10.1332c-1.6557,0-3-1.3443-3-3V14.3867c0-1.6557,1.3443-3,3-3Z" transform="translate(16.7387 54.9334) rotate(-135)"/>
</svg>
@@ -51,7 +51,7 @@ export const csvStrategy = {
},
/**
* Decode a generic or bitwarden (vault) CSV string.
* Decode a generic or bitwarden Password CSV string.
* @param {string} csvText
* @returns {VaultItem[]}
*/
@@ -63,14 +63,14 @@ export const csvStrategy = {
const headers = this._splitCsvLine(lines[0]).map(h => h.toLowerCase())
const rawVault = []
const isBitwardenVault = headers.includes('login_totp')
const isBitwardenPass = headers.includes('login_totp')
const isBitwardenAuth = headers.includes('otpauth') && !headers.includes('title')
const is1Password = headers.includes('otpauth') && headers.includes('title')
const isProtonPass = headers.includes('totp') && headers.includes('vault') && headers.includes('createtime')
const isDashlane = headers.includes('otpurl') && headers.includes('title') && headers.includes('username')
const isGeneric = headers.includes('issuer') || headers.includes('secret') || headers.includes('name')
if (!isBitwardenVault && !isBitwardenAuth && !is1Password && !isProtonPass && !isDashlane && !isGeneric) return []
if (!isBitwardenPass && !isBitwardenAuth && !is1Password && !isProtonPass && !isDashlane && !isGeneric) return []
for (let i = 1; i < lines.length; i++) {
const row = this._splitCsvLine(lines[i])
@@ -87,7 +87,7 @@ export const csvStrategy = {
rawVault.push(accData)
}
}
} else if (isBitwardenVault || isBitwardenAuth) {
} else if (isBitwardenPass || isBitwardenAuth) {
const totpStr = (rowData['login_totp'] || rowData['otpauth'] || rowData['totp'] || '').trim()
if (totpStr) {
let accData = null