feat(opaque): improve password change

- rebuild the opaque envoloppe
- revoke all other useer's sessions
- send a security email to user
This commit is contained in:
Edouard Vanbelle
2026-08-05 23:35:05 +02:00
parent 60cf9d976b
commit 21607e3e7f
29 changed files with 611 additions and 33 deletions
+13 -6
View File
@@ -68,12 +68,19 @@ export async function changePassword(currentPw: string, newPw: string): Promise<
body: JSON.stringify({ current_password: currentPw, new_password: newPw })
});
if (!res.ok) throw new Error(`password change failed: ${res.status}`);
// Re-mint the OPAQUE envelope under the new passphrase — session
// stays valid across change-password (backend doesn't invalidate),
// so the session-authenticated register endpoints are reachable
// straight away. Non-fatal on failure: silent migration on next
// legacy login recovers the envelope. See
// `$lib/api/endpoints/opaque.ts::syncOpaqueEnvelope`.
// Re-mint the OPAQUE envelope under the new passphrase — SAME
// session is still valid after change_password (the backend now
// preserves the caller's session via `revoke_other_user_sessions`;
// only OTHER devices are logged out). That means the session-
// authenticated register endpoints are reachable straight away,
// no 401 race like the earlier `revoke_all_user_sessions` shape.
//
// This is the PRIMARY migration path: the envelope transitions
// straight from OLD-password bound to NEW-password bound with no
// null intermediate. `opaque_migrated_at` stays intact, admin
// dashboards don't see a spurious "unmigrated" blip. Non-fatal
// on failure — silent-migration on next legacy login (post
// `oxicloud-cli opaque reset` recovery) is the fallback.
//
// Dynamic import keeps the ~200 KiB `@serenity-kit/opaque` WASM
// bundle out of the profile route's initial chunk — the module
+11
View File
@@ -227,6 +227,17 @@ export interface User {
* missing → `false`.
*/
force_password_change?: boolean;
/**
* TRUE when the account has a local Argon2id `password_hash` on
* file. Distinct from `auth_provider`: an SSO-linked account can
* ALSO carry a local password (hybrid posture — SSO for daily
* login, local password as fallback). The profile page's
* change-password card gates on this flag rather than on
* `auth_provider === 'local'` so hybrid users can rotate their
* local credential. Optional on the wire for older-backend
* compatibility; missing → `false` (safe default: hide the card).
*/
has_password?: boolean;
}
/** Fields rendered by the paginated admin table. Full account details remain
+11 -1
View File
@@ -71,7 +71,17 @@
const usernameClaimed = $derived(!!session.user?.username);
const isAdmin = $derived(session.user?.role === 'admin');
const canEditImage = $derived(session.user?.can_edit_image === true && isLocal);
const showPasswordCard = $derived(isLocal && passwordLoginEnabled);
// Show the change-password card when the user CAN change their
// local password: they have `password_hash` on file AND the
// deployment offers password login (backend `change_password`
// refuses on either count — see `AuthApplicationService::change_password`).
// Distinct from the OLD `isLocal && passwordLoginEnabled` gate,
// which refused any SSO-linked account regardless of whether they
// carried a local password. Hybrid accounts (OIDC + local
// password) are a legitimate posture and MUST be able to rotate
// their local credential; the new gate lets them, and the backend
// refusal covers the pure-SSO case where has_password is false.
const showPasswordCard = $derived((session.user?.has_password ?? false) && passwordLoginEnabled);
/**
* Mandatory change-password mode. TRUE when the backend has
+4 -2
View File
@@ -14,7 +14,8 @@ const { session, ui } = vi.hoisted(() => ({
role: 'admin',
storage_used_bytes: 100,
storage_quota_bytes: 1000,
is_external: false
is_external: false,
has_password: true
}
},
ui: { notify: vi.fn() }
@@ -54,7 +55,8 @@ beforeEach(() => {
role: 'admin',
storage_used_bytes: 100,
storage_quota_bytes: 1000,
is_external: false
is_external: false,
has_password: true
};
m(profile.listAppPasswords).mockResolvedValue([]);
m(profile.updateProfile).mockResolvedValue(undefined);
+7 -1
View File
@@ -36,6 +36,12 @@
"subject": "شارك {{inviter}} معك {{kind}} على OxiCloud",
"body": "شارك {{inviter_full}} معك {{kind}} على OxiCloud.\n\nافتح OxiCloud لعرض مشاركتك الجديدة:\n{{login_link}}\n\nقد تكون لديك مشاركات جديدة أخرى من {{inviter}} — سجّل الدخول لرؤية جميع العناصر المشاركة معك.\n\n— OxiCloud\n\nأنت تتلقى هذه الرسالة لأن لديك حسابًا في OxiCloud وتفضيل إشعارات المشاركة مُفعّل. يمكنك تعطيله من ملفك الشخصي (راسلني عندما يشاركني شخص ما)."
}
},
"security": {
"password_changed": {
"subject": "تم تغيير كلمة مرور OxiCloud الخاصة بك",
"body": "مرحباً،\n\nتم تغيير كلمة مرور OxiCloud الخاصة بك للتو في {{timestamp}} (UTC) من عنوان IP {{ip}}.\n\nإذا كنت أنت من قام بذلك، فلا حاجة لأي إجراء — يمكنك تجاهل هذه الرسالة.\n\nإذا لم تكن أنت، فاتصل بمسؤول النظام فوراً. قد يكون شخص ما قد وصل إلى حسابك.\n\n— OxiCloud"
}
}
},
"server_status": {
@@ -1335,4 +1341,4 @@
"wrong_drop_zone_msg": "الرفع يعمل فقط في قسم الملفات — افتح قسم الملفات وأفلت العناصر هناك.",
"wrong_drop_zone_action": "انتقل إلى الملفات"
}
}
}
+7 -1
View File
@@ -36,6 +36,12 @@
"subject": "{{inviter}} hat einen {{kind}} mit Ihnen auf OxiCloud geteilt",
"body": "{{inviter_full}} hat einen {{kind}} mit Ihnen auf OxiCloud geteilt.\n\nÖffnen Sie OxiCloud, um Ihre neue Freigabe zu sehen:\n{{login_link}}\n\nMöglicherweise gibt es weitere neue Freigaben von {{inviter}} — melden Sie sich an, um alle Ihre freigegebenen Elemente zu sehen.\n\n— OxiCloud\n\nSie erhalten diese Nachricht, weil Sie ein OxiCloud-Konto haben und die Benachrichtigung über Freigaben aktiviert ist. Sie können sie in Ihrem Profil deaktivieren (Per E-Mail benachrichtigen, wenn jemand mit mir teilt)."
}
},
"security": {
"password_changed": {
"subject": "Ihr OxiCloud-Passwort wurde geändert",
"body": "Hallo,\n\nIhr OxiCloud-Passwort wurde soeben am {{timestamp}} (UTC) von der IP-Adresse {{ip}} geändert.\n\nWenn Sie das waren, ist keine Aktion erforderlich — Sie können diese Nachricht ignorieren.\n\nWenn Sie das NICHT waren, wenden Sie sich sofort an Ihren Administrator. Möglicherweise hat jemand Zugriff auf Ihr Konto erhalten.\n\n— OxiCloud"
}
}
},
"server_status": {
@@ -1335,4 +1341,4 @@
"wrong_drop_zone_msg": "Uploads funktionieren nur in Dateien — öffne den Bereich Dateien und lege die Elemente dort ab.",
"wrong_drop_zone_action": "Zu Dateien wechseln"
}
}
}
+7 -1
View File
@@ -36,6 +36,12 @@
"subject": "{{inviter}} shared a {{kind}} with you on OxiCloud",
"body": "{{inviter_full}} shared a {{kind}} with you on OxiCloud.\n\nOpen OxiCloud to see your new share:\n{{login_link}}\n\nYou may have additional new shares from {{inviter}} — sign in to see all your shared items.\n\n— OxiCloud\n\nYou're receiving this message because you have an OxiCloud account and your share-notification preference is on. You can turn it off in your profile (Email me when someone shares with me)."
}
},
"security": {
"password_changed": {
"subject": "Your OxiCloud password was changed",
"body": "Hello,\n\nYour OxiCloud password was just changed at {{timestamp}} (UTC) from IP address {{ip}}.\n\nIf this was you, no action is needed — you can ignore this message.\n\nIf this was NOT you, contact your administrator immediately. Someone may have gained access to your account.\n\n— OxiCloud"
}
}
},
"server_status": {
@@ -1765,4 +1771,4 @@
"wrong_drop_zone_msg": "Uploads only work in Files — open the Files section and drop there.",
"wrong_drop_zone_action": "Go to Files"
}
}
}
+7 -1
View File
@@ -36,6 +36,12 @@
"subject": "{{inviter}} ha compartido un {{kind}} contigo en OxiCloud",
"body": "{{inviter_full}} ha compartido un {{kind}} contigo en OxiCloud.\n\nAbre OxiCloud para ver tu nuevo recurso compartido:\n{{login_link}}\n\nPuede que tengas más recursos compartidos nuevos de {{inviter}} — inicia sesión para ver todos tus elementos compartidos.\n\n— OxiCloud\n\nRecibes este mensaje porque tienes una cuenta de OxiCloud y la preferencia de notificación de recursos compartidos está activada. Puedes desactivarla en tu perfil (Enviarme un correo cuando alguien comparta conmigo)."
}
},
"security": {
"password_changed": {
"subject": "Se cambió su contraseña de OxiCloud",
"body": "Hola,\n\nSu contraseña de OxiCloud acaba de cambiarse el {{timestamp}} (UTC) desde la dirección IP {{ip}}.\n\nSi fue usted, no se requiere ninguna acción — puede ignorar este mensaje.\n\nSi NO fue usted, contacte a su administrador inmediatamente. Alguien pudo haber obtenido acceso a su cuenta.\n\n— OxiCloud"
}
}
},
"server_status": {
@@ -1350,4 +1356,4 @@
"wrong_drop_zone_msg": "Las subidas solo funcionan en Archivos — abre la sección Archivos y suelta ahí los elementos.",
"wrong_drop_zone_action": "Ir a Archivos"
}
}
}
+7 -1
View File
@@ -36,6 +36,12 @@
"subject": "{{inviter}} یک {{kind}} را با شما در OxiCloud به اشتراک گذاشت",
"body": "{{inviter_full}} یک {{kind}} را با شما در OxiCloud به اشتراک گذاشت.\n\nبرای دیدن اشتراک‌گذاری جدید خود، OxiCloud را باز کنید:\n{{login_link}}\n\nممکن است اشتراک‌گذاری‌های جدید دیگری از {{inviter}} داشته باشید — وارد شوید تا همه موارد به اشتراک گذاشته‌شده با خود را ببینید.\n\n— OxiCloud\n\nشما این پیام را دریافت می‌کنید زیرا حساب OxiCloud دارید و گزینه اعلان اشتراک‌گذاری شما روشن است. می‌توانید آن را در پروفایل خود خاموش کنید (وقتی کسی با من چیزی به اشتراک می‌گذارد، به من ایمیل بزن)."
}
},
"security": {
"password_changed": {
"subject": "رمز عبور OxiCloud شما تغییر کرد",
"body": "سلام،\n\nرمز عبور OxiCloud شما هم‌اکنون در {{timestamp}} (UTC) از نشانی IP {{ip}} تغییر یافت.\n\nاگر خودتان این کار را کرده‌اید، نیازی به اقدامی نیست — می‌توانید این پیام را نادیده بگیرید.\n\nاگر شما این کار را نکرده‌اید، فوراً با مدیر سیستم تماس بگیرید. ممکن است شخصی به حساب شما دسترسی پیدا کرده باشد.\n\n— OxiCloud"
}
}
},
"server_status": {
@@ -1335,4 +1341,4 @@
"wrong_drop_zone_msg": "بارگذاری فقط در بخش پرونده‌ها کار می‌کند — بخش پرونده‌ها را باز کنید و آنجا رها کنید.",
"wrong_drop_zone_action": "برو به پرونده‌ها"
}
}
}
+7 -1
View File
@@ -36,6 +36,12 @@
"subject": "{{inviter}} a partagé un {{kind}} avec vous sur OxiCloud",
"body": "{{inviter_full}} a partagé un {{kind}} avec vous sur OxiCloud.\n\nOuvrez OxiCloud pour voir votre nouveau partage :\n{{login_link}}\n\nVous avez peut-être d'autres nouveaux partages de {{inviter}} — connectez-vous pour voir tous vos éléments partagés.\n\n— OxiCloud\n\nVous recevez ce message parce que vous avez un compte OxiCloud et que la préférence de notification de partage est activée. Vous pouvez la désactiver dans votre profil (M'avertir par e-mail quand quelqu'un partage avec moi)."
}
},
"security": {
"password_changed": {
"subject": "Votre mot de passe OxiCloud a été modifié",
"body": "Bonjour,\n\nVotre mot de passe OxiCloud vient d'être modifié le {{timestamp}} (UTC) depuis l'adresse IP {{ip}}.\n\nSi c'était vous, aucune action n'est nécessaire — vous pouvez ignorer ce message.\n\nSi ce n'était PAS vous, contactez immédiatement votre administrateur. Quelqu'un a peut-être obtenu accès à votre compte.\n\n— OxiCloud"
}
}
},
"server_status": {
@@ -1338,4 +1344,4 @@
"wrong_drop_zone_msg": "Les envois ne fonctionnent que dans Fichiers — ouvrez la section Fichiers et déposez-y vos éléments.",
"wrong_drop_zone_action": "Aller aux Fichiers"
}
}
}
+7 -1
View File
@@ -36,6 +36,12 @@
"subject": "{{inviter}} ने OxiCloud पर आपके साथ एक {{kind}} साझा किया",
"body": "{{inviter_full}} ने OxiCloud पर आपके साथ एक {{kind}} साझा किया है।\n\nअपना नया साझाकरण देखने के लिए OxiCloud खोलें:\n{{login_link}}\n\nहो सकता है आपके पास {{inviter}} से और भी नए साझाकरण हों — साइन इन करें और अपने सभी साझा किए गए आइटम देखें।\n\n— OxiCloud\n\nआपको यह संदेश इसलिए मिल रहा है क्योंकि आपका OxiCloud खाता है और साझाकरण-सूचना प्राथमिकता चालू है। आप इसे अपनी प्रोफ़ाइल में बंद कर सकते हैं (जब कोई मेरे साथ साझा करे तो मुझे ईमेल भेजें)।"
}
},
"security": {
"password_changed": {
"subject": "आपका OxiCloud पासवर्ड बदल दिया गया",
"body": "नमस्ते,\n\nआपका OxiCloud पासवर्ड अभी-अभी {{timestamp}} (UTC) पर IP पते {{ip}} से बदला गया।\n\nयदि यह आपने किया, तो कोई कार्रवाई आवश्यक नहीं है — आप इस संदेश को अनदेखा कर सकते हैं।\n\nयदि यह आपने नहीं किया, तो तुरंत अपने प्रशासक से संपर्क करें। हो सकता है किसी ने आपके खाते तक पहुंच प्राप्त कर ली हो।\n\n— OxiCloud"
}
}
},
"server_status": {
@@ -1335,4 +1341,4 @@
"wrong_drop_zone_msg": "अपलोड केवल फ़ाइलें अनुभाग में काम करता है — फ़ाइलें अनुभाग खोलें और वहीं छोड़ें।",
"wrong_drop_zone_action": "फ़ाइलों पर जाएँ"
}
}
}
+7 -1
View File
@@ -36,6 +36,12 @@
"subject": "{{inviter}} ha condiviso un {{kind}} con te su OxiCloud",
"body": "{{inviter_full}} ha condiviso un {{kind}} con te su OxiCloud.\n\nApri OxiCloud per vedere la tua nuova condivisione:\n{{login_link}}\n\nPotresti avere altre nuove condivisioni da {{inviter}} — accedi per vedere tutti gli elementi condivisi con te.\n\n— OxiCloud\n\nRicevi questo messaggio perché hai un account OxiCloud e la preferenza di notifica delle condivisioni è attiva. Puoi disattivarla dal tuo profilo (Avvisami via email quando qualcuno condivide con me)."
}
},
"security": {
"password_changed": {
"subject": "La tua password OxiCloud è stata modificata",
"body": "Ciao,\n\nLa tua password OxiCloud è stata appena modificata il {{timestamp}} (UTC) dall'indirizzo IP {{ip}}.\n\nSe sei stato tu, non è richiesta alcuna azione — puoi ignorare questo messaggio.\n\nSe NON sei stato tu, contatta immediatamente il tuo amministratore. Qualcuno potrebbe aver ottenuto accesso al tuo account.\n\n— OxiCloud"
}
}
},
"server_status": {
@@ -1335,4 +1341,4 @@
"wrong_drop_zone_msg": "I caricamenti funzionano solo in File — apri la sezione File e trascina lì gli elementi.",
"wrong_drop_zone_action": "Vai a File"
}
}
}
+7 -1
View File
@@ -36,6 +36,12 @@
"subject": "{{inviter}} さんが OxiCloud で {{kind}} をあなたと共有しました",
"body": "{{inviter_full}} さんが OxiCloud で {{kind}} をあなたと共有しました。\n\n新しい共有を確認するには OxiCloud を開いてください:\n{{login_link}}\n\n{{inviter}} さんから他にも新しい共有があるかもしれません — サインインしてあなたと共有されたすべての項目を確認してください。\n\n— OxiCloud\n\nOxiCloud のアカウントをお持ちで、共有通知の設定が有効になっているため、このメッセージが届いています。プロフィールでオフにできます(誰かが共有したときにメールで通知する)。"
}
},
"security": {
"password_changed": {
"subject": "OxiCloudのパスワードが変更されました",
"body": "こんにちは、\n\nお使いのOxiCloudパスワードが {{timestamp}} (UTC) にIPアドレス {{ip}} から変更されました。\n\nご自身で行った場合は、対応は不要です — このメッセージは無視してください。\n\nご自身で行っていない場合は、直ちに管理者に連絡してください。第三者がアカウントにアクセスした可能性があります。\n\n— OxiCloud"
}
}
},
"server_status": {
@@ -1335,4 +1341,4 @@
"wrong_drop_zone_msg": "アップロードはファイル セクションでのみ機能します。ファイル セクションを開いてそこにドロップしてください。",
"wrong_drop_zone_action": "ファイルへ移動"
}
}
}
+7 -1
View File
@@ -36,6 +36,12 @@
"subject": "{{inviter}}님이 OxiCloud에서 {{kind}}을(를) 공유했습니다",
"body": "{{inviter_full}}님이 OxiCloud에서 {{kind}}을(를) 공유했습니다.\n\n새 공유 항목을 확인하려면 OxiCloud를 여세요:\n{{login_link}}\n\n{{inviter}}님이 추가로 공유한 항목이 있을 수 있습니다 — 로그인하여 공유받은 모든 항목을 확인하세요.\n\n— OxiCloud\n\nOxiCloud 계정이 있고 공유 알림 기본 설정이 켜져 있어 이 메시지를 받았습니다. 프로필에서 끌 수 있습니다(다른 사람이 나에게 공유할 때 이메일로 알림 받기)."
}
},
"security": {
"password_changed": {
"subject": "OxiCloud 비밀번호가 변경되었습니다",
"body": "안녕하세요,\n\n귀하의 OxiCloud 비밀번호가 방금 {{timestamp}} (UTC)에 IP 주소 {{ip}}에서 변경되었습니다.\n\n본인이 변경한 것이라면 별도의 조치가 필요하지 않습니다 — 이 메시지를 무시하셔도 됩니다.\n\n본인이 변경한 것이 아니라면 즉시 관리자에게 연락하십시오. 누군가 귀하의 계정에 접근했을 수 있습니다.\n\n— OxiCloud"
}
}
},
"server_status": {
@@ -1690,4 +1696,4 @@
"wrong_drop_zone_msg": "업로드는 파일 섹션에서만 작동합니다. 파일 섹션을 열고 거기에 놓아 주세요.",
"wrong_drop_zone_action": "파일로 이동"
}
}
}
+7 -1
View File
@@ -36,6 +36,12 @@
"subject": "{{inviter}} heeft een {{kind}} met je gedeeld op OxiCloud",
"body": "{{inviter_full}} heeft een {{kind}} met je gedeeld op OxiCloud.\n\nOpen OxiCloud om je nieuwe gedeelde item te bekijken:\n{{login_link}}\n\nMisschien heb je nog meer nieuwe gedeelde items van {{inviter}} — meld je aan om al je gedeelde items te zien.\n\n— OxiCloud\n\nJe ontvangt dit bericht omdat je een OxiCloud-account hebt en je voorkeur voor deelmeldingen aanstaat. Je kunt het uitzetten in je profiel (Stuur me een e-mail wanneer iemand iets met mij deelt)."
}
},
"security": {
"password_changed": {
"subject": "Uw OxiCloud-wachtwoord is gewijzigd",
"body": "Hallo,\n\nUw OxiCloud-wachtwoord is zojuist gewijzigd op {{timestamp}} (UTC) vanaf IP-adres {{ip}}.\n\nAls u dit was, is er geen actie nodig — u kunt dit bericht negeren.\n\nAls u dit NIET was, neem dan onmiddellijk contact op met uw beheerder. Iemand kan toegang hebben verkregen tot uw account.\n\n— OxiCloud"
}
}
},
"server_status": {
@@ -1335,4 +1341,4 @@
"wrong_drop_zone_msg": "Uploaden werkt alleen in Bestanden — open het onderdeel Bestanden en zet ze daar neer.",
"wrong_drop_zone_action": "Naar Bestanden"
}
}
}
+7 -1
View File
@@ -36,6 +36,12 @@
"subject": "{{inviter}} udostępnił Ci {{kind}} w OxiCloud",
"body": "{{inviter_full}} udostępnił Ci {{kind}} w OxiCloud.\n\nOtwórz OxiCloud, aby zobaczyć nowe udostępnienie:\n{{login_link}}\n\nMożesz mieć dodatkowe nowe udostępnienia od {{inviter}} — zaloguj się, aby zobaczyć wszystkie udostępnione Ci elementy.\n\n— OxiCloud\n\nOtrzymujesz tę wiadomość, ponieważ masz konto OxiCloud i preferencja powiadomień o udostępnieniach jest włączona. Możesz ją wyłączyć w swoim profilu (Wyślij mi e-mail, gdy ktoś coś mi udostępni)."
}
},
"security": {
"password_changed": {
"subject": "Twoje hasło OxiCloud zostało zmienione",
"body": "Cześć,\n\nTwoje hasło OxiCloud zostało właśnie zmienione w dniu {{timestamp}} (UTC) z adresu IP {{ip}}.\n\nJeśli to byłeś Ty, żadne działanie nie jest wymagane — możesz zignorować tę wiadomość.\n\nJeśli to NIE byłeś Ty, natychmiast skontaktuj się z administratorem. Ktoś mógł uzyskać dostęp do Twojego konta.\n\n— OxiCloud"
}
}
},
"server_status": {
@@ -1335,4 +1341,4 @@
"wrong_drop_zone_msg": "Przesyłanie działa tylko w Plikach — otwórz sekcję Pliki i upuść tam pliki.",
"wrong_drop_zone_action": "Przejdź do Plików"
}
}
}
+7 -1
View File
@@ -36,6 +36,12 @@
"subject": "{{inviter}} partilhou um {{kind}} consigo no OxiCloud",
"body": "{{inviter_full}} partilhou um {{kind}} consigo no OxiCloud.\n\nAbra o OxiCloud para ver a sua nova partilha:\n{{login_link}}\n\nPode ter mais partilhas novas de {{inviter}} — inicie sessão para ver todos os itens partilhados consigo.\n\n— OxiCloud\n\nRecebeu esta mensagem porque tem uma conta OxiCloud e a preferência de notificação de partilhas está ativada. Pode desativá-la no seu perfil (Avisar-me por e-mail quando alguém compartilhar comigo)."
}
},
"security": {
"password_changed": {
"subject": "Sua senha do OxiCloud foi alterada",
"body": "Olá,\n\nSua senha do OxiCloud foi alterada em {{timestamp}} (UTC) a partir do endereço IP {{ip}}.\n\nSe foi você, nenhuma ação é necessária — pode ignorar esta mensagem.\n\nSe NÃO foi você, entre em contato com o seu administrador imediatamente. Alguém pode ter obtido acesso à sua conta.\n\n— OxiCloud"
}
}
},
"server_status": {
@@ -1335,4 +1341,4 @@
"wrong_drop_zone_msg": "Os envios só funcionam em Ficheiros — abra a secção Ficheiros e largue-os aí.",
"wrong_drop_zone_action": "Ir para Arquivos"
}
}
}
+7 -1
View File
@@ -36,6 +36,12 @@
"subject": "{{inviter}} поделился(ась) с вами {{kind}} в OxiCloud",
"body": "{{inviter_full}} поделился(ась) с вами {{kind}} в OxiCloud.\n\nОткройте OxiCloud, чтобы увидеть новый общий ресурс:\n{{login_link}}\n\nВозможно, у вас есть и другие новые общие ресурсы от {{inviter}} — войдите, чтобы увидеть все элементы, которыми с вами поделились.\n\n— OxiCloud\n\nВы получаете это сообщение, потому что у вас есть учётная запись OxiCloud и предпочтение уведомлений об общих ресурсах включено. Вы можете отключить его в своём профиле (Уведомлять меня по электронной почте, когда кто-то делится со мной)."
}
},
"security": {
"password_changed": {
"subject": "Ваш пароль OxiCloud был изменён",
"body": "Здравствуйте,\n\nВаш пароль OxiCloud только что был изменён {{timestamp}} (UTC) с IP-адреса {{ip}}.\n\nЕсли это были вы, никаких действий не требуется — можете проигнорировать это сообщение.\n\nЕсли это были НЕ вы, немедленно свяжитесь с администратором. Кто-то мог получить доступ к вашей учётной записи.\n\n— OxiCloud"
}
}
},
"server_status": {
@@ -1335,4 +1341,4 @@
"wrong_drop_zone_msg": "Загрузки работают только в разделе Файлы — откройте раздел Файлы и перетащите туда.",
"wrong_drop_zone_action": "Перейти к файлам"
}
}
}
+7 -1
View File
@@ -36,6 +36,12 @@
"subject": "{{inviter}} 在 OxiCloud 上與您分享了一個{{kind}}",
"body": "{{inviter_full}} 在 OxiCloud 上與您分享了一個{{kind}}。\n\n開啟 OxiCloud 檢視您的新分享:\n{{login_link}}\n\n您可能還有來自 {{inviter}} 的其他新分享 — 登入以檢視所有與您分享的項目。\n\n— OxiCloud\n\n您收到此訊息是因為您擁有 OxiCloud 帳戶且分享通知偏好已開啟。您可以在個人資料中關閉它(當有人與我分享時透過電子郵件通知我)。"
}
},
"security": {
"password_changed": {
"subject": "您的 OxiCloud 密碼已變更",
"body": "您好,\n\n您的 OxiCloud 密碼剛剛於 {{timestamp}} (UTC) 從 IP 位址 {{ip}} 被變更。\n\n如果是您本人操作,無需採取任何行動 — 可以忽略此訊息。\n\n如果不是您本人操作,請立即聯絡您的管理員。可能有人取得了您帳號的存取權限。\n\n— OxiCloud"
}
}
},
"server_status": {
@@ -1335,4 +1341,4 @@
"wrong_drop_zone_msg": "上傳僅在「檔案」中有效 — 請開啟檔案區並在該處拖放。",
"wrong_drop_zone_action": "前往檔案"
}
}
}
+7 -1
View File
@@ -36,6 +36,12 @@
"subject": "{{inviter}} 在 OxiCloud 上与您共享了一个{{kind}}",
"body": "{{inviter_full}} 在 OxiCloud 上与您共享了一个{{kind}}。\n\n打开 OxiCloud 查看您的新共享:\n{{login_link}}\n\n您可能还有来自 {{inviter}} 的其他新共享 — 登录以查看所有共享给您的项目。\n\n— OxiCloud\n\n您收到此消息是因为您拥有 OxiCloud 账户且共享通知偏好已开启。您可以在个人资料中关闭它(当有人与我共享时通过电子邮件通知我)。"
}
},
"security": {
"password_changed": {
"subject": "您的 OxiCloud 密码已更改",
"body": "您好,\n\n您的 OxiCloud 密码刚刚于 {{timestamp}} (UTC) 从 IP 地址 {{ip}} 被更改。\n\n如果是您本人操作,无需采取任何行动 — 可以忽略此消息。\n\n如果不是您本人操作,请立即联系您的管理员。可能有人获得了对您账户的访问权限。\n\n— OxiCloud"
}
}
},
"server_status": {
@@ -1335,4 +1341,4 @@
"wrong_drop_zone_msg": "上传仅在 “文件” 中生效 — 请打开文件区并在那里拖放。",
"wrong_drop_zone_action": "前往文件"
}
}
}