Convert JS to TS (#47)

This commit is contained in:
Vladyslav Matsiiako
2022-12-11 13:06:25 -05:00
parent 7cdafe0eed
commit eae2fc813a
21 changed files with 332 additions and 273 deletions
+6 -10
View File
@@ -54,20 +54,19 @@ const attemptLogin = async (
await login2(email, clientProof);
SecurityClient.setToken(token);
const privateKey = Aes256Gcm.decrypt(
encryptedPrivateKey,
const privateKey = Aes256Gcm.decrypt({
ciphertext: encryptedPrivateKey,
iv,
tag,
password
secret: password
.slice(0, 32)
.padStart(
32 + (password.slice(0, 32).length - new Blob([password]).size),
'0'
)
);
});
saveTokenToLocalStorage({
token,
publicKey,
encryptedPrivateKey,
iv,
@@ -114,11 +113,8 @@ const attemptLogin = async (
'personal'
],
DB_USERNAME: ['user1234', 'personal'],
DB_PASSWORD: ['ah8jak3hk8dhiu4dw7whxwe1l', 'personal'],
TWILIO_AUTH_TOKEN: [
'hgSIwDAKvz8PJfkj6xkzYqzGmAP3HLuG',
'shared'
],
DB_PASSWORD: ['example_password', 'personal'],
TWILIO_AUTH_TOKEN: ['example_twillion_token', 'shared'],
WEBSITE_URL: ['http://localhost:3000', 'shared'],
STRIPE_SECRET_KEY: ['sk_test_7348oyho4hfq398HIUOH78', 'shared']
},
@@ -1,63 +0,0 @@
/**
* @fileoverview Provides easy encryption/decryption methods using AES 256 GCM.
*/
"use strict";
const crypto = require("crypto");
const ALGORITHM = "aes-256-gcm";
const BLOCK_SIZE_BYTES = 16; // 128 bit
/**
* Provides easy encryption/decryption methods using AES 256 GCM.
*/
class Aes256Gcm {
/**
* No need to run the constructor. The class only has static methods.
*/
constructor() {}
/**
* Encrypts text with AES 256 GCM.
* @param {string} text - Cleartext to encode.
* @param {string} secret - Shared secret key, must be 32 bytes.
* @returns {object}
*/
static encrypt(text, secret) {
const iv = crypto.randomBytes(BLOCK_SIZE_BYTES);
const cipher = crypto.createCipheriv(ALGORITHM, secret, iv);
let ciphertext = cipher.update(text, "utf8", "base64");
ciphertext += cipher.final("base64");
return {
ciphertext,
iv: iv.toString("base64"),
tag: cipher.getAuthTag().toString("base64"),
};
}
/**
* Decrypts AES 256 CGM encrypted text.
* @param {string} ciphertext - Base64-encoded ciphertext.
* @param {string} iv - The base64-encoded initialization vector.
* @param {string} tag - The base64-encoded authentication tag generated by getAuthTag().
* @param {string} secret - Shared secret key, must be 32 bytes.
* @returns {string}
*/
static decrypt(ciphertext, iv, tag, secret) {
const decipher = crypto.createDecipheriv(
ALGORITHM,
secret,
Buffer.from(iv, "base64")
);
decipher.setAuthTag(Buffer.from(tag, "base64"));
let cleartext = decipher.update(ciphertext, "base64", "utf8");
cleartext += decipher.final("utf8");
return cleartext;
}
}
module.exports = Aes256Gcm;
@@ -0,0 +1,82 @@
/**
* @fileoverview Provides easy encryption/decryption methods using AES 256 GCM.
*/
import crypto from 'crypto';
const ALGORITHM = 'aes-256-gcm';
const BLOCK_SIZE_BYTES = 16; // 128 bit
interface EncryptProps {
text: string;
secret: string;
}
interface DecryptProps {
ciphertext: string;
iv: string;
tag: string;
secret: string;
}
interface EncryptOutputProps {
ciphertext: string;
iv: string;
tag: string;
}
/**
* Provides easy encryption/decryption methods using AES 256 GCM.
*/
class Aes256Gcm {
/**
* No need to run the constructor. The class only has static methods.
*/
constructor() {}
/**
* Encrypts text with AES 256 GCM.
* @param {object} obj
* @param {string} obj.text - Cleartext to encode.
* @param {string} obj.secret - Shared secret key, must be 32 bytes.
* @returns {object}
*/
// { ciphertext: string; iv: string; tag: string; }
static encrypt({ text, secret }: EncryptProps): EncryptOutputProps {
const iv = crypto.randomBytes(BLOCK_SIZE_BYTES);
const cipher = crypto.createCipheriv(ALGORITHM, secret, iv);
let ciphertext = cipher.update(text, 'utf8', 'base64');
ciphertext += cipher.final('base64');
return {
ciphertext,
iv: iv.toString('base64'),
tag: cipher.getAuthTag().toString('base64')
};
}
/**
* Decrypts AES 256 CGM encrypted text.
* @param {object} obj
* @param {string} obj.ciphertext - Base64-encoded ciphertext.
* @param {string} obj.iv - The base64-encoded initialization vector.
* @param {string} obj.tag - The base64-encoded authentication tag generated by getAuthTag().
* @param {string} obj.secret - Shared secret key, must be 32 bytes.
* @returns {string}
*/
static decrypt({ ciphertext, iv, tag, secret }: DecryptProps): string {
const decipher = crypto.createDecipheriv(
ALGORITHM,
secret,
Buffer.from(iv, 'base64')
);
decipher.setAuthTag(Buffer.from(tag, 'base64'));
let cleartext = decipher.update(ciphertext, 'base64', 'utf8');
cleartext += decipher.final('utf8');
return cleartext;
}
}
export default Aes256Gcm;
@@ -1,11 +1,11 @@
import changePassword2 from "~/pages/api/auth/ChangePassword2";
import SRP1 from "~/pages/api/auth/SRP1";
import changePassword2 from '~/pages/api/auth/ChangePassword2';
import SRP1 from '~/pages/api/auth/SRP1';
import Aes256Gcm from "./aes-256-gcm";
import Aes256Gcm from './aes-256-gcm';
const nacl = require("tweetnacl");
nacl.util = require("tweetnacl-util");
const jsrp = require("jsrp");
const nacl = require('tweetnacl');
nacl.util = require('tweetnacl-util');
const jsrp = require('jsrp');
const clientOldPassword = new jsrp.client();
const clientNewPassword = new jsrp.client();
@@ -34,7 +34,7 @@ const changePassword = async (
clientOldPassword.init(
{
username: email,
password: currentPassword,
password: currentPassword
},
async () => {
const clientPublicKey = clientOldPassword.getPublicKey();
@@ -42,13 +42,13 @@ const changePassword = async (
let serverPublicKey, salt;
try {
const res = await SRP1({
clientPublicKey: clientPublicKey,
clientPublicKey: clientPublicKey
});
serverPublicKey = res.serverPublicKey;
salt = res.salt;
} catch (err) {
setCurrentPasswordError(true);
console.log("Wrong current password", err, 1);
console.log('Wrong current password', err, 1);
}
clientOldPassword.setSalt(salt);
@@ -58,27 +58,27 @@ const changePassword = async (
clientNewPassword.init(
{
username: email,
password: newPassword,
password: newPassword
},
async () => {
clientNewPassword.createVerifier(async (err, result) => {
// The Blob part here is needed to account for symbols that count as 2+ bytes (e.g., é, å, ø)
let { ciphertext, iv, tag } = Aes256Gcm.encrypt(
localStorage.getItem("PRIVATE_KEY"),
newPassword
const { ciphertext, iv, tag } = Aes256Gcm.encrypt({
text: localStorage.getItem('PRIVATE_KEY'),
secret: newPassword
.slice(0, 32)
.padStart(
32 +
(newPassword.slice(0, 32).length -
new Blob([newPassword]).size),
"0"
'0'
)
);
});
if (ciphertext) {
localStorage.setItem("encryptedPrivateKey", ciphertext);
localStorage.setItem("iv", iv);
localStorage.setItem("tag", tag);
localStorage.setItem('encryptedPrivateKey', ciphertext);
localStorage.setItem('iv', iv);
localStorage.setItem('tag', tag);
let res;
try {
@@ -88,14 +88,14 @@ const changePassword = async (
tag,
salt: result.salt,
verifier: result.verifier,
clientProof,
clientProof
});
if (res.status == 400) {
setCurrentPasswordError(true);
} else if (res.status == 200) {
setPasswordChanged(true);
setCurrentPassword("");
setNewPassword("");
setCurrentPassword('');
setNewPassword('');
}
} catch (err) {
setCurrentPasswordError(true);
@@ -108,7 +108,7 @@ const changePassword = async (
}
);
} catch (error) {
console.log("Something went wrong during changing the password");
console.log('Something went wrong during changing the password');
}
return true;
};
@@ -1,12 +1,12 @@
const nacl = require("tweetnacl");
nacl.util = require("tweetnacl-util");
const aes = require("./aes-256-gcm");
const nacl = require('tweetnacl');
nacl.util = require('tweetnacl-util');
import aes from './aes-256-gcm';
type encryptAsymmetricProps = {
plaintext: string;
publicKey: string;
privateKey: string;
}
};
/**
* Return assymmetrically encrypted [plaintext] using [publicKey] where
@@ -19,7 +19,11 @@ type encryptAsymmetricProps = {
* @returns {String} ciphertext - base64-encoded ciphertext
* @returns {String} nonce - base64-encoded nonce
*/
const encryptAssymmetric = ({ plaintext, publicKey, privateKey }: encryptAsymmetricProps): object => {
const encryptAssymmetric = ({
plaintext,
publicKey,
privateKey
}: encryptAsymmetricProps): object => {
const nonce = nacl.randomBytes(24);
const ciphertext = nacl.box(
nacl.util.decodeUTF8(plaintext),
@@ -30,7 +34,7 @@ const encryptAssymmetric = ({ plaintext, publicKey, privateKey }: encryptAsymmet
return {
ciphertext: nacl.util.encodeBase64(ciphertext),
nonce: nacl.util.encodeBase64(nonce),
nonce: nacl.util.encodeBase64(nonce)
};
};
@@ -39,7 +43,7 @@ type decryptAsymmetricProps = {
nonce: string;
publicKey: string;
privateKey: string;
}
};
/**
* Return assymmetrically decrypted [ciphertext] using [privateKey] where
@@ -49,9 +53,13 @@ type decryptAsymmetricProps = {
* @param {String} obj.nonce - nonce
* @param {String} obj.publicKey - base64-encoded public key of the sender
* @param {String} obj.privateKey - base64-encoded private key of the receiver (current user)
* @param {String} plaintext - UTF8 plaintext
*/
const decryptAssymmetric = ({ ciphertext, nonce, publicKey, privateKey }: decryptAsymmetricProps): string => {
const decryptAssymmetric = ({
ciphertext,
nonce,
publicKey,
privateKey
}: decryptAsymmetricProps): string => {
const plaintext = nacl.box.open(
nacl.util.decodeBase64(ciphertext),
nacl.util.decodeBase64(nonce),
@@ -65,7 +73,7 @@ const decryptAssymmetric = ({ ciphertext, nonce, publicKey, privateKey }: decryp
type encryptSymmetricProps = {
plaintext: string;
key: string;
}
};
/**
* Return symmetrically encrypted [plaintext] using [key].
@@ -73,15 +81,18 @@ type encryptSymmetricProps = {
* @param {String} obj.plaintext - plaintext to encrypt
* @param {String} obj.key - 16-byte hex key
*/
const encryptSymmetric = ({ plaintext, key }: encryptSymmetricProps): object => {
const encryptSymmetric = ({
plaintext,
key
}: encryptSymmetricProps): object => {
let ciphertext, iv, tag;
try {
const obj = aes.encrypt(plaintext, key);
const obj = aes.encrypt({ text: plaintext, secret: key });
ciphertext = obj.ciphertext;
iv = obj.iv;
tag = obj.tag;
} catch (err) {
console.log("Failed to perform encryption");
console.log('Failed to perform encryption');
console.log(err);
process.exit(1);
}
@@ -89,7 +100,7 @@ const encryptSymmetric = ({ plaintext, key }: encryptSymmetricProps): object =>
return {
ciphertext,
iv,
tag,
tag
};
};
@@ -98,7 +109,7 @@ type decryptSymmetricProps = {
iv: string;
tag: string;
key: string;
}
};
/**
* Return symmetrically decypted [ciphertext] using [iv], [tag],
@@ -110,12 +121,17 @@ type decryptSymmetricProps = {
* @param {String} obj.key - 32-byte hex key
*
*/
const decryptSymmetric = ({ ciphertext, iv, tag, key }: decryptSymmetricProps): string => {
const decryptSymmetric = ({
ciphertext,
iv,
tag,
key
}: decryptSymmetricProps): string => {
let plaintext;
try {
plaintext = aes.decrypt(ciphertext, iv, tag, key);
plaintext = aes.decrypt({ ciphertext, iv, tag, secret: key });
} catch (err) {
console.log("Failed to perform decryption");
console.log('Failed to perform decryption');
process.exit(1);
}
@@ -126,5 +142,5 @@ export {
decryptAssymmetric,
decryptSymmetric,
encryptAssymmetric,
encryptSymmetric,
encryptSymmetric
};
@@ -1,7 +1,6 @@
import issueBackupPrivateKey from '~/pages/api/auth/IssueBackupPrivateKey';
import SRP1 from '~/pages/api/auth/SRP1';
import { tempLocalStorage } from '../checks/tempLocalStorage';
import generateBackupPDF from '../generateBackupPDF';
import Aes256Gcm from './aes-256-gcm';
@@ -12,21 +11,22 @@ const clientPassword = new jsrp.client();
const clientKey = new jsrp.client();
const crypto = require('crypto');
interface Props {
interface BackupKeyProps {
email: string;
password: string;
personalName: string;
setBackupKeyError: any;
setBackupKeyIssued: any;
setBackupKeyError: (value: boolean) => void;
setBackupKeyIssued: (value: boolean) => void;
}
/**
* This function loggs in the user (whether it's right after signup, or a normal login)
* @param {*} email
* @param {*} password
* @param {*} setErrorLogin
* @param {*} router
* @param {*} isSignUp
* This function issue a backup key for a user
* @param {obkect} obj
* @param {string} obj.email - email of a user issuing a backup key
* @param {string} obj.password - password of a user issuing a backup key
* @param {string} obj.personalName - name of a user issuing a backup key
* @param {function} obj.setBackupKeyError - state function that turns true if there is an erorr with a backup key
* @param {function} obj.setBackupKeyIssued - state function that turns true if a backup key was issued correctly
* @returns
*/
const issueBackupKey = async ({
@@ -35,7 +35,7 @@ const issueBackupKey = async ({
personalName,
setBackupKeyError,
setBackupKeyIssued
}: Props) => {
}: BackupKeyProps) => {
try {
setBackupKeyError(false);
setBackupKeyIssued(false);
@@ -72,14 +72,11 @@ const issueBackupKey = async ({
},
async () => {
clientKey.createVerifier(
async (_: any, result: { salt: string; verifier: string }) => {
// TODO: Fix this
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const { ciphertext, iv, tag } = Aes256Gcm.encrypt(
tempLocalStorage('PRIVATE_KEY'),
generatedKey
);
async (err: any, result: { salt: string; verifier: string }) => {
const { ciphertext, iv, tag } = Aes256Gcm.encrypt({
text: String(localStorage.getItem('PRIVATE_KEY')),
secret: generatedKey
});
const res = await issueBackupPrivateKey({
encryptedPrivateKey: ciphertext,
@@ -90,10 +87,14 @@ const issueBackupKey = async ({
clientProof
});
if (res && res.status == 400) {
if (res?.status == 400) {
setBackupKeyError(true);
} else if (res && res.status == 200) {
generateBackupPDF(personalName, email, generatedKey);
} else if (res?.status == 200) {
generateBackupPDF({
personalName,
personalEmail: email,
generatedKey
});
setBackupKeyIssued(true);
}
}
File diff suppressed because one or more lines are too long