diff --git a/Cargo.lock b/Cargo.lock index 82a10fd8..a876f0e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -252,6 +252,17 @@ version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +[[package]] +name = "apple-native-keyring-store" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7be2f067ccd8d4b4d4a66ddafe0f32a5dff31732f32dbff85fefc40929b1f72" +dependencies = [ + "keyring-core", + "log", + "security-framework", +] + [[package]] name = "arbitrary" version = "1.4.2" @@ -640,6 +651,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-padding" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" +dependencies = [ + "generic-array", +] + [[package]] name = "block2" version = "0.6.2" @@ -889,6 +909,15 @@ dependencies = [ "toml 0.9.12+spec-1.1.0", ] +[[package]] +name = "cbc" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" +dependencies = [ + "cipher", +] + [[package]] name = "cc" version = "1.2.58" @@ -1514,10 +1543,29 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "708b509edf7889e53d7efb0ffadd994cc6c2345ccb62f55cfd6b0682165e4fa6" dependencies = [ + "aes", + "block-padding", + "cbc", "dbus", + "fastrand", + "hkdf", + "num", + "once_cell", + "openssl", + "sha2", "zeroize", ] +[[package]] +name = "dbus-secret-service-keyring-store" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21d8f54da401bb5eb2a4d873ac4b359f4a599df2ca8634bb5b8c045e5ee78757" +dependencies = [ + "dbus-secret-service", + "keyring-core", +] + [[package]] name = "default-net" version = "0.22.0" @@ -1629,6 +1677,7 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", + "subtle", ] [[package]] @@ -2808,6 +2857,24 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + [[package]] name = "home" version = "0.5.12" @@ -3195,6 +3262,7 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" dependencies = [ + "block-padding", "generic-array", ] @@ -3426,18 +3494,12 @@ dependencies = [ ] [[package]] -name = "keyring" -version = "3.6.3" +name = "keyring-core" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eebcc3aff044e5944a8fbaf69eb277d11986064cba30c468730e8b9909fb551c" +checksum = "fb1e621458ca9c51aa110bd0339d4751a056b9576bf1253aee1aa560dda0fc9d" dependencies = [ - "byteorder", - "dbus-secret-service", "log", - "security-framework 2.11.1", - "security-framework 3.7.0", - "windows-sys 0.60.2", - "zeroize", ] [[package]] @@ -3532,6 +3594,7 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "328c4789d42200f1eeec05bd86c9c13c7f091d2ba9a6ea35acdf51f31bc0f043" dependencies = [ + "cc", "pkg-config", ] @@ -3931,7 +3994,7 @@ dependencies = [ "openssl-probe", "openssl-sys", "schannel", - "security-framework 3.7.0", + "security-framework", "security-framework-sys", "tempfile", ] @@ -4148,6 +4211,20 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + [[package]] name = "num-bigint" version = "0.4.6" @@ -4158,6 +4235,15 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + [[package]] name = "num-conv" version = "0.2.1" @@ -4173,6 +4259,28 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -5995,7 +6103,7 @@ dependencies = [ "openssl-probe", "rustls-pki-types", "schannel", - "security-framework 3.7.0", + "security-framework", ] [[package]] @@ -6023,7 +6131,7 @@ dependencies = [ "rustls-native-certs", "rustls-platform-verifier-android", "rustls-webpki", - "security-framework 3.7.0", + "security-framework", "security-framework-sys", "webpki-root-certs", "windows-sys 0.61.2", @@ -6172,19 +6280,6 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" -[[package]] -name = "security-framework" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" -dependencies = [ - "bitflags 2.11.0", - "core-foundation 0.9.4", - "core-foundation-sys 0.8.7", - "libc", - "security-framework-sys", -] - [[package]] name = "security-framework" version = "3.7.0" @@ -7496,13 +7591,16 @@ dependencies = [ name = "tauri-plugin-native-bridge" version = "0.1.0" dependencies = [ + "apple-native-keyring-store", + "dbus-secret-service-keyring-store", "font-enumeration", - "keyring", + "keyring-core", "schemars 0.8.22", "serde", "tauri", "tauri-plugin", "thiserror 2.0.18", + "windows-native-keyring-store", ] [[package]] @@ -9463,6 +9561,19 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-native-keyring-store" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5fd986f648459dd29aa252ed3a5ad11a60c0b1251bf81625fb03a86c69d274e" +dependencies = [ + "byteorder", + "keyring-core", + "regex", + "windows-sys 0.61.2", + "zeroize", +] + [[package]] name = "windows-numerics" version = "0.2.0" diff --git a/apps/readest-app/public/locales/ar/translation.json b/apps/readest-app/public/locales/ar/translation.json index 9dfd7426..f3e3650f 100644 --- a/apps/readest-app/public/locales/ar/translation.json +++ b/apps/readest-app/public/locales/ar/translation.json @@ -1443,8 +1443,6 @@ "This permanently deletes the encrypted credentials we sync (e.g., OPDS catalog passwords) on every device. Local copies are preserved. You will need to re-enter the sync passphrase or set a new one. Continue?": "سيؤدي هذا إلى حذف بيانات الاعتماد المشفرة التي نقوم بمزامنتها (مثل كلمات مرور كتالوج OPDS) على كل جهاز بشكل دائم. سيتم الاحتفاظ بالنسخ المحلية. ستحتاج إلى إعادة إدخال عبارة مرور المزامنة أو تعيين عبارة جديدة. هل تريد المتابعة؟", "Sync passphrase forgotten — all encrypted fields cleared": "تم نسيان عبارة مرور المزامنة — تم مسح جميع الحقول المشفرة", "Sync passphrase": "عبارة مرور المزامنة", - "Encrypts sensitive synced fields (like OPDS catalog credentials) before they leave your device. Set one now or wait — it will be requested when needed.": "يقوم بتشفير الحقول الحساسة المتزامنة (مثل بيانات اعتماد كتالوج OPDS) قبل مغادرتها لجهازك. قم بتعيين عبارة الآن أو انتظر — سيُطلب منك ذلك عند الحاجة.", - "Set on this account. Will be requested when needed to decrypt synced credentials.": "تم تعيينها في هذا الحساب. سيُطلب منك إدخالها عند الحاجة لفك تشفير بيانات الاعتماد المتزامنة.", "Set passphrase": "تعيين عبارة المرور", "Forgot passphrase": "نسيت عبارة المرور", "Incorrect PIN": "رمز PIN غير صحيح", @@ -1492,5 +1490,9 @@ "Theme, highlight colours, integrations (KOSync, Readwise, Hardcover), and dictionary order": "السمة وألوان التظليل والتكاملات (KOSync وReadwise وHardcover) وترتيب القواميس", "Required while Dictionaries sync is enabled": "مطلوب أثناء تفعيل مزامنة القواميس", "Resets in {{hours}} hr {{minutes}} min": "يُعاد الضبط خلال {{hours}} س {{minutes}} د", - "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "اختر رمز PIN مكوّنًا من 4 أرقام. ستحتاج إلى إدخاله في كل مرة تفتح فيها Readest. لا توجد طريقة لاستعادة رمز PIN المنسي. مسح بيانات التطبيق هو الطريقة الوحيدة لإعادة ضبطه." + "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "اختر رمز PIN مكوّنًا من 4 أرقام. ستحتاج إلى إدخاله في كل مرة تفتح فيها Readest. لا توجد طريقة لاستعادة رمز PIN المنسي. مسح بيانات التطبيق هو الطريقة الوحيدة لإعادة ضبطه.", + "Credentials": "بيانات الاعتماد", + "Tokens, usernames, and passwords for OPDS, KOReader, Hardcover, and Readwise. When disabled, credentials remain on this device only and are never uploaded.": "الرموز وأسماء المستخدمين وكلمات المرور لـ OPDS و KOReader و Hardcover و Readwise. عند التعطيل، تبقى بيانات الاعتماد على هذا الجهاز فقط ولا تُرفع أبدًا.", + "Sensitive synced fields are encrypted before upload. Set a passphrase now or later when encryption is needed.": "تُشفَّر الحقول الحساسة المتزامنة قبل الرفع. عيّن عبارة مرور الآن أو لاحقًا عند الحاجة إلى التشفير.", + "Saved to this account. You will be prompted for it when decrypting credentials.": "محفوظة في هذا الحساب. سيُطلب منك إدخالها عند فك تشفير بيانات الاعتماد." } diff --git a/apps/readest-app/public/locales/bn/translation.json b/apps/readest-app/public/locales/bn/translation.json index c576f49b..6f973083 100644 --- a/apps/readest-app/public/locales/bn/translation.json +++ b/apps/readest-app/public/locales/bn/translation.json @@ -1347,8 +1347,6 @@ "This permanently deletes the encrypted credentials we sync (e.g., OPDS catalog passwords) on every device. Local copies are preserved. You will need to re-enter the sync passphrase or set a new one. Continue?": "এটি প্রতিটি ডিভাইসে আমরা সিঙ্ক করি এমন এনক্রিপ্ট করা শংসাপত্র (যেমন, OPDS ক্যাটালগ পাসওয়ার্ড) স্থায়ীভাবে মুছে ফেলে। স্থানীয় কপিগুলি সংরক্ষিত থাকে। আপনাকে সিঙ্ক পাসফ্রেজ পুনরায় প্রবেশ করতে হবে বা একটি নতুন সেট করতে হবে। চালিয়ে যাবেন?", "Sync passphrase forgotten — all encrypted fields cleared": "সিঙ্ক পাসফ্রেজ ভুলে গিয়েছেন — সমস্ত এনক্রিপ্ট করা ক্ষেত্র সাফ করা হয়েছে", "Sync passphrase": "সিঙ্ক পাসফ্রেজ", - "Encrypts sensitive synced fields (like OPDS catalog credentials) before they leave your device. Set one now or wait — it will be requested when needed.": "সংবেদনশীল সিঙ্ক করা ক্ষেত্রগুলি (যেমন OPDS ক্যাটালগ শংসাপত্র) আপনার ডিভাইস ছেড়ে যাওয়ার আগে এনক্রিপ্ট করে। এখন একটি সেট করুন বা অপেক্ষা করুন — প্রয়োজন হলে এটি অনুরোধ করা হবে।", - "Set on this account. Will be requested when needed to decrypt synced credentials.": "এই অ্যাকাউন্টে সেট করা হয়েছে। সিঙ্ক করা শংসাপত্রগুলি ডিক্রিপ্ট করার জন্য প্রয়োজন হলে এটি অনুরোধ করা হবে।", "Set passphrase": "পাসফ্রেজ সেট করুন", "Forgot passphrase": "পাসফ্রেজ ভুলে গেছেন", "Incorrect PIN": "ভুল PIN", @@ -1396,5 +1394,9 @@ "Theme, highlight colours, integrations (KOSync, Readwise, Hardcover), and dictionary order": "থিম, হাইলাইট রং, ইন্টিগ্রেশন (KOSync, Readwise, Hardcover) এবং অভিধানের ক্রম", "Required while Dictionaries sync is enabled": "অভিধান সিঙ্ক সক্রিয় থাকাকালীন প্রয়োজনীয়", "Resets in {{hours}} hr {{minutes}} min": "{{hours}} ঘ {{minutes}} মি পরে রিসেট হবে", - "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "একটি ৪-অঙ্কের পিন বেছে নিন। প্রতিবার Readest খোলার সময় আপনাকে এটি প্রবেশ করাতে হবে। ভুলে যাওয়া পিন পুনরুদ্ধারের কোনো উপায় নেই। অ্যাপের ডেটা মুছে ফেলাই এটি রিসেট করার একমাত্র উপায়।" + "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "একটি ৪-অঙ্কের পিন বেছে নিন। প্রতিবার Readest খোলার সময় আপনাকে এটি প্রবেশ করাতে হবে। ভুলে যাওয়া পিন পুনরুদ্ধারের কোনো উপায় নেই। অ্যাপের ডেটা মুছে ফেলাই এটি রিসেট করার একমাত্র উপায়।", + "Credentials": "ক্রেডেনশিয়াল", + "Tokens, usernames, and passwords for OPDS, KOReader, Hardcover, and Readwise. When disabled, credentials remain on this device only and are never uploaded.": "OPDS, KOReader, Hardcover এবং Readwise-এর জন্য টোকেন, ব্যবহারকারীর নাম এবং পাসওয়ার্ড। নিষ্ক্রিয় থাকলে ক্রেডেনশিয়ালগুলি কেবল এই ডিভাইসেই থাকে এবং কখনই আপলোড হয় না।", + "Sensitive synced fields are encrypted before upload. Set a passphrase now or later when encryption is needed.": "সংবেদনশীল সিঙ্ক করা ক্ষেত্রগুলি আপলোডের আগে এনক্রিপ্ট করা হয়। এনক্রিপশনের প্রয়োজন হলে এখনই অথবা পরে একটি পাসফ্রেজ সেট করুন।", + "Saved to this account. You will be prompted for it when decrypting credentials.": "এই অ্যাকাউন্টে সংরক্ষিত। ক্রেডেনশিয়াল ডিক্রিপ্ট করার সময় আপনাকে এটি দিতে বলা হবে।" } diff --git a/apps/readest-app/public/locales/bo/translation.json b/apps/readest-app/public/locales/bo/translation.json index e131d8b9..8906ae0d 100644 --- a/apps/readest-app/public/locales/bo/translation.json +++ b/apps/readest-app/public/locales/bo/translation.json @@ -1323,8 +1323,6 @@ "This permanently deletes the encrypted credentials we sync (e.g., OPDS catalog passwords) on every device. Local copies are preserved. You will need to re-enter the sync passphrase or set a new one. Continue?": "འདིས་ཡིག་ཆ་ཁག་གསང་སྦས་སུ་མཉམ་སྦྱོར་བྱས་པ་རྣམས་ (དཔེར་ན། OPDS དཀར་ཆག་གི་གསང་ཨང་) སྒྲིག་ཆས་རེ་རེའི་ཐོག་གཏན་འཇགས་སུ་སུབ་སྲིད། ས་གནས་ཀྱི་པར་གཞི་ཉར་ཡོད། ཁྱོད་ཀྱིས་མཉམ་སྦྱོར་གསང་ཚིག་སྔར་བཞིན་འཇུག་པའམ་གསར་པ་སྒྲིག་དགོས། མུ་མཐུད་དམ།", "Sync passphrase forgotten — all encrypted fields cleared": "མཉམ་སྦྱོར་གསང་ཚིག་བརྗེད་སོང་ — གསང་སྦས་ཀྱི་ས་སྟོང་ཚང་མ་སུབ་ཟིན།", "Sync passphrase": "མཉམ་སྦྱོར་གསང་ཚིག", - "Encrypts sensitive synced fields (like OPDS catalog credentials) before they leave your device. Set one now or wait — it will be requested when needed.": "ཁྱོད་ཀྱི་སྒྲིག་ཆས་ལས་མ་འགྲོ་གོང་གལ་ཆེའི་མཉམ་སྦྱོར་ས་སྟོང་རྣམས་ (དཔེར་ན་ OPDS དཀར་ཆག་གི་ངོས་འཛིན་ཆ་འཕྲིན) གསང་སྦས་སུ་སྒྱུར། ད་ལྟ་གཅིག་སྒྲིག་པའམ་སྒུག་ཡོད། — དགོས་མཁོ་འབྱུང་སྐབས་ཞུ་འདུག", - "Set on this account. Will be requested when needed to decrypt synced credentials.": "ཁྱེད་ཀྱི་རྩིས་ཐོ་འདིར་སྒྲིག་ཟིན། མཉམ་སྦྱོར་གྱི་ངོས་འཛིན་ཆ་འཕྲིན་གསང་སྦས་འགྲོལ་སྐབས་དགོས་ཚེ་ཞུ་འདུག", "Set passphrase": "གསང་ཚིག་སྒྲིག་པ།", "Forgot passphrase": "གསང་ཚིག་བརྗེད་སོང་།", "Incorrect PIN": "PIN ནོར་འདུག", @@ -1372,5 +1370,9 @@ "Theme, highlight colours, integrations (KOSync, Readwise, Hardcover), and dictionary order": "བརྗོད་གཞི། གསལ་རྟགས་ཁ་དོག ཟུང་འབྲེལ་ (KOSync, Readwise, Hardcover) དང་ཚིག་མཛོད་ཀྱི་གོ་རིམ།", "Required while Dictionaries sync is enabled": "ཚིག་མཛོད་ཁག་མཉམ་འགྲོ་སྤྱོད་སྐབས་དགོས་མཁོ་ཡོད།", "Resets in {{hours}} hr {{minutes}} min": "{{hours}} ཆུ་ཚོད་ {{minutes}} སྐར་མ་ནང་སླར་གསོ་བྱེད།", - "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "ཨང་གྲངས་བཞི་ཅན་གྱི་ PIN ཞིག་འདེམས་རོགས། Readest ཕྱེ་རུས་ཐེངས་རེར་ཁྱེད་ཀྱིས་དེ་ནང་འཇུག་དགོས། བརྗེད་སོང་བའི་ PIN ཞིག་སླར་གསོ་བྱེད་ཐབས་མེད། ཉེར་སྤྱོད་ཀྱི་གཞི་གྲངས་གཙང་སེལ་བྱེད་པ་ནི་སླར་སྒྲིག་བྱེད་ཐབས་གཅིག་པོ་ཡིན།" + "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "ཨང་གྲངས་བཞི་ཅན་གྱི་ PIN ཞིག་འདེམས་རོགས། Readest ཕྱེ་རུས་ཐེངས་རེར་ཁྱེད་ཀྱིས་དེ་ནང་འཇུག་དགོས། བརྗེད་སོང་བའི་ PIN ཞིག་སླར་གསོ་བྱེད་ཐབས་མེད། ཉེར་སྤྱོད་ཀྱི་གཞི་གྲངས་གཙང་སེལ་བྱེད་པ་ནི་སླར་སྒྲིག་བྱེད་ཐབས་གཅིག་པོ་ཡིན།", + "Credentials": "ངོས་སྦྱོར་ཆ་འཕྲིན།", + "Tokens, usernames, and passwords for OPDS, KOReader, Hardcover, and Readwise. When disabled, credentials remain on this device only and are never uploaded.": "OPDS, KOReader, Hardcover, དང་ Readwise བཅས་ཀྱི་ཐོ་ཀེན་དང་སྤྱོད་མི་མིང་དང་གསང་གྲངས། སྤོ་འཛུགས་མེད་པའི་སྐབས། ངོས་སྦྱོར་ཆ་འཕྲིན་ཡིག་ཆས་འདི་ཁོ་ནར་གནས་པ་དང་ནམ་ཡང་སྤོ་གཏོང་མི་བྱེད།", + "Sensitive synced fields are encrypted before upload. Set a passphrase now or later when encryption is needed.": "གཙོ་གནད་ཆགས་པའི་མཉམ་སྡེབ་ཐོ་ཁོངས་ཡིག་ཆ་སྤོ་གཏོང་མ་བྱས་སྔོན་ལ་གསང་སྦས་སུ་འགྱུར་བར་བཟོ། གསང་སྦས་དགོས་སྐབས་ད་ལྟ་འམ་ཕྱིས་སུ་གསང་ཚིག་ཕྲེང་གཅིག་སྒྲིག་འཛུགས་གནང་རོགས།", + "Saved to this account. You will be prompted for it when decrypting credentials.": "རྩིས་ཐོ་འདིར་ཉར་ཚགས་བྱས་ཡོད། ངོས་སྦྱོར་ཆ་འཕྲིན་ལ་གསང་སྦས་འགྲོལ་སྐབས་ཁྱེད་ལ་འདྲི་སློང་གནང་འགྱུར།" } diff --git a/apps/readest-app/public/locales/de/translation.json b/apps/readest-app/public/locales/de/translation.json index 9e934f39..a742bed6 100644 --- a/apps/readest-app/public/locales/de/translation.json +++ b/apps/readest-app/public/locales/de/translation.json @@ -1347,8 +1347,6 @@ "This permanently deletes the encrypted credentials we sync (e.g., OPDS catalog passwords) on every device. Local copies are preserved. You will need to re-enter the sync passphrase or set a new one. Continue?": "Dies löscht dauerhaft die verschlüsselten Anmeldedaten, die wir auf jedem Gerät synchronisieren (z. B. OPDS-Katalog-Passwörter). Lokale Kopien bleiben erhalten. Sie müssen die Sync-Passphrase erneut eingeben oder eine neue festlegen. Fortfahren?", "Sync passphrase forgotten — all encrypted fields cleared": "Sync-Passphrase vergessen — alle verschlüsselten Felder wurden gelöscht", "Sync passphrase": "Sync-Passphrase", - "Encrypts sensitive synced fields (like OPDS catalog credentials) before they leave your device. Set one now or wait — it will be requested when needed.": "Verschlüsselt sensible synchronisierte Felder (z. B. OPDS-Katalog-Anmeldedaten), bevor sie Ihr Gerät verlassen. Legen Sie jetzt eine fest oder warten Sie — sie wird bei Bedarf angefordert.", - "Set on this account. Will be requested when needed to decrypt synced credentials.": "Für dieses Konto festgelegt. Wird bei Bedarf angefordert, um synchronisierte Anmeldedaten zu entschlüsseln.", "Set passphrase": "Passphrase festlegen", "Forgot passphrase": "Passphrase vergessen", "Incorrect PIN": "Falsche PIN", @@ -1396,5 +1394,9 @@ "Theme, highlight colours, integrations (KOSync, Readwise, Hardcover), and dictionary order": "Design, Hervorhebungsfarben, Integrationen (KOSync, Readwise, Hardcover) und Wörterbuchreihenfolge", "Required while Dictionaries sync is enabled": "Erforderlich, solange die Synchronisierung von Wörterbüchern aktiviert ist", "Resets in {{hours}} hr {{minutes}} min": "Zurückgesetzt in {{hours}} Std. {{minutes}} Min.", - "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Wählen Sie eine 4-stellige PIN. Sie müssen sie jedes Mal eingeben, wenn Sie Readest öffnen. Eine vergessene PIN kann nicht wiederhergestellt werden. Das Löschen der App-Daten ist die einzige Möglichkeit, sie zurückzusetzen." + "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Wählen Sie eine 4-stellige PIN. Sie müssen sie jedes Mal eingeben, wenn Sie Readest öffnen. Eine vergessene PIN kann nicht wiederhergestellt werden. Das Löschen der App-Daten ist die einzige Möglichkeit, sie zurückzusetzen.", + "Credentials": "Anmeldedaten", + "Tokens, usernames, and passwords for OPDS, KOReader, Hardcover, and Readwise. When disabled, credentials remain on this device only and are never uploaded.": "Tokens, Benutzernamen und Passwörter für OPDS, KOReader, Hardcover und Readwise. Wenn deaktiviert, bleiben die Anmeldedaten nur auf diesem Gerät und werden nie hochgeladen.", + "Sensitive synced fields are encrypted before upload. Set a passphrase now or later when encryption is needed.": "Sensible synchronisierte Felder werden vor dem Hochladen verschlüsselt. Lege jetzt oder später eine Passphrase fest, wenn die Verschlüsselung benötigt wird.", + "Saved to this account. You will be prompted for it when decrypting credentials.": "In diesem Konto gespeichert. Du wirst beim Entschlüsseln von Anmeldedaten danach gefragt." } diff --git a/apps/readest-app/public/locales/el/translation.json b/apps/readest-app/public/locales/el/translation.json index 5c350bb4..0b05e9c2 100644 --- a/apps/readest-app/public/locales/el/translation.json +++ b/apps/readest-app/public/locales/el/translation.json @@ -1347,8 +1347,6 @@ "This permanently deletes the encrypted credentials we sync (e.g., OPDS catalog passwords) on every device. Local copies are preserved. You will need to re-enter the sync passphrase or set a new one. Continue?": "Αυτό διαγράφει οριστικά τα κρυπτογραφημένα διαπιστευτήρια που συγχρονίζουμε (π.χ. κωδικούς καταλόγου OPDS) σε κάθε συσκευή. Τα τοπικά αντίγραφα διατηρούνται. Θα χρειαστεί να εισαγάγετε ξανά τη φράση πρόσβασης συγχρονισμού ή να ορίσετε μια νέα. Συνέχεια;", "Sync passphrase forgotten — all encrypted fields cleared": "Η φράση πρόσβασης συγχρονισμού ξεχάστηκε — όλα τα κρυπτογραφημένα πεδία διαγράφηκαν", "Sync passphrase": "Φράση πρόσβασης συγχρονισμού", - "Encrypts sensitive synced fields (like OPDS catalog credentials) before they leave your device. Set one now or wait — it will be requested when needed.": "Κρυπτογραφεί ευαίσθητα συγχρονισμένα πεδία (όπως διαπιστευτήρια καταλόγου OPDS) πριν φύγουν από τη συσκευή σας. Ορίστε μία τώρα ή περιμένετε — θα ζητηθεί όταν χρειαστεί.", - "Set on this account. Will be requested when needed to decrypt synced credentials.": "Έχει οριστεί σε αυτόν τον λογαριασμό. Θα ζητηθεί όταν χρειαστεί για την αποκρυπτογράφηση συγχρονισμένων διαπιστευτηρίων.", "Set passphrase": "Ορισμός φράσης πρόσβασης", "Forgot passphrase": "Ξεχάσατε τη φράση πρόσβασης", "Incorrect PIN": "Λανθασμένο PIN", @@ -1396,5 +1394,9 @@ "Theme, highlight colours, integrations (KOSync, Readwise, Hardcover), and dictionary order": "Θέμα, χρώματα επισήμανσης, ενσωματώσεις (KOSync, Readwise, Hardcover) και σειρά λεξικών", "Required while Dictionaries sync is enabled": "Απαιτείται όσο είναι ενεργός ο συγχρονισμός Λεξικών", "Resets in {{hours}} hr {{minutes}} min": "Επαναφορά σε {{hours}} ώρ. {{minutes}} λεπ.", - "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Επιλέξτε ένα 4ψήφιο PIN. Θα πρέπει να το εισάγετε κάθε φορά που ανοίγετε το Readest. Δεν υπάρχει τρόπος ανάκτησης ενός ξεχασμένου PIN. Η εκκαθάριση των δεδομένων της εφαρμογής είναι ο μοναδικός τρόπος επαναφοράς του." + "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Επιλέξτε ένα 4ψήφιο PIN. Θα πρέπει να το εισάγετε κάθε φορά που ανοίγετε το Readest. Δεν υπάρχει τρόπος ανάκτησης ενός ξεχασμένου PIN. Η εκκαθάριση των δεδομένων της εφαρμογής είναι ο μοναδικός τρόπος επαναφοράς του.", + "Credentials": "Διαπιστευτήρια", + "Tokens, usernames, and passwords for OPDS, KOReader, Hardcover, and Readwise. When disabled, credentials remain on this device only and are never uploaded.": "Διακριτικά, ονόματα χρήστη και κωδικοί πρόσβασης για OPDS, KOReader, Hardcover και Readwise. Όταν είναι απενεργοποιημένο, τα διαπιστευτήρια παραμένουν μόνο σε αυτή τη συσκευή και δεν αποστέλλονται ποτέ.", + "Sensitive synced fields are encrypted before upload. Set a passphrase now or later when encryption is needed.": "Τα ευαίσθητα συγχρονισμένα πεδία κρυπτογραφούνται πριν τη μεταφόρτωση. Ορίστε μια φράση πρόσβασης τώρα ή αργότερα, όταν χρειαστεί η κρυπτογράφηση.", + "Saved to this account. You will be prompted for it when decrypting credentials.": "Αποθηκεύτηκε σε αυτόν τον λογαριασμό. Θα σας ζητηθεί όταν χρειαστεί να αποκρυπτογραφηθούν διαπιστευτήρια." } diff --git a/apps/readest-app/public/locales/es/translation.json b/apps/readest-app/public/locales/es/translation.json index bb5fb5cd..d28db4af 100644 --- a/apps/readest-app/public/locales/es/translation.json +++ b/apps/readest-app/public/locales/es/translation.json @@ -1371,8 +1371,6 @@ "This permanently deletes the encrypted credentials we sync (e.g., OPDS catalog passwords) on every device. Local copies are preserved. You will need to re-enter the sync passphrase or set a new one. Continue?": "Esto elimina permanentemente las credenciales cifradas que sincronizamos (p. ej., contraseñas del catálogo OPDS) en cada dispositivo. Se conservan las copias locales. Tendrás que volver a introducir la frase de contraseña de sincronización o establecer una nueva. ¿Continuar?", "Sync passphrase forgotten — all encrypted fields cleared": "Frase de contraseña de sincronización olvidada — todos los campos cifrados se han borrado", "Sync passphrase": "Frase de contraseña de sincronización", - "Encrypts sensitive synced fields (like OPDS catalog credentials) before they leave your device. Set one now or wait — it will be requested when needed.": "Cifra los campos sensibles sincronizados (como las credenciales del catálogo OPDS) antes de que salgan de tu dispositivo. Establece una ahora o espera — se solicitará cuando sea necesario.", - "Set on this account. Will be requested when needed to decrypt synced credentials.": "Establecida en esta cuenta. Se solicitará cuando sea necesario descifrar las credenciales sincronizadas.", "Set passphrase": "Establecer frase de contraseña", "Forgot passphrase": "Olvidé la frase de contraseña", "Incorrect PIN": "PIN incorrecto", @@ -1420,5 +1418,9 @@ "Theme, highlight colours, integrations (KOSync, Readwise, Hardcover), and dictionary order": "Tema, colores de resaltado, integraciones (KOSync, Readwise, Hardcover) y orden de los diccionarios", "Required while Dictionaries sync is enabled": "Necesario mientras la sincronización de Diccionarios esté activada", "Resets in {{hours}} hr {{minutes}} min": "Se restablece en {{hours}} h {{minutes}} min", - "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Elige un PIN de 4 dígitos. Tendrás que introducirlo cada vez que abras Readest. No hay forma de recuperar un PIN olvidado. Borrar los datos de la aplicación es la única forma de restablecerlo." + "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Elige un PIN de 4 dígitos. Tendrás que introducirlo cada vez que abras Readest. No hay forma de recuperar un PIN olvidado. Borrar los datos de la aplicación es la única forma de restablecerlo.", + "Credentials": "Credenciales", + "Tokens, usernames, and passwords for OPDS, KOReader, Hardcover, and Readwise. When disabled, credentials remain on this device only and are never uploaded.": "Tokens, nombres de usuario y contraseñas de OPDS, KOReader, Hardcover y Readwise. Si está desactivado, las credenciales permanecen solo en este dispositivo y nunca se cargan.", + "Sensitive synced fields are encrypted before upload. Set a passphrase now or later when encryption is needed.": "Los campos sincronizados sensibles se cifran antes de subirlos. Establece una frase de contraseña ahora o más tarde, cuando se necesite el cifrado.", + "Saved to this account. You will be prompted for it when decrypting credentials.": "Guardada en esta cuenta. Se te pedirá cuando se necesite descifrar credenciales." } diff --git a/apps/readest-app/public/locales/fa/translation.json b/apps/readest-app/public/locales/fa/translation.json index 498f333f..b0857a33 100644 --- a/apps/readest-app/public/locales/fa/translation.json +++ b/apps/readest-app/public/locales/fa/translation.json @@ -1347,8 +1347,6 @@ "This permanently deletes the encrypted credentials we sync (e.g., OPDS catalog passwords) on every device. Local copies are preserved. You will need to re-enter the sync passphrase or set a new one. Continue?": "این به طور دائم اعتبارنامه‌های رمزگذاری‌شده‌ای را که همگام‌سازی می‌کنیم (مانند رمزهای کاتالوگ OPDS) در همه دستگاه‌ها حذف می‌کند. نسخه‌های محلی حفظ می‌شوند. باید عبارت عبور همگام‌سازی را دوباره وارد کنید یا یک عبارت جدید تنظیم کنید. ادامه می‌دهید؟", "Sync passphrase forgotten — all encrypted fields cleared": "عبارت عبور همگام‌سازی فراموش شد — تمام فیلدهای رمزگذاری‌شده پاک شدند", "Sync passphrase": "عبارت عبور همگام‌سازی", - "Encrypts sensitive synced fields (like OPDS catalog credentials) before they leave your device. Set one now or wait — it will be requested when needed.": "فیلدهای حساس همگام‌سازی‌شده (مانند اعتبارنامه‌های کاتالوگ OPDS) را قبل از خروج از دستگاه شما رمزگذاری می‌کند. اکنون یکی تنظیم کنید یا منتظر بمانید — هنگام نیاز درخواست خواهد شد.", - "Set on this account. Will be requested when needed to decrypt synced credentials.": "در این حساب تنظیم شده است. هنگام نیاز برای رمزگشایی اعتبارنامه‌های همگام‌سازی‌شده درخواست خواهد شد.", "Set passphrase": "تنظیم عبارت عبور", "Forgot passphrase": "عبارت عبور را فراموش کرده‌اید", "Incorrect PIN": "PIN نادرست", @@ -1396,5 +1394,9 @@ "Theme, highlight colours, integrations (KOSync, Readwise, Hardcover), and dictionary order": "پوسته، رنگ‌های هایلایت، یکپارچه‌سازی‌ها (KOSync، Readwise، Hardcover) و ترتیب فرهنگ‌لغت‌ها", "Required while Dictionaries sync is enabled": "هنگام فعال‌بودن همگام‌سازی فرهنگ‌لغت‌ها لازم است", "Resets in {{hours}} hr {{minutes}} min": "تنظیم مجدد در {{hours}} ساعت {{minutes}} دقیقه", - "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "یک پین ۴ رقمی انتخاب کنید. هر بار که Readest را باز می‌کنید باید آن را وارد کنید. راهی برای بازیابی پین فراموش‌شده وجود ندارد. پاک کردن داده‌های برنامه تنها راه بازنشانی آن است." + "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "یک پین ۴ رقمی انتخاب کنید. هر بار که Readest را باز می‌کنید باید آن را وارد کنید. راهی برای بازیابی پین فراموش‌شده وجود ندارد. پاک کردن داده‌های برنامه تنها راه بازنشانی آن است.", + "Credentials": "اعتبارنامه‌ها", + "Tokens, usernames, and passwords for OPDS, KOReader, Hardcover, and Readwise. When disabled, credentials remain on this device only and are never uploaded.": "توکن‌ها، نام‌های کاربری و رمزهای عبور OPDS، KOReader، Hardcover و Readwise. هنگام غیرفعال بودن، اعتبارنامه‌ها فقط روی این دستگاه باقی می‌مانند و هرگز بارگذاری نمی‌شوند.", + "Sensitive synced fields are encrypted before upload. Set a passphrase now or later when encryption is needed.": "فیلدهای حساسِ همگام‌سازی‌شده پیش از بارگذاری رمزگذاری می‌شوند. اکنون یا بعداً، هنگامی که به رمزگذاری نیاز شد، یک عبارت عبور تنظیم کنید.", + "Saved to this account. You will be prompted for it when decrypting credentials.": "در این حساب ذخیره شد. هنگام رمزگشایی اعتبارنامه‌ها از شما خواسته می‌شود." } diff --git a/apps/readest-app/public/locales/fr/translation.json b/apps/readest-app/public/locales/fr/translation.json index b0fb4a22..ac83d629 100644 --- a/apps/readest-app/public/locales/fr/translation.json +++ b/apps/readest-app/public/locales/fr/translation.json @@ -1371,8 +1371,6 @@ "This permanently deletes the encrypted credentials we sync (e.g., OPDS catalog passwords) on every device. Local copies are preserved. You will need to re-enter the sync passphrase or set a new one. Continue?": "Cela supprime définitivement les identifiants chiffrés que nous synchronisons (par exemple, les mots de passe du catalogue OPDS) sur chaque appareil. Les copies locales sont conservées. Vous devrez ressaisir la phrase secrète de synchronisation ou en définir une nouvelle. Continuer ?", "Sync passphrase forgotten — all encrypted fields cleared": "Phrase secrète de synchronisation oubliée — tous les champs chiffrés ont été effacés", "Sync passphrase": "Phrase secrète de synchronisation", - "Encrypts sensitive synced fields (like OPDS catalog credentials) before they leave your device. Set one now or wait — it will be requested when needed.": "Chiffre les champs synchronisés sensibles (comme les identifiants du catalogue OPDS) avant qu'ils ne quittent votre appareil. Définissez-en une maintenant ou attendez — elle sera demandée si nécessaire.", - "Set on this account. Will be requested when needed to decrypt synced credentials.": "Définie pour ce compte. Sera demandée lorsque nécessaire pour déchiffrer les identifiants synchronisés.", "Set passphrase": "Définir la phrase secrète", "Forgot passphrase": "Phrase secrète oubliée", "Incorrect PIN": "PIN incorrect", @@ -1420,5 +1418,9 @@ "Theme, highlight colours, integrations (KOSync, Readwise, Hardcover), and dictionary order": "Thème, couleurs de surlignage, intégrations (KOSync, Readwise, Hardcover) et ordre des dictionnaires", "Required while Dictionaries sync is enabled": "Requis tant que la synchronisation des dictionnaires est activée", "Resets in {{hours}} hr {{minutes}} min": "Réinitialisation dans {{hours}} h {{minutes}} min", - "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Choisissez un code PIN à 4 chiffres. Vous devrez le saisir chaque fois que vous ouvrirez Readest. Il n'existe aucun moyen de récupérer un code PIN oublié. Effacer les données de l'application est le seul moyen de le réinitialiser." + "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Choisissez un code PIN à 4 chiffres. Vous devrez le saisir chaque fois que vous ouvrirez Readest. Il n'existe aucun moyen de récupérer un code PIN oublié. Effacer les données de l'application est le seul moyen de le réinitialiser.", + "Credentials": "Identifiants", + "Tokens, usernames, and passwords for OPDS, KOReader, Hardcover, and Readwise. When disabled, credentials remain on this device only and are never uploaded.": "Jetons, noms d'utilisateur et mots de passe pour OPDS, KOReader, Hardcover et Readwise. Lorsqu'ils sont désactivés, les identifiants restent uniquement sur cet appareil et ne sont jamais téléversés.", + "Sensitive synced fields are encrypted before upload. Set a passphrase now or later when encryption is needed.": "Les champs sensibles synchronisés sont chiffrés avant l'envoi. Définissez une phrase de passe maintenant ou plus tard, lorsque le chiffrement sera nécessaire.", + "Saved to this account. You will be prompted for it when decrypting credentials.": "Enregistrée sur ce compte. Elle vous sera demandée lors du déchiffrement des identifiants." } diff --git a/apps/readest-app/public/locales/he/translation.json b/apps/readest-app/public/locales/he/translation.json index 56f16d39..252d86fa 100644 --- a/apps/readest-app/public/locales/he/translation.json +++ b/apps/readest-app/public/locales/he/translation.json @@ -1371,8 +1371,6 @@ "This permanently deletes the encrypted credentials we sync (e.g., OPDS catalog passwords) on every device. Local copies are preserved. You will need to re-enter the sync passphrase or set a new one. Continue?": "פעולה זו מוחקת לצמיתות את פרטי ההתחברות המוצפנים שאנו מסנכרנים (למשל, סיסמאות קטלוג OPDS) בכל מכשיר. עותקים מקומיים נשמרים. תצטרך להזין מחדש את ביטוי הסיסמה לסנכרון או להגדיר אחד חדש. להמשיך?", "Sync passphrase forgotten — all encrypted fields cleared": "ביטוי הסיסמה לסנכרון נשכח — כל השדות המוצפנים נמחקו", "Sync passphrase": "ביטוי סיסמה לסנכרון", - "Encrypts sensitive synced fields (like OPDS catalog credentials) before they leave your device. Set one now or wait — it will be requested when needed.": "מצפין שדות מסונכרנים רגישים (כמו פרטי התחברות לקטלוג OPDS) לפני שהם עוזבים את המכשיר שלך. הגדר ביטוי עכשיו או המתן — נבקש אותו כשיידרש.", - "Set on this account. Will be requested when needed to decrypt synced credentials.": "הוגדר בחשבון זה. נבקש אותו כשיידרש לפענח פרטי התחברות מסונכרנים.", "Set passphrase": "הגדרת ביטוי סיסמה", "Forgot passphrase": "שכחת את ביטוי הסיסמה", "Incorrect PIN": "PIN שגוי", @@ -1420,5 +1418,9 @@ "Theme, highlight colours, integrations (KOSync, Readwise, Hardcover), and dictionary order": "ערכת נושא, צבעי הדגשה, שילובים (KOSync, Readwise, Hardcover) וסדר המילונים", "Required while Dictionaries sync is enabled": "נדרש כל עוד סנכרון המילונים מופעל", "Resets in {{hours}} hr {{minutes}} min": "מתאפס בעוד {{hours}} ש׳ {{minutes}} ד׳", - "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "בחר PIN בן 4 ספרות. תצטרך להזין אותו בכל פעם שתפתח את Readest. אין דרך לשחזר PIN שנשכח. ניקוי נתוני האפליקציה הוא הדרך היחידה לאפס אותו." + "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "בחר PIN בן 4 ספרות. תצטרך להזין אותו בכל פעם שתפתח את Readest. אין דרך לשחזר PIN שנשכח. ניקוי נתוני האפליקציה הוא הדרך היחידה לאפס אותו.", + "Credentials": "אישורים", + "Tokens, usernames, and passwords for OPDS, KOReader, Hardcover, and Readwise. When disabled, credentials remain on this device only and are never uploaded.": "אסימונים, שמות משתמש וסיסמאות עבור OPDS, KOReader, Hardcover ו-Readwise. כאשר מבוטל, האישורים נשמרים רק במכשיר זה ולעולם אינם מועלים.", + "Sensitive synced fields are encrypted before upload. Set a passphrase now or later when encryption is needed.": "שדות מסונכרנים רגישים מוצפנים לפני העלאה. הגדר ביטוי סיסמה עכשיו או מאוחר יותר, כאשר תידרש הצפנה.", + "Saved to this account. You will be prompted for it when decrypting credentials.": "נשמר בחשבון זה. תתבקש להזינו בעת פענוח אישורים." } diff --git a/apps/readest-app/public/locales/hi/translation.json b/apps/readest-app/public/locales/hi/translation.json index 40caf016..ccdb2756 100644 --- a/apps/readest-app/public/locales/hi/translation.json +++ b/apps/readest-app/public/locales/hi/translation.json @@ -1347,8 +1347,6 @@ "This permanently deletes the encrypted credentials we sync (e.g., OPDS catalog passwords) on every device. Local copies are preserved. You will need to re-enter the sync passphrase or set a new one. Continue?": "यह हर डिवाइस पर हमारे सिंक किए गए एन्क्रिप्टेड क्रेडेंशियल (जैसे, OPDS कैटलॉग पासवर्ड) को स्थायी रूप से हटा देता है। स्थानीय प्रतियां सुरक्षित रहती हैं। आपको सिंक पासफ़्रेज़ फिर से दर्ज करना होगा या एक नया सेट करना होगा। जारी रखें?", "Sync passphrase forgotten — all encrypted fields cleared": "सिंक पासफ़्रेज़ भूल गए — सभी एन्क्रिप्टेड फ़ील्ड हटा दिए गए", "Sync passphrase": "सिंक पासफ़्रेज़", - "Encrypts sensitive synced fields (like OPDS catalog credentials) before they leave your device. Set one now or wait — it will be requested when needed.": "संवेदनशील सिंक किए गए फ़ील्ड (जैसे OPDS कैटलॉग क्रेडेंशियल) को आपके डिवाइस से बाहर जाने से पहले एन्क्रिप्ट करता है। अभी एक सेट करें या प्रतीक्षा करें — आवश्यकता पड़ने पर इसका अनुरोध किया जाएगा।", - "Set on this account. Will be requested when needed to decrypt synced credentials.": "इस खाते पर सेट किया गया है। सिंक किए गए क्रेडेंशियल को डिक्रिप्ट करने के लिए आवश्यकता पड़ने पर इसका अनुरोध किया जाएगा।", "Set passphrase": "पासफ़्रेज़ सेट करें", "Forgot passphrase": "पासफ़्रेज़ भूल गए", "Incorrect PIN": "गलत PIN", @@ -1396,5 +1394,9 @@ "Theme, highlight colours, integrations (KOSync, Readwise, Hardcover), and dictionary order": "थीम, हाइलाइट रंग, एकीकरण (KOSync, Readwise, Hardcover) और शब्दकोश क्रम", "Required while Dictionaries sync is enabled": "शब्दकोश सिंक सक्षम होने पर आवश्यक", "Resets in {{hours}} hr {{minutes}} min": "{{hours}} घं {{minutes}} मि में रीसेट", - "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "एक 4-अंकों का पिन चुनें। Readest खोलने पर आपको हर बार इसे दर्ज करना होगा। भूले हुए पिन को पुनः प्राप्त करने का कोई तरीका नहीं है। ऐप डेटा मिटाना इसे रीसेट करने का एकमात्र तरीका है।" + "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "एक 4-अंकों का पिन चुनें। Readest खोलने पर आपको हर बार इसे दर्ज करना होगा। भूले हुए पिन को पुनः प्राप्त करने का कोई तरीका नहीं है। ऐप डेटा मिटाना इसे रीसेट करने का एकमात्र तरीका है।", + "Credentials": "क्रेडेंशियल", + "Tokens, usernames, and passwords for OPDS, KOReader, Hardcover, and Readwise. When disabled, credentials remain on this device only and are never uploaded.": "OPDS, KOReader, Hardcover और Readwise के लिए टोकन, उपयोगकर्ता नाम और पासवर्ड। अक्षम होने पर, क्रेडेंशियल केवल इसी डिवाइस पर रहते हैं और कभी अपलोड नहीं किए जाते।", + "Sensitive synced fields are encrypted before upload. Set a passphrase now or later when encryption is needed.": "संवेदनशील सिंक किए गए फ़ील्ड अपलोड से पहले एन्क्रिप्ट किए जाते हैं। अभी पासफ़्रेज़ सेट करें या बाद में जब एन्क्रिप्शन की आवश्यकता हो।", + "Saved to this account. You will be prompted for it when decrypting credentials.": "इस खाते में सहेजा गया। क्रेडेंशियल डिक्रिप्ट करते समय आपसे पूछा जाएगा।" } diff --git a/apps/readest-app/public/locales/hu/translation.json b/apps/readest-app/public/locales/hu/translation.json index b90b1dec..683f7b08 100644 --- a/apps/readest-app/public/locales/hu/translation.json +++ b/apps/readest-app/public/locales/hu/translation.json @@ -1347,8 +1347,6 @@ "This permanently deletes the encrypted credentials we sync (e.g., OPDS catalog passwords) on every device. Local copies are preserved. You will need to re-enter the sync passphrase or set a new one. Continue?": "Ez véglegesen törli a szinkronizált titkosított hitelesítő adatokat (pl. OPDS-katalógusjelszavak) minden eszközön. A helyi másolatok megmaradnak. Újra meg kell adnia a szinkronizálási jelmondatot, vagy újat kell beállítania. Folytatja?", "Sync passphrase forgotten — all encrypted fields cleared": "Szinkronizálási jelmondat elfelejtve — az összes titkosított mező törölve", "Sync passphrase": "Szinkronizálási jelmondat", - "Encrypts sensitive synced fields (like OPDS catalog credentials) before they leave your device. Set one now or wait — it will be requested when needed.": "Titkosítja az érzékeny szinkronizált mezőket (például OPDS-katalógus hitelesítő adatait), mielőtt elhagyják az eszközét. Állítson be egyet most vagy várjon — szükség esetén kérni fogjuk.", - "Set on this account. Will be requested when needed to decrypt synced credentials.": "Beállítva ezen a fiókon. Szükség esetén kérni fogjuk a szinkronizált hitelesítő adatok visszafejtéséhez.", "Set passphrase": "Jelmondat beállítása", "Forgot passphrase": "Elfelejtett jelmondat", "Incorrect PIN": "Helytelen PIN", @@ -1396,5 +1394,9 @@ "Theme, highlight colours, integrations (KOSync, Readwise, Hardcover), and dictionary order": "Téma, kiemelési színek, integrációk (KOSync, Readwise, Hardcover) és szótárak sorrendje", "Required while Dictionaries sync is enabled": "Szükséges, amíg a Szótárak szinkronizálása be van kapcsolva", "Resets in {{hours}} hr {{minutes}} min": "Visszaállás {{hours}} ó {{minutes}} p múlva", - "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Válasszon egy 4 számjegyű PIN-kódot. Minden alkalommal meg kell adnia, amikor megnyitja a Readestet. Az elfelejtett PIN-kódot nem lehet visszaállítani. Az alkalmazás adatainak törlése az egyetlen módja a visszaállításának." + "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Válasszon egy 4 számjegyű PIN-kódot. Minden alkalommal meg kell adnia, amikor megnyitja a Readestet. Az elfelejtett PIN-kódot nem lehet visszaállítani. Az alkalmazás adatainak törlése az egyetlen módja a visszaállításának.", + "Credentials": "Hitelesítő adatok", + "Tokens, usernames, and passwords for OPDS, KOReader, Hardcover, and Readwise. When disabled, credentials remain on this device only and are never uploaded.": "Tokenek, felhasználónevek és jelszavak az OPDS, KOReader, Hardcover és Readwise szolgáltatásokhoz. Ha le van tiltva, a hitelesítő adatok csak ezen az eszközön maradnak, és soha nem töltődnek fel.", + "Sensitive synced fields are encrypted before upload. Set a passphrase now or later when encryption is needed.": "Az érzékeny szinkronizált mezők feltöltés előtt titkosítva vannak. Állíts be egy jelmondatot most, vagy később, amikor titkosításra lesz szükség.", + "Saved to this account. You will be prompted for it when decrypting credentials.": "Mentve ehhez a fiókhoz. Akkor kérjük majd, amikor hitelesítő adatokat kell visszafejteni." } diff --git a/apps/readest-app/public/locales/id/translation.json b/apps/readest-app/public/locales/id/translation.json index 38a15210..ee8c4ffc 100644 --- a/apps/readest-app/public/locales/id/translation.json +++ b/apps/readest-app/public/locales/id/translation.json @@ -1323,8 +1323,6 @@ "This permanently deletes the encrypted credentials we sync (e.g., OPDS catalog passwords) on every device. Local copies are preserved. You will need to re-enter the sync passphrase or set a new one. Continue?": "Ini secara permanen menghapus kredensial terenkripsi yang kami sinkronkan (mis., kata sandi katalog OPDS) di setiap perangkat. Salinan lokal disimpan. Anda perlu memasukkan kembali frasa sandi sinkronisasi atau menyetel yang baru. Lanjutkan?", "Sync passphrase forgotten — all encrypted fields cleared": "Frasa sandi sinkronisasi terlupakan — semua bidang terenkripsi dihapus", "Sync passphrase": "Frasa sandi sinkronisasi", - "Encrypts sensitive synced fields (like OPDS catalog credentials) before they leave your device. Set one now or wait — it will be requested when needed.": "Mengenkripsi bidang tersinkron yang sensitif (seperti kredensial katalog OPDS) sebelum meninggalkan perangkat Anda. Setel sekarang atau tunggu — akan diminta saat dibutuhkan.", - "Set on this account. Will be requested when needed to decrypt synced credentials.": "Disetel pada akun ini. Akan diminta saat dibutuhkan untuk mendekripsi kredensial yang tersinkron.", "Set passphrase": "Setel frasa sandi", "Forgot passphrase": "Lupa frasa sandi", "Incorrect PIN": "PIN salah", @@ -1372,5 +1370,9 @@ "Theme, highlight colours, integrations (KOSync, Readwise, Hardcover), and dictionary order": "Tema, warna sorotan, integrasi (KOSync, Readwise, Hardcover), dan urutan kamus", "Required while Dictionaries sync is enabled": "Diperlukan saat sinkronisasi Kamus diaktifkan", "Resets in {{hours}} hr {{minutes}} min": "Direset dalam {{hours}} j {{minutes}} mnt", - "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Pilih PIN 4 digit. Anda harus memasukkannya setiap kali membuka Readest. Tidak ada cara untuk memulihkan PIN yang terlupa. Menghapus data aplikasi adalah satu-satunya cara untuk mengaturnya ulang." + "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Pilih PIN 4 digit. Anda harus memasukkannya setiap kali membuka Readest. Tidak ada cara untuk memulihkan PIN yang terlupa. Menghapus data aplikasi adalah satu-satunya cara untuk mengaturnya ulang.", + "Credentials": "Kredensial", + "Tokens, usernames, and passwords for OPDS, KOReader, Hardcover, and Readwise. When disabled, credentials remain on this device only and are never uploaded.": "Token, nama pengguna, dan kata sandi untuk OPDS, KOReader, Hardcover, dan Readwise. Saat dinonaktifkan, kredensial hanya tetap di perangkat ini dan tidak pernah diunggah.", + "Sensitive synced fields are encrypted before upload. Set a passphrase now or later when encryption is needed.": "Bidang sinkron yang sensitif dienkripsi sebelum diunggah. Atur frasa sandi sekarang atau nanti saat enkripsi diperlukan.", + "Saved to this account. You will be prompted for it when decrypting credentials.": "Disimpan di akun ini. Anda akan diminta memasukkannya saat mendekripsi kredensial." } diff --git a/apps/readest-app/public/locales/it/translation.json b/apps/readest-app/public/locales/it/translation.json index eac6fbf1..01ea5b02 100644 --- a/apps/readest-app/public/locales/it/translation.json +++ b/apps/readest-app/public/locales/it/translation.json @@ -1371,8 +1371,6 @@ "This permanently deletes the encrypted credentials we sync (e.g., OPDS catalog passwords) on every device. Local copies are preserved. You will need to re-enter the sync passphrase or set a new one. Continue?": "Questa operazione elimina in modo permanente le credenziali crittografate che sincronizziamo (ad es. le password del catalogo OPDS) su ogni dispositivo. Le copie locali vengono conservate. Dovrai reinserire la passphrase di sincronizzazione o impostarne una nuova. Continuare?", "Sync passphrase forgotten — all encrypted fields cleared": "Passphrase di sincronizzazione dimenticata — tutti i campi crittografati cancellati", "Sync passphrase": "Passphrase di sincronizzazione", - "Encrypts sensitive synced fields (like OPDS catalog credentials) before they leave your device. Set one now or wait — it will be requested when needed.": "Crittografa i campi sincronizzati sensibili (come le credenziali del catalogo OPDS) prima che lascino il tuo dispositivo. Impostane una ora o attendi — verrà richiesta quando necessario.", - "Set on this account. Will be requested when needed to decrypt synced credentials.": "Impostata su questo account. Verrà richiesta quando necessario per decrittografare le credenziali sincronizzate.", "Set passphrase": "Imposta passphrase", "Forgot passphrase": "Passphrase dimenticata", "Incorrect PIN": "PIN errato", @@ -1420,5 +1418,9 @@ "Theme, highlight colours, integrations (KOSync, Readwise, Hardcover), and dictionary order": "Tema, colori delle evidenziazioni, integrazioni (KOSync, Readwise, Hardcover) e ordine dei dizionari", "Required while Dictionaries sync is enabled": "Necessario mentre la sincronizzazione dei Dizionari è attiva", "Resets in {{hours}} hr {{minutes}} min": "Si reimposta tra {{hours}} h {{minutes}} min", - "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Scegli un PIN di 4 cifre. Dovrai inserirlo ogni volta che apri Readest. Non c'è modo di recuperare un PIN dimenticato. Cancellare i dati dell'app è l'unico modo per reimpostarlo." + "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Scegli un PIN di 4 cifre. Dovrai inserirlo ogni volta che apri Readest. Non c'è modo di recuperare un PIN dimenticato. Cancellare i dati dell'app è l'unico modo per reimpostarlo.", + "Credentials": "Credenziali", + "Tokens, usernames, and passwords for OPDS, KOReader, Hardcover, and Readwise. When disabled, credentials remain on this device only and are never uploaded.": "Token, nomi utente e password per OPDS, KOReader, Hardcover e Readwise. Quando disattivato, le credenziali restano solo su questo dispositivo e non vengono mai caricate.", + "Sensitive synced fields are encrypted before upload. Set a passphrase now or later when encryption is needed.": "I campi sincronizzati sensibili vengono cifrati prima del caricamento. Imposta una passphrase ora o più tardi, quando servirà la cifratura.", + "Saved to this account. You will be prompted for it when decrypting credentials.": "Salvata in questo account. Ti verrà richiesta quando occorrerà decifrare le credenziali." } diff --git a/apps/readest-app/public/locales/ja/translation.json b/apps/readest-app/public/locales/ja/translation.json index 641a3eab..7fe1c032 100644 --- a/apps/readest-app/public/locales/ja/translation.json +++ b/apps/readest-app/public/locales/ja/translation.json @@ -1323,8 +1323,6 @@ "This permanently deletes the encrypted credentials we sync (e.g., OPDS catalog passwords) on every device. Local copies are preserved. You will need to re-enter the sync passphrase or set a new one. Continue?": "これにより、各デバイスで同期している暗号化された資格情報(OPDS カタログのパスワードなど)が永続的に削除されます。ローカルのコピーは保持されます。同期パスフレーズを再入力するか、新しく設定する必要があります。続行しますか?", "Sync passphrase forgotten — all encrypted fields cleared": "同期パスフレーズを忘れました — 暗号化されたフィールドはすべてクリアされました", "Sync passphrase": "同期パスフレーズ", - "Encrypts sensitive synced fields (like OPDS catalog credentials) before they leave your device. Set one now or wait — it will be requested when needed.": "機密性の高い同期フィールド(OPDS カタログの認証情報など)を、デバイスから出る前に暗号化します。今すぐ設定するか、待つこともできます — 必要なときに要求されます。", - "Set on this account. Will be requested when needed to decrypt synced credentials.": "このアカウントで設定済みです。同期された資格情報を復号化する必要があるときに要求されます。", "Set passphrase": "パスフレーズを設定", "Forgot passphrase": "パスフレーズを忘れました", "Incorrect PIN": "PINが正しくありません", @@ -1372,5 +1370,9 @@ "Theme, highlight colours, integrations (KOSync, Readwise, Hardcover), and dictionary order": "テーマ、ハイライトの色、連携 (KOSync、Readwise、Hardcover)、辞書の順序", "Required while Dictionaries sync is enabled": "辞書の同期が有効な間は必須", "Resets in {{hours}} hr {{minutes}} min": "{{hours}}時間{{minutes}}分でリセット", - "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "4桁のPINを設定してください。Readestを開くたびに入力する必要があります。忘れたPINを復元する方法はありません。アプリのデータを消去することがリセットする唯一の方法です。" + "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "4桁のPINを設定してください。Readestを開くたびに入力する必要があります。忘れたPINを復元する方法はありません。アプリのデータを消去することがリセットする唯一の方法です。", + "Credentials": "認証情報", + "Tokens, usernames, and passwords for OPDS, KOReader, Hardcover, and Readwise. When disabled, credentials remain on this device only and are never uploaded.": "OPDS、KOReader、Hardcover、Readwise のトークン、ユーザー名、パスワード。無効にすると、認証情報はこのデバイスにのみ残り、アップロードされません。", + "Sensitive synced fields are encrypted before upload. Set a passphrase now or later when encryption is needed.": "機密性の高い同期フィールドはアップロード前に暗号化されます。パスフレーズは今すぐ設定するか、暗号化が必要なときに後で設定できます。", + "Saved to this account. You will be prompted for it when decrypting credentials.": "このアカウントに保存されました。認証情報を復号する際に入力を求められます。" } diff --git a/apps/readest-app/public/locales/ko/translation.json b/apps/readest-app/public/locales/ko/translation.json index 2d131e29..7b51bc6f 100644 --- a/apps/readest-app/public/locales/ko/translation.json +++ b/apps/readest-app/public/locales/ko/translation.json @@ -1323,8 +1323,6 @@ "This permanently deletes the encrypted credentials we sync (e.g., OPDS catalog passwords) on every device. Local copies are preserved. You will need to re-enter the sync passphrase or set a new one. Continue?": "이 작업을 수행하면 모든 기기에서 동기화하는 암호화된 자격 증명(예: OPDS 카탈로그 비밀번호)이 영구적으로 삭제됩니다. 로컬 복사본은 보존됩니다. 동기화 암호 문구를 다시 입력하거나 새로 설정해야 합니다. 계속하시겠습니까?", "Sync passphrase forgotten — all encrypted fields cleared": "동기화 암호 문구를 잊었습니다 — 모든 암호화된 필드가 지워졌습니다", "Sync passphrase": "동기화 암호 문구", - "Encrypts sensitive synced fields (like OPDS catalog credentials) before they leave your device. Set one now or wait — it will be requested when needed.": "민감한 동기화 필드(예: OPDS 카탈로그 자격 증명)를 기기에서 나가기 전에 암호화합니다. 지금 설정하거나 나중에 — 필요할 때 요청됩니다.", - "Set on this account. Will be requested when needed to decrypt synced credentials.": "이 계정에 설정되어 있습니다. 동기화된 자격 증명을 복호화해야 할 때 요청됩니다.", "Set passphrase": "암호 문구 설정", "Forgot passphrase": "암호 문구를 잊으셨나요", "Incorrect PIN": "잘못된 PIN", @@ -1372,5 +1370,9 @@ "Theme, highlight colours, integrations (KOSync, Readwise, Hardcover), and dictionary order": "테마, 하이라이트 색상, 연동 (KOSync, Readwise, Hardcover), 사전 순서", "Required while Dictionaries sync is enabled": "사전 동기화가 켜져 있는 동안 필요", "Resets in {{hours}} hr {{minutes}} min": "{{hours}}시간 {{minutes}}분 후 재설정", - "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "4자리 PIN을 선택하세요. Readest를 열 때마다 입력해야 합니다. 잊어버린 PIN을 복구할 방법은 없습니다. 앱 데이터를 지우는 것이 PIN을 재설정하는 유일한 방법입니다." + "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "4자리 PIN을 선택하세요. Readest를 열 때마다 입력해야 합니다. 잊어버린 PIN을 복구할 방법은 없습니다. 앱 데이터를 지우는 것이 PIN을 재설정하는 유일한 방법입니다.", + "Credentials": "자격 증명", + "Tokens, usernames, and passwords for OPDS, KOReader, Hardcover, and Readwise. When disabled, credentials remain on this device only and are never uploaded.": "OPDS, KOReader, Hardcover, Readwise의 토큰, 사용자 이름, 비밀번호입니다. 비활성화되면 자격 증명이 이 기기에만 남아 있고 절대 업로드되지 않습니다.", + "Sensitive synced fields are encrypted before upload. Set a passphrase now or later when encryption is needed.": "민감한 동기화 필드는 업로드 전에 암호화됩니다. 지금 또는 암호화가 필요할 때 나중에 암호 문구를 설정하세요.", + "Saved to this account. You will be prompted for it when decrypting credentials.": "이 계정에 저장되었습니다. 자격 증명을 복호화할 때 입력하라는 메시지가 표시됩니다." } diff --git a/apps/readest-app/public/locales/ms/translation.json b/apps/readest-app/public/locales/ms/translation.json index 101aedcd..54673cc6 100644 --- a/apps/readest-app/public/locales/ms/translation.json +++ b/apps/readest-app/public/locales/ms/translation.json @@ -1323,8 +1323,6 @@ "This permanently deletes the encrypted credentials we sync (e.g., OPDS catalog passwords) on every device. Local copies are preserved. You will need to re-enter the sync passphrase or set a new one. Continue?": "Ini memadamkan secara kekal bukti kelayakan tersulit yang kami selaraskan (cth., kata laluan katalog OPDS) pada setiap peranti. Salinan tempatan dikekalkan. Anda perlu memasukkan semula frasa laluan penyegerakan atau menetapkan yang baharu. Teruskan?", "Sync passphrase forgotten — all encrypted fields cleared": "Frasa laluan penyegerakan dilupakan — semua medan tersulit dikosongkan", "Sync passphrase": "Frasa laluan penyegerakan", - "Encrypts sensitive synced fields (like OPDS catalog credentials) before they leave your device. Set one now or wait — it will be requested when needed.": "Mengenkripsi medan tersegerak sensitif (seperti bukti kelayakan katalog OPDS) sebelum ia meninggalkan peranti anda. Tetapkan satu sekarang atau tunggu — ia akan diminta apabila diperlukan.", - "Set on this account. Will be requested when needed to decrypt synced credentials.": "Ditetapkan pada akaun ini. Akan diminta apabila diperlukan untuk menyahsulit bukti kelayakan yang disegerakkan.", "Set passphrase": "Tetapkan frasa laluan", "Forgot passphrase": "Lupa frasa laluan", "Incorrect PIN": "PIN salah", @@ -1372,5 +1370,9 @@ "Theme, highlight colours, integrations (KOSync, Readwise, Hardcover), and dictionary order": "Tema, warna sorotan, integrasi (KOSync, Readwise, Hardcover), dan susunan kamus", "Required while Dictionaries sync is enabled": "Diperlukan semasa penyegerakan Kamus didayakan", "Resets in {{hours}} hr {{minutes}} min": "Set semula dalam {{hours}} j {{minutes}} min", - "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Pilih PIN 4 digit. Anda perlu memasukkannya setiap kali anda membuka Readest. Tiada cara untuk memulihkan PIN yang terlupa. Mengosongkan data aplikasi adalah satu-satunya cara untuk menetapkannya semula." + "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Pilih PIN 4 digit. Anda perlu memasukkannya setiap kali anda membuka Readest. Tiada cara untuk memulihkan PIN yang terlupa. Mengosongkan data aplikasi adalah satu-satunya cara untuk menetapkannya semula.", + "Credentials": "Kelayakan", + "Tokens, usernames, and passwords for OPDS, KOReader, Hardcover, and Readwise. When disabled, credentials remain on this device only and are never uploaded.": "Token, nama pengguna dan kata laluan untuk OPDS, KOReader, Hardcover dan Readwise. Apabila dilumpuhkan, kelayakan hanya kekal pada peranti ini dan tidak pernah dimuat naik.", + "Sensitive synced fields are encrypted before upload. Set a passphrase now or later when encryption is needed.": "Medan disegerakkan yang sensitif disulitkan sebelum dimuat naik. Tetapkan frasa laluan sekarang atau kemudian apabila penyulitan diperlukan.", + "Saved to this account. You will be prompted for it when decrypting credentials.": "Disimpan dalam akaun ini. Anda akan diminta memasukkannya apabila kelayakan perlu dinyahsulit." } diff --git a/apps/readest-app/public/locales/nl/translation.json b/apps/readest-app/public/locales/nl/translation.json index 2f8e0f0f..f2f3e9d7 100644 --- a/apps/readest-app/public/locales/nl/translation.json +++ b/apps/readest-app/public/locales/nl/translation.json @@ -1347,8 +1347,6 @@ "This permanently deletes the encrypted credentials we sync (e.g., OPDS catalog passwords) on every device. Local copies are preserved. You will need to re-enter the sync passphrase or set a new one. Continue?": "Dit verwijdert permanent de versleutelde inloggegevens die we synchroniseren (bijv. OPDS-catalogi-wachtwoorden) op elk apparaat. Lokale kopieën blijven behouden. Je moet de sync-wachtwoordzin opnieuw invoeren of een nieuwe instellen. Doorgaan?", "Sync passphrase forgotten — all encrypted fields cleared": "Sync-wachtwoordzin vergeten — alle versleutelde velden gewist", "Sync passphrase": "Sync-wachtwoordzin", - "Encrypts sensitive synced fields (like OPDS catalog credentials) before they leave your device. Set one now or wait — it will be requested when needed.": "Versleutelt gevoelige gesynchroniseerde velden (zoals OPDS-cataloguscredentials) voordat ze je apparaat verlaten. Stel er nu een in of wacht — er wordt om gevraagd wanneer nodig.", - "Set on this account. Will be requested when needed to decrypt synced credentials.": "Ingesteld voor dit account. Wordt opgevraagd wanneer nodig om gesynchroniseerde inloggegevens te ontsleutelen.", "Set passphrase": "Wachtwoordzin instellen", "Forgot passphrase": "Wachtwoordzin vergeten", "Incorrect PIN": "Onjuiste PIN", @@ -1396,5 +1394,9 @@ "Theme, highlight colours, integrations (KOSync, Readwise, Hardcover), and dictionary order": "Thema, markeringskleuren, integraties (KOSync, Readwise, Hardcover) en woordenboekvolgorde", "Required while Dictionaries sync is enabled": "Vereist zolang synchronisatie van Woordenboeken is ingeschakeld", "Resets in {{hours}} hr {{minutes}} min": "Reset over {{hours}} u {{minutes}} min", - "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Kies een viercijferige pincode. Je moet deze elke keer invoeren wanneer je Readest opent. Een vergeten pincode kan niet worden hersteld. Het wissen van de app-gegevens is de enige manier om deze opnieuw in te stellen." + "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Kies een viercijferige pincode. Je moet deze elke keer invoeren wanneer je Readest opent. Een vergeten pincode kan niet worden hersteld. Het wissen van de app-gegevens is de enige manier om deze opnieuw in te stellen.", + "Credentials": "Inloggegevens", + "Tokens, usernames, and passwords for OPDS, KOReader, Hardcover, and Readwise. When disabled, credentials remain on this device only and are never uploaded.": "Tokens, gebruikersnamen en wachtwoorden voor OPDS, KOReader, Hardcover en Readwise. Wanneer uitgeschakeld blijven inloggegevens alleen op dit apparaat en worden ze nooit geüpload.", + "Sensitive synced fields are encrypted before upload. Set a passphrase now or later when encryption is needed.": "Gevoelige gesynchroniseerde velden worden vóór het uploaden versleuteld. Stel nu of later een wachtwoordzin in wanneer versleuteling nodig is.", + "Saved to this account. You will be prompted for it when decrypting credentials.": "Opgeslagen op dit account. Er wordt om gevraagd wanneer inloggegevens ontsleuteld moeten worden." } diff --git a/apps/readest-app/public/locales/pl/translation.json b/apps/readest-app/public/locales/pl/translation.json index 83dcdf52..75b82e4d 100644 --- a/apps/readest-app/public/locales/pl/translation.json +++ b/apps/readest-app/public/locales/pl/translation.json @@ -1395,8 +1395,6 @@ "This permanently deletes the encrypted credentials we sync (e.g., OPDS catalog passwords) on every device. Local copies are preserved. You will need to re-enter the sync passphrase or set a new one. Continue?": "Spowoduje to trwałe usunięcie zaszyfrowanych danych uwierzytelniających, które synchronizujemy (np. haseł katalogu OPDS), na każdym urządzeniu. Lokalne kopie zostaną zachowane. Konieczne będzie ponowne wprowadzenie hasła synchronizacji lub ustawienie nowego. Kontynuować?", "Sync passphrase forgotten — all encrypted fields cleared": "Zapomniano hasła synchronizacji — wszystkie zaszyfrowane pola wyczyszczone", "Sync passphrase": "Hasło synchronizacji", - "Encrypts sensitive synced fields (like OPDS catalog credentials) before they leave your device. Set one now or wait — it will be requested when needed.": "Szyfruje wrażliwe synchronizowane pola (np. dane uwierzytelniające katalogu OPDS) przed opuszczeniem Twojego urządzenia. Ustaw je teraz lub poczekaj — zostanie poproszone, gdy będzie potrzebne.", - "Set on this account. Will be requested when needed to decrypt synced credentials.": "Ustawione na tym koncie. Zostanie poproszone, gdy będzie potrzebne do odszyfrowania zsynchronizowanych danych uwierzytelniających.", "Set passphrase": "Ustaw hasło", "Forgot passphrase": "Zapomniałem hasła", "Incorrect PIN": "Nieprawidłowy PIN", @@ -1444,5 +1442,9 @@ "Theme, highlight colours, integrations (KOSync, Readwise, Hardcover), and dictionary order": "Motyw, kolory podświetleń, integracje (KOSync, Readwise, Hardcover) oraz kolejność słowników", "Required while Dictionaries sync is enabled": "Wymagane, gdy włączona jest synchronizacja Słowników", "Resets in {{hours}} hr {{minutes}} min": "Resetuje się za {{hours}} godz. {{minutes}} min", - "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Wybierz 4-cyfrowy PIN. Będziesz musiał go wprowadzać za każdym razem, gdy otworzysz Readest. Nie ma sposobu na odzyskanie zapomnianego PIN-u. Wyczyszczenie danych aplikacji to jedyny sposób, aby go zresetować." + "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Wybierz 4-cyfrowy PIN. Będziesz musiał go wprowadzać za każdym razem, gdy otworzysz Readest. Nie ma sposobu na odzyskanie zapomnianego PIN-u. Wyczyszczenie danych aplikacji to jedyny sposób, aby go zresetować.", + "Credentials": "Poświadczenia", + "Tokens, usernames, and passwords for OPDS, KOReader, Hardcover, and Readwise. When disabled, credentials remain on this device only and are never uploaded.": "Tokeny, nazwy użytkowników i hasła do OPDS, KOReader, Hardcover i Readwise. Gdy wyłączone, poświadczenia pozostają tylko na tym urządzeniu i nigdy nie są przesyłane.", + "Sensitive synced fields are encrypted before upload. Set a passphrase now or later when encryption is needed.": "Wrażliwe zsynchronizowane pola są szyfrowane przed wysłaniem. Ustaw hasło teraz lub później, gdy szyfrowanie będzie potrzebne.", + "Saved to this account. You will be prompted for it when decrypting credentials.": "Zapisane w tym koncie. Zostaniesz o nie poproszony przy odszyfrowywaniu poświadczeń." } diff --git a/apps/readest-app/public/locales/pt-BR/translation.json b/apps/readest-app/public/locales/pt-BR/translation.json index 34200cf4..6e635362 100644 --- a/apps/readest-app/public/locales/pt-BR/translation.json +++ b/apps/readest-app/public/locales/pt-BR/translation.json @@ -1371,8 +1371,6 @@ "This permanently deletes the encrypted credentials we sync (e.g., OPDS catalog passwords) on every device. Local copies are preserved. You will need to re-enter the sync passphrase or set a new one. Continue?": "Isso exclui permanentemente as credenciais criptografadas que sincronizamos (por exemplo, senhas do catálogo OPDS) em todos os dispositivos. As cópias locais são preservadas. Você precisará digitar novamente a frase secreta de sincronização ou definir uma nova. Continuar?", "Sync passphrase forgotten — all encrypted fields cleared": "Frase secreta de sincronização esquecida — todos os campos criptografados foram limpos", "Sync passphrase": "Frase secreta de sincronização", - "Encrypts sensitive synced fields (like OPDS catalog credentials) before they leave your device. Set one now or wait — it will be requested when needed.": "Criptografa campos sincronizados sensíveis (como credenciais de catálogo OPDS) antes que saiam do seu dispositivo. Defina uma agora ou aguarde — será solicitada quando necessário.", - "Set on this account. Will be requested when needed to decrypt synced credentials.": "Definida nesta conta. Será solicitada quando necessária para descriptografar credenciais sincronizadas.", "Set passphrase": "Definir frase secreta", "Forgot passphrase": "Esqueci a frase secreta", "Incorrect PIN": "PIN incorreto", @@ -1420,5 +1418,9 @@ "Sync passphrase data on the server was reset. Re-encrypting your credentials under the new passphrase…": "Os dados da senha de sincronização no servidor foram redefinidos. Recriptografando suas credenciais com a nova senha…", "Failed to decrypt synced credentials": "Falha ao descriptografar credenciais sincronizadas", "Resets in {{hours}} hr {{minutes}} min": "Redefine em {{hours}} h {{minutes}} min", - "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Escolha um PIN de 4 dígitos. Você precisará digitá-lo toda vez que abrir o Readest. Não há como recuperar um PIN esquecido. Limpar os dados do aplicativo é a única forma de redefini-lo." + "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Escolha um PIN de 4 dígitos. Você precisará digitá-lo toda vez que abrir o Readest. Não há como recuperar um PIN esquecido. Limpar os dados do aplicativo é a única forma de redefini-lo.", + "Credentials": "Credenciais", + "Tokens, usernames, and passwords for OPDS, KOReader, Hardcover, and Readwise. When disabled, credentials remain on this device only and are never uploaded.": "Tokens, nomes de usuário e senhas para OPDS, KOReader, Hardcover e Readwise. Quando desativado, as credenciais permanecem apenas neste dispositivo e nunca são enviadas.", + "Sensitive synced fields are encrypted before upload. Set a passphrase now or later when encryption is needed.": "Os campos sincronizados sensíveis são criptografados antes do envio. Defina uma senha agora ou mais tarde, quando a criptografia for necessária.", + "Saved to this account. You will be prompted for it when decrypting credentials.": "Salva nesta conta. Você será solicitado a informá-la quando precisar descriptografar credenciais." } diff --git a/apps/readest-app/public/locales/pt/translation.json b/apps/readest-app/public/locales/pt/translation.json index af0f564c..5e7f67c2 100644 --- a/apps/readest-app/public/locales/pt/translation.json +++ b/apps/readest-app/public/locales/pt/translation.json @@ -1371,8 +1371,6 @@ "This permanently deletes the encrypted credentials we sync (e.g., OPDS catalog passwords) on every device. Local copies are preserved. You will need to re-enter the sync passphrase or set a new one. Continue?": "Isto elimina permanentemente as credenciais encriptadas que sincronizamos (por exemplo, palavras-passe do catálogo OPDS) em todos os dispositivos. As cópias locais são preservadas. Terá de voltar a introduzir a frase-passe de sincronização ou definir uma nova. Continuar?", "Sync passphrase forgotten — all encrypted fields cleared": "Frase-passe de sincronização esquecida — todos os campos encriptados foram apagados", "Sync passphrase": "Frase-passe de sincronização", - "Encrypts sensitive synced fields (like OPDS catalog credentials) before they leave your device. Set one now or wait — it will be requested when needed.": "Encripta campos sincronizados sensíveis (como credenciais do catálogo OPDS) antes de saírem do seu dispositivo. Defina uma agora ou aguarde — será solicitada quando necessário.", - "Set on this account. Will be requested when needed to decrypt synced credentials.": "Definida nesta conta. Será solicitada quando for necessária para desencriptar credenciais sincronizadas.", "Set passphrase": "Definir frase-passe", "Forgot passphrase": "Esqueci a frase-passe", "Incorrect PIN": "PIN incorreto", @@ -1420,5 +1418,9 @@ "Theme, highlight colours, integrations (KOSync, Readwise, Hardcover), and dictionary order": "Tema, cores de destaque, integrações (KOSync, Readwise, Hardcover) e ordem dos dicionários", "Required while Dictionaries sync is enabled": "Necessário enquanto a sincronização de Dicionários estiver ativada", "Resets in {{hours}} hr {{minutes}} min": "Repõe em {{hours}} h {{minutes}} min", - "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Escolha um PIN de 4 dígitos. Terá de o introduzir sempre que abrir o Readest. Não há forma de recuperar um PIN esquecido. Limpar os dados da aplicação é a única maneira de o redefinir." + "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Escolha um PIN de 4 dígitos. Terá de o introduzir sempre que abrir o Readest. Não há forma de recuperar um PIN esquecido. Limpar os dados da aplicação é a única maneira de o redefinir.", + "Credentials": "Credenciais", + "Tokens, usernames, and passwords for OPDS, KOReader, Hardcover, and Readwise. When disabled, credentials remain on this device only and are never uploaded.": "Tokens, nomes de utilizador e palavras-passe para OPDS, KOReader, Hardcover e Readwise. Quando desativado, as credenciais permanecem apenas neste dispositivo e nunca são enviadas.", + "Sensitive synced fields are encrypted before upload. Set a passphrase now or later when encryption is needed.": "Os campos sincronizados sensíveis são cifrados antes do envio. Defina uma frase-senha agora ou mais tarde, quando a cifragem for necessária.", + "Saved to this account. You will be prompted for it when decrypting credentials.": "Guardada nesta conta. Ser-lhe-á pedida quando precisar de decifrar credenciais." } diff --git a/apps/readest-app/public/locales/ro/translation.json b/apps/readest-app/public/locales/ro/translation.json index 455f19f7..c0707093 100644 --- a/apps/readest-app/public/locales/ro/translation.json +++ b/apps/readest-app/public/locales/ro/translation.json @@ -1371,8 +1371,6 @@ "This permanently deletes the encrypted credentials we sync (e.g., OPDS catalog passwords) on every device. Local copies are preserved. You will need to re-enter the sync passphrase or set a new one. Continue?": "Această acțiune șterge definitiv datele de autentificare criptate pe care le sincronizăm (de exemplu, parolele catalogului OPDS) pe fiecare dispozitiv. Copiile locale sunt păstrate. Va trebui să reintroduci fraza de acces pentru sincronizare sau să setezi una nouă. Continui?", "Sync passphrase forgotten — all encrypted fields cleared": "Fraza de acces pentru sincronizare a fost uitată — toate câmpurile criptate au fost șterse", "Sync passphrase": "Frază de acces pentru sincronizare", - "Encrypts sensitive synced fields (like OPDS catalog credentials) before they leave your device. Set one now or wait — it will be requested when needed.": "Criptează câmpurile sensibile sincronizate (cum ar fi datele de autentificare ale catalogului OPDS) înainte ca acestea să părăsească dispozitivul tău. Setează una acum sau așteaptă — va fi solicitată când va fi nevoie.", - "Set on this account. Will be requested when needed to decrypt synced credentials.": "Setată pe acest cont. Va fi solicitată atunci când va fi necesară pentru a decripta datele de autentificare sincronizate.", "Set passphrase": "Setează fraza de acces", "Forgot passphrase": "Am uitat fraza de acces", "Incorrect PIN": "PIN incorect", @@ -1420,5 +1418,9 @@ "Theme, highlight colours, integrations (KOSync, Readwise, Hardcover), and dictionary order": "Temă, culorile evidențierilor, integrări (KOSync, Readwise, Hardcover) și ordinea dicționarelor", "Required while Dictionaries sync is enabled": "Necesar cât timp sincronizarea Dicționarelor este activată", "Resets in {{hours}} hr {{minutes}} min": "Se resetează în {{hours}} h {{minutes}} min", - "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Alege un PIN din 4 cifre. Va trebui să îl introduci de fiecare dată când deschizi Readest. Nu există nicio modalitate de a recupera un PIN uitat. Ștergerea datelor aplicației este singura modalitate de a-l reseta." + "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Alege un PIN din 4 cifre. Va trebui să îl introduci de fiecare dată când deschizi Readest. Nu există nicio modalitate de a recupera un PIN uitat. Ștergerea datelor aplicației este singura modalitate de a-l reseta.", + "Credentials": "Acreditări", + "Tokens, usernames, and passwords for OPDS, KOReader, Hardcover, and Readwise. When disabled, credentials remain on this device only and are never uploaded.": "Token-uri, nume de utilizator și parole pentru OPDS, KOReader, Hardcover și Readwise. Când sunt dezactivate, acreditările rămân doar pe acest dispozitiv și nu sunt niciodată încărcate.", + "Sensitive synced fields are encrypted before upload. Set a passphrase now or later when encryption is needed.": "Câmpurile sincronizate sensibile sunt criptate înainte de încărcare. Setați o frază de acces acum sau mai târziu, când criptarea va fi necesară.", + "Saved to this account. You will be prompted for it when decrypting credentials.": "Salvată în acest cont. Vi se va cere când va trebui să se decripteze acreditările." } diff --git a/apps/readest-app/public/locales/ru/translation.json b/apps/readest-app/public/locales/ru/translation.json index 44e7e534..4aba93bf 100644 --- a/apps/readest-app/public/locales/ru/translation.json +++ b/apps/readest-app/public/locales/ru/translation.json @@ -1395,8 +1395,6 @@ "This permanently deletes the encrypted credentials we sync (e.g., OPDS catalog passwords) on every device. Local copies are preserved. You will need to re-enter the sync passphrase or set a new one. Continue?": "Это окончательно удалит зашифрованные учётные данные, которые мы синхронизируем (например, пароли каталога OPDS), на каждом устройстве. Локальные копии сохраняются. Вам потребуется ввести секретную фразу синхронизации заново или задать новую. Продолжить?", "Sync passphrase forgotten — all encrypted fields cleared": "Секретная фраза синхронизации забыта — все зашифрованные поля очищены", "Sync passphrase": "Секретная фраза синхронизации", - "Encrypts sensitive synced fields (like OPDS catalog credentials) before they leave your device. Set one now or wait — it will be requested when needed.": "Шифрует конфиденциальные синхронизируемые поля (например, учётные данные каталога OPDS) перед тем, как они покинут ваше устройство. Задайте её сейчас или позже — она будет запрошена при необходимости.", - "Set on this account. Will be requested when needed to decrypt synced credentials.": "Задана для этого аккаунта. Будет запрошена при необходимости для расшифровки синхронизированных учётных данных.", "Set passphrase": "Задать секретную фразу", "Forgot passphrase": "Забыли секретную фразу", "Incorrect PIN": "Неверный PIN", @@ -1444,5 +1442,9 @@ "Theme, highlight colours, integrations (KOSync, Readwise, Hardcover), and dictionary order": "Тема, цвета выделений, интеграции (KOSync, Readwise, Hardcover) и порядок словарей", "Required while Dictionaries sync is enabled": "Требуется, пока включена синхронизация Словарей", "Resets in {{hours}} hr {{minutes}} min": "Сброс через {{hours}} ч {{minutes}} мин", - "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Выберите 4-значный PIN-код. Вам нужно будет вводить его каждый раз при открытии Readest. Восстановить забытый PIN-код невозможно. Очистка данных приложения — единственный способ его сбросить." + "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Выберите 4-значный PIN-код. Вам нужно будет вводить его каждый раз при открытии Readest. Восстановить забытый PIN-код невозможно. Очистка данных приложения — единственный способ его сбросить.", + "Credentials": "Учётные данные", + "Tokens, usernames, and passwords for OPDS, KOReader, Hardcover, and Readwise. When disabled, credentials remain on this device only and are never uploaded.": "Токены, имена пользователей и пароли для OPDS, KOReader, Hardcover и Readwise. Если отключено, учётные данные остаются только на этом устройстве и никогда не отправляются.", + "Sensitive synced fields are encrypted before upload. Set a passphrase now or later when encryption is needed.": "Конфиденциальные синхронизируемые поля шифруются перед загрузкой. Задайте парольную фразу сейчас или позже, когда понадобится шифрование.", + "Saved to this account. You will be prompted for it when decrypting credentials.": "Сохранено в этой учётной записи. Вы получите запрос при расшифровке учётных данных." } diff --git a/apps/readest-app/public/locales/si/translation.json b/apps/readest-app/public/locales/si/translation.json index f8c950ce..0a1992d6 100644 --- a/apps/readest-app/public/locales/si/translation.json +++ b/apps/readest-app/public/locales/si/translation.json @@ -1347,8 +1347,6 @@ "This permanently deletes the encrypted credentials we sync (e.g., OPDS catalog passwords) on every device. Local copies are preserved. You will need to re-enter the sync passphrase or set a new one. Continue?": "මෙය සෑම උපාංගයකම අප සමමුහුර්ත කරන සංකේතාංකිත අක්තපත්‍ර (උදා., OPDS නාමාවලි මුරපද) ස්ථිරවම මකා දමයි. දේශීය පිටපත් රැකේ. ඔබට සමමුහුර්ත මුරපදය නැවත ඇතුළත් කිරීමට හෝ අලුත් එකක් සැකසීමට සිදුවේ. ඉදිරියට යන්නද?", "Sync passphrase forgotten — all encrypted fields cleared": "සමමුහුර්ත මුරපදය අමතක විය — සියලුම සංකේතාංකිත ක්ෂේත්‍ර හිස් කරන ලදී", "Sync passphrase": "සමමුහුර්ත මුරපදය", - "Encrypts sensitive synced fields (like OPDS catalog credentials) before they leave your device. Set one now or wait — it will be requested when needed.": "ඔබේ උපාංගයෙන් පිටවීමට පෙර සංවේදී සමමුහුර්ත ක්ෂේත්‍ර (OPDS නාමාවලි අක්තපත්‍ර වැනි) සංකේතාංකනය කරයි. දැන් එකක් සකසන්න හෝ රැඳී සිටින්න — අවශ්‍ය වූ විට එය ඉල්ලනු ඇත.", - "Set on this account. Will be requested when needed to decrypt synced credentials.": "මෙම ගිණුමේ සකස් කර ඇත. සමමුහුර්ත අක්තපත්‍ර විකේතනය කිරීම සඳහා අවශ්‍ය වූ විට එය ඉල්ලනු ඇත.", "Set passphrase": "මුරපදය සකසන්න", "Forgot passphrase": "මුරපදය අමතකද", "Incorrect PIN": "වැරදි PIN", @@ -1396,5 +1394,9 @@ "Theme, highlight colours, integrations (KOSync, Readwise, Hardcover), and dictionary order": "තේමාව, උද්දීපන වර්ණ, ඒකාබද්ධතා (KOSync, Readwise, Hardcover) සහ ශබ්දකෝෂ අනුපිළිවෙල", "Required while Dictionaries sync is enabled": "ශබ්දකෝෂ සමමුහූර්තය සක්‍රිය වී ඇති විට අවශ්‍යයි", "Resets in {{hours}} hr {{minutes}} min": "{{hours}} පැ {{minutes}} මි කින් යළි පිහිටුවයි", - "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "අංක 4ක PIN එකක් තෝරන්න. ඔබ Readest විවෘත කරන සෑම විටම ඔබට එය ඇතුළත් කිරීමට අවශ්‍ය වේ. අමතක වූ PIN එකක් ලබා ගැනීමට ක්‍රමයක් නැත. එය යළි පිහිටුවීමට ඇති එකම ක්‍රමය යෙදුම් දත්ත මකා දැමීමයි." + "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "අංක 4ක PIN එකක් තෝරන්න. ඔබ Readest විවෘත කරන සෑම විටම ඔබට එය ඇතුළත් කිරීමට අවශ්‍ය වේ. අමතක වූ PIN එකක් ලබා ගැනීමට ක්‍රමයක් නැත. එය යළි පිහිටුවීමට ඇති එකම ක්‍රමය යෙදුම් දත්ත මකා දැමීමයි.", + "Credentials": "අක්තපත්‍ර", + "Tokens, usernames, and passwords for OPDS, KOReader, Hardcover, and Readwise. When disabled, credentials remain on this device only and are never uploaded.": "OPDS, KOReader, Hardcover, සහ Readwise සඳහා ටෝකන, පරිශීලක නාම සහ මුරපද. අක්‍රිය කළ විට, අක්තපත්‍ර මෙම උපාංගයේ පමණක් රැඳී පවතින අතර කිසිදා උඩුගත නොකෙරේ.", + "Sensitive synced fields are encrypted before upload. Set a passphrase now or later when encryption is needed.": "සංවේදී සමමුහූර්ත ක්ෂේත්‍ර උඩුගත කිරීමට පෙර සංකේතනය වේ. සංකේතනය අවශ්‍ය වූ විට දැන් හෝ පසුව මුර වැකියක් සකසන්න.", + "Saved to this account. You will be prompted for it when decrypting credentials.": "මෙම ගිණුමට සුරකින ලදී. අක්තපත්‍ර විකේතනය කිරීමේදී ඔබෙන් එය ඉල්ලනු ලැබේ." } diff --git a/apps/readest-app/public/locales/sl/translation.json b/apps/readest-app/public/locales/sl/translation.json index 2a1f133c..5680c375 100644 --- a/apps/readest-app/public/locales/sl/translation.json +++ b/apps/readest-app/public/locales/sl/translation.json @@ -1395,8 +1395,6 @@ "This permanently deletes the encrypted credentials we sync (e.g., OPDS catalog passwords) on every device. Local copies are preserved. You will need to re-enter the sync passphrase or set a new one. Continue?": "S tem boste trajno izbrisali šifrirane poverilnice, ki jih sinhroniziramo (npr. gesla kataloga OPDS), v vseh napravah. Lokalne kopije se ohranijo. Znova boste morali vnesti sinhronizacijsko geslo ali nastaviti novo. Nadaljujem?", "Sync passphrase forgotten — all encrypted fields cleared": "Sinhronizacijsko geslo pozabljeno — vsa šifrirana polja so izbrisana", "Sync passphrase": "Sinhronizacijsko geslo", - "Encrypts sensitive synced fields (like OPDS catalog credentials) before they leave your device. Set one now or wait — it will be requested when needed.": "Šifrira občutljiva sinhronizirana polja (na primer poverilnice kataloga OPDS), preden zapustijo vašo napravo. Nastavite ga zdaj ali počakajte — zahtevan bo, ko bo potreben.", - "Set on this account. Will be requested when needed to decrypt synced credentials.": "Nastavljeno za ta račun. Zahtevano bo, ko bo potrebno za dešifriranje sinhroniziranih poverilnic.", "Set passphrase": "Nastavi geslo", "Forgot passphrase": "Pozabljeno geslo", "Incorrect PIN": "Napačen PIN", @@ -1444,5 +1442,9 @@ "Theme, highlight colours, integrations (KOSync, Readwise, Hardcover), and dictionary order": "Tema, barve označb, integracije (KOSync, Readwise, Hardcover) in vrstni red slovarjev", "Required while Dictionaries sync is enabled": "Zahtevano, dokler je sinhronizacija Slovarjev omogočena", "Resets in {{hours}} hr {{minutes}} min": "Ponastavi se čez {{hours}} h {{minutes}} min", - "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Izberite 4-mestno kodo PIN. Vnesti jo boste morali vsakič, ko boste odprli Readest. Pozabljene kode PIN ni mogoče obnoviti. Edini način za ponastavitev je brisanje podatkov aplikacije." + "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Izberite 4-mestno kodo PIN. Vnesti jo boste morali vsakič, ko boste odprli Readest. Pozabljene kode PIN ni mogoče obnoviti. Edini način za ponastavitev je brisanje podatkov aplikacije.", + "Credentials": "Poverilnice", + "Tokens, usernames, and passwords for OPDS, KOReader, Hardcover, and Readwise. When disabled, credentials remain on this device only and are never uploaded.": "Žetoni, uporabniška imena in gesla za OPDS, KOReader, Hardcover in Readwise. Ko je onemogočeno, poverilnice ostanejo le na tej napravi in se nikoli ne naložijo.", + "Sensitive synced fields are encrypted before upload. Set a passphrase now or later when encryption is needed.": "Občutljiva sinhronizirana polja so pred nalaganjem šifrirana. Nastavite geselsko frazo zdaj ali pozneje, ko bo šifriranje potrebno.", + "Saved to this account. You will be prompted for it when decrypting credentials.": "Shranjeno v tem računu. Pozvani boste, ko bo treba dešifrirati poverilnice." } diff --git a/apps/readest-app/public/locales/sv/translation.json b/apps/readest-app/public/locales/sv/translation.json index bf00fa33..360c58d6 100644 --- a/apps/readest-app/public/locales/sv/translation.json +++ b/apps/readest-app/public/locales/sv/translation.json @@ -1347,8 +1347,6 @@ "This permanently deletes the encrypted credentials we sync (e.g., OPDS catalog passwords) on every device. Local copies are preserved. You will need to re-enter the sync passphrase or set a new one. Continue?": "Detta tar permanent bort de krypterade autentiseringsuppgifterna som vi synkroniserar (t.ex. lösenord för OPDS-kataloger) på alla enheter. Lokala kopior bevaras. Du behöver ange synkroniseringslösenfrasen igen eller välja en ny. Fortsätta?", "Sync passphrase forgotten — all encrypted fields cleared": "Synkroniseringslösenfrasen glömdes — alla krypterade fält rensade", "Sync passphrase": "Synkroniseringslösenfras", - "Encrypts sensitive synced fields (like OPDS catalog credentials) before they leave your device. Set one now or wait — it will be requested when needed.": "Krypterar känsliga synkroniserade fält (t.ex. OPDS-katalogautentiseringsuppgifter) innan de lämnar din enhet. Ange en nu eller vänta — den efterfrågas när det behövs.", - "Set on this account. Will be requested when needed to decrypt synced credentials.": "Inställd för det här kontot. Efterfrågas när det behövs för att dekryptera synkroniserade autentiseringsuppgifter.", "Set passphrase": "Ange lösenfras", "Forgot passphrase": "Glömt lösenfras", "Incorrect PIN": "Felaktig PIN", @@ -1396,5 +1394,9 @@ "Theme, highlight colours, integrations (KOSync, Readwise, Hardcover), and dictionary order": "Tema, markeringsfärger, integrationer (KOSync, Readwise, Hardcover) och ordbokens ordning", "Required while Dictionaries sync is enabled": "Krävs så länge synkronisering av Ordböcker är aktiverad", "Resets in {{hours}} hr {{minutes}} min": "Återställs om {{hours}} tim {{minutes}} min", - "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Välj en 4-siffrig PIN-kod. Du kommer att behöva ange den varje gång du öppnar Readest. Det finns inget sätt att återställa en glömd PIN-kod. Att rensa appdata är det enda sättet att återställa den." + "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Välj en 4-siffrig PIN-kod. Du kommer att behöva ange den varje gång du öppnar Readest. Det finns inget sätt att återställa en glömd PIN-kod. Att rensa appdata är det enda sättet att återställa den.", + "Credentials": "Inloggningsuppgifter", + "Tokens, usernames, and passwords for OPDS, KOReader, Hardcover, and Readwise. When disabled, credentials remain on this device only and are never uploaded.": "Tokens, användarnamn och lösenord för OPDS, KOReader, Hardcover och Readwise. När inaktiverat förblir inloggningsuppgifterna endast på denna enhet och laddas aldrig upp.", + "Sensitive synced fields are encrypted before upload. Set a passphrase now or later when encryption is needed.": "Känsliga synkroniserade fält krypteras före uppladdning. Ange en lösenfras nu eller senare när kryptering behövs.", + "Saved to this account. You will be prompted for it when decrypting credentials.": "Sparad på det här kontot. Du blir tillfrågad när inloggningsuppgifter ska dekrypteras." } diff --git a/apps/readest-app/public/locales/ta/translation.json b/apps/readest-app/public/locales/ta/translation.json index 57ed4abe..e06b416c 100644 --- a/apps/readest-app/public/locales/ta/translation.json +++ b/apps/readest-app/public/locales/ta/translation.json @@ -1347,8 +1347,6 @@ "This permanently deletes the encrypted credentials we sync (e.g., OPDS catalog passwords) on every device. Local copies are preserved. You will need to re-enter the sync passphrase or set a new one. Continue?": "இது ஒவ்வொரு சாதனத்திலும் நாங்கள் ஒத்திசைக்கும் குறியாக்கம் செய்யப்பட்ட சான்றுகளை (எ.கா., OPDS பட்டியல் கடவுச்சொற்கள்) நிரந்தரமாக நீக்குகிறது. உள்ளூர் நகல்கள் பாதுகாக்கப்படுகின்றன. நீங்கள் ஒத்திசைவு கடவுச்சொற்றொடரை மீண்டும் உள்ளிட வேண்டும் அல்லது புதியதை அமைக்க வேண்டும். தொடரவா?", "Sync passphrase forgotten — all encrypted fields cleared": "ஒத்திசைவு கடவுச்சொற்றொடர் மறக்கப்பட்டது — அனைத்து குறியாக்கம் செய்யப்பட்ட புலங்களும் அழிக்கப்பட்டன", "Sync passphrase": "ஒத்திசைவு கடவுச்சொற்றொடர்", - "Encrypts sensitive synced fields (like OPDS catalog credentials) before they leave your device. Set one now or wait — it will be requested when needed.": "உங்கள் சாதனத்தை விட்டு வெளியேறுவதற்கு முன், முக்கியமான ஒத்திசைக்கப்பட்ட புலங்களை (OPDS பட்டியல் சான்றுகள் போன்றவை) குறியாக்கம் செய்கிறது. இப்போது ஒன்றை அமைக்கவும் அல்லது காத்திருக்கவும் — தேவைப்படும் போது கேட்கப்படும்.", - "Set on this account. Will be requested when needed to decrypt synced credentials.": "இந்த கணக்கில் அமைக்கப்பட்டுள்ளது. ஒத்திசைக்கப்பட்ட சான்றுகளை விகுதியாக்க தேவைப்படும்போது கேட்கப்படும்.", "Set passphrase": "கடவுச்சொற்றொடரை அமைக்கவும்", "Forgot passphrase": "கடவுச்சொற்றொடரை மறந்துவிட்டீர்களா", "Incorrect PIN": "தவறான PIN", @@ -1396,5 +1394,9 @@ "Theme, highlight colours, integrations (KOSync, Readwise, Hardcover), and dictionary order": "தீம், ஹைலைட் வண்ணங்கள், ஒருங்கிணைப்புகள் (KOSync, Readwise, Hardcover) மற்றும் அகராதி வரிசை", "Required while Dictionaries sync is enabled": "அகராதிகள் ஒத்திசைவு இயக்கத்தில் இருக்கும்போது தேவை", "Resets in {{hours}} hr {{minutes}} min": "{{hours}} மணி {{minutes}} நிமிடத்தில் மீட்டமைக்கப்படும்", - "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "4 இலக்க PIN ஒன்றைத் தேர்ந்தெடுக்கவும். Readest திறக்கும் ஒவ்வொரு முறையும் அதை உள்ளிட வேண்டும். மறந்துபோன PIN ஐ மீட்டெடுக்க வழியில்லை. அதை மீட்டமைக்க ஒரே வழி பயன்பாட்டுத் தரவை அழிப்பதே ஆகும்." + "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "4 இலக்க PIN ஒன்றைத் தேர்ந்தெடுக்கவும். Readest திறக்கும் ஒவ்வொரு முறையும் அதை உள்ளிட வேண்டும். மறந்துபோன PIN ஐ மீட்டெடுக்க வழியில்லை. அதை மீட்டமைக்க ஒரே வழி பயன்பாட்டுத் தரவை அழிப்பதே ஆகும்.", + "Credentials": "அங்கீகாரத் தரவுகள்", + "Tokens, usernames, and passwords for OPDS, KOReader, Hardcover, and Readwise. When disabled, credentials remain on this device only and are never uploaded.": "OPDS, KOReader, Hardcover மற்றும் Readwise-க்கான டோக்கன்கள், பயனர் பெயர்கள் மற்றும் கடவுச்சொற்கள். முடக்கப்பட்டிருக்கும் போது, அங்கீகாரத் தரவுகள் இந்த சாதனத்தில் மட்டுமே இருக்கும், ஒருபோதும் பதிவேற்றப்படாது.", + "Sensitive synced fields are encrypted before upload. Set a passphrase now or later when encryption is needed.": "முக்கியமான ஒத்திசைக்கப்பட்ட புலங்கள் பதிவேற்றத்திற்கு முன் குறியாக்கம் செய்யப்படுகின்றன. குறியாக்கம் தேவைப்படும் போது இப்போது அல்லது பின்னர் கடவுச்சொற்றொடரை அமைக்கவும்.", + "Saved to this account. You will be prompted for it when decrypting credentials.": "இந்த கணக்கில் சேமிக்கப்பட்டது. அங்கீகாரத் தரவுகளை மறைகுறியாக்கும்போது உங்களிடம் கேட்கப்படும்." } diff --git a/apps/readest-app/public/locales/th/translation.json b/apps/readest-app/public/locales/th/translation.json index 96214849..45f8e6fc 100644 --- a/apps/readest-app/public/locales/th/translation.json +++ b/apps/readest-app/public/locales/th/translation.json @@ -1323,8 +1323,6 @@ "This permanently deletes the encrypted credentials we sync (e.g., OPDS catalog passwords) on every device. Local copies are preserved. You will need to re-enter the sync passphrase or set a new one. Continue?": "การกระทำนี้จะลบข้อมูลรับรองที่เข้ารหัสซึ่งเราซิงค์ไว้ (เช่น รหัสผ่านของแคตตาล็อก OPDS) บนทุกอุปกรณ์อย่างถาวร สำเนาที่อยู่ในเครื่องจะถูกเก็บไว้ คุณจะต้องป้อนวลีรหัสผ่านสำหรับซิงค์อีกครั้งหรือตั้งค่าใหม่ ดำเนินการต่อหรือไม่?", "Sync passphrase forgotten — all encrypted fields cleared": "ลืมวลีรหัสผ่านสำหรับซิงค์ — ฟิลด์ที่เข้ารหัสทั้งหมดถูกล้างแล้ว", "Sync passphrase": "วลีรหัสผ่านสำหรับซิงค์", - "Encrypts sensitive synced fields (like OPDS catalog credentials) before they leave your device. Set one now or wait — it will be requested when needed.": "เข้ารหัสฟิลด์ที่ซิงค์ซึ่งมีข้อมูลละเอียดอ่อน (เช่น ข้อมูลรับรองแคตตาล็อก OPDS) ก่อนออกจากอุปกรณ์ของคุณ ตั้งค่าเดี๋ยวนี้หรือรอไว้ก่อน — ระบบจะร้องขอเมื่อจำเป็น", - "Set on this account. Will be requested when needed to decrypt synced credentials.": "ตั้งค่าไว้ในบัญชีนี้แล้ว จะถูกร้องขอเมื่อจำเป็นต้องถอดรหัสข้อมูลรับรองที่ซิงค์ไว้", "Set passphrase": "ตั้งค่าวลีรหัสผ่าน", "Forgot passphrase": "ลืมวลีรหัสผ่าน", "Incorrect PIN": "PIN ไม่ถูกต้อง", @@ -1372,5 +1370,9 @@ "Theme, highlight colours, integrations (KOSync, Readwise, Hardcover), and dictionary order": "ธีม สีไฮไลต์ การเชื่อมต่อ (KOSync, Readwise, Hardcover) และลำดับพจนานุกรม", "Required while Dictionaries sync is enabled": "จำเป็นเมื่อเปิดใช้การซิงค์พจนานุกรม", "Resets in {{hours}} hr {{minutes}} min": "รีเซ็ตใน {{hours}} ชม. {{minutes}} นาที", - "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "เลือก PIN 4 หลัก คุณจะต้องป้อนทุกครั้งที่เปิด Readest ไม่มีวิธีกู้คืน PIN ที่ลืม การล้างข้อมูลแอปเป็นวิธีเดียวในการรีเซ็ต" + "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "เลือก PIN 4 หลัก คุณจะต้องป้อนทุกครั้งที่เปิด Readest ไม่มีวิธีกู้คืน PIN ที่ลืม การล้างข้อมูลแอปเป็นวิธีเดียวในการรีเซ็ต", + "Credentials": "ข้อมูลรับรอง", + "Tokens, usernames, and passwords for OPDS, KOReader, Hardcover, and Readwise. When disabled, credentials remain on this device only and are never uploaded.": "โทเคน ชื่อผู้ใช้ และรหัสผ่านสำหรับ OPDS, KOReader, Hardcover และ Readwise เมื่อปิดใช้งาน ข้อมูลรับรองจะยังคงอยู่ในอุปกรณ์นี้เท่านั้นและจะไม่ถูกอัปโหลด", + "Sensitive synced fields are encrypted before upload. Set a passphrase now or later when encryption is needed.": "ฟิลด์ที่ซิงค์ที่มีความละเอียดอ่อนจะถูกเข้ารหัสก่อนอัปโหลด ตั้งวลีรหัสผ่านตอนนี้หรือภายหลังเมื่อจำเป็นต้องเข้ารหัส", + "Saved to this account. You will be prompted for it when decrypting credentials.": "บันทึกในบัญชีนี้แล้ว คุณจะได้รับแจ้งเมื่อจำเป็นต้องถอดรหัสข้อมูลรับรอง" } diff --git a/apps/readest-app/public/locales/tr/translation.json b/apps/readest-app/public/locales/tr/translation.json index 40442c65..bee55199 100644 --- a/apps/readest-app/public/locales/tr/translation.json +++ b/apps/readest-app/public/locales/tr/translation.json @@ -1347,8 +1347,6 @@ "This permanently deletes the encrypted credentials we sync (e.g., OPDS catalog passwords) on every device. Local copies are preserved. You will need to re-enter the sync passphrase or set a new one. Continue?": "Bu işlem, her cihazda eşitlediğimiz şifrelenmiş kimlik bilgilerini (ör. OPDS kataloğu parolaları) kalıcı olarak siler. Yerel kopyalar korunur. Eşitleme parolasını yeniden girmeniz veya yeni bir tane belirlemeniz gerekecek. Devam edilsin mi?", "Sync passphrase forgotten — all encrypted fields cleared": "Eşitleme parolası unutuldu — tüm şifrelenmiş alanlar temizlendi", "Sync passphrase": "Eşitleme parolası", - "Encrypts sensitive synced fields (like OPDS catalog credentials) before they leave your device. Set one now or wait — it will be requested when needed.": "Hassas eşitlenen alanları (OPDS kataloğu kimlik bilgileri gibi) cihazınızdan ayrılmadan önce şifreler. Şimdi bir tane belirleyin ya da bekleyin — gerektiğinde istenecektir.", - "Set on this account. Will be requested when needed to decrypt synced credentials.": "Bu hesapta ayarlandı. Eşitlenen kimlik bilgilerinin şifresini çözmek için gerektiğinde istenecektir.", "Set passphrase": "Parolayı belirle", "Forgot passphrase": "Parolayı unuttum", "Incorrect PIN": "Yanlış PIN", @@ -1396,5 +1394,9 @@ "Theme, highlight colours, integrations (KOSync, Readwise, Hardcover), and dictionary order": "Tema, vurgu renkleri, entegrasyonlar (KOSync, Readwise, Hardcover) ve sözlük sırası", "Required while Dictionaries sync is enabled": "Sözlük eşitlemesi etkinken gereklidir", "Resets in {{hours}} hr {{minutes}} min": "{{hours}} sa {{minutes}} dk içinde sıfırlanır", - "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "4 haneli bir PIN seçin. Readest'i her açtığınızda bunu girmeniz gerekecek. Unutulan bir PIN'i kurtarmanın yolu yoktur. Uygulama verilerini temizlemek, sıfırlamanın tek yoludur." + "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "4 haneli bir PIN seçin. Readest'i her açtığınızda bunu girmeniz gerekecek. Unutulan bir PIN'i kurtarmanın yolu yoktur. Uygulama verilerini temizlemek, sıfırlamanın tek yoludur.", + "Credentials": "Kimlik Bilgileri", + "Tokens, usernames, and passwords for OPDS, KOReader, Hardcover, and Readwise. When disabled, credentials remain on this device only and are never uploaded.": "OPDS, KOReader, Hardcover ve Readwise için belirteçler, kullanıcı adları ve parolalar. Devre dışı bırakıldığında kimlik bilgileri yalnızca bu cihazda kalır ve hiçbir zaman karşıya yüklenmez.", + "Sensitive synced fields are encrypted before upload. Set a passphrase now or later when encryption is needed.": "Hassas senkronize alanlar yüklemeden önce şifrelenir. Şifreleme gerektiğinde şimdi ya da daha sonra bir parola tümcesi belirleyin.", + "Saved to this account. You will be prompted for it when decrypting credentials.": "Bu hesaba kaydedildi. Kimlik bilgileri şifresi çözülürken sizden istenecektir." } diff --git a/apps/readest-app/public/locales/uk/translation.json b/apps/readest-app/public/locales/uk/translation.json index 0fe0d20b..4491f600 100644 --- a/apps/readest-app/public/locales/uk/translation.json +++ b/apps/readest-app/public/locales/uk/translation.json @@ -1395,8 +1395,6 @@ "This permanently deletes the encrypted credentials we sync (e.g., OPDS catalog passwords) on every device. Local copies are preserved. You will need to re-enter the sync passphrase or set a new one. Continue?": "Це остаточно видалить зашифровані облікові дані, які ми синхронізуємо (наприклад, паролі каталогу OPDS), на кожному пристрої. Локальні копії зберігаються. Вам потрібно буде повторно ввести парольну фразу синхронізації або встановити нову. Продовжити?", "Sync passphrase forgotten — all encrypted fields cleared": "Парольну фразу синхронізації забуто — усі зашифровані поля очищено", "Sync passphrase": "Парольна фраза синхронізації", - "Encrypts sensitive synced fields (like OPDS catalog credentials) before they leave your device. Set one now or wait — it will be requested when needed.": "Шифрує конфіденційні синхронізовані поля (наприклад, облікові дані каталогу OPDS) перед тим, як вони залишать ваш пристрій. Установіть її зараз або зачекайте — її буде запитано за потреби.", - "Set on this account. Will be requested when needed to decrypt synced credentials.": "Установлено для цього облікового запису. Запитуватиметься за потреби для розшифрування синхронізованих облікових даних.", "Set passphrase": "Установити парольну фразу", "Forgot passphrase": "Забули парольну фразу", "Incorrect PIN": "Неправильний PIN", @@ -1444,5 +1442,9 @@ "Theme, highlight colours, integrations (KOSync, Readwise, Hardcover), and dictionary order": "Тема, кольори виділень, інтеграції (KOSync, Readwise, Hardcover) і порядок словників", "Required while Dictionaries sync is enabled": "Потрібне, доки увімкнено синхронізацію Словників", "Resets in {{hours}} hr {{minutes}} min": "Скидання через {{hours}} год {{minutes}} хв", - "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Виберіть 4-значний PIN-код. Вам потрібно буде вводити його щоразу, коли ви відкриваєте Readest. Відновити забутий PIN-код неможливо. Очищення даних застосунку — єдиний спосіб його скинути." + "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Виберіть 4-значний PIN-код. Вам потрібно буде вводити його щоразу, коли ви відкриваєте Readest. Відновити забутий PIN-код неможливо. Очищення даних застосунку — єдиний спосіб його скинути.", + "Credentials": "Облікові дані", + "Tokens, usernames, and passwords for OPDS, KOReader, Hardcover, and Readwise. When disabled, credentials remain on this device only and are never uploaded.": "Токени, імена користувачів і паролі для OPDS, KOReader, Hardcover та Readwise. Якщо вимкнено, облікові дані залишаються лише на цьому пристрої і ніколи не вивантажуються.", + "Sensitive synced fields are encrypted before upload. Set a passphrase now or later when encryption is needed.": "Конфіденційні синхронізовані поля шифруються перед вивантаженням. Установіть парольну фразу зараз або пізніше, коли знадобиться шифрування.", + "Saved to this account. You will be prompted for it when decrypting credentials.": "Збережено в цьому обліковому записі. Вас запитають про неї під час розшифровування облікових даних." } diff --git a/apps/readest-app/public/locales/uz/translation.json b/apps/readest-app/public/locales/uz/translation.json index 8ff6cc48..2b524b6e 100644 --- a/apps/readest-app/public/locales/uz/translation.json +++ b/apps/readest-app/public/locales/uz/translation.json @@ -1347,8 +1347,6 @@ "This permanently deletes the encrypted credentials we sync (e.g., OPDS catalog passwords) on every device. Local copies are preserved. You will need to re-enter the sync passphrase or set a new one. Continue?": "Bu har bir qurilmada biz sinxronlaydigan shifrlangan hisob ma’lumotlarini (masalan, OPDS katalogi parollarini) butunlay o‘chiradi. Mahalliy nusxalar saqlanadi. Sinxronlash parol iborasini qaytadan kiritishingiz yoki yangisini o‘rnatishingiz kerak bo‘ladi. Davom etilsinmi?", "Sync passphrase forgotten — all encrypted fields cleared": "Sinxronlash parol iborasi unutildi — barcha shifrlangan maydonlar tozalandi", "Sync passphrase": "Sinxronlash parol iborasi", - "Encrypts sensitive synced fields (like OPDS catalog credentials) before they leave your device. Set one now or wait — it will be requested when needed.": "Maxfiy sinxronlangan maydonlarni (masalan, OPDS katalogi hisob ma’lumotlari) qurilmangizdan chiqishidan oldin shifrlaydi. Hozir o‘rnating yoki kuting — kerak bo‘lganda so‘raladi.", - "Set on this account. Will be requested when needed to decrypt synced credentials.": "Ushbu hisobda o‘rnatilgan. Sinxronlangan hisob ma’lumotlarini deshifrlash uchun kerak bo‘lganda so‘raladi.", "Set passphrase": "Parol iborasini o‘rnatish", "Forgot passphrase": "Parol iborasini unutdingizmi", "Incorrect PIN": "Noto'g'ri PIN", @@ -1396,5 +1394,9 @@ "Sync passphrase data on the server was reset. Re-encrypting your credentials under the new passphrase…": "Serverdagi sinxronlash paroli maʼlumotlari tiklandi. Hisob maʼlumotlaringiz yangi parol bilan qayta shifrlanmoqda…", "Failed to decrypt synced credentials": "Sinxronlangan hisob maʼlumotlari shifrini ochib boʻlmadi", "Resets in {{hours}} hr {{minutes}} min": "{{hours}} soat {{minutes}} daqiqada tiklanadi", - "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "4 raqamli PIN tanlang. Readestni har ochganingizda uni kiritishingiz kerak bo'ladi. Unutilgan PIN-ni tiklash imkoni yo'q. Uni qayta tiklashning yagona yo'li — ilova ma'lumotlarini tozalash." + "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "4 raqamli PIN tanlang. Readestni har ochganingizda uni kiritishingiz kerak bo'ladi. Unutilgan PIN-ni tiklash imkoni yo'q. Uni qayta tiklashning yagona yo'li — ilova ma'lumotlarini tozalash.", + "Credentials": "Hisob ma'lumotlari", + "Tokens, usernames, and passwords for OPDS, KOReader, Hardcover, and Readwise. When disabled, credentials remain on this device only and are never uploaded.": "OPDS, KOReader, Hardcover va Readwise uchun tokenlar, foydalanuvchi nomlari va parollar. O'chirilganda, hisob ma'lumotlari faqat shu qurilmada qoladi va hech qachon yuklanmaydi.", + "Sensitive synced fields are encrypted before upload. Set a passphrase now or later when encryption is needed.": "Maxfiy sinxronlashtirilgan maydonlar yuklashdan oldin shifrlanadi. Hozir yoki keyinroq, shifrlash kerak bo'lganda parol iborasini o'rnating.", + "Saved to this account. You will be prompted for it when decrypting credentials.": "Ushbu hisobga saqlangan. Hisob ma'lumotlarini deshifrlashda sizdan so'raladi." } diff --git a/apps/readest-app/public/locales/vi/translation.json b/apps/readest-app/public/locales/vi/translation.json index d80a5aaa..e09e30ec 100644 --- a/apps/readest-app/public/locales/vi/translation.json +++ b/apps/readest-app/public/locales/vi/translation.json @@ -1323,8 +1323,6 @@ "This permanently deletes the encrypted credentials we sync (e.g., OPDS catalog passwords) on every device. Local copies are preserved. You will need to re-enter the sync passphrase or set a new one. Continue?": "Điều này sẽ xóa vĩnh viễn các thông tin đăng nhập đã mã hóa mà chúng tôi đồng bộ (ví dụ: mật khẩu danh mục OPDS) trên mọi thiết bị. Các bản sao cục bộ được giữ lại. Bạn sẽ cần nhập lại cụm mật khẩu đồng bộ hoặc đặt cụm mới. Tiếp tục?", "Sync passphrase forgotten — all encrypted fields cleared": "Đã quên cụm mật khẩu đồng bộ — tất cả các trường đã mã hóa đã được xóa", "Sync passphrase": "Cụm mật khẩu đồng bộ", - "Encrypts sensitive synced fields (like OPDS catalog credentials) before they leave your device. Set one now or wait — it will be requested when needed.": "Mã hóa các trường được đồng bộ nhạy cảm (như thông tin đăng nhập danh mục OPDS) trước khi chúng rời khỏi thiết bị của bạn. Đặt ngay bây giờ hoặc chờ — sẽ được yêu cầu khi cần.", - "Set on this account. Will be requested when needed to decrypt synced credentials.": "Đã đặt trên tài khoản này. Sẽ được yêu cầu khi cần để giải mã thông tin đăng nhập đã đồng bộ.", "Set passphrase": "Đặt cụm mật khẩu", "Forgot passphrase": "Quên cụm mật khẩu", "Incorrect PIN": "Mã PIN không đúng", @@ -1372,5 +1370,9 @@ "Theme, highlight colours, integrations (KOSync, Readwise, Hardcover), and dictionary order": "Chủ đề, màu tô sáng, tích hợp (KOSync, Readwise, Hardcover) và thứ tự từ điển", "Required while Dictionaries sync is enabled": "Bắt buộc khi đồng bộ Từ điển đang bật", "Resets in {{hours}} hr {{minutes}} min": "Đặt lại sau {{hours}} g {{minutes}} ph", - "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Chọn mã PIN 4 chữ số. Bạn sẽ cần nhập mã mỗi khi mở Readest. Không có cách nào để khôi phục mã PIN đã quên. Xóa dữ liệu ứng dụng là cách duy nhất để đặt lại mã." + "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "Chọn mã PIN 4 chữ số. Bạn sẽ cần nhập mã mỗi khi mở Readest. Không có cách nào để khôi phục mã PIN đã quên. Xóa dữ liệu ứng dụng là cách duy nhất để đặt lại mã.", + "Credentials": "Thông tin xác thực", + "Tokens, usernames, and passwords for OPDS, KOReader, Hardcover, and Readwise. When disabled, credentials remain on this device only and are never uploaded.": "Mã thông báo, tên người dùng và mật khẩu cho OPDS, KOReader, Hardcover và Readwise. Khi bị tắt, thông tin xác thực chỉ ở trên thiết bị này và không bao giờ được tải lên.", + "Sensitive synced fields are encrypted before upload. Set a passphrase now or later when encryption is needed.": "Các trường đồng bộ nhạy cảm được mã hóa trước khi tải lên. Đặt cụm mật khẩu ngay bây giờ hoặc sau khi cần mã hóa.", + "Saved to this account. You will be prompted for it when decrypting credentials.": "Đã lưu vào tài khoản này. Bạn sẽ được nhắc nhập khi cần giải mã thông tin xác thực." } diff --git a/apps/readest-app/public/locales/zh-CN/translation.json b/apps/readest-app/public/locales/zh-CN/translation.json index 5a67daa6..c28c3da1 100644 --- a/apps/readest-app/public/locales/zh-CN/translation.json +++ b/apps/readest-app/public/locales/zh-CN/translation.json @@ -1323,8 +1323,6 @@ "This permanently deletes the encrypted credentials we sync (e.g., OPDS catalog passwords) on every device. Local copies are preserved. You will need to re-enter the sync passphrase or set a new one. Continue?": "这将在每台设备上永久删除我们同步的加密凭据(例如 OPDS 目录密码)。本地副本会保留。您需要重新输入同步密语或设置新的密语。是否继续?", "Sync passphrase forgotten — all encrypted fields cleared": "已忘记同步密语 — 所有加密字段已清除", "Sync passphrase": "同步密语", - "Encrypts sensitive synced fields (like OPDS catalog credentials) before they leave your device. Set one now or wait — it will be requested when needed.": "在敏感的同步字段(例如 OPDS 目录凭据)离开您的设备之前对其进行加密。立即设置或稍后再设 — 需要时会请求输入。", - "Set on this account. Will be requested when needed to decrypt synced credentials.": "已在此账户上设置。需要解密同步凭据时将请求输入。", "Set passphrase": "设置密语", "Forgot passphrase": "忘记密语", "Incorrect PIN": "PIN 码错误", @@ -1372,5 +1370,9 @@ "Theme, highlight colours, integrations (KOSync, Readwise, Hardcover), and dictionary order": "主题、高亮颜色、第三方集成(KOSync、Readwise、Hardcover)以及词典顺序", "Required while Dictionaries sync is enabled": "启用词典同步时必需", "Resets in {{hours}} hr {{minutes}} min": "{{hours}} 小时 {{minutes}} 分钟后重置", - "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "请设置一个 4 位数字 PIN 码。每次打开 Readest 时都需要输入。忘记的 PIN 码无法找回,清除应用数据是重置它的唯一方法。" + "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "请设置一个 4 位数字 PIN 码。每次打开 Readest 时都需要输入。忘记的 PIN 码无法找回,清除应用数据是重置它的唯一方法。", + "Credentials": "凭据", + "Tokens, usernames, and passwords for OPDS, KOReader, Hardcover, and Readwise. When disabled, credentials remain on this device only and are never uploaded.": "OPDS、KOReader、Hardcover 和 Readwise 的令牌、用户名和密码。关闭时,凭据仅保留在此设备上,永远不会上传。", + "Sensitive synced fields are encrypted before upload. Set a passphrase now or later when encryption is needed.": "敏感的同步字段在上传前会被加密。立即设置密码短语,或稍后在需要加密时再设置。", + "Saved to this account. You will be prompted for it when decrypting credentials.": "已保存到此账户。需要解密凭据时会提示您输入。" } diff --git a/apps/readest-app/public/locales/zh-TW/translation.json b/apps/readest-app/public/locales/zh-TW/translation.json index 79d70bce..4283b00f 100644 --- a/apps/readest-app/public/locales/zh-TW/translation.json +++ b/apps/readest-app/public/locales/zh-TW/translation.json @@ -1323,8 +1323,6 @@ "This permanently deletes the encrypted credentials we sync (e.g., OPDS catalog passwords) on every device. Local copies are preserved. You will need to re-enter the sync passphrase or set a new one. Continue?": "這將在每台裝置上永久刪除我們同步的加密憑證(例如 OPDS 目錄密碼)。本機副本會保留。您需要重新輸入同步密語或設定新的密語。是否繼續?", "Sync passphrase forgotten — all encrypted fields cleared": "已忘記同步密語 — 所有加密欄位已清除", "Sync passphrase": "同步密語", - "Encrypts sensitive synced fields (like OPDS catalog credentials) before they leave your device. Set one now or wait — it will be requested when needed.": "在敏感的同步欄位(例如 OPDS 目錄憑證)離開您的裝置之前對其進行加密。立即設定或稍後再設 — 需要時會請求輸入。", - "Set on this account. Will be requested when needed to decrypt synced credentials.": "已在此帳戶上設定。需要解密同步憑證時將請求輸入。", "Set passphrase": "設定密語", "Forgot passphrase": "忘記密語", "Incorrect PIN": "PIN 碼錯誤", @@ -1372,5 +1370,9 @@ "Theme, highlight colours, integrations (KOSync, Readwise, Hardcover), and dictionary order": "主題、螢光標記顏色、第三方整合(KOSync、Readwise、Hardcover)以及詞典順序", "Required while Dictionaries sync is enabled": "啟用詞典同步時必須", "Resets in {{hours}} hr {{minutes}} min": "{{hours}} 小時 {{minutes}} 分鐘後重設", - "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "請設定一組 4 位數的 PIN 碼。每次開啟 Readest 時都需要輸入。遺忘的 PIN 碼無法復原,清除應用程式資料是重設它的唯一方法。" + "Pick a 4-digit PIN. You will need to enter it every time you open Readest. There is no way to recover a forgotten PIN. Clearing the app data is the only way to reset it.": "請設定一組 4 位數的 PIN 碼。每次開啟 Readest 時都需要輸入。遺忘的 PIN 碼無法復原,清除應用程式資料是重設它的唯一方法。", + "Credentials": "憑證", + "Tokens, usernames, and passwords for OPDS, KOReader, Hardcover, and Readwise. When disabled, credentials remain on this device only and are never uploaded.": "OPDS、KOReader、Hardcover 與 Readwise 的權杖、使用者名稱與密碼。停用時,憑證僅留在此裝置上,永不上傳。", + "Sensitive synced fields are encrypted before upload. Set a passphrase now or later when encryption is needed.": "敏感的同步欄位會在上傳前加密。立即設定密碼短語,或稍後在需要加密時再設定。", + "Saved to this account. You will be prompted for it when decrypting credentials.": "已儲存到此帳號。需要解密憑證時會提示您輸入。" } diff --git a/apps/readest-app/src-tauri/plugins/tauri-plugin-native-bridge/Cargo.toml b/apps/readest-app/src-tauri/plugins/tauri-plugin-native-bridge/Cargo.toml index 46bea58a..4ced5ffe 100644 --- a/apps/readest-app/src-tauri/plugins/tauri-plugin-native-bridge/Cargo.toml +++ b/apps/readest-app/src-tauri/plugins/tauri-plugin-native-bridge/Cargo.toml @@ -4,7 +4,10 @@ version = "0.1.0" authors = [ "You" ] description = "a bridge between tauri app and native OS functionality" edition = "2021" -rust-version = "1.77.2" +# `keyring-core` v1 and the per-platform store crates require Rust +# 1.85 (apple-native) / 1.88 (windows-native, dbus-secret-service). +# Bumping the floor here so cargo lets them compile. +rust-version = "1.88" exclude = ["/examples", "/dist-js", "/guest-js", "/node_modules"] links = "tauri-plugin-native-bridge" @@ -20,17 +23,23 @@ schemars = "0.8" [target.'cfg(any(target_os = "macos", windows, target_os = "linux"))'.dependencies] font-enumeration = "0.9.0" +# OS-keychain backed secret storage for the sync passphrase. The +# `keyring` crate v4 was demoted to a sample CLI app; the library +# moved to `keyring-core` v1 plus a separate per-platform credential +# store crate. We register the right store at plugin init time +# (see `desktop.rs`). iOS / Android take a different path entirely: +# Swift's Security framework + Android's EncryptedSharedPreferences, +# dispatched via mobile.rs. +keyring-core = "1" -# OS-keychain backed secret storage for the sync passphrase. Each -# desktop target enables exactly the native backend it can compile. -# iOS / Android take a different path entirely: Swift's Security -# framework + Android's EncryptedSharedPreferences, dispatched via -# mobile.rs. [target.'cfg(target_os = "macos")'.dependencies] -keyring = { version = "3", default-features = false, features = ["apple-native"] } +apple-native-keyring-store = { version = "1", features = ["keychain"] } [target.'cfg(target_os = "windows")'.dependencies] -keyring = { version = "3", default-features = false, features = ["windows-native"] } +windows-native-keyring-store = "1" [target.'cfg(target_os = "linux")'.dependencies] -keyring = { version = "3", default-features = false, features = ["sync-secret-service"] } +# `vendored` statically links libdbus + openssl so we don't depend on +# the host distribution's versions, mirroring the previous +# `sync-secret-service` feature on keyring v3. +dbus-secret-service-keyring-store = { version = "1", features = ["crypto-rust", "vendored"] } diff --git a/apps/readest-app/src-tauri/plugins/tauri-plugin-native-bridge/src/desktop.rs b/apps/readest-app/src-tauri/plugins/tauri-plugin-native-bridge/src/desktop.rs index 3a6627b9..cb4f4461 100644 --- a/apps/readest-app/src-tauri/plugins/tauri-plugin-native-bridge/src/desktop.rs +++ b/apps/readest-app/src-tauri/plugins/tauri-plugin-native-bridge/src/desktop.rs @@ -8,9 +8,42 @@ pub fn init( app: &AppHandle, _api: PluginApi, ) -> crate::Result> { + // keyring v4 split the library into `keyring-core` plus a + // per-platform credential-store crate. The default store is a + // process-wide global that must be installed before the first + // `Entry::new` call. `set_default_store` is idempotent — calling + // it again on plugin re-init just replaces the previous handle. + // We log and swallow errors so a misconfigured keychain doesn't + // block plugin init; downstream calls then fail with NoDefaultStore + // and the TS layer falls back to the ephemeral store. + install_default_keyring_store(); Ok(NativeBridge(app.clone())) } +#[cfg(target_os = "macos")] +fn install_default_keyring_store() { + match apple_native_keyring_store::keychain::Store::new() { + Ok(store) => keyring_core::set_default_store(store), + Err(err) => eprintln!("[native-bridge] keychain store init failed: {err}"), + } +} + +#[cfg(target_os = "windows")] +fn install_default_keyring_store() { + match windows_native_keyring_store::Store::new() { + Ok(store) => keyring_core::set_default_store(store), + Err(err) => eprintln!("[native-bridge] credential manager init failed: {err}"), + } +} + +#[cfg(target_os = "linux")] +fn install_default_keyring_store() { + match dbus_secret_service_keyring_store::Store::new() { + Ok(store) => keyring_core::set_default_store(store), + Err(err) => eprintln!("[native-bridge] secret service init failed: {err}"), + } +} + /// Access to the native-bridge APIs. pub struct NativeBridge(AppHandle); @@ -149,10 +182,11 @@ impl NativeBridge { // ── Sync passphrase keychain ──────────────────────────────────────── // - // Uses the `keyring` crate, which transparently maps to: - // * macOS → Security framework Keychain - // * Windows → Credential Manager - // * Linux → Secret Service (libsecret-compatible) + // Uses `keyring-core` v1 with a platform-specific credential store + // installed in `init()` above: + // * macOS → Security framework Keychain (apple-native-keyring-store) + // * Windows → Credential Manager (windows-native-keyring-store) + // * Linux → Secret Service (dbus-secret-service-keyring-store) // // `service` and `user` form the keychain item identity. Service is // the bundle id; user is a stable string ("default") so multiple @@ -181,7 +215,7 @@ impl NativeBridge { passphrase: Some(passphrase), error: None, }), - Err(keyring::Error::NoEntry) => Ok(GetSyncPassphraseResponse { + Err(keyring_core::Error::NoEntry) => Ok(GetSyncPassphraseResponse { passphrase: None, error: None, }), @@ -194,7 +228,7 @@ impl NativeBridge { pub fn clear_sync_passphrase(&self) -> crate::Result { match keyring_entry().and_then(|e| e.delete_credential()) { - Ok(()) | Err(keyring::Error::NoEntry) => Ok(SyncPassphraseResponse { + Ok(()) | Err(keyring_core::Error::NoEntry) => Ok(SyncPassphraseResponse { success: true, error: None, }), @@ -222,9 +256,9 @@ impl NativeBridge { } } -const KEYRING_SERVICE: &str = "com.bilingify.readest.sync-passphrase"; +const KEYRING_SERVICE: &str = "Readest Safe Storage"; const KEYRING_USER: &str = "default"; -fn keyring_entry() -> std::result::Result { - keyring::Entry::new(KEYRING_SERVICE, KEYRING_USER) +fn keyring_entry() -> std::result::Result { + keyring_core::Entry::new(KEYRING_SERVICE, KEYRING_USER) } diff --git a/apps/readest-app/src/__tests__/services/sync/replicaPublish.test.ts b/apps/readest-app/src/__tests__/services/sync/replicaPublish.test.ts index 9b5ce676..59118411 100644 --- a/apps/readest-app/src/__tests__/services/sync/replicaPublish.test.ts +++ b/apps/readest-app/src/__tests__/services/sync/replicaPublish.test.ts @@ -8,6 +8,20 @@ vi.mock('@/services/sync/replicaSync', () => ({ getReplicaSync: vi.fn(), })); +const cryptoMocks = vi.hoisted(() => ({ + isUnlocked: vi.fn(() => true), + encryptField: vi.fn(async (v: string) => ({ v, kdf: 'mock' })), +})); + +vi.mock('@/libs/crypto/session', () => ({ + cryptoSession: { + isUnlocked: () => cryptoMocks.isUnlocked(), + encryptField: (v: string) => cryptoMocks.encryptField(v), + decryptField: vi.fn(), + forget: vi.fn(), + }, +})); + import { getUserID } from '@/utils/access'; import { getReplicaSync } from '@/services/sync/replicaSync'; import { @@ -316,6 +330,109 @@ describe('publishReplica* sync category gate', () => { }); }); +describe('publishReplicaUpsert credentials gate', () => { + // The 'credentials' meta-toggle defaults OFF. When OFF, the publish + // pipeline must drop adapter.encryptedFields from the packed row so + // sensitive fields (OPDS username/password, kosync credentials, + // readwise/hardcover tokens) never leave the device. Plaintext fields + // (catalog name/url, etc.) still ship — the row itself isn't gated, + // only its encrypted slots. + const setCredentialsCategory = async (enabled: boolean | undefined): Promise => { + const { useSettingsStore } = await import('@/store/settingsStore'); + const map = enabled === undefined ? {} : { credentials: enabled }; + useSettingsStore.setState({ + settings: { syncCategories: map } as never, + } as never); + }; + + const restoreSettings = async (): Promise => { + const { useSettingsStore } = await import('@/store/settingsStore'); + useSettingsStore.setState({ settings: undefined } as never); + }; + + afterEach(async () => { + await restoreSettings(); + cryptoMocks.isUnlocked.mockReset(); + cryptoMocks.isUnlocked.mockReturnValue(true); + cryptoMocks.encryptField.mockReset(); + cryptoMocks.encryptField.mockImplementation(async (v: string) => ({ v, kdf: 'mock' })); + }); + + test('drops encryptedFields from the packed row when credentials sync is OFF (default)', async () => { + // No syncCategories map at all → credentials defaults OFF. + await setCredentialsCategory(undefined); + const { opdsCatalogAdapter } = await import('@/services/sync/adapters/opdsCatalog'); + registerReplicaAdapter(opdsCatalogAdapter); + const ctx = makeFakeCtx(); + (getReplicaSync as ReturnType).mockReturnValue(ctx); + (getUserID as ReturnType).mockResolvedValue('user-1'); + + await publishReplicaUpsert( + 'opds_catalog', + { + id: 'cat-1', + name: 'Project Gutenberg', + url: 'https://example.com/opds', + username: 'alice', + password: 'hunter2', + }, + 'cat-content-id', + ); + + expect(ctx.manager.markDirty).toHaveBeenCalledOnce(); + const row = ctx.manager.markDirty.mock.calls[0]![0] as ReplicaRow; + // Plaintext metadata still ships + expect(row.fields_jsonb['name']?.v).toBe('Project Gutenberg'); + expect(row.fields_jsonb['url']?.v).toBe('https://example.com/opds'); + // Encrypted fields are dropped entirely (no plaintext leak, no cipher attempt) + expect(row.fields_jsonb['username']).toBeUndefined(); + expect(row.fields_jsonb['password']).toBeUndefined(); + // Crypto session was never invoked — credentials OFF short-circuited + // the field set before the middleware could even check unlock state. + expect(cryptoMocks.encryptField).not.toHaveBeenCalled(); + }); + + test('drops encryptedFields when credentials sync is explicitly disabled', async () => { + await setCredentialsCategory(false); + const { opdsCatalogAdapter } = await import('@/services/sync/adapters/opdsCatalog'); + registerReplicaAdapter(opdsCatalogAdapter); + const ctx = makeFakeCtx(); + (getReplicaSync as ReturnType).mockReturnValue(ctx); + (getUserID as ReturnType).mockResolvedValue('user-1'); + + await publishReplicaUpsert( + 'opds_catalog', + { id: 'cat-1', name: 'PG', url: 'u', username: 'alice', password: 'pw' }, + 'cat-content-id', + ); + + const row = ctx.manager.markDirty.mock.calls[0]![0] as ReplicaRow; + expect(row.fields_jsonb['username']).toBeUndefined(); + expect(row.fields_jsonb['password']).toBeUndefined(); + }); + + test('encrypts the fields normally when credentials sync is ON', async () => { + await setCredentialsCategory(true); + const { opdsCatalogAdapter } = await import('@/services/sync/adapters/opdsCatalog'); + registerReplicaAdapter(opdsCatalogAdapter); + const ctx = makeFakeCtx(); + (getReplicaSync as ReturnType).mockReturnValue(ctx); + (getUserID as ReturnType).mockResolvedValue('user-1'); + + await publishReplicaUpsert( + 'opds_catalog', + { id: 'cat-1', name: 'PG', url: 'u', username: 'alice', password: 'pw' }, + 'cat-content-id', + ); + + const row = ctx.manager.markDirty.mock.calls[0]![0] as ReplicaRow; + // Encrypted slots present (cipher envelope shape from our mock) + expect(row.fields_jsonb['username']?.v).toEqual({ v: 'alice', kdf: 'mock' }); + expect(row.fields_jsonb['password']?.v).toEqual({ v: 'pw', kdf: 'mock' }); + expect(cryptoMocks.encryptField).toHaveBeenCalledTimes(2); + }); +}); + // Suppress unused import lint when running standalone void hlcPack; void ({} as Hlc); diff --git a/apps/readest-app/src/__tests__/services/sync/replicaPullAndApply.test.ts b/apps/readest-app/src/__tests__/services/sync/replicaPullAndApply.test.ts index 009fbf24..cd69e5af 100644 --- a/apps/readest-app/src/__tests__/services/sync/replicaPullAndApply.test.ts +++ b/apps/readest-app/src/__tests__/services/sync/replicaPullAndApply.test.ts @@ -1,9 +1,34 @@ import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'; + +const cryptoMocks = vi.hoisted(() => ({ + isUnlocked: vi.fn(() => false), + decryptField: vi.fn(), +})); +vi.mock('@/libs/crypto/session', () => ({ + cryptoSession: { + isUnlocked: () => cryptoMocks.isUnlocked(), + decryptField: (...args: unknown[]) => cryptoMocks.decryptField(...args), + encryptField: vi.fn(), + forget: vi.fn(), + }, +})); + +const passphraseMocks = vi.hoisted(() => ({ + ensure: vi.fn(async () => {}), +})); +vi.mock('@/services/sync/passphraseGate', () => ({ + ensurePassphraseUnlocked: () => passphraseMocks.ensure(), +})); + import { replicaPullAndApply, type PullAndApplyDeps } from '@/services/sync/replicaPullAndApply'; import { dictionaryAdapter } from '@/services/sync/adapters/dictionary'; +import { opdsCatalogAdapter } from '@/services/sync/adapters/opdsCatalog'; import { hlcPack } from '@/libs/crdt'; -import type { Hlc, Manifest, ReplicaRow } from '@/types/replica'; +import type { CipherEnvelope, Hlc, Manifest, ReplicaRow } from '@/types/replica'; import type { ImportedDictionary } from '@/services/dictionaries/types'; +import type { OPDSCatalog } from '@/types/opds'; +import { useSettingsStore } from '@/store/settingsStore'; +import type { SystemSettings } from '@/types/settings'; const NOW = 1_700_000_000_000; const DEV = 'dev-a'; @@ -389,3 +414,127 @@ describe('replicaPullAndApply (dictionary adapter)', () => { expect(deps.applyRemote).toHaveBeenCalledOnce(); }); }); + +describe('replicaPullAndApply credentials category gate (opds adapter)', () => { + const cipher: CipherEnvelope = { + c: 'CIPHERTEXT', + i: 'IV', + s: 'SALTID', + alg: 'AES-GCM', + h: 'INTEGRITY', + }; + + const setCredentialsCategory = (enabled: boolean | undefined): void => { + const map = enabled === undefined ? {} : { credentials: enabled }; + useSettingsStore.setState({ + settings: { syncCategories: map } as never, + } as never); + }; + + const opdsRow = (): ReplicaRow => ({ + user_id: 'u1', + kind: 'opds_catalog', + replica_id: 'opds-content-1', + fields_jsonb: { + name: { v: 'Project Gutenberg', t: hlcPack(NOW, 0, DEV) as Hlc, s: DEV }, + url: { v: 'https://example.com/opds', t: hlcPack(NOW, 1, DEV) as Hlc, s: DEV }, + // Cipher envelopes wrapped in CRDT field envelopes — same shape + // the publish path emits when credentials sync is on. + username: { v: cipher, t: hlcPack(NOW, 2, DEV) as Hlc, s: DEV }, + password: { v: cipher, t: hlcPack(NOW, 3, DEV) as Hlc, s: DEV }, + }, + manifest_jsonb: null, + deleted_at_ts: null, + reincarnation: null, + updated_at_ts: hlcPack(NOW, 3, DEV) as Hlc, + schema_version: 1, + }); + + const makeOpdsDeps = (): PullAndApplyDeps => { + const findByContentId = vi.fn((_id: string): OPDSCatalog | undefined => undefined); + return { + adapter: opdsCatalogAdapter, + pull: vi.fn(async () => [] as ReplicaRow[]), + findByContentId, + applyRemote: vi.fn<(record: OPDSCatalog) => void>(), + softDeleteByContentId: vi.fn(), + // Metadata-only kind — these are required by the type but unused here. + createBundleDir: vi.fn(async () => ''), + queueReplicaDownload: vi.fn(() => null), + filesExist: vi.fn(async () => true), + } satisfies PullAndApplyDeps; + }; + + beforeEach(() => { + cryptoMocks.isUnlocked.mockReset(); + cryptoMocks.isUnlocked.mockReturnValue(false); + cryptoMocks.decryptField.mockReset(); + passphraseMocks.ensure.mockReset(); + passphraseMocks.ensure.mockResolvedValue(undefined); + }); + + afterEach(() => { + useSettingsStore.setState({ settings: undefined as unknown as SystemSettings } as never); + }); + + test('strips cipher fields and never prompts when credentials sync is OFF (default)', async () => { + setCredentialsCategory(undefined); // default OFF + const deps = makeOpdsDeps(); + (deps.pull as ReturnType).mockResolvedValue([opdsRow()]); + + await replicaPullAndApply(deps); + + // Plaintext metadata applied — the row itself isn't gated. + expect(deps.applyRemote).toHaveBeenCalledOnce(); + const applied = (deps.applyRemote as ReturnType).mock.calls[0]![0] as OPDSCatalog; + expect(applied.name).toBe('Project Gutenberg'); + expect(applied.url).toBe('https://example.com/opds'); + // Cipher payloads were stripped before unpack — no plaintext, no + // ciphertext bleeds through to the local store. + expect(applied.username).toBeUndefined(); + expect(applied.password).toBeUndefined(); + + // Passphrase gate was NEVER prompted — there were no cipher fields + // left to decrypt by the time captureCipherTexts ran. + expect(passphraseMocks.ensure).not.toHaveBeenCalled(); + // Decrypt was NEVER attempted — credentials gate short-circuited + // before the middleware ran. + expect(cryptoMocks.decryptField).not.toHaveBeenCalled(); + }); + + test('strips cipher fields when credentials sync is explicitly OFF', async () => { + setCredentialsCategory(false); + const deps = makeOpdsDeps(); + (deps.pull as ReturnType).mockResolvedValue([opdsRow()]); + + await replicaPullAndApply(deps); + + const applied = (deps.applyRemote as ReturnType).mock.calls[0]![0] as OPDSCatalog; + expect(applied.username).toBeUndefined(); + expect(applied.password).toBeUndefined(); + expect(passphraseMocks.ensure).not.toHaveBeenCalled(); + }); + + test('prompts and decrypts as before when credentials sync is ON', async () => { + setCredentialsCategory(true); + cryptoMocks.isUnlocked.mockReturnValue(false); + // Simulate the gate flipping to unlocked after prompt. + passphraseMocks.ensure.mockImplementation(async () => { + cryptoMocks.isUnlocked.mockReturnValue(true); + }); + cryptoMocks.decryptField.mockImplementation(async (env: unknown) => { + // Pretend the username decrypts to 'alice' and the password to 'pw'. + const c = (env as CipherEnvelope).c; + return c === 'CIPHERTEXT' ? 'plain' : 'plain'; + }); + + const deps = makeOpdsDeps(); + (deps.pull as ReturnType).mockResolvedValue([opdsRow()]); + + await replicaPullAndApply(deps); + + // Gate prompted (cipher present + locked + cipher fingerprint not seen). + expect(passphraseMocks.ensure).toHaveBeenCalledTimes(1); + expect(cryptoMocks.decryptField).toHaveBeenCalledTimes(2); + }); +}); diff --git a/apps/readest-app/src/__tests__/services/sync/replicaSettingsSync.test.ts b/apps/readest-app/src/__tests__/services/sync/replicaSettingsSync.test.ts index 5ab4911d..5ffe072a 100644 --- a/apps/readest-app/src/__tests__/services/sync/replicaSettingsSync.test.ts +++ b/apps/readest-app/src/__tests__/services/sync/replicaSettingsSync.test.ts @@ -49,6 +49,19 @@ const makeSettings = (overrides: Partial = {}): SystemSettings = const makeEnvConfig = (): EnvConfigType => ({ getAppService: vi.fn() }) as unknown as EnvConfigType; +/** + * Opt the current test into credential sync. Most tests in this file + * exercise the encryption path (gate prompts, hash storage, etc.) which + * is gated by the 'credentials' meta-toggle — and that toggle defaults + * OFF. Call this before driving an encrypted-credential scenario. + */ +const enableCredentialsSync = (): void => { + const current = useSettingsStore.getState().settings; + useSettingsStore.setState({ + settings: { ...current, syncCategories: { credentials: true } } as never, + } as never); +}; + beforeEach(() => { publishMock.mockReset(); ensurePassphraseMock.mockReset(); @@ -202,6 +215,7 @@ describe('publishSettingsIfChanged', () => { }); test('triggers the passphrase gate when an encrypted field gets meaningful content while locked', async () => { + enableCredentialsSync(); isUnlocked = false; await publishSettingsIfChanged( makeSettings({ @@ -217,6 +231,113 @@ describe('publishSettingsIfChanged', () => { expect(publishMock).toHaveBeenCalledTimes(1); }); + describe('credentials category gate', () => { + // The 'credentials' meta-toggle defaults OFF. When OFF, the settings + // publisher must skip every ENCRYPTED_PATH (kosync.username/userkey/ + // password, readwise.accessToken, hardcover.accessToken) entirely: + // no patch entry, no proactive passphrase prompt, no stored hash. + // Non-credential plaintext settings still publish normally. + const setCredentials = async (enabled: boolean | undefined): Promise => { + const { useSettingsStore } = await import('@/store/settingsStore'); + const map = enabled === undefined ? {} : { credentials: enabled }; + const current = useSettingsStore.getState().settings; + useSettingsStore.setState({ + settings: { ...current, syncCategories: map } as never, + } as never); + }; + + test('does NOT trigger the passphrase gate when credentials sync is OFF and a kosync password is set', async () => { + await setCredentials(undefined); // default OFF + isUnlocked = false; + await publishSettingsIfChanged( + makeSettings({ + kosync: { + serverUrl: 'https://kosync.example', + username: 'alice', + userkey: 'secret-key', + password: 'hunter2', + } as SystemSettings['kosync'], + }), + ); + expect(ensurePassphraseMock).not.toHaveBeenCalled(); + }); + + test('omits all credential paths from the patch when credentials sync is OFF', async () => { + await setCredentials(undefined); + isUnlocked = false; + await publishSettingsIfChanged( + makeSettings({ + kosync: { + serverUrl: 'https://kosync.example', + username: 'alice', + userkey: 'secret-key', + password: 'hunter2', + } as SystemSettings['kosync'], + readwise: { + accessToken: 'rw-token', + enabled: true, + lastSyncedAt: 0, + } as SystemSettings['readwise'], + hardcover: { + accessToken: 'hc-token', + enabled: true, + lastSyncedAt: 0, + } as SystemSettings['hardcover'], + }), + ); + // Plaintext kosync.serverUrl still publishes — only the credential + // sub-fields are gated. + expect(publishMock).toHaveBeenCalledTimes(1); + const patch = publishMock.mock.calls[0]![1].patch as Partial; + expect(patch.kosync?.serverUrl).toBe('https://kosync.example'); + expect(patch.kosync?.username).toBeUndefined(); + expect(patch.kosync?.userkey).toBeUndefined(); + expect(patch.kosync?.password).toBeUndefined(); + expect(patch.readwise?.accessToken).toBeUndefined(); + expect(patch.hardcover?.accessToken).toBeUndefined(); + }); + + test('publishes credential paths normally when credentials sync is ON', async () => { + await setCredentials(true); + isUnlocked = true; + await publishSettingsIfChanged( + makeSettings({ + kosync: { + serverUrl: '', + username: '', + userkey: '', + password: 'hunter2', + } as SystemSettings['kosync'], + }), + ); + expect(publishMock).toHaveBeenCalledTimes(1); + const patch = publishMock.mock.calls[0]![1].patch as Partial; + expect(patch.kosync?.password).toBe('hunter2'); + }); + + test('skipping all of the only-credential changes is a clean no-op (no empty publish)', async () => { + await setCredentials(undefined); + isUnlocked = false; + // Prime the snapshot so the first publish drains everything. + await publishSettingsIfChanged(makeSettings()); + publishMock.mockReset(); + ensurePassphraseMock.mockReset(); + // Only encrypted-credential fields change; nothing plaintext does. + await publishSettingsIfChanged( + makeSettings({ + readwise: { + accessToken: 'rw-token', + enabled: true, + lastSyncedAt: 0, + } as SystemSettings['readwise'], + }), + ); + // No publish at all — credentials gate dropped the only diff. + expect(publishMock).not.toHaveBeenCalled(); + expect(ensurePassphraseMock).not.toHaveBeenCalled(); + }); + }); + test('empty encrypted credential is dropped from publish entirely (no gate, no patch)', async () => { isUnlocked = false; // makeSettings has all kosync credentials as ''. Plaintext changes @@ -304,6 +425,7 @@ describe('publishSettingsIfChanged', () => { }); test('user cancels the gate prompt → encrypted hash NOT stored, next save retries', async () => { + enableCredentialsSync(); isUnlocked = false; ensurePassphraseMock.mockImplementationOnce(async () => { throw new Error('user cancelled'); @@ -340,6 +462,7 @@ describe('publishSettingsIfChanged', () => { }); test('encrypted-field publish while unlocked records the value (no retry next save)', async () => { + enableCredentialsSync(); isUnlocked = true; await publishSettingsIfChanged( makeSettings({ diff --git a/apps/readest-app/src/__tests__/services/sync/syncCategories.test.ts b/apps/readest-app/src/__tests__/services/sync/syncCategories.test.ts index 38421319..5d2c5d36 100644 --- a/apps/readest-app/src/__tests__/services/sync/syncCategories.test.ts +++ b/apps/readest-app/src/__tests__/services/sync/syncCategories.test.ts @@ -2,6 +2,7 @@ import { afterEach, beforeEach, describe, expect, test } from 'vitest'; import { SYNC_CATEGORIES, + isCredentialsSyncEnabled, isSyncCategoryEnabled, isSyncCategoryLocked, } from '@/services/sync/syncCategories'; @@ -104,6 +105,40 @@ describe('isSyncCategoryEnabled', () => { }); }); + describe('credentials category', () => { + test('defaults to OFF when settings are not loaded', () => { + // Unique among categories: credentials must be opt-in, so the + // default for an absent map / missing key is false rather than the + // global "missing key → on" default. + expect(isSyncCategoryEnabled('credentials')).toBe(false); + expect(isCredentialsSyncEnabled()).toBe(false); + }); + + test('defaults to OFF when syncCategories map is missing', () => { + setSettings({}); + expect(isSyncCategoryEnabled('credentials')).toBe(false); + expect(isCredentialsSyncEnabled()).toBe(false); + }); + + test('defaults to OFF when explicitly absent from a populated map', () => { + setSettings({ syncCategories: { book: true, settings: true } }); + expect(isSyncCategoryEnabled('credentials')).toBe(false); + expect(isCredentialsSyncEnabled()).toBe(false); + }); + + test('returns true only when explicitly opted in', () => { + setSettings({ syncCategories: { credentials: true } }); + expect(isSyncCategoryEnabled('credentials')).toBe(true); + expect(isCredentialsSyncEnabled()).toBe(true); + }); + + test('returns false when explicitly false', () => { + setSettings({ syncCategories: { credentials: false } }); + expect(isSyncCategoryEnabled('credentials')).toBe(false); + expect(isCredentialsSyncEnabled()).toBe(false); + }); + }); + test('legacy SyncType ids map to categories (configs → progress, books → book, notes → note)', () => { setSettings({ syncCategories: { progress: false, book: false, note: false } }); expect(isSyncCategoryEnabled('configs')).toBe(false); @@ -114,10 +149,11 @@ describe('isSyncCategoryEnabled', () => { }); describe('SYNC_CATEGORIES', () => { - test('covers all eight user-facing categories (incl. settings)', () => { + test('covers all nine user-facing categories (incl. settings + credentials)', () => { expect([...SYNC_CATEGORIES].sort()).toEqual( [ 'book', + 'credentials', 'dictionary', 'font', 'note', @@ -128,4 +164,8 @@ describe('SYNC_CATEGORIES', () => { ].sort(), ); }); + + test('credentials is the last item (rendered as the last toggle in Manage Sync)', () => { + expect(SYNC_CATEGORIES[SYNC_CATEGORIES.length - 1]).toBe('credentials'); + }); }); diff --git a/apps/readest-app/src/app/user/components/SyncCategoriesSection.tsx b/apps/readest-app/src/app/user/components/SyncCategoriesSection.tsx index bdb2b71d..c40c426c 100644 --- a/apps/readest-app/src/app/user/components/SyncCategoriesSection.tsx +++ b/apps/readest-app/src/app/user/components/SyncCategoriesSection.tsx @@ -53,6 +53,12 @@ const useCategoryCopy = (): Record => { 'Theme, highlight colours, integrations (KOSync, Readwise, Hardcover), and dictionary order', ), }, + credentials: { + title: _('Credentials'), + description: _( + 'Tokens, usernames, and passwords for OPDS, KOReader, Hardcover, and Readwise. When disabled, credentials remain on this device only and are never uploaded.', + ), + }, }; }; @@ -64,8 +70,14 @@ export function SyncCategoriesSection() { if (!settings) return null; - const enabled = (category: SyncCategory): boolean => - settings.syncCategories?.[category] !== false; + const enabled = (category: SyncCategory): boolean => { + const value = settings.syncCategories?.[category]; + // 'credentials' is the only category that defaults OFF — sync of + // sensitive fields (OPDS / KOSync / Readwise / Hardcover tokens) is + // explicit opt-in. Every other category defaults ON when unset. + if (category === 'credentials') return value === true; + return value !== false; + }; const handleToggle = (category: SyncCategory, next: boolean) => { const updated: SystemSettings = { diff --git a/apps/readest-app/src/app/user/components/SyncPassphraseSection.tsx b/apps/readest-app/src/app/user/components/SyncPassphraseSection.tsx index ed7c94dd..ff959d9b 100644 --- a/apps/readest-app/src/app/user/components/SyncPassphraseSection.tsx +++ b/apps/readest-app/src/app/user/components/SyncPassphraseSection.tsx @@ -6,6 +6,7 @@ import { cryptoSession } from '@/libs/crypto/session'; import { ensurePassphraseUnlocked } from '@/services/sync/passphraseGate'; import { replicaSyncClient } from '@/libs/replicaSyncClient'; import { isSyncError } from '@/libs/errors'; +import { useSettingsStore } from '@/store/settingsStore'; type SyncPassphraseStatus = 'loading' | 'unset' | 'set' | 'error'; @@ -13,6 +14,14 @@ const isAuthError = (err: unknown): boolean => isSyncError(err) && err.code === export function SyncPassphraseSection() { const _ = useTranslation(); + // Tied to the 'credentials' Manage Sync toggle. When credentials sync + // is off (the default), the passphrase machinery has no purpose — the + // user has explicitly opted out of sending sensitive fields, so set/ + // forget controls just confuse. Subscribing means the panel pops in / + // out reactively when the toggle flips. + const credentialsSync = useSettingsStore( + (state) => state.settings?.syncCategories?.credentials === true, + ); const [status, setStatus] = useState('loading'); const [busy, setBusy] = useState(false); const [message, setMessage] = useState(null); @@ -33,9 +42,13 @@ export function SyncPassphraseSection() { }; useEffect(() => { + if (!credentialsSync) return; void refreshStatus(); - }, []); + }, [credentialsSync]); + // Credentials sync off → no passphrase UI at all (set / forget / + // status indicator are all hidden). + if (!credentialsSync) return null; if (status === 'loading') return null; // First-time setup: when the user has no replica_keys row yet, the @@ -86,9 +99,9 @@ export function SyncPassphraseSection() {

