Skip to main content
يمتلك Twenty عائلتين مستقلتين من المفاتيح:
  • مفاتيح توقيع JWT — أزواج مفاتيح غير متماثلة ES256 (مع علامة kid) مُخزَّنة في core."signingKey"، تُستخدم لتوقيع والتحقق من رموز الوصول / التحديث.
  • مفتاح التشفير أثناء السكون (At-rest encryption key)ENCRYPTION_KEY، يُستخدم لتشفير رموز OAuth، ومتغيرات التطبيق، ومفاتيح التوقيع الخاصة، وقيم الإعدادات الحساسة، وأسرار TOTP داخل غلاف enc:v2:.
يُعد APP_SECRET سراً قديماً مُحتفَظاً به لأغراض التوافق مع الإصدارات السابقة: عندما لا يكون ENCRYPTION_KEY مضبوطاً، فإنه يعمل كحل احتياطي لمفتاح التشفير أثناء السكون / ملفات تعريف الارتباط للجلسة، ولا يزال يتحقق من رموز الوصول HS256 الموجودة مسبقاً. سيتم إهماله (إيقاف دعمه).

مفاتيح توقيع JWT

يحمل كل مفتاح قيمة publicKey (يُحتفَظ بها إلى أجل غير مسمى حتى يمكنها التحقق من الرموز المصدرة مسبقاً)، وprivateKey مُشفَّراً (يُستخدم فقط أثناء كون المفتاح حالياً)، وراية isCurrent (صف واحد فقط في كل وقت)، وحقل revokedAt اختياري.

تدوير المفتاح الحالي

اضبط SIGNING_KEY_ROTATION_DAYS للتفعيل: عندها تصدر مهمة cron يومية مفتاحًا حاليًا جديدًا بمجرد أن يصبح المفتاح القائم أقدم من تلك العتبة. لا يتم إبطال المفاتيح السابقة، لذلك تستمر الرموز الموقعة تحتها في التحقق. اترك المتغير غير معيّن لتعطيل التدوير التلقائي.
ميزة التدوير التلقائي متوفّرة ابتداءً من الإصدار v2.6+.

إبطال مفتاح (في حالات التسريب / الطوارئ فقط)

Settings → Admin Panel → Signing keys → Revoke على صف غير حالي. تعمل على مسح المادة الخاصة المشفرة، وتعيين revokedAt، ورفض كل رمز حالي موقَّع تحت هذا الـ kid.

تدوير ENCRYPTION_KEY

أمر secret-encryption:rotate الموضَّح أدناه متوفر ابتداءً من الإصدار v2.6+.
يُغلَّف كل مقدار مُشفَّر بالشكل enc:v2:\<keyId>:\<payload>، حيث إن \<keyId> هو بادئة مكوَّنة من 8 أرقام ست عشرية مشتقة من المفتاح الخام. تتم عملية التدوير (الاستبدال) أثناء العمل، وقابلة للاستئناف.
  1. إنشاء مفتاح جديد: openssl rand -base64 32.
  2. ضَبْط المفتاحين معاً جنباً إلى جنب في ملف .env، ثم إعادة تشغيل الخدمة:
    ENCRYPTION_KEY=NEW_VALUE
    FALLBACK_ENCRYPTION_KEY=OLD_VALUE
    
    تستخدم عمليات الكتابة الجديدة المفتاح الجديد، بينما لا تزال الصفوف الحالية تُفك تشفيرها عبر المفتاح الاحتياطي (fallback).
  3. إعادة تشفير الصفوف الحالية:
    docker exec -it {server_container} yarn command:prod secret-encryption:rotate
    
    يتناول الأمر ستة مواقع (connected-account-tokens، application-variable، application-registration-variable، signing-key-private-keys، sensitive-config-storage، totp-secrets). يُهمِل عامل تصفية SQL الصفوف الموجودة بالفعل على \<keyId> الجديد، لذلك يكون الأمر عديم الأثر التكراري (idempotent): يمكنك مقاطعته وإعادة تشغيله حسب الحاجة. يخرج بقيمة مختلفة عن الصفر إذا فشل أي صف — أعد تشغيله لإعادة المحاولة.
    خيارالوصف
    -s, --site \<site>حصر التنفيذ على موقع واحد فقط.
    -b, --batch-size \<n>عدد الصفوف في كل دفعة (الافتراضي 200، والحد الأقصى 5000).
    -d, --dry-runفك التشفير + إعادة التشفير في الذاكرة، مع تخطي جملة UPDATE.
  4. إزالة المفتاح الاحتياطي (fallback) بمجرد أن يُظهِر الخيار --dry-run عدم وجود صفوف متبقية: أزِل FALLBACK_ENCRYPTION_KEY وأعد التشغيل.

دعم APP_SECRET القديم

تستخدم النُسخ الأقدم التي لم تُعيِّن ENCRYPTION_KEY مطلقاً المتغيِّر APP_SECRET كمفتاح التشفير أثناء السكون (وكسرّ ملف تعريف الارتباط الخاص بالجلسة، المشتقّ منه). يُحفَظ هذا المسار لأغراض التوافق مع الإصدارات السابقة ولكنه مهمل (موقوف الدعم) — عيِّن متغير ENCRYPTION_KEY مخصَّصاً واتبع إجراء التدوير الموضَّح أعلاه للانتقال بعيداً عنه. يبقى APP_SECRET نفسه قيد الاستخدام للتحقق من رموز الوصول HS256 القديمة.