1629217630132-encrypt_encoded_mfa_settings.ts 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. import { MigrationInterface, QueryRunner } from 'typeorm'
  2. import { CryptoNode } from '@standardnotes/sncrypto-node'
  3. export class encryptEncodedMfaSettings1629217630132 implements MigrationInterface {
  4. public async up(queryRunner: QueryRunner): Promise<void> {
  5. const encodedMFASettings = await queryRunner.manager.query(
  6. 'SELECT s.uuid as uuid, s.value as value, u.encrypted_server_key as encrypted_server_key FROM settings s LEFT JOIN users u ON u.uuid = s.user_uuid WHERE s.name = "MFA_SECRET" AND s.server_encryption_version = 0',
  7. )
  8. for (const encodedMFASetting of encodedMFASettings) {
  9. if (!encodedMFASetting['value']) {
  10. continue
  11. }
  12. const mfaSecret = this.getDecodedMFASecret(encodedMFASetting['value'])
  13. if (!mfaSecret) {
  14. continue
  15. }
  16. const encryptedMFASecret = await this.encryptMFASecret(mfaSecret, encodedMFASetting['encrypted_server_key'])
  17. await queryRunner.manager.query(
  18. `UPDATE settings s SET s.value = '${encryptedMFASecret}', s.server_encryption_version = 1 WHERE s.uuid="${encodedMFASetting['uuid']}"`,
  19. )
  20. }
  21. }
  22. public async down(): Promise<void> {
  23. return
  24. }
  25. private async encryptMFASecret(secret: string, userEncryptedServerKey: string): Promise<string> {
  26. const crypto = new CryptoNode()
  27. const userServerKey = JSON.parse(userEncryptedServerKey)
  28. const decryptedUserServerKey = await crypto.aes256GcmDecrypt(
  29. userServerKey.encrypted,
  30. process.env.ENCRYPTION_SERVER_KEY as string,
  31. )
  32. const iv = await crypto.generateRandomKey(128)
  33. const encrypted = await crypto.aes256GcmEncrypt({
  34. unencrypted: secret,
  35. iv,
  36. key: decryptedUserServerKey,
  37. })
  38. return JSON.stringify({ version: 1, encrypted })
  39. }
  40. private getDecodedMFASecret(encodedValue: string): string | undefined {
  41. const valueBuffer = Buffer.from(encodedValue.substring(3), 'base64')
  42. const decodedValue = valueBuffer.toString()
  43. const decodedMFASecretObject = JSON.parse(decodedValue)
  44. if ('secret' in decodedMFASecretObject && decodedMFASecretObject.secret) {
  45. return decodedMFASecretObject.secret
  46. }
  47. return undefined
  48. }
  49. }