Просмотр исходного кода

feat: create encryption and otp utils

Nicolas Meienberger 2 лет назад
Родитель
Сommit
96bb7e9a3d

+ 32 - 0
src/server/utils/__tests__/encryption.test.ts

@@ -0,0 +1,32 @@
+import { faker } from '@faker-js/faker';
+import { setConfig } from '../../core/TipiConfig';
+import { encrypt, decrypt } from '../encryption';
+
+describe('Test: encrypt', () => {
+  it('should encrypt the provided data', () => {
+    // arrange
+    setConfig('jwtSecret', faker.random.word());
+    const data = faker.random.word();
+    const salt = faker.random.word();
+
+    // act
+    const encryptedData = encrypt(data, salt);
+
+    // assert
+    expect(encryptedData).not.toEqual(data);
+  });
+
+  it('should decrypt the provided data', () => {
+    // arrange
+    setConfig('jwtSecret', faker.random.word());
+    const data = faker.random.word();
+    const salt = faker.random.word();
+
+    // act
+    const encryptedData = encrypt(data, salt);
+    const decryptedData = decrypt(encryptedData, salt);
+
+    // assert
+    expect(decryptedData).toEqual(data);
+  });
+});

+ 45 - 0
src/server/utils/encryption.ts

@@ -0,0 +1,45 @@
+import crypto from 'crypto';
+import { getConfig } from '../core/TipiConfig';
+
+const algorithm = 'aes-256-gcm';
+const keyLength = 32;
+
+/**
+ * Given a string, encrypts it using the provided salt
+ *
+ * @param {string} data - The data to encrypt
+ * @param {string} salt - The salt to use to encrypt the data
+ * @returns {string} - The encrypted data
+ */
+export const encrypt = (data: string, salt: string) => {
+  const key = crypto.pbkdf2Sync(getConfig().jwtSecret, salt, 100000, keyLength, 'sha256');
+  const iv = crypto.randomBytes(12);
+
+  const cipher = crypto.createCipheriv(algorithm, key, iv);
+  const encrypted = Buffer.concat([cipher.update(data), cipher.final()]);
+
+  const tag = cipher.getAuthTag();
+  return `${iv.toString('hex')}:${encrypted.toString('hex')}:${tag.toString('hex')}`;
+};
+
+/**
+ * Given an encrypted string, decrypts it using the provided salt
+ *
+ * @param {string} encryptedData - The data to decrypt
+ * @param {string} salt - The salt used to encrypt the data
+ * @returns {string} - The decrypted data
+ */
+export const decrypt = (encryptedData: string, salt: string) => {
+  const key = crypto.pbkdf2Sync(getConfig().jwtSecret, salt, 100000, keyLength, 'sha256');
+  const parts = encryptedData.split(':');
+  const iv = Buffer.from(parts.shift() as string, 'hex');
+  const encrypted = Buffer.from(parts.shift() as string, 'hex');
+  const tag = Buffer.from(parts.shift() as string, 'hex');
+  const decipher = crypto.createDecipheriv(algorithm, key, iv);
+
+  decipher.setAuthTag(tag);
+  let decrypted = decipher.update(encrypted);
+  decrypted = Buffer.concat([decrypted, decipher.final()]);
+
+  return decrypted.toString();
+};

+ 5 - 0
src/server/utils/totp.ts

@@ -0,0 +1,5 @@
+import { Authenticator } from '@otplib/core';
+import { keyDecoder, keyEncoder } from '@otplib/plugin-thirty-two';
+import { createDigest, createRandomBytes } from '@otplib/plugin-crypto';
+
+export const TotpAuthenticator = new Authenticator({ createDigest, createRandomBytes, keyEncoder, keyDecoder });