{status === 'unset' ? _( - 'Encrypts sensitive synced fields (like OPDS catalog credentials) before they leave your device. Set one now or wait — it will be requested when needed.', + 'Sensitive synced fields are encrypted before upload. Set a passphrase now or later when encryption is needed.', ) - : _('Set on this account. Will be requested when needed to decrypt synced credentials.')} + : _('Saved to this account. You will be prompted for it when decrypting credentials.')}

{message &&

{message}

}
diff --git a/apps/readest-app/src/services/sync/replicaPublish.ts b/apps/readest-app/src/services/sync/replicaPublish.ts index f4435017..69d3dca0 100644 --- a/apps/readest-app/src/services/sync/replicaPublish.ts +++ b/apps/readest-app/src/services/sync/replicaPublish.ts @@ -3,7 +3,7 @@ import { getUserID } from '@/utils/access'; import { getReplicaAdapter } from './replicaRegistry'; import { getReplicaSync } from './replicaSync'; import { encryptPackedFields } from './replicaCryptoMiddleware'; -import { isSyncCategoryEnabled } from './syncCategories'; +import { isCredentialsSyncEnabled, isSyncCategoryEnabled } from './syncCategories'; import type { FieldsObject, Hlc, ReplicaRow } from '@/types/replica'; /** @@ -32,7 +32,22 @@ export const publishReplicaUpsert = async ( if (!userId) return; const packed = adapter.pack(record); - // Encrypts the named encryptedFields in place. Locked session → + // Credentials meta-toggle (default OFF): when the user hasn't opted + // into syncing sensitive fields, drop adapter.encryptedFields from + // the packed object before the crypto middleware ever sees them. No + // ciphertext is produced, no passphrase prompt fires, and nothing + // sensitive leaves the device. Plaintext metadata in the same row + // (catalog name/url, kosync.serverUrl, etc.) still ships. + if ( + adapter.encryptedFields && + adapter.encryptedFields.length > 0 && + !isCredentialsSyncEnabled() + ) { + for (const field of adapter.encryptedFields) { + delete packed[field]; + } + } + // Encrypts the remaining encryptedFields in place. Locked session → // those fields are dropped from the push (sync without creds). await encryptPackedFields(packed, adapter.encryptedFields); let fields: FieldsObject = {}; diff --git a/apps/readest-app/src/services/sync/replicaPullAndApply.ts b/apps/readest-app/src/services/sync/replicaPullAndApply.ts index e0a0e257..e877f8c7 100644 --- a/apps/readest-app/src/services/sync/replicaPullAndApply.ts +++ b/apps/readest-app/src/services/sync/replicaPullAndApply.ts @@ -10,6 +10,7 @@ import { decryptRowFields, } from './replicaCryptoMiddleware'; import { ensurePassphraseUnlocked } from './passphraseGate'; +import { isCredentialsSyncEnabled } from './syncCategories'; import { cryptoSession } from '@/libs/crypto/session'; export interface ReplicaLocalRecord { @@ -147,6 +148,18 @@ const applyRow = async ( // Cancel / failure leaves the field absent; the store's applyRemote // merge preserves any local plaintext copy. const encryptedFields = deps.adapter.encryptedFields; + // Credentials meta-toggle (default OFF): when the user hasn't opted + // in, every cipher payload in this row's encrypted slots gets stripped + // before we even capture the cipher fingerprint. The decrypt loop + // sees nothing, the prompt never fires, and the adapter unpacks + // without the credential fields. The store's applyRemote merge keeps + // any local plaintext copy intact (same code path as the locked- + // session case). + if (encryptedFields && encryptedFields.length > 0 && !isCredentialsSyncEnabled()) { + for (const field of encryptedFields) { + delete row.fields_jsonb[field]; + } + } const beforeDecrypt = captureCipherTexts(row.fields_jsonb, encryptedFields); const localLastSeen = local?.lastSeenCipher; diff --git a/apps/readest-app/src/services/sync/replicaSettingsSync.ts b/apps/readest-app/src/services/sync/replicaSettingsSync.ts index 9e9dd447..384e1d0d 100644 --- a/apps/readest-app/src/services/sync/replicaSettingsSync.ts +++ b/apps/readest-app/src/services/sync/replicaSettingsSync.ts @@ -38,6 +38,7 @@ import { } from '@/services/sync/adapters/settings'; import { cryptoSession } from '@/libs/crypto/session'; import { ensurePassphraseUnlocked } from '@/services/sync/passphraseGate'; +import { isCredentialsSyncEnabled } from '@/services/sync/syncCategories'; import { useCustomDictionaryStore } from '@/store/customDictionaryStore'; const ENCRYPTED_PATHS: ReadonlySet = new Set(SETTINGS_ENCRYPTED_FIELDS); @@ -205,11 +206,20 @@ export const publishSettingsIfChanged = async (settings: SystemSettings): Promis const encryptedChanged: Array<{ path: string; value: unknown; hash: string }> = []; let hasNewEncryptedContent = false; + // Credentials meta-toggle (default OFF). When the user hasn't opted + // in, every ENCRYPTED_PATH is short-circuited here so the diff loop + // never produces an entry for it, the proactive passphrase gate is + // never triggered, and stored encrypted-hashes stay untouched. The + // belt-and-braces filter in `publishReplicaUpsert` would still drop + // the field at the wire, but doing it here also avoids the prompt. + const credentialsSync = isCredentialsSyncEnabled(); + for (const path of SETTINGS_WHITELIST) { const current = readPath(settings, path); if (current === undefined) continue; if (ENCRYPTED_PATHS.has(path)) { + if (!credentialsSync) continue; // Skip empty / cleared credentials entirely — there's nothing // useful to encrypt and pushing a plaintext "" would make the // server-side schema mix cipher envelopes with bare empty diff --git a/apps/readest-app/src/services/sync/syncCategories.ts b/apps/readest-app/src/services/sync/syncCategories.ts index fc7dcdc1..5e6da637 100644 --- a/apps/readest-app/src/services/sync/syncCategories.ts +++ b/apps/readest-app/src/services/sync/syncCategories.ts @@ -13,6 +13,11 @@ * * Defaults to enabled when unset so users who never visit the panel * keep the cross-device behaviour they had before this shipped. + * Exception: `credentials` defaults to OFF — it's a meta-toggle that + * controls whether sensitive fields (OPDS / KOSync / Readwise / Hardcover + * usernames, passwords, tokens) ever leave the device. Sync of those + * fields is opt-in; users who never touch the panel keep their + * credentials local-only. See `DEFAULT_OFF_CATEGORIES`. * * Dependencies: some categories are required by others. Disabling the * dependency would silently break the dependent feature, so the @@ -38,6 +43,21 @@ const CATEGORY_DEPENDENTS: Partial dictionary: ['settings'], }; +/** + * Categories whose default (when the user hasn't visited the panel and + * `syncCategories[category]` is absent) is OFF rather than the global + * "missing key → on" default. + * + * `credentials` is the only such category today: it gates the + * encrypted-credential fields (OPDS username/password, kosync.username + * / .userkey / .password, readwise.accessToken, hardcover.accessToken) + * across the OPDS-catalog and bundled-settings replicas. Sync of those + * fields is opt-in by deliberate policy — users who never visit the + * panel keep their credentials local-only and never see the + * sync-passphrase dialog. + */ +const DEFAULT_OFF_CATEGORIES: ReadonlySet = new Set(['credentials']); + /** * Map a callsite identifier (replica kind, legacy SyncType, etc.) to * the corresponding category. Returns null for identifiers that aren't @@ -57,8 +77,11 @@ const toCategory = (id: string): SyncCategory | null => { const isCategoryRawEnabled = (category: SyncCategory): boolean => { const settings = useSettingsStore.getState().settings; - if (!settings) return true; - return settings.syncCategories?.[category] !== false; + const defaultOn = !DEFAULT_OFF_CATEGORIES.has(category); + if (!settings) return defaultOn; + const value = settings.syncCategories?.[category]; + if (value === undefined) return defaultOn; + return value !== false; }; /** @@ -84,3 +107,17 @@ export const isSyncCategoryEnabled = (id: string): boolean => { if (isSyncCategoryLocked(category)) return true; // forced by a dependent return isCategoryRawEnabled(category); }; + +/** + * Whether the user has opted into syncing sensitive credential fields + * (OPDS username/password, KOSync username/userkey/password, Readwise + * and Hardcover access tokens). Defaults to false: sync of these + * fields is explicit opt-in. + * + * Push pipelines drop the encrypted fields from the wire when this + * returns false; pull pipelines strip incoming cipher payloads before + * they hit any adapter unpack so the local plaintext copy is preserved + * and the passphrase prompt never fires. The Sync passphrase UI is + * hidden in this state. + */ +export const isCredentialsSyncEnabled = (): boolean => isCategoryRawEnabled('credentials'); diff --git a/apps/readest-app/src/types/settings.ts b/apps/readest-app/src/types/settings.ts index 036bc347..e5874fb7 100644 --- a/apps/readest-app/src/types/settings.ts +++ b/apps/readest-app/src/types/settings.ts @@ -83,7 +83,10 @@ export interface HardcoverSettings { * User-facing sync categories. 'progress' gates the existing book-config * (reading progress) sync, 'note' gates annotations, 'book' gates book * binaries + metadata, 'dictionary' gates the imported-dictionary replica - * sync. Adding a new replica kind extends this union. + * sync. 'credentials' is a meta-toggle that gates the encrypted-credential + * fields (OPDS username/password, KOSync credentials, Readwise / Hardcover + * tokens) across whichever replica kinds carry them. Adding a new replica + * kind extends this union. */ export type SyncCategory = | 'book' @@ -93,7 +96,8 @@ export type SyncCategory = | 'font' | 'texture' | 'opds_catalog' - | 'settings'; + | 'settings' + | 'credentials'; export const SYNC_CATEGORIES: readonly SyncCategory[] = [ 'book', @@ -104,6 +108,7 @@ export const SYNC_CATEGORIES: readonly SyncCategory[] = [ 'texture', 'opds_catalog', 'settings', + 'credentials', ] as const; export interface SystemSettings {