+ );
+};
+
+export default SecurityPanel;
diff --git a/app/src/lib/coreState/__tests__/store.test.ts b/app/src/lib/coreState/__tests__/store.test.ts
index 56f1b31a5c..9d5d40b29e 100644
--- a/app/src/lib/coreState/__tests__/store.test.ts
+++ b/app/src/lib/coreState/__tests__/store.test.ts
@@ -11,7 +11,13 @@ function makeSnapshot(overrides: Partial = {}): CoreAppSnapshot
chatOnboardingCompleted: false,
analyticsEnabled: false,
meetAutoOrchestratorHandoff: false,
- localState: { encryptionKey: null, onboardingTasks: null },
+ localState: { encryptionKey: null, onboardingTasks: null, keyringConsent: null },
+ keyringStatus: {
+ available: true,
+ failureReason: null,
+ activeMode: 'os_keyring',
+ backendName: 'os',
+ },
runtime: { screenIntelligence: null, localAi: null, autocomplete: null, service: null },
...overrides,
};
diff --git a/app/src/lib/coreState/store.ts b/app/src/lib/coreState/store.ts
index bf96a32c23..194f440819 100644
--- a/app/src/lib/coreState/store.ts
+++ b/app/src/lib/coreState/store.ts
@@ -14,9 +14,22 @@ export interface CoreOnboardingTasks {
updatedAtMs?: number;
}
+export interface KeyringConsentPreference {
+ storageMode: string;
+ consentedAtMs?: number;
+}
+
+export interface KeyringStatus {
+ available: boolean;
+ failureReason?: string | null;
+ activeMode: string;
+ backendName: string;
+}
+
export interface CoreLocalState {
encryptionKey: string | null;
onboardingTasks: CoreOnboardingTasks | null;
+ keyringConsent: KeyringConsentPreference | null;
}
export interface CoreRuntimeSnapshot {
@@ -55,6 +68,7 @@ export interface CoreAppSnapshot {
*/
meetAutoOrchestratorHandoff: boolean;
localState: CoreLocalState;
+ keyringStatus: KeyringStatus;
runtime: CoreRuntimeSnapshot;
}
@@ -75,7 +89,13 @@ const emptySnapshot: CoreAppSnapshot = {
chatOnboardingCompleted: false,
analyticsEnabled: false,
meetAutoOrchestratorHandoff: false,
- localState: { encryptionKey: null, onboardingTasks: null },
+ localState: { encryptionKey: null, onboardingTasks: null, keyringConsent: null },
+ keyringStatus: {
+ available: true,
+ failureReason: null,
+ activeMode: 'os_keyring',
+ backendName: 'os',
+ },
runtime: { screenIntelligence: null, localAi: null, autocomplete: null, service: null },
};
diff --git a/app/src/lib/i18n/ar.ts b/app/src/lib/i18n/ar.ts
index 9f59dfcaab..11613b672b 100644
--- a/app/src/lib/i18n/ar.ts
+++ b/app/src/lib/i18n/ar.ts
@@ -4307,6 +4307,41 @@ const messages: TranslationMap = {
'graphCohesion.summaryCaption': 'متوسط التجميع {avg} · التعدّي {transitivity}',
'graphCohesion.title': 'تماسك الرسم البياني',
'memory.tab.cohesion': 'Cohesion',
+
+ 'keyring.consent.title': 'التخزين الآمن غير متاح',
+ 'keyring.consent.description':
+ 'سلسلة مفاتيح نظام التشغيل غير متاحة. يحتاج OpenHuman إلى إذنك لتخزين الأسرار باستخدام التخزين المشفّر المحلي بدلاً من ذلك.',
+ 'keyring.consent.reasonPrefix': 'السبب:',
+ 'keyring.consent.showDetails': 'ماذا يعني هذا؟',
+ 'keyring.consent.hideDetails': 'إخفاء التفاصيل',
+ 'keyring.consent.tradeoffTitle': 'مقايضة أمنية',
+ 'keyring.consent.tradeoffBody':
+ 'مع التخزين المشفّر المحلي، تُشفَّر أسرارك على القرص باستخدام مفتاح رئيسي مخزَّن بجانب البيانات. يُعدّ هذا أقل أماناً من OS Keychain الذي يستخدم حماية مدعومة بالأجهزة. قد تتضمن النسخ الاحتياطية أو مزامنة الملفات البيانات المشفّرة.',
+ 'keyring.consent.consentButton': 'استخدام التخزين المشفّر المحلي',
+ 'keyring.consent.retryButton': 'إعادة المحاولة مع OS Keychain',
+ 'keyring.consent.declineButton': 'رفض',
+ 'keyring.consent.retrying': 'جارٍ إعادة المحاولة…',
+ 'keyring.consent.error': 'فشل حفظ التفضيل. يرجى المحاولة مرة أخرى.',
+ 'keyring.consent.retryFailed': 'سلسلة المفاتيح لا تزال غير متاحة.',
+ 'keyring.settings.title': 'الأمان',
+ 'keyring.settings.storageMode': 'وضع تخزين الأسرار',
+ 'keyring.settings.mode.osKeychain': 'سلسلة مفاتيح النظام',
+ 'keyring.settings.mode.encryptedFile': 'مشفَّر محلياً',
+ 'keyring.settings.mode.consentPending': 'غير مُهيَّأ',
+ 'keyring.settings.mode.declined': 'مرفوض',
+ 'keyring.settings.availability': 'توفّر سلسلة المفاتيح',
+ 'keyring.settings.available': 'OS Keychain متاح',
+ 'keyring.settings.unavailable': 'OS Keychain غير متاح',
+ 'keyring.settings.backend': 'الواجهة الخلفية',
+ 'keyring.settings.retryButton': 'إعادة محاولة الكشف عن سلسلة المفاتيح',
+ 'keyring.settings.retryFailed': 'فشلت إعادة المحاولة. سلسلة المفاتيح لا تزال غير متاحة.',
+ 'keyring.settings.consentTitle': 'موافقة التخزين',
+ 'keyring.settings.consentDescription':
+ 'اختر كيفية تخزين الأسرار عندما لا تكون سلسلة مفاتيح نظام التشغيل متاحة.',
+ 'keyring.settings.grantConsent': 'السماح بالتخزين المشفّر المحلي',
+ 'keyring.settings.revokeConsent': 'رفض التخزين المحلي',
+ 'pages.settings.account.security': 'الأمان',
+ 'pages.settings.account.securityDesc': 'وضع تخزين الأسرار وحالة سلسلة المفاتيح',
};
export default messages;
diff --git a/app/src/lib/i18n/bn.ts b/app/src/lib/i18n/bn.ts
index 21c1cd4fc8..c9640bfb0b 100644
--- a/app/src/lib/i18n/bn.ts
+++ b/app/src/lib/i18n/bn.ts
@@ -4382,6 +4382,42 @@ const messages: TranslationMap = {
'graphCohesion.summaryCaption': 'গড় ক্লাস্টারিং {avg} · সংক্রমণতা {transitivity}',
'graphCohesion.title': 'গ্রাফ সংসক্তি',
'memory.tab.cohesion': 'Cohesion',
+
+ // Keyring consent & security
+ 'keyring.consent.title': 'নিরাপদ সঞ্চয়স্থান অনুপলব্ধ',
+ 'keyring.consent.description':
+ 'আপনার অপারেটিং সিস্টেমের কিচেন অ্যাক্সেসযোগ্য নয়। OpenHuman-এর পরিবর্তে স্থানীয় এনক্রিপ্টেড সঞ্চয়স্থান ব্যবহার করে গোপনীয়তা সংরক্ষণ করতে আপনার অনুমতি প্রয়োজন।',
+ 'keyring.consent.reasonPrefix': 'কারণ:',
+ 'keyring.consent.showDetails': 'এটার মানে কী?',
+ 'keyring.consent.hideDetails': 'বিবরণ লুকান',
+ 'keyring.consent.tradeoffTitle': 'নিরাপত্তা বিনিময়',
+ 'keyring.consent.tradeoffBody':
+ 'স্থানীয় এনক্রিপ্টেড সঞ্চয়স্থানে, আপনার গোপনীয়তা ডিস্কে একটি মাস্টার কী দিয়ে এনক্রিপ্ট করা হয় যা ডেটার পাশাপাশি সংরক্ষিত থাকে। এটি OS কিচেনের চেয়ে কম নিরাপদ, যা হার্ডওয়্যার-সমর্থিত সুরক্ষা ব্যবহার করে। ব্যাকআপ বা ফাইল সিঙ্কিংয়ে এনক্রিপ্টেড ডেটা অন্তর্ভুক্ত হতে পারে।',
+ 'keyring.consent.consentButton': 'স্থানীয় এনক্রিপ্টেড সঞ্চয়স্থান ব্যবহার করুন',
+ 'keyring.consent.retryButton': 'OS Keychain পুনরায় চেষ্টা করুন',
+ 'keyring.consent.declineButton': 'প্রত্যাখ্যান করুন',
+ 'keyring.consent.retrying': 'পুনরায় চেষ্টা হচ্ছে…',
+ 'keyring.consent.error': 'পছন্দ সংরক্ষণ ব্যর্থ। অনুগ্রহ করে আবার চেষ্টা করুন।',
+ 'keyring.consent.retryFailed': 'কিচেন এখনও অনুপলব্ধ।',
+ 'keyring.settings.title': 'নিরাপত্তা',
+ 'keyring.settings.storageMode': 'গোপনীয়তা সঞ্চয়স্থান মোড',
+ 'keyring.settings.mode.osKeychain': 'OS কীচেইন',
+ 'keyring.settings.mode.encryptedFile': 'স্থানীয় এনক্রিপ্টেড',
+ 'keyring.settings.mode.consentPending': 'কনফিগার করা হয়নি',
+ 'keyring.settings.mode.declined': 'প্রত্যাখ্যান করা হয়েছে',
+ 'keyring.settings.availability': 'কিচেন প্রাপ্যতা',
+ 'keyring.settings.available': 'OS কিচেন উপলব্ধ',
+ 'keyring.settings.unavailable': 'OS কিচেন অনুপলব্ধ',
+ 'keyring.settings.backend': 'ব্যাকএন্ড',
+ 'keyring.settings.retryButton': 'কিচেন সনাক্তকরণ পুনরায় চেষ্টা করুন',
+ 'keyring.settings.retryFailed': 'পুনরায় চেষ্টা ব্যর্থ। কিচেন এখনও অনুপলব্ধ।',
+ 'keyring.settings.consentTitle': 'সঞ্চয়স্থান সম্মতি',
+ 'keyring.settings.consentDescription':
+ 'OS কিচেন অনুপলব্ধ থাকলে গোপনীয়তা কীভাবে সংরক্ষণ করা হবে তা বেছে নিন।',
+ 'keyring.settings.grantConsent': 'স্থানীয় এনক্রিপ্টেড সঞ্চয়স্থান অনুমতি দিন',
+ 'keyring.settings.revokeConsent': 'স্থানীয় সঞ্চয়স্থান প্রত্যাখ্যান করুন',
+ 'pages.settings.account.security': 'নিরাপত্তা',
+ 'pages.settings.account.securityDesc': 'গোপনীয়তা সঞ্চয়স্থান মোড এবং কিচেন অবস্থা',
};
export default messages;
diff --git a/app/src/lib/i18n/de.ts b/app/src/lib/i18n/de.ts
index 95fa2102a7..8d776aa339 100644
--- a/app/src/lib/i18n/de.ts
+++ b/app/src/lib/i18n/de.ts
@@ -4498,6 +4498,42 @@ const messages: TranslationMap = {
'Durchschnittliches Clustering {avg} · Transitivität {transitivity}',
'graphCohesion.title': 'Graph-Kohäsion',
'memory.tab.cohesion': 'Cohesion',
+
+ 'keyring.consent.title': 'Sicherer Speicher nicht verfügbar',
+ 'keyring.consent.description':
+ 'Der Schlüsselbund Ihres Betriebssystems ist nicht erreichbar. OpenHuman benötigt Ihre Erlaubnis, Geheimnisse stattdessen in einem lokal verschlüsselten Speicher abzulegen.',
+ 'keyring.consent.reasonPrefix': 'Grund:',
+ 'keyring.consent.showDetails': 'Was bedeutet das?',
+ 'keyring.consent.hideDetails': 'Details ausblenden',
+ 'keyring.consent.tradeoffTitle': 'Sicherheitskompromiss',
+ 'keyring.consent.tradeoffBody':
+ 'Bei lokal verschlüsseltem Speicher werden Ihre Geheimnisse mit einem Hauptschlüssel verschlüsselt, der neben den Daten gespeichert wird. Dies ist weniger sicher als der OS-Schlüsselbund, der hardwaregestützten Schutz bietet. Backups oder Dateisynchronisation können die verschlüsselten Daten enthalten.',
+ 'keyring.consent.consentButton': 'Lokal verschlüsselten Speicher verwenden',
+ 'keyring.consent.retryButton': 'OS Keychain erneut versuchen',
+ 'keyring.consent.declineButton': 'Ablehnen',
+ 'keyring.consent.retrying': 'Erneuter Versuch…',
+ 'keyring.consent.error': 'Einstellung konnte nicht gespeichert werden. Bitte erneut versuchen.',
+ 'keyring.consent.retryFailed': 'Schlüsselbund ist weiterhin nicht verfügbar.',
+ 'keyring.settings.title': 'Sicherheit',
+ 'keyring.settings.storageMode': 'Geheimnisspeicher-Modus',
+ 'keyring.settings.mode.osKeychain': 'OS-Schlüsselbund',
+ 'keyring.settings.mode.encryptedFile': 'Lokal verschlüsselt',
+ 'keyring.settings.mode.consentPending': 'Nicht konfiguriert',
+ 'keyring.settings.mode.declined': 'Abgelehnt',
+ 'keyring.settings.availability': 'Schlüsselbund-Verfügbarkeit',
+ 'keyring.settings.available': 'OS-Schlüsselbund ist verfügbar',
+ 'keyring.settings.unavailable': 'OS-Schlüsselbund ist nicht verfügbar',
+ 'keyring.settings.backend': 'Backend',
+ 'keyring.settings.retryButton': 'Schlüsselbund-Erkennung wiederholen',
+ 'keyring.settings.retryFailed':
+ 'Erneuter Versuch fehlgeschlagen. Schlüsselbund weiterhin nicht verfügbar.',
+ 'keyring.settings.consentTitle': 'Speicherzustimmung',
+ 'keyring.settings.consentDescription':
+ 'Wählen Sie, wie Geheimnisse gespeichert werden, wenn der OS-Schlüsselbund nicht verfügbar ist.',
+ 'keyring.settings.grantConsent': 'Lokal verschlüsselten Speicher erlauben',
+ 'keyring.settings.revokeConsent': 'Lokalen Speicher ablehnen',
+ 'pages.settings.account.security': 'Sicherheit',
+ 'pages.settings.account.securityDesc': 'Geheimnisspeicher-Modus und Schlüsselbund-Status',
};
export default messages;
diff --git a/app/src/lib/i18n/en.ts b/app/src/lib/i18n/en.ts
index 3443c761be..693f76cbee 100644
--- a/app/src/lib/i18n/en.ts
+++ b/app/src/lib/i18n/en.ts
@@ -941,7 +941,7 @@ const en: TranslationMap = {
'settings.search.menuDesc':
'Default to OpenHuman-managed search or wire up your own provider with an API key.',
'settings.search.description':
- 'Pick the search engine the agent uses, or disable search tools entirely. Managed uses OpenHuman’s backend (no setup). Parallel, Brave, and Querit run direct from your machine using your API key.',
+ "Pick the search engine the agent uses, or disable search tools entirely. Managed uses OpenHuman's backend (no setup). Parallel, Brave, and Querit run direct from your machine using your API key.",
'settings.search.engineAria': 'Search engine',
'settings.search.engineDisabledLabel': 'Disabled',
'settings.search.engineDisabledDesc':
@@ -2384,7 +2384,7 @@ const en: TranslationMap = {
'composio.envVarOverrides': 'is set, it overrides this setting.',
'composio.previewBadge': 'Preview',
'composio.previewTooltip':
- 'Agent integration coming soon — you can connect, but the agent can’t use this toolkit yet.',
+ "Agent integration coming soon — you can connect, but the agent can't use this toolkit yet.",
// Memory: day-of-week labels for heatmap
'memory.day.sun': 'Sun',
@@ -2493,7 +2493,7 @@ const en: TranslationMap = {
'app.openhumanLink.notifications.send': 'Send test notification',
'app.openhumanLink.notifications.sendFailed': "Couldn't send: {error}",
'app.openhumanLink.notifications.sent':
- 'Test notification sent. If you didn’t receive it, go to System Settings → Notifications → OpenHuman, turn on Allow Notifications, and set Banner Style to Persistent.',
+ "Test notification sent. If you didn't receive it, go to System Settings → Notifications → OpenHuman, turn on Allow Notifications, and set Banner Style to Persistent.",
'app.openhumanLink.skipForNow': 'Skip for now',
'app.openhumanLink.telegramUnavailable': 'Telegram unavailable',
'app.openhumanLink.title.accounts': 'Connect your apps',
@@ -3702,7 +3702,7 @@ const en: TranslationMap = {
'settings.skillsRunner.repoPicker.empty':
'No repositories returned. Connect GitHub via Composio to populate this list.',
'settings.skillsRunner.repoPicker.notConnected':
- 'GitHub isn’t connected via Composio. Connect it under Skills → Composio first.',
+ "GitHub isn't connected via Composio. Connect it under Skills → Composio first.",
'settings.skillsRunner.repoPicker.privateTag': '(private)',
'settings.skillsRunner.branchPicker.needRepo': 'Pick a repo first…',
'settings.skillsRunner.branchPicker.loading': 'Loading branches…',
@@ -4399,7 +4399,7 @@ const en: TranslationMap = {
'walletBalances.errorGeneric':
'Unable to load wallet balances. Set up your wallet in Recovery Phrase and try again.',
'walletBalances.setupHint':
- 'Your recovery phrase isn’t set up yet. Set it up to enable your wallet and see live balances.',
+ "Your recovery phrase isn't set up yet. Set it up to enable your wallet and see live balances.",
'walletBalances.setupCta': 'Set up recovery phrase',
'walletBalances.notSetUp': 'Not set up',
'walletBalances.send': 'Send',
@@ -4606,11 +4606,47 @@ const en: TranslationMap = {
'settings.agents.editor.toolsAllowAll': 'Allow all tools (*)',
'settings.agents.editor.toolsAllowAllHint': 'This agent can use every available tool.',
'settings.agents.editor.toolsLoading': 'Loading tools…',
- 'settings.agents.editor.toolsLoadError': 'Couldn’t load tools',
+ 'settings.agents.editor.toolsLoadError': "Couldn't load tools",
'settings.agents.editor.toolsEmpty': 'No tools match your search.',
'settings.agents.editor.toolsDone': 'Done',
'settings.agents.editor.builtInReadonly':
- 'Built-in agents can’t be edited. You can enable, disable, or reset them from the agents list.',
+ "Built-in agents can't be edited. You can enable, disable, or reset them from the agents list.",
+
+ // Keyring consent & security
+ 'keyring.consent.title': 'Secure Storage Unavailable',
+ 'keyring.consent.description':
+ 'Your operating system keychain is not accessible. OpenHuman needs your permission to store secrets using local encrypted storage instead.',
+ 'keyring.consent.reasonPrefix': 'Reason:',
+ 'keyring.consent.showDetails': 'What does this mean?',
+ 'keyring.consent.hideDetails': 'Hide details',
+ 'keyring.consent.tradeoffTitle': 'Security tradeoff',
+ 'keyring.consent.tradeoffBody':
+ 'With local encrypted storage, your secrets are encrypted on disk using a master key stored alongside the data. This is less secure than the OS keychain, which uses hardware-backed protection. Backups or file syncing may include the encrypted data.',
+ 'keyring.consent.consentButton': 'Use Local Encrypted Storage',
+ 'keyring.consent.retryButton': 'Retry OS Keychain',
+ 'keyring.consent.declineButton': 'Skip',
+ 'keyring.consent.retrying': 'Retrying…',
+ 'keyring.consent.error': 'Failed to save preference. Please try again.',
+ 'keyring.consent.retryFailed': 'Keychain is still unavailable.',
+ 'keyring.settings.title': 'Security',
+ 'keyring.settings.storageMode': 'Secret storage mode',
+ 'keyring.settings.mode.osKeychain': 'OS Keychain',
+ 'keyring.settings.mode.encryptedFile': 'Local Encrypted',
+ 'keyring.settings.mode.consentPending': 'Not configured',
+ 'keyring.settings.mode.declined': 'Declined',
+ 'keyring.settings.availability': 'Keychain availability',
+ 'keyring.settings.available': 'OS keychain is available',
+ 'keyring.settings.unavailable': 'OS keychain is unavailable',
+ 'keyring.settings.backend': 'Backend',
+ 'keyring.settings.retryButton': 'Retry keychain detection',
+ 'keyring.settings.retryFailed': 'Retry failed. Keychain is still unavailable.',
+ 'keyring.settings.consentTitle': 'Storage consent',
+ 'keyring.settings.consentDescription':
+ 'Choose how secrets are stored when the OS keychain is not available.',
+ 'keyring.settings.grantConsent': 'Allow local encrypted storage',
+ 'keyring.settings.revokeConsent': 'Decline local storage',
+ 'pages.settings.account.security': 'Security',
+ 'pages.settings.account.securityDesc': 'Secret storage mode and keychain status',
};
export default en;
diff --git a/app/src/lib/i18n/es.ts b/app/src/lib/i18n/es.ts
index 44e40d448c..8700f867c8 100644
--- a/app/src/lib/i18n/es.ts
+++ b/app/src/lib/i18n/es.ts
@@ -4465,6 +4465,41 @@ const messages: TranslationMap = {
'graphCohesion.summaryCaption': 'Agrupamiento promedio {avg} · transitividad {transitivity}',
'graphCohesion.title': 'Cohesión del grafo',
'memory.tab.cohesion': 'Cohesion',
+
+ 'keyring.consent.title': 'Almacenamiento seguro no disponible',
+ 'keyring.consent.description':
+ 'El llavero de su sistema operativo no está accesible. OpenHuman necesita su permiso para almacenar secretos usando almacenamiento local cifrado.',
+ 'keyring.consent.reasonPrefix': 'Motivo:',
+ 'keyring.consent.showDetails': '¿Qué significa esto?',
+ 'keyring.consent.hideDetails': 'Ocultar detalles',
+ 'keyring.consent.tradeoffTitle': 'Compromiso de seguridad',
+ 'keyring.consent.tradeoffBody':
+ 'Con el almacenamiento local cifrado, sus secretos se cifran en disco usando una clave maestra almacenada junto a los datos. Esto es menos seguro que el llavero del SO, que usa protección respaldada por hardware. Las copias de seguridad o la sincronización de archivos pueden incluir los datos cifrados.',
+ 'keyring.consent.consentButton': 'Usar almacenamiento local cifrado',
+ 'keyring.consent.retryButton': 'Reintentar OS Keychain',
+ 'keyring.consent.declineButton': 'Rechazar',
+ 'keyring.consent.retrying': 'Reintentando…',
+ 'keyring.consent.error': 'No se pudo guardar la preferencia. Inténtelo de nuevo.',
+ 'keyring.consent.retryFailed': 'El llavero sigue sin estar disponible.',
+ 'keyring.settings.title': 'Seguridad',
+ 'keyring.settings.storageMode': 'Modo de almacenamiento de secretos',
+ 'keyring.settings.mode.osKeychain': 'Llavero del SO',
+ 'keyring.settings.mode.encryptedFile': 'Local cifrado',
+ 'keyring.settings.mode.consentPending': 'No configurado',
+ 'keyring.settings.mode.declined': 'Rechazado',
+ 'keyring.settings.availability': 'Disponibilidad del llavero',
+ 'keyring.settings.available': 'El llavero del SO está disponible',
+ 'keyring.settings.unavailable': 'El llavero del SO no está disponible',
+ 'keyring.settings.backend': 'Motor',
+ 'keyring.settings.retryButton': 'Reintentar detección del llavero',
+ 'keyring.settings.retryFailed': 'Reintento fallido. El llavero sigue sin estar disponible.',
+ 'keyring.settings.consentTitle': 'Consentimiento de almacenamiento',
+ 'keyring.settings.consentDescription':
+ 'Elija cómo se almacenan los secretos cuando el llavero del SO no está disponible.',
+ 'keyring.settings.grantConsent': 'Permitir almacenamiento local cifrado',
+ 'keyring.settings.revokeConsent': 'Rechazar almacenamiento local',
+ 'pages.settings.account.security': 'Seguridad',
+ 'pages.settings.account.securityDesc': 'Modo de almacenamiento de secretos y estado del llavero',
};
export default messages;
diff --git a/app/src/lib/i18n/fr.ts b/app/src/lib/i18n/fr.ts
index 8c209e1aa2..dc895de729 100644
--- a/app/src/lib/i18n/fr.ts
+++ b/app/src/lib/i18n/fr.ts
@@ -4480,6 +4480,41 @@ const messages: TranslationMap = {
'graphCohesion.summaryCaption': 'Regroupement moyen {avg} · transitivité {transitivity}',
'graphCohesion.title': 'Cohésion du graphe',
'memory.tab.cohesion': 'Cohesion',
+
+ 'keyring.consent.title': 'Stockage sécurisé indisponible',
+ 'keyring.consent.description':
+ "Le trousseau de votre système d'exploitation n'est pas accessible. OpenHuman a besoin de votre autorisation pour stocker les secrets en utilisant un stockage local chiffré.",
+ 'keyring.consent.reasonPrefix': 'Raison :',
+ 'keyring.consent.showDetails': "Qu'est-ce que cela signifie ?",
+ 'keyring.consent.hideDetails': 'Masquer les détails',
+ 'keyring.consent.tradeoffTitle': 'Compromis de sécurité',
+ 'keyring.consent.tradeoffBody':
+ "Avec le stockage local chiffré, vos secrets sont chiffrés sur disque à l'aide d'une clé maître stockée à côté des données. C'est moins sécurisé que le trousseau du système, qui utilise une protection matérielle. Les sauvegardes ou la synchronisation de fichiers peuvent inclure les données chiffrées.",
+ 'keyring.consent.consentButton': 'Utiliser le stockage local chiffré',
+ 'keyring.consent.retryButton': 'Réessayer OS Keychain',
+ 'keyring.consent.declineButton': 'Refuser',
+ 'keyring.consent.retrying': 'Nouvelle tentative…',
+ 'keyring.consent.error': "Impossible d'enregistrer la préférence. Veuillez réessayer.",
+ 'keyring.consent.retryFailed': 'Le trousseau est toujours indisponible.',
+ 'keyring.settings.title': 'Sécurité',
+ 'keyring.settings.storageMode': 'Mode de stockage des secrets',
+ 'keyring.settings.mode.osKeychain': 'Trousseau du système',
+ 'keyring.settings.mode.encryptedFile': 'Local chiffré',
+ 'keyring.settings.mode.consentPending': 'Non configuré',
+ 'keyring.settings.mode.declined': 'Refusé',
+ 'keyring.settings.availability': 'Disponibilité du trousseau',
+ 'keyring.settings.available': 'Le trousseau du système est disponible',
+ 'keyring.settings.unavailable': 'Le trousseau du système est indisponible',
+ 'keyring.settings.backend': 'Moteur',
+ 'keyring.settings.retryButton': 'Réessayer la détection du trousseau',
+ 'keyring.settings.retryFailed': 'Échec de la tentative. Le trousseau est toujours indisponible.',
+ 'keyring.settings.consentTitle': 'Consentement de stockage',
+ 'keyring.settings.consentDescription':
+ "Choisissez comment les secrets sont stockés lorsque le trousseau du système n'est pas disponible.",
+ 'keyring.settings.grantConsent': 'Autoriser le stockage local chiffré',
+ 'keyring.settings.revokeConsent': 'Refuser le stockage local',
+ 'pages.settings.account.security': 'Sécurité',
+ 'pages.settings.account.securityDesc': 'Mode de stockage des secrets et état du trousseau',
};
export default messages;
diff --git a/app/src/lib/i18n/hi.ts b/app/src/lib/i18n/hi.ts
index 9174de2fc7..ab05bbd618 100644
--- a/app/src/lib/i18n/hi.ts
+++ b/app/src/lib/i18n/hi.ts
@@ -4390,6 +4390,41 @@ const messages: TranslationMap = {
'graphCohesion.summaryCaption': 'औसत क्लस्टरिंग {avg} · सकर्मकता {transitivity}',
'graphCohesion.title': 'ग्राफ संसक्ति',
'memory.tab.cohesion': 'Cohesion',
+
+ 'keyring.consent.title': 'सुरक्षित भंडारण अनुपलब्ध',
+ 'keyring.consent.description':
+ 'आपके ऑपरेटिंग सिस्टम का कीचेन सुलभ नहीं है। OpenHuman को इसके बजाय स्थानीय एन्क्रिप्टेड भंडारण का उपयोग करके रहस्य संग्रहीत करने के लिए आपकी अनुमति चाहिए।',
+ 'keyring.consent.reasonPrefix': 'कारण:',
+ 'keyring.consent.showDetails': 'इसका क्या मतलब है?',
+ 'keyring.consent.hideDetails': 'विवरण छिपाएं',
+ 'keyring.consent.tradeoffTitle': 'सुरक्षा समझौता',
+ 'keyring.consent.tradeoffBody':
+ 'स्थानीय एन्क्रिप्टेड भंडारण में, आपके रहस्य डिस्क पर एक मास्टर कुंजी से एन्क्रिप्ट किए जाते हैं जो डेटा के साथ संग्रहीत होती है। यह OS कीचेन से कम सुरक्षित है, जो हार्डवेयर-समर्थित सुरक्षा का उपयोग करता है। बैकअप या फ़ाइल सिंकिंग में एन्क्रिप्टेड डेटा शामिल हो सकता है।',
+ 'keyring.consent.consentButton': 'स्थानीय एन्क्रिप्टेड भंडारण का उपयोग करें',
+ 'keyring.consent.retryButton': 'OS Keychain पुनः प्रयास करें',
+ 'keyring.consent.declineButton': 'अस्वीकार करें',
+ 'keyring.consent.retrying': 'पुनः प्रयास हो रहा है…',
+ 'keyring.consent.error': 'प्राथमिकता सहेजने में विफल। कृपया पुनः प्रयास करें।',
+ 'keyring.consent.retryFailed': 'कीचेन अभी भी अनुपलब्ध है।',
+ 'keyring.settings.title': 'सुरक्षा',
+ 'keyring.settings.storageMode': 'रहस्य भंडारण मोड',
+ 'keyring.settings.mode.osKeychain': 'OS कीचेन',
+ 'keyring.settings.mode.encryptedFile': 'स्थानीय एन्क्रिप्टेड',
+ 'keyring.settings.mode.consentPending': 'कॉन्फ़िगर नहीं किया गया',
+ 'keyring.settings.mode.declined': 'अस्वीकृत',
+ 'keyring.settings.availability': 'कीचेन उपलब्धता',
+ 'keyring.settings.available': 'OS कीचेन उपलब्ध है',
+ 'keyring.settings.unavailable': 'OS कीचेन अनुपलब्ध है',
+ 'keyring.settings.backend': 'बैकएंड',
+ 'keyring.settings.retryButton': 'कीचेन पहचान पुनः प्रयास करें',
+ 'keyring.settings.retryFailed': 'पुनः प्रयास विफल। कीचेन अभी भी अनुपलब्ध है।',
+ 'keyring.settings.consentTitle': 'भंडारण सहमति',
+ 'keyring.settings.consentDescription':
+ 'चुनें कि OS कीचेन अनुपलब्ध होने पर रहस्य कैसे संग्रहीत किए जाएं।',
+ 'keyring.settings.grantConsent': 'स्थानीय एन्क्रिप्टेड भंडारण की अनुमति दें',
+ 'keyring.settings.revokeConsent': 'स्थानीय भंडारण अस्वीकार करें',
+ 'pages.settings.account.security': 'सुरक्षा',
+ 'pages.settings.account.securityDesc': 'रहस्य भंडारण मोड और कीचेन स्थिति',
};
export default messages;
diff --git a/app/src/lib/i18n/id.ts b/app/src/lib/i18n/id.ts
index 4b885c4dff..1e4a18904a 100644
--- a/app/src/lib/i18n/id.ts
+++ b/app/src/lib/i18n/id.ts
@@ -4399,6 +4399,41 @@ const messages: TranslationMap = {
'graphCohesion.summaryCaption': 'Pengelompokan rata-rata {avg} · transitivitas {transitivity}',
'graphCohesion.title': 'Kohesi Graf',
'memory.tab.cohesion': 'Cohesion',
+
+ 'keyring.consent.title': 'Penyimpanan aman tidak tersedia',
+ 'keyring.consent.description':
+ 'Keychain sistem operasi Anda tidak dapat diakses. OpenHuman memerlukan izin Anda untuk menyimpan rahasia menggunakan penyimpanan lokal terenkripsi.',
+ 'keyring.consent.reasonPrefix': 'Alasan:',
+ 'keyring.consent.showDetails': 'Apa artinya ini?',
+ 'keyring.consent.hideDetails': 'Sembunyikan detail',
+ 'keyring.consent.tradeoffTitle': 'Kompromi keamanan',
+ 'keyring.consent.tradeoffBody':
+ 'Dengan penyimpanan lokal terenkripsi, rahasia Anda dienkripsi di disk menggunakan kunci master yang disimpan bersama data. Ini kurang aman dibandingkan keychain OS yang menggunakan perlindungan berbasis perangkat keras. Pencadangan atau sinkronisasi file mungkin menyertakan data terenkripsi.',
+ 'keyring.consent.consentButton': 'Gunakan penyimpanan lokal terenkripsi',
+ 'keyring.consent.retryButton': 'Coba ulang OS Keychain',
+ 'keyring.consent.declineButton': 'Tolak',
+ 'keyring.consent.retrying': 'Mencoba ulang…',
+ 'keyring.consent.error': 'Gagal menyimpan preferensi. Silakan coba lagi.',
+ 'keyring.consent.retryFailed': 'Keychain masih tidak tersedia.',
+ 'keyring.settings.title': 'Keamanan',
+ 'keyring.settings.storageMode': 'Mode penyimpanan rahasia',
+ 'keyring.settings.mode.osKeychain': 'Keychain OS',
+ 'keyring.settings.mode.encryptedFile': 'Lokal terenkripsi',
+ 'keyring.settings.mode.consentPending': 'Belum dikonfigurasi',
+ 'keyring.settings.mode.declined': 'Ditolak',
+ 'keyring.settings.availability': 'Ketersediaan keychain',
+ 'keyring.settings.available': 'OS keychain tersedia',
+ 'keyring.settings.unavailable': 'OS keychain tidak tersedia',
+ 'keyring.settings.backend': 'Backend',
+ 'keyring.settings.retryButton': 'Coba ulang deteksi keychain',
+ 'keyring.settings.retryFailed': 'Percobaan ulang gagal. Keychain masih tidak tersedia.',
+ 'keyring.settings.consentTitle': 'Persetujuan penyimpanan',
+ 'keyring.settings.consentDescription':
+ 'Pilih bagaimana rahasia disimpan saat keychain OS tidak tersedia.',
+ 'keyring.settings.grantConsent': 'Izinkan penyimpanan lokal terenkripsi',
+ 'keyring.settings.revokeConsent': 'Tolak penyimpanan lokal',
+ 'pages.settings.account.security': 'Keamanan',
+ 'pages.settings.account.securityDesc': 'Mode penyimpanan rahasia dan status keychain',
};
export default messages;
diff --git a/app/src/lib/i18n/it.ts b/app/src/lib/i18n/it.ts
index 2ccf962a5c..41e461f7d7 100644
--- a/app/src/lib/i18n/it.ts
+++ b/app/src/lib/i18n/it.ts
@@ -4457,6 +4457,41 @@ const messages: TranslationMap = {
'graphCohesion.summaryCaption': 'Raggruppamento medio {avg} · transitività {transitivity}',
'graphCohesion.title': 'Coesione del grafo',
'memory.tab.cohesion': 'Cohesion',
+
+ 'keyring.consent.title': 'Archivio sicuro non disponibile',
+ 'keyring.consent.description':
+ "Il portachiavi del sistema operativo non è accessibile. OpenHuman necessita del tuo permesso per archiviare i segreti utilizzando l'archiviazione locale crittografata.",
+ 'keyring.consent.reasonPrefix': 'Motivo:',
+ 'keyring.consent.showDetails': 'Cosa significa?',
+ 'keyring.consent.hideDetails': 'Nascondi dettagli',
+ 'keyring.consent.tradeoffTitle': 'Compromesso di sicurezza',
+ 'keyring.consent.tradeoffBody':
+ "Con l'archiviazione locale crittografata, i tuoi segreti vengono crittografati su disco utilizzando una chiave master archiviata insieme ai dati. Questo è meno sicuro del portachiavi del SO, che utilizza protezione hardware. I backup o la sincronizzazione dei file possono includere i dati crittografati.",
+ 'keyring.consent.consentButton': 'Usa archiviazione locale crittografata',
+ 'keyring.consent.retryButton': 'Riprova OS Keychain',
+ 'keyring.consent.declineButton': 'Rifiuta',
+ 'keyring.consent.retrying': 'Nuovo tentativo…',
+ 'keyring.consent.error': 'Impossibile salvare la preferenza. Riprova.',
+ 'keyring.consent.retryFailed': 'Il portachiavi è ancora non disponibile.',
+ 'keyring.settings.title': 'Sicurezza',
+ 'keyring.settings.storageMode': 'Modalità archiviazione segreti',
+ 'keyring.settings.mode.osKeychain': 'Portachiavi del SO',
+ 'keyring.settings.mode.encryptedFile': 'Locale crittografato',
+ 'keyring.settings.mode.consentPending': 'Non configurato',
+ 'keyring.settings.mode.declined': 'Rifiutato',
+ 'keyring.settings.availability': 'Disponibilità portachiavi',
+ 'keyring.settings.available': 'Il portachiavi del SO è disponibile',
+ 'keyring.settings.unavailable': 'Il portachiavi del SO non è disponibile',
+ 'keyring.settings.backend': 'Motore',
+ 'keyring.settings.retryButton': 'Riprova rilevamento portachiavi',
+ 'keyring.settings.retryFailed': 'Tentativo fallito. Il portachiavi è ancora non disponibile.',
+ 'keyring.settings.consentTitle': 'Consenso archiviazione',
+ 'keyring.settings.consentDescription':
+ 'Scegli come vengono archiviati i segreti quando il portachiavi del SO non è disponibile.',
+ 'keyring.settings.grantConsent': 'Consenti archiviazione locale crittografata',
+ 'keyring.settings.revokeConsent': 'Rifiuta archiviazione locale',
+ 'pages.settings.account.security': 'Sicurezza',
+ 'pages.settings.account.securityDesc': 'Modalità archiviazione segreti e stato del portachiavi',
};
export default messages;
diff --git a/app/src/lib/i18n/ko.ts b/app/src/lib/i18n/ko.ts
index 33e179022f..846b5c237d 100644
--- a/app/src/lib/i18n/ko.ts
+++ b/app/src/lib/i18n/ko.ts
@@ -4350,6 +4350,41 @@ const messages: TranslationMap = {
'graphCohesion.summaryCaption': '평균 군집계수 {avg} · 전이성 {transitivity}',
'graphCohesion.title': '그래프 응집도',
'memory.tab.cohesion': 'Cohesion',
+
+ 'keyring.consent.title': '보안 저장소를 사용할 수 없음',
+ 'keyring.consent.description':
+ '운영 체제 키체인에 접근할 수 없습니다. OpenHuman이 로컬 암호화 저장소를 사용하여 비밀을 저장하려면 귀하의 허가가 필요합니다.',
+ 'keyring.consent.reasonPrefix': '이유:',
+ 'keyring.consent.showDetails': '이것은 무엇을 의미하나요?',
+ 'keyring.consent.hideDetails': '세부 정보 숨기기',
+ 'keyring.consent.tradeoffTitle': '보안 절충',
+ 'keyring.consent.tradeoffBody':
+ '로컬 암호화 저장소에서는 데이터와 함께 저장된 마스터 키를 사용하여 비밀이 디스크에 암호화됩니다. 이는 하드웨어 기반 보호를 사용하는 OS 키체인보다 덜 안전합니다. 백업이나 파일 동기화에 암호화된 데이터가 포함될 수 있습니다.',
+ 'keyring.consent.consentButton': '로컬 암호화 저장소 사용',
+ 'keyring.consent.retryButton': 'OS Keychain 재시도',
+ 'keyring.consent.declineButton': '거부',
+ 'keyring.consent.retrying': '재시도 중…',
+ 'keyring.consent.error': '설정을 저장하지 못했습니다. 다시 시도해 주세요.',
+ 'keyring.consent.retryFailed': '키체인이 여전히 사용할 수 없습니다.',
+ 'keyring.settings.title': '보안',
+ 'keyring.settings.storageMode': '비밀 저장 모드',
+ 'keyring.settings.mode.osKeychain': 'OS 키체인',
+ 'keyring.settings.mode.encryptedFile': '로컬 암호화',
+ 'keyring.settings.mode.consentPending': '구성되지 않음',
+ 'keyring.settings.mode.declined': '거부됨',
+ 'keyring.settings.availability': '키체인 가용성',
+ 'keyring.settings.available': 'OS 키체인 사용 가능',
+ 'keyring.settings.unavailable': 'OS 키체인 사용 불가',
+ 'keyring.settings.backend': '백엔드',
+ 'keyring.settings.retryButton': '키체인 감지 재시도',
+ 'keyring.settings.retryFailed': '재시도 실패. 키체인이 여전히 사용할 수 없습니다.',
+ 'keyring.settings.consentTitle': '저장소 동의',
+ 'keyring.settings.consentDescription':
+ 'OS 키체인을 사용할 수 없을 때 비밀을 저장하는 방법을 선택하세요.',
+ 'keyring.settings.grantConsent': '로컬 암호화 저장소 허용',
+ 'keyring.settings.revokeConsent': '로컬 저장소 거부',
+ 'pages.settings.account.security': '보안',
+ 'pages.settings.account.securityDesc': '비밀 저장 모드 및 키체인 상태',
};
export default messages;
diff --git a/app/src/lib/i18n/pl.ts b/app/src/lib/i18n/pl.ts
index 1eaa55f239..eb541365c9 100644
--- a/app/src/lib/i18n/pl.ts
+++ b/app/src/lib/i18n/pl.ts
@@ -4456,6 +4456,42 @@ const messages: TranslationMap = {
'graphCohesion.summaryCaption': 'Średnia klasteryzacja {avg} · tranzytywność {transitivity}',
'graphCohesion.title': 'Spójność grafu',
'memory.tab.cohesion': 'Cohesion',
+
+ 'keyring.consent.title': 'Bezpieczne przechowywanie niedostępne',
+ 'keyring.consent.description':
+ 'Pęk kluczy systemu operacyjnego jest niedostępny. OpenHuman potrzebuje Twojej zgody na przechowywanie sekretów w lokalnym zaszyfrowanym magazynie.',
+ 'keyring.consent.reasonPrefix': 'Powód:',
+ 'keyring.consent.showDetails': 'Co to oznacza?',
+ 'keyring.consent.hideDetails': 'Ukryj szczegóły',
+ 'keyring.consent.tradeoffTitle': 'Kompromis bezpieczeństwa',
+ 'keyring.consent.tradeoffBody':
+ 'W przypadku lokalnego zaszyfrowanego magazynu sekrety są szyfrowane na dysku przy użyciu klucza głównego przechowywanego obok danych. Jest to mniej bezpieczne niż pęk kluczy systemu, który wykorzystuje ochronę sprzętową. Kopie zapasowe lub synchronizacja plików mogą zawierać zaszyfrowane dane.',
+ 'keyring.consent.consentButton': 'Użyj lokalnego zaszyfrowanego magazynu',
+ 'keyring.consent.retryButton': 'Ponów próbę OS Keychain',
+ 'keyring.consent.declineButton': 'Odrzuć',
+ 'keyring.consent.retrying': 'Ponawiam próbę…',
+ 'keyring.consent.error': 'Nie udało się zapisać preferencji. Spróbuj ponownie.',
+ 'keyring.consent.retryFailed': 'Pęk kluczy jest nadal niedostępny.',
+ 'keyring.settings.title': 'Bezpieczeństwo',
+ 'keyring.settings.storageMode': 'Tryb przechowywania sekretów',
+ 'keyring.settings.mode.osKeychain': 'Pęk kluczy systemu',
+ 'keyring.settings.mode.encryptedFile': 'Lokalnie zaszyfrowany',
+ 'keyring.settings.mode.consentPending': 'Nie skonfigurowano',
+ 'keyring.settings.mode.declined': 'Odrzucono',
+ 'keyring.settings.availability': 'Dostępność pęku kluczy',
+ 'keyring.settings.available': 'Pęk kluczy systemu jest dostępny',
+ 'keyring.settings.unavailable': 'Pęk kluczy systemu jest niedostępny',
+ 'keyring.settings.backend': 'Silnik',
+ 'keyring.settings.retryButton': 'Ponów wykrywanie pęku kluczy',
+ 'keyring.settings.retryFailed':
+ 'Ponowna próba nie powiodła się. Pęk kluczy jest nadal niedostępny.',
+ 'keyring.settings.consentTitle': 'Zgoda na przechowywanie',
+ 'keyring.settings.consentDescription':
+ 'Wybierz sposób przechowywania sekretów, gdy pęk kluczy systemu jest niedostępny.',
+ 'keyring.settings.grantConsent': 'Zezwól na lokalne zaszyfrowane przechowywanie',
+ 'keyring.settings.revokeConsent': 'Odmów lokalnego przechowywania',
+ 'pages.settings.account.security': 'Bezpieczeństwo',
+ 'pages.settings.account.securityDesc': 'Tryb przechowywania sekretów i stan pęku kluczy',
};
export default messages;
diff --git a/app/src/lib/i18n/pt.ts b/app/src/lib/i18n/pt.ts
index 1612b29a13..af6f68ae59 100644
--- a/app/src/lib/i18n/pt.ts
+++ b/app/src/lib/i18n/pt.ts
@@ -4455,6 +4455,41 @@ const messages: TranslationMap = {
'graphCohesion.summaryCaption': 'Agrupamento médio {avg} · transitividade {transitivity}',
'graphCohesion.title': 'Coesão do grafo',
'memory.tab.cohesion': 'Cohesion',
+
+ 'keyring.consent.title': 'Armazenamento seguro indisponível',
+ 'keyring.consent.description':
+ 'O chaveiro do sistema operacional não está acessível. O OpenHuman precisa da sua permissão para armazenar segredos usando armazenamento local criptografado.',
+ 'keyring.consent.reasonPrefix': 'Motivo:',
+ 'keyring.consent.showDetails': 'O que isso significa?',
+ 'keyring.consent.hideDetails': 'Ocultar detalhes',
+ 'keyring.consent.tradeoffTitle': 'Compromisso de segurança',
+ 'keyring.consent.tradeoffBody':
+ 'Com o armazenamento local criptografado, seus segredos são criptografados no disco usando uma chave mestra armazenada junto aos dados. Isso é menos seguro que o chaveiro do SO, que usa proteção por hardware. Backups ou sincronização de arquivos podem incluir os dados criptografados.',
+ 'keyring.consent.consentButton': 'Usar armazenamento local criptografado',
+ 'keyring.consent.retryButton': 'Tentar novamente OS Keychain',
+ 'keyring.consent.declineButton': 'Recusar',
+ 'keyring.consent.retrying': 'Tentando novamente…',
+ 'keyring.consent.error': 'Falha ao salvar preferência. Tente novamente.',
+ 'keyring.consent.retryFailed': 'O chaveiro ainda está indisponível.',
+ 'keyring.settings.title': 'Segurança',
+ 'keyring.settings.storageMode': 'Modo de armazenamento de segredos',
+ 'keyring.settings.mode.osKeychain': 'Chaveiro do SO',
+ 'keyring.settings.mode.encryptedFile': 'Local criptografado',
+ 'keyring.settings.mode.consentPending': 'Não configurado',
+ 'keyring.settings.mode.declined': 'Recusado',
+ 'keyring.settings.availability': 'Disponibilidade do chaveiro',
+ 'keyring.settings.available': 'O chaveiro do SO está disponível',
+ 'keyring.settings.unavailable': 'O chaveiro do SO está indisponível',
+ 'keyring.settings.backend': 'Motor',
+ 'keyring.settings.retryButton': 'Tentar novamente detecção do chaveiro',
+ 'keyring.settings.retryFailed': 'Tentativa falhou. O chaveiro ainda está indisponível.',
+ 'keyring.settings.consentTitle': 'Consentimento de armazenamento',
+ 'keyring.settings.consentDescription':
+ 'Escolha como os segredos são armazenados quando o chaveiro do SO não está disponível.',
+ 'keyring.settings.grantConsent': 'Permitir armazenamento local criptografado',
+ 'keyring.settings.revokeConsent': 'Recusar armazenamento local',
+ 'pages.settings.account.security': 'Segurança',
+ 'pages.settings.account.securityDesc': 'Modo de armazenamento de segredos e status do chaveiro',
};
export default messages;
diff --git a/app/src/lib/i18n/ru.ts b/app/src/lib/i18n/ru.ts
index 5ded85544f..f2cbb7254c 100644
--- a/app/src/lib/i18n/ru.ts
+++ b/app/src/lib/i18n/ru.ts
@@ -4424,6 +4424,42 @@ const messages: TranslationMap = {
'graphCohesion.summaryCaption': 'Средняя кластеризация {avg} · транзитивность {transitivity}',
'graphCohesion.title': 'Связность графа',
'memory.tab.cohesion': 'Cohesion',
+
+ 'keyring.consent.title': 'Безопасное хранилище недоступно',
+ 'keyring.consent.description':
+ 'Связка ключей вашей операционной системы недоступна. OpenHuman необходимо ваше разрешение на хранение секретов в локальном зашифрованном хранилище.',
+ 'keyring.consent.reasonPrefix': 'Причина:',
+ 'keyring.consent.showDetails': 'Что это значит?',
+ 'keyring.consent.hideDetails': 'Скрыть подробности',
+ 'keyring.consent.tradeoffTitle': 'Компромисс безопасности',
+ 'keyring.consent.tradeoffBody':
+ 'При локальном зашифрованном хранении ваши секреты шифруются на диске с помощью мастер-ключа, который хранится рядом с данными. Это менее безопасно, чем связка ключей ОС, которая использует аппаратную защиту. Резервные копии или синхронизация файлов могут включать зашифрованные данные.',
+ 'keyring.consent.consentButton': 'Использовать локальное зашифрованное хранилище',
+ 'keyring.consent.retryButton': 'Повторить OS Keychain',
+ 'keyring.consent.declineButton': 'Отклонить',
+ 'keyring.consent.retrying': 'Повторная попытка…',
+ 'keyring.consent.error': 'Не удалось сохранить настройку. Попробуйте снова.',
+ 'keyring.consent.retryFailed': 'Связка ключей по-прежнему недоступна.',
+ 'keyring.settings.title': 'Безопасность',
+ 'keyring.settings.storageMode': 'Режим хранения секретов',
+ 'keyring.settings.mode.osKeychain': 'Связка ключей ОС',
+ 'keyring.settings.mode.encryptedFile': 'Локальное шифрование',
+ 'keyring.settings.mode.consentPending': 'Не настроено',
+ 'keyring.settings.mode.declined': 'Отклонено',
+ 'keyring.settings.availability': 'Доступность связки ключей',
+ 'keyring.settings.available': 'Связка ключей ОС доступна',
+ 'keyring.settings.unavailable': 'Связка ключей ОС недоступна',
+ 'keyring.settings.backend': 'Движок',
+ 'keyring.settings.retryButton': 'Повторить обнаружение связки ключей',
+ 'keyring.settings.retryFailed':
+ 'Повторная попытка не удалась. Связка ключей по-прежнему недоступна.',
+ 'keyring.settings.consentTitle': 'Согласие на хранение',
+ 'keyring.settings.consentDescription':
+ 'Выберите способ хранения секретов, когда связка ключей ОС недоступна.',
+ 'keyring.settings.grantConsent': 'Разрешить локальное зашифрованное хранилище',
+ 'keyring.settings.revokeConsent': 'Отклонить локальное хранилище',
+ 'pages.settings.account.security': 'Безопасность',
+ 'pages.settings.account.securityDesc': 'Режим хранения секретов и статус связки ключей',
};
export default messages;
diff --git a/app/src/lib/i18n/zh-CN.ts b/app/src/lib/i18n/zh-CN.ts
index 34b5aa53c3..86091f51e9 100644
--- a/app/src/lib/i18n/zh-CN.ts
+++ b/app/src/lib/i18n/zh-CN.ts
@@ -4173,6 +4173,40 @@ const messages: TranslationMap = {
'graphCohesion.summaryCaption': '平均聚类系数 {avg} · 传递性 {transitivity}',
'graphCohesion.title': '图的凝聚度',
'memory.tab.cohesion': 'Cohesion',
+
+ 'keyring.consent.title': '安全存储不可用',
+ 'keyring.consent.description':
+ '您的操作系统密钥链不可访问。OpenHuman 需要您的许可,以便使用本地加密存储来保存密钥。',
+ 'keyring.consent.reasonPrefix': '原因:',
+ 'keyring.consent.showDetails': '这是什么意思?',
+ 'keyring.consent.hideDetails': '隐藏详情',
+ 'keyring.consent.tradeoffTitle': '安全权衡',
+ 'keyring.consent.tradeoffBody':
+ '使用本地加密存储时,您的密钥使用与数据一起存储的主密钥进行磁盘加密。这不如使用硬件保护的操作系统密钥链安全。备份或文件同步可能包含加密数据。',
+ 'keyring.consent.consentButton': '使用本地加密存储',
+ 'keyring.consent.retryButton': '重试 OS Keychain',
+ 'keyring.consent.declineButton': '拒绝',
+ 'keyring.consent.retrying': '正在重试…',
+ 'keyring.consent.error': '保存偏好失败,请重试。',
+ 'keyring.consent.retryFailed': '密钥链仍然不可用。',
+ 'keyring.settings.title': '安全',
+ 'keyring.settings.storageMode': '密钥存储模式',
+ 'keyring.settings.mode.osKeychain': '操作系统密钥链',
+ 'keyring.settings.mode.encryptedFile': '本地加密',
+ 'keyring.settings.mode.consentPending': '未配置',
+ 'keyring.settings.mode.declined': '已拒绝',
+ 'keyring.settings.availability': '密钥链可用性',
+ 'keyring.settings.available': '操作系统密钥链可用',
+ 'keyring.settings.unavailable': '操作系统密钥链不可用',
+ 'keyring.settings.backend': '后端',
+ 'keyring.settings.retryButton': '重试密钥链检测',
+ 'keyring.settings.retryFailed': '重试失败。密钥链仍然不可用。',
+ 'keyring.settings.consentTitle': '存储同意',
+ 'keyring.settings.consentDescription': '选择操作系统密钥链不可用时如何存储密钥。',
+ 'keyring.settings.grantConsent': '允许本地加密存储',
+ 'keyring.settings.revokeConsent': '拒绝本地存储',
+ 'pages.settings.account.security': '安全',
+ 'pages.settings.account.securityDesc': '密钥存储模式和密钥链状态',
};
export default messages;
diff --git a/app/src/pages/Settings.tsx b/app/src/pages/Settings.tsx
index 4c0b5752a3..d1c451e4f2 100644
--- a/app/src/pages/Settings.tsx
+++ b/app/src/pages/Settings.tsx
@@ -40,6 +40,7 @@ import RecoveryPhrasePanel from '../components/settings/panels/RecoveryPhrasePan
import ScreenAwarenessDebugPanel from '../components/settings/panels/ScreenAwarenessDebugPanel';
import ScreenIntelligencePanel from '../components/settings/panels/ScreenIntelligencePanel';
import SearchPanel from '../components/settings/panels/SearchPanel';
+import SecurityPanel from '../components/settings/panels/SecurityPanel';
import SkillsRunnerPanel from '../components/settings/panels/SkillsRunnerPanel';
import TaskSourcesPanel from '../components/settings/panels/TaskSourcesPanel';
import TeamInvitesPanel from '../components/settings/panels/TeamInvitesPanel';
@@ -90,6 +91,16 @@ const PrivacyIcon = (
/>
);
+const SecurityIcon = (
+
+);
const MigrationIcon = (