mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-06 22:27:22 +00:00
Convert JS to TS (#47)
This commit is contained in:
@@ -54,20 +54,19 @@ const attemptLogin = async (
|
|||||||
await login2(email, clientProof);
|
await login2(email, clientProof);
|
||||||
SecurityClient.setToken(token);
|
SecurityClient.setToken(token);
|
||||||
|
|
||||||
const privateKey = Aes256Gcm.decrypt(
|
const privateKey = Aes256Gcm.decrypt({
|
||||||
encryptedPrivateKey,
|
ciphertext: encryptedPrivateKey,
|
||||||
iv,
|
iv,
|
||||||
tag,
|
tag,
|
||||||
password
|
secret: password
|
||||||
.slice(0, 32)
|
.slice(0, 32)
|
||||||
.padStart(
|
.padStart(
|
||||||
32 + (password.slice(0, 32).length - new Blob([password]).size),
|
32 + (password.slice(0, 32).length - new Blob([password]).size),
|
||||||
'0'
|
'0'
|
||||||
)
|
)
|
||||||
);
|
});
|
||||||
|
|
||||||
saveTokenToLocalStorage({
|
saveTokenToLocalStorage({
|
||||||
token,
|
|
||||||
publicKey,
|
publicKey,
|
||||||
encryptedPrivateKey,
|
encryptedPrivateKey,
|
||||||
iv,
|
iv,
|
||||||
@@ -114,11 +113,8 @@ const attemptLogin = async (
|
|||||||
'personal'
|
'personal'
|
||||||
],
|
],
|
||||||
DB_USERNAME: ['user1234', 'personal'],
|
DB_USERNAME: ['user1234', 'personal'],
|
||||||
DB_PASSWORD: ['ah8jak3hk8dhiu4dw7whxwe1l', 'personal'],
|
DB_PASSWORD: ['example_password', 'personal'],
|
||||||
TWILIO_AUTH_TOKEN: [
|
TWILIO_AUTH_TOKEN: ['example_twillion_token', 'shared'],
|
||||||
'hgSIwDAKvz8PJfkj6xkzYqzGmAP3HLuG',
|
|
||||||
'shared'
|
|
||||||
],
|
|
||||||
WEBSITE_URL: ['http://localhost:3000', 'shared'],
|
WEBSITE_URL: ['http://localhost:3000', 'shared'],
|
||||||
STRIPE_SECRET_KEY: ['sk_test_7348oyho4hfq398HIUOH78', '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 changePassword2 from '~/pages/api/auth/ChangePassword2';
|
||||||
import SRP1 from "~/pages/api/auth/SRP1";
|
import SRP1 from '~/pages/api/auth/SRP1';
|
||||||
|
|
||||||
import Aes256Gcm from "./aes-256-gcm";
|
import Aes256Gcm from './aes-256-gcm';
|
||||||
|
|
||||||
const nacl = require("tweetnacl");
|
const nacl = require('tweetnacl');
|
||||||
nacl.util = require("tweetnacl-util");
|
nacl.util = require('tweetnacl-util');
|
||||||
const jsrp = require("jsrp");
|
const jsrp = require('jsrp');
|
||||||
const clientOldPassword = new jsrp.client();
|
const clientOldPassword = new jsrp.client();
|
||||||
const clientNewPassword = new jsrp.client();
|
const clientNewPassword = new jsrp.client();
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ const changePassword = async (
|
|||||||
clientOldPassword.init(
|
clientOldPassword.init(
|
||||||
{
|
{
|
||||||
username: email,
|
username: email,
|
||||||
password: currentPassword,
|
password: currentPassword
|
||||||
},
|
},
|
||||||
async () => {
|
async () => {
|
||||||
const clientPublicKey = clientOldPassword.getPublicKey();
|
const clientPublicKey = clientOldPassword.getPublicKey();
|
||||||
@@ -42,13 +42,13 @@ const changePassword = async (
|
|||||||
let serverPublicKey, salt;
|
let serverPublicKey, salt;
|
||||||
try {
|
try {
|
||||||
const res = await SRP1({
|
const res = await SRP1({
|
||||||
clientPublicKey: clientPublicKey,
|
clientPublicKey: clientPublicKey
|
||||||
});
|
});
|
||||||
serverPublicKey = res.serverPublicKey;
|
serverPublicKey = res.serverPublicKey;
|
||||||
salt = res.salt;
|
salt = res.salt;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setCurrentPasswordError(true);
|
setCurrentPasswordError(true);
|
||||||
console.log("Wrong current password", err, 1);
|
console.log('Wrong current password', err, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
clientOldPassword.setSalt(salt);
|
clientOldPassword.setSalt(salt);
|
||||||
@@ -58,27 +58,27 @@ const changePassword = async (
|
|||||||
clientNewPassword.init(
|
clientNewPassword.init(
|
||||||
{
|
{
|
||||||
username: email,
|
username: email,
|
||||||
password: newPassword,
|
password: newPassword
|
||||||
},
|
},
|
||||||
async () => {
|
async () => {
|
||||||
clientNewPassword.createVerifier(async (err, result) => {
|
clientNewPassword.createVerifier(async (err, result) => {
|
||||||
// The Blob part here is needed to account for symbols that count as 2+ bytes (e.g., é, å, ø)
|
// The Blob part here is needed to account for symbols that count as 2+ bytes (e.g., é, å, ø)
|
||||||
let { ciphertext, iv, tag } = Aes256Gcm.encrypt(
|
const { ciphertext, iv, tag } = Aes256Gcm.encrypt({
|
||||||
localStorage.getItem("PRIVATE_KEY"),
|
text: localStorage.getItem('PRIVATE_KEY'),
|
||||||
newPassword
|
secret: newPassword
|
||||||
.slice(0, 32)
|
.slice(0, 32)
|
||||||
.padStart(
|
.padStart(
|
||||||
32 +
|
32 +
|
||||||
(newPassword.slice(0, 32).length -
|
(newPassword.slice(0, 32).length -
|
||||||
new Blob([newPassword]).size),
|
new Blob([newPassword]).size),
|
||||||
"0"
|
'0'
|
||||||
)
|
)
|
||||||
);
|
});
|
||||||
|
|
||||||
if (ciphertext) {
|
if (ciphertext) {
|
||||||
localStorage.setItem("encryptedPrivateKey", ciphertext);
|
localStorage.setItem('encryptedPrivateKey', ciphertext);
|
||||||
localStorage.setItem("iv", iv);
|
localStorage.setItem('iv', iv);
|
||||||
localStorage.setItem("tag", tag);
|
localStorage.setItem('tag', tag);
|
||||||
|
|
||||||
let res;
|
let res;
|
||||||
try {
|
try {
|
||||||
@@ -88,14 +88,14 @@ const changePassword = async (
|
|||||||
tag,
|
tag,
|
||||||
salt: result.salt,
|
salt: result.salt,
|
||||||
verifier: result.verifier,
|
verifier: result.verifier,
|
||||||
clientProof,
|
clientProof
|
||||||
});
|
});
|
||||||
if (res.status == 400) {
|
if (res.status == 400) {
|
||||||
setCurrentPasswordError(true);
|
setCurrentPasswordError(true);
|
||||||
} else if (res.status == 200) {
|
} else if (res.status == 200) {
|
||||||
setPasswordChanged(true);
|
setPasswordChanged(true);
|
||||||
setCurrentPassword("");
|
setCurrentPassword('');
|
||||||
setNewPassword("");
|
setNewPassword('');
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setCurrentPasswordError(true);
|
setCurrentPasswordError(true);
|
||||||
@@ -108,7 +108,7 @@ const changePassword = async (
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("Something went wrong during changing the password");
|
console.log('Something went wrong during changing the password');
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
const nacl = require("tweetnacl");
|
const nacl = require('tweetnacl');
|
||||||
nacl.util = require("tweetnacl-util");
|
nacl.util = require('tweetnacl-util');
|
||||||
const aes = require("./aes-256-gcm");
|
import aes from './aes-256-gcm';
|
||||||
|
|
||||||
type encryptAsymmetricProps = {
|
type encryptAsymmetricProps = {
|
||||||
plaintext: string;
|
plaintext: string;
|
||||||
publicKey: string;
|
publicKey: string;
|
||||||
privateKey: string;
|
privateKey: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return assymmetrically encrypted [plaintext] using [publicKey] where
|
* Return assymmetrically encrypted [plaintext] using [publicKey] where
|
||||||
@@ -19,7 +19,11 @@ type encryptAsymmetricProps = {
|
|||||||
* @returns {String} ciphertext - base64-encoded ciphertext
|
* @returns {String} ciphertext - base64-encoded ciphertext
|
||||||
* @returns {String} nonce - base64-encoded nonce
|
* @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 nonce = nacl.randomBytes(24);
|
||||||
const ciphertext = nacl.box(
|
const ciphertext = nacl.box(
|
||||||
nacl.util.decodeUTF8(plaintext),
|
nacl.util.decodeUTF8(plaintext),
|
||||||
@@ -30,7 +34,7 @@ const encryptAssymmetric = ({ plaintext, publicKey, privateKey }: encryptAsymmet
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
ciphertext: nacl.util.encodeBase64(ciphertext),
|
ciphertext: nacl.util.encodeBase64(ciphertext),
|
||||||
nonce: nacl.util.encodeBase64(nonce),
|
nonce: nacl.util.encodeBase64(nonce)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -39,7 +43,7 @@ type decryptAsymmetricProps = {
|
|||||||
nonce: string;
|
nonce: string;
|
||||||
publicKey: string;
|
publicKey: string;
|
||||||
privateKey: string;
|
privateKey: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return assymmetrically decrypted [ciphertext] using [privateKey] where
|
* Return assymmetrically decrypted [ciphertext] using [privateKey] where
|
||||||
@@ -49,9 +53,13 @@ type decryptAsymmetricProps = {
|
|||||||
* @param {String} obj.nonce - nonce
|
* @param {String} obj.nonce - nonce
|
||||||
* @param {String} obj.publicKey - base64-encoded public key of the sender
|
* @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} 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(
|
const plaintext = nacl.box.open(
|
||||||
nacl.util.decodeBase64(ciphertext),
|
nacl.util.decodeBase64(ciphertext),
|
||||||
nacl.util.decodeBase64(nonce),
|
nacl.util.decodeBase64(nonce),
|
||||||
@@ -65,7 +73,7 @@ const decryptAssymmetric = ({ ciphertext, nonce, publicKey, privateKey }: decryp
|
|||||||
type encryptSymmetricProps = {
|
type encryptSymmetricProps = {
|
||||||
plaintext: string;
|
plaintext: string;
|
||||||
key: string;
|
key: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return symmetrically encrypted [plaintext] using [key].
|
* Return symmetrically encrypted [plaintext] using [key].
|
||||||
@@ -73,15 +81,18 @@ type encryptSymmetricProps = {
|
|||||||
* @param {String} obj.plaintext - plaintext to encrypt
|
* @param {String} obj.plaintext - plaintext to encrypt
|
||||||
* @param {String} obj.key - 16-byte hex key
|
* @param {String} obj.key - 16-byte hex key
|
||||||
*/
|
*/
|
||||||
const encryptSymmetric = ({ plaintext, key }: encryptSymmetricProps): object => {
|
const encryptSymmetric = ({
|
||||||
|
plaintext,
|
||||||
|
key
|
||||||
|
}: encryptSymmetricProps): object => {
|
||||||
let ciphertext, iv, tag;
|
let ciphertext, iv, tag;
|
||||||
try {
|
try {
|
||||||
const obj = aes.encrypt(plaintext, key);
|
const obj = aes.encrypt({ text: plaintext, secret: key });
|
||||||
ciphertext = obj.ciphertext;
|
ciphertext = obj.ciphertext;
|
||||||
iv = obj.iv;
|
iv = obj.iv;
|
||||||
tag = obj.tag;
|
tag = obj.tag;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("Failed to perform encryption");
|
console.log('Failed to perform encryption');
|
||||||
console.log(err);
|
console.log(err);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
@@ -89,7 +100,7 @@ const encryptSymmetric = ({ plaintext, key }: encryptSymmetricProps): object =>
|
|||||||
return {
|
return {
|
||||||
ciphertext,
|
ciphertext,
|
||||||
iv,
|
iv,
|
||||||
tag,
|
tag
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -98,7 +109,7 @@ type decryptSymmetricProps = {
|
|||||||
iv: string;
|
iv: string;
|
||||||
tag: string;
|
tag: string;
|
||||||
key: string;
|
key: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return symmetrically decypted [ciphertext] using [iv], [tag],
|
* Return symmetrically decypted [ciphertext] using [iv], [tag],
|
||||||
@@ -110,12 +121,17 @@ type decryptSymmetricProps = {
|
|||||||
* @param {String} obj.key - 32-byte hex key
|
* @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;
|
let plaintext;
|
||||||
try {
|
try {
|
||||||
plaintext = aes.decrypt(ciphertext, iv, tag, key);
|
plaintext = aes.decrypt({ ciphertext, iv, tag, secret: key });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("Failed to perform decryption");
|
console.log('Failed to perform decryption');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,5 +142,5 @@ export {
|
|||||||
decryptAssymmetric,
|
decryptAssymmetric,
|
||||||
decryptSymmetric,
|
decryptSymmetric,
|
||||||
encryptAssymmetric,
|
encryptAssymmetric,
|
||||||
encryptSymmetric,
|
encryptSymmetric
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import issueBackupPrivateKey from '~/pages/api/auth/IssueBackupPrivateKey';
|
import issueBackupPrivateKey from '~/pages/api/auth/IssueBackupPrivateKey';
|
||||||
import SRP1 from '~/pages/api/auth/SRP1';
|
import SRP1 from '~/pages/api/auth/SRP1';
|
||||||
|
|
||||||
import { tempLocalStorage } from '../checks/tempLocalStorage';
|
|
||||||
import generateBackupPDF from '../generateBackupPDF';
|
import generateBackupPDF from '../generateBackupPDF';
|
||||||
import Aes256Gcm from './aes-256-gcm';
|
import Aes256Gcm from './aes-256-gcm';
|
||||||
|
|
||||||
@@ -12,21 +11,22 @@ const clientPassword = new jsrp.client();
|
|||||||
const clientKey = new jsrp.client();
|
const clientKey = new jsrp.client();
|
||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
|
|
||||||
interface Props {
|
interface BackupKeyProps {
|
||||||
email: string;
|
email: string;
|
||||||
password: string;
|
password: string;
|
||||||
personalName: string;
|
personalName: string;
|
||||||
setBackupKeyError: any;
|
setBackupKeyError: (value: boolean) => void;
|
||||||
setBackupKeyIssued: any;
|
setBackupKeyIssued: (value: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function loggs in the user (whether it's right after signup, or a normal login)
|
* This function issue a backup key for a user
|
||||||
* @param {*} email
|
* @param {obkect} obj
|
||||||
* @param {*} password
|
* @param {string} obj.email - email of a user issuing a backup key
|
||||||
* @param {*} setErrorLogin
|
* @param {string} obj.password - password of a user issuing a backup key
|
||||||
* @param {*} router
|
* @param {string} obj.personalName - name of a user issuing a backup key
|
||||||
* @param {*} isSignUp
|
* @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
|
* @returns
|
||||||
*/
|
*/
|
||||||
const issueBackupKey = async ({
|
const issueBackupKey = async ({
|
||||||
@@ -35,7 +35,7 @@ const issueBackupKey = async ({
|
|||||||
personalName,
|
personalName,
|
||||||
setBackupKeyError,
|
setBackupKeyError,
|
||||||
setBackupKeyIssued
|
setBackupKeyIssued
|
||||||
}: Props) => {
|
}: BackupKeyProps) => {
|
||||||
try {
|
try {
|
||||||
setBackupKeyError(false);
|
setBackupKeyError(false);
|
||||||
setBackupKeyIssued(false);
|
setBackupKeyIssued(false);
|
||||||
@@ -72,14 +72,11 @@ const issueBackupKey = async ({
|
|||||||
},
|
},
|
||||||
async () => {
|
async () => {
|
||||||
clientKey.createVerifier(
|
clientKey.createVerifier(
|
||||||
async (_: any, result: { salt: string; verifier: string }) => {
|
async (err: any, result: { salt: string; verifier: string }) => {
|
||||||
// TODO: Fix this
|
const { ciphertext, iv, tag } = Aes256Gcm.encrypt({
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
text: String(localStorage.getItem('PRIVATE_KEY')),
|
||||||
// @ts-ignore
|
secret: generatedKey
|
||||||
const { ciphertext, iv, tag } = Aes256Gcm.encrypt(
|
});
|
||||||
tempLocalStorage('PRIVATE_KEY'),
|
|
||||||
generatedKey
|
|
||||||
);
|
|
||||||
|
|
||||||
const res = await issueBackupPrivateKey({
|
const res = await issueBackupPrivateKey({
|
||||||
encryptedPrivateKey: ciphertext,
|
encryptedPrivateKey: ciphertext,
|
||||||
@@ -90,10 +87,14 @@ const issueBackupKey = async ({
|
|||||||
clientProof
|
clientProof
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res && res.status == 400) {
|
if (res?.status == 400) {
|
||||||
setBackupKeyError(true);
|
setBackupKeyError(true);
|
||||||
} else if (res && res.status == 200) {
|
} else if (res?.status == 200) {
|
||||||
generateBackupPDF(personalName, email, generatedKey);
|
generateBackupPDF({
|
||||||
|
personalName,
|
||||||
|
personalEmail: email,
|
||||||
|
generatedKey
|
||||||
|
});
|
||||||
setBackupKeyIssued(true);
|
setBackupKeyIssued(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+59
-49
File diff suppressed because one or more lines are too long
@@ -3,9 +3,6 @@ import SecurityClient from '~/utilities/SecurityClient';
|
|||||||
/**
|
/**
|
||||||
* This function is used to check if the user is authenticated.
|
* This function is used to check if the user is authenticated.
|
||||||
* To do that, we get their tokens from cookies, and verify if they are good.
|
* To do that, we get their tokens from cookies, and verify if they are good.
|
||||||
* @param {*} req
|
|
||||||
* @param {*} res
|
|
||||||
* @returns
|
|
||||||
*/
|
*/
|
||||||
const checkAuth = async () => {
|
const checkAuth = async () => {
|
||||||
return SecurityClient.fetchCall('/api/v1/auth/checkAuth', {
|
return SecurityClient.fetchCall('/api/v1/auth/checkAuth', {
|
||||||
|
|||||||
@@ -5,8 +5,9 @@ interface Props {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This route check the verification code from the email that user just recieved
|
* This route check the verification code from the email that user just recieved
|
||||||
* @param {*} email
|
* @param {object} obj
|
||||||
* @param {*} code
|
* @param {string} obj.email
|
||||||
|
* @param {string} obj.code
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const checkEmailVerificationCode = ({ email, code }: Props) => {
|
const checkEmailVerificationCode = ({ email, code }: Props) => {
|
||||||
|
|||||||
@@ -15,16 +15,18 @@ interface Props {
|
|||||||
/**
|
/**
|
||||||
* This function is called in the end of the signup process.
|
* This function is called in the end of the signup process.
|
||||||
* It sends all the necessary nformation to the server.
|
* It sends all the necessary nformation to the server.
|
||||||
* @param {*} email
|
* @param {object} obj
|
||||||
* @param {*} firstName
|
* @param {string} obj.email - email of the user completing signup
|
||||||
* @param {*} lastName
|
* @param {string} obj.firstName - first name of the user completing signup
|
||||||
* @param {*} workspace
|
* @param {string} obj.lastName - last name of the user completing sign up
|
||||||
* @param {*} publicKey
|
* @param {string} obj.organizationName - organization name for this user (usually, [FIRST_NAME]'s organization)
|
||||||
* @param {*} ciphertext
|
* @param {string} obj.publicKey - public key of the user completing signup
|
||||||
* @param {*} iv
|
* @param {string} obj.ciphertext
|
||||||
* @param {*} tag
|
* @param {string} obj.iv
|
||||||
* @param {*} salt
|
* @param {string} obj.tag
|
||||||
* @param {*} verifier
|
* @param {string} obj.salt
|
||||||
|
* @param {string} obj.verifier
|
||||||
|
* @param {string} obj.token - token that confirms a user's identity
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const completeAccountInformationSignup = ({
|
const completeAccountInformationSignup = ({
|
||||||
|
|||||||
@@ -14,15 +14,17 @@ interface Props {
|
|||||||
/**
|
/**
|
||||||
* This function is called in the end of the signup process.
|
* This function is called in the end of the signup process.
|
||||||
* It sends all the necessary nformation to the server.
|
* It sends all the necessary nformation to the server.
|
||||||
* @param {*} email
|
* @param {object} obj
|
||||||
* @param {*} firstName
|
* @param {string} obj.email - email of the user completing signupinvite flow
|
||||||
* @param {*} lastName
|
* @param {string} obj.firstName - first name of the user completing signupinvite flow
|
||||||
* @param {*} publicKey
|
* @param {string} obj.lastName - last name of the user completing signupinvite flow
|
||||||
* @param {*} ciphertext
|
* @param {string} obj.publicKey - public key of the user completing signupinvite flow
|
||||||
* @param {*} iv
|
* @param {string} obj.ciphertext
|
||||||
* @param {*} tag
|
* @param {string} obj.iv
|
||||||
* @param {*} salt
|
* @param {string} obj.tag
|
||||||
* @param {*} verifier
|
* @param {string} obj.salt
|
||||||
|
* @param {string} obj.verifier
|
||||||
|
* @param {string} obj.token - token that confirms a user's identity
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const completeAccountInformationSignupInvite = ({
|
const completeAccountInformationSignupInvite = ({
|
||||||
|
|||||||
@@ -11,6 +11,14 @@ interface Props {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the route that issues a backup private key that will afterwards be added into a pdf
|
* This is the route that issues a backup private key that will afterwards be added into a pdf
|
||||||
|
* @param {object} obj
|
||||||
|
* @param {string} obj.encryptedPrivateKey
|
||||||
|
* @param {string} obj.iv
|
||||||
|
* @param {string} obj.tag
|
||||||
|
* @param {string} obj.salt
|
||||||
|
* @param {string} obj.verifier
|
||||||
|
* @param {string} obj.clientProof
|
||||||
|
* @returns
|
||||||
*/
|
*/
|
||||||
const issueBackupPrivateKey = ({
|
const issueBackupPrivateKey = ({
|
||||||
encryptedPrivateKey,
|
encryptedPrivateKey,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ interface Props {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the first step of the change password process (pake)
|
* This is the first step of the change password process (pake)
|
||||||
* @param {*} clientPublicKey
|
* @param {string} clientPublicKey
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const SRP1 = ({ clientPublicKey }: Props) => {
|
const SRP1 = ({ clientPublicKey }: Props) => {
|
||||||
|
|||||||
@@ -5,8 +5,9 @@ interface Props {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This route verifies the signup invite link
|
* This route verifies the signup invite link
|
||||||
* @param {*} email
|
* @param {object} obj
|
||||||
* @param {*} code
|
* @param {string} obj.email - email that a user is trying to verify
|
||||||
|
* @param {string} obj.code - code that a user received to the abovementioned email
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const verifySignupInvite = ({ email, code }: Props) => {
|
const verifySignupInvite = ({ email, code }: Props) => {
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import SecurityClient from '~/utilities/SecurityClient';
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This function fetches the encrypted secrets from the .env file
|
* This function fetches the encrypted secrets from the .env file
|
||||||
* @param {*} workspaceId
|
* @param {string} workspaceId - project is for which a user is trying to get secrets
|
||||||
* @param {*} env
|
* @param {string} env - environment of a project for which a user is trying ot get secrets
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const getSecrets = async (workspaceId: string, env: string) => {
|
const getSecrets = async (workspaceId: string, env: string) => {
|
||||||
|
|||||||
@@ -9,8 +9,11 @@ interface Props {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This function uploads the encrypted .env file
|
* This function uploads the encrypted .env file
|
||||||
* @param {*} req
|
* @param {object} obj
|
||||||
* @param {*} res
|
* @param {string} obj.workspaceId
|
||||||
|
* @param {} obj.secrets
|
||||||
|
* @param {} obj.keys
|
||||||
|
* @param {string} obj.environment
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const uploadSecrets = async ({
|
const uploadSecrets = async ({
|
||||||
|
|||||||
@@ -7,7 +7,10 @@ interface Props {
|
|||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* This is the first step of the change password process (pake)
|
* This is the first step of the change password process (pake)
|
||||||
* @param {*} clientPublicKey
|
* @param {object} obj
|
||||||
|
* @param {object} obj.workspaceId - project id for which we want to authorize the integration
|
||||||
|
* @param {object} obj.code
|
||||||
|
* @param {object} obj.integration - integration which a user is trying to turn on
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const AuthorizeIntegration = ({ workspaceId, code, integration }: Props) => {
|
const AuthorizeIntegration = ({ workspaceId, code, integration }: Props) => {
|
||||||
|
|||||||
@@ -385,14 +385,14 @@ export default function Dashboard() {
|
|||||||
|
|
||||||
if (nameErrors) {
|
if (nameErrors) {
|
||||||
return createNotification({
|
return createNotification({
|
||||||
text: 'Solve all name errors first!',
|
text: 'Solve all name errors before saving secrets.',
|
||||||
type: 'error'
|
type: 'error'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (duplicatesExist) {
|
if (duplicatesExist) {
|
||||||
return createNotification({
|
return createNotification({
|
||||||
text: "Your secrets weren't saved; please fix the conflicts first.",
|
text: 'Remove duplicated secret names before saving.',
|
||||||
type: 'error'
|
type: 'error'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ const learningItem = ({
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
if (userAction) {
|
if (userAction && userAction != 'first_time_secrets_pushed') {
|
||||||
await registerUserAction({
|
await registerUserAction({
|
||||||
action: userAction
|
action: userAction
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import React, { useEffect, useRef, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import ReactCodeInput from 'react-code-input';
|
import ReactCodeInput from 'react-code-input';
|
||||||
import dynamic from 'next/dynamic';
|
|
||||||
import Head from 'next/head';
|
import Head from 'next/head';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
@@ -181,15 +180,15 @@ export default function SignUp() {
|
|||||||
const PRIVATE_KEY = nacl.util.encodeBase64(secretKeyUint8Array);
|
const PRIVATE_KEY = nacl.util.encodeBase64(secretKeyUint8Array);
|
||||||
const PUBLIC_KEY = nacl.util.encodeBase64(publicKeyUint8Array);
|
const PUBLIC_KEY = nacl.util.encodeBase64(publicKeyUint8Array);
|
||||||
|
|
||||||
const { ciphertext, iv, tag } = Aes256Gcm.encrypt(
|
const { ciphertext, iv, tag } = Aes256Gcm.encrypt({
|
||||||
PRIVATE_KEY,
|
text: PRIVATE_KEY,
|
||||||
password
|
secret: password
|
||||||
.slice(0, 32)
|
.slice(0, 32)
|
||||||
.padStart(
|
.padStart(
|
||||||
32 + (password.slice(0, 32).length - new Blob([password]).size),
|
32 + (password.slice(0, 32).length - new Blob([password]).size),
|
||||||
'0'
|
'0'
|
||||||
)
|
)
|
||||||
) as { ciphertext: string; iv: string; tag: string };
|
}) as { ciphertext: string; iv: string; tag: string };
|
||||||
|
|
||||||
localStorage.setItem('PRIVATE_KEY', PRIVATE_KEY);
|
localStorage.setItem('PRIVATE_KEY', PRIVATE_KEY);
|
||||||
|
|
||||||
|
|||||||
@@ -1,38 +1,38 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from 'react';
|
||||||
import Head from "next/head";
|
import Head from 'next/head';
|
||||||
import Image from "next/image";
|
import Image from 'next/image';
|
||||||
import Link from "next/link";
|
import Link from 'next/link';
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from 'next/router';
|
||||||
import { faCheck, faWarning, faX } from "@fortawesome/free-solid-svg-icons";
|
import { faCheck, faWarning, faX } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
|
||||||
import Button from "~/components/basic/buttons/Button";
|
import Button from '~/components/basic/buttons/Button';
|
||||||
import InputField from "~/components/basic/InputField";
|
import InputField from '~/components/basic/InputField';
|
||||||
import Aes256Gcm from "~/components/utilities/cryptography/aes-256-gcm";
|
import Aes256Gcm from '~/components/utilities/cryptography/aes-256-gcm';
|
||||||
import issueBackupKey from "~/components/utilities/cryptography/issueBackupKey";
|
import issueBackupKey from '~/components/utilities/cryptography/issueBackupKey';
|
||||||
import attemptLogin from "~/utilities/attemptLogin";
|
import attemptLogin from '~/utilities/attemptLogin';
|
||||||
import passwordCheck from "~/utilities/checks/PasswordCheck";
|
import passwordCheck from '~/utilities/checks/PasswordCheck';
|
||||||
|
|
||||||
import completeAccountInformationSignupInvite from "./api/auth/CompleteAccountInformationSignupInvite";
|
import completeAccountInformationSignupInvite from './api/auth/CompleteAccountInformationSignupInvite';
|
||||||
import verifySignupInvite from "./api/auth/VerifySignupInvite";
|
import verifySignupInvite from './api/auth/VerifySignupInvite';
|
||||||
|
|
||||||
const nacl = require("tweetnacl");
|
const nacl = require('tweetnacl');
|
||||||
const jsrp = require("jsrp");
|
const jsrp = require('jsrp');
|
||||||
nacl.util = require("tweetnacl-util");
|
nacl.util = require('tweetnacl-util');
|
||||||
const client = new jsrp.client();
|
const client = new jsrp.client();
|
||||||
const queryString = require("query-string");
|
const queryString = require('query-string');
|
||||||
|
|
||||||
export default function SignupInvite() {
|
export default function SignupInvite() {
|
||||||
const [password, setPassword] = useState("");
|
const [password, setPassword] = useState('');
|
||||||
const [firstName, setFirstName] = useState("");
|
const [firstName, setFirstName] = useState('');
|
||||||
const [lastName, setLastName] = useState("");
|
const [lastName, setLastName] = useState('');
|
||||||
const [firstNameError, setFirstNameError] = useState(false);
|
const [firstNameError, setFirstNameError] = useState(false);
|
||||||
const [lastNameError, setLastNameError] = useState(false);
|
const [lastNameError, setLastNameError] = useState(false);
|
||||||
const [passwordErrorLength, setPasswordErrorLength] = useState(false);
|
const [passwordErrorLength, setPasswordErrorLength] = useState(false);
|
||||||
const [passwordErrorNumber, setPasswordErrorNumber] = useState(false);
|
const [passwordErrorNumber, setPasswordErrorNumber] = useState(false);
|
||||||
const [passwordErrorLowerCase, setPasswordErrorLowerCase] = useState(false);
|
const [passwordErrorLowerCase, setPasswordErrorLowerCase] = useState(false);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const parsedUrl = queryString.parse(router.asPath.split("?")[1]);
|
const parsedUrl = queryString.parse(router.asPath.split('?')[1]);
|
||||||
const [email, setEmail] = useState(parsedUrl.to);
|
const [email, setEmail] = useState(parsedUrl.to);
|
||||||
const token = parsedUrl.token;
|
const token = parsedUrl.token;
|
||||||
const [errorLogin, setErrorLogin] = useState(false);
|
const [errorLogin, setErrorLogin] = useState(false);
|
||||||
@@ -74,21 +74,22 @@ export default function SignupInvite() {
|
|||||||
const PRIVATE_KEY = nacl.util.encodeBase64(secretKeyUint8Array);
|
const PRIVATE_KEY = nacl.util.encodeBase64(secretKeyUint8Array);
|
||||||
const PUBLIC_KEY = nacl.util.encodeBase64(publicKeyUint8Array);
|
const PUBLIC_KEY = nacl.util.encodeBase64(publicKeyUint8Array);
|
||||||
|
|
||||||
const { ciphertext, iv, tag } = Aes256Gcm.encrypt(
|
const { ciphertext, iv, tag } = Aes256Gcm.encrypt({
|
||||||
PRIVATE_KEY,
|
text: PRIVATE_KEY,
|
||||||
password
|
secret: password
|
||||||
.slice(0, 32)
|
.slice(0, 32)
|
||||||
.padStart(
|
.padStart(
|
||||||
32 + (password.slice(0, 32).length - new Blob([password]).size),
|
32 + (password.slice(0, 32).length - new Blob([password]).size),
|
||||||
"0"
|
'0'
|
||||||
)
|
)
|
||||||
);
|
});
|
||||||
localStorage.setItem("PRIVATE_KEY", PRIVATE_KEY);
|
|
||||||
|
localStorage.setItem('PRIVATE_KEY', PRIVATE_KEY);
|
||||||
|
|
||||||
client.init(
|
client.init(
|
||||||
{
|
{
|
||||||
username: email,
|
username: email,
|
||||||
password: password,
|
password: password
|
||||||
},
|
},
|
||||||
async () => {
|
async () => {
|
||||||
client.createVerifier(async (err, result) => {
|
client.createVerifier(async (err, result) => {
|
||||||
@@ -102,17 +103,17 @@ export default function SignupInvite() {
|
|||||||
tag,
|
tag,
|
||||||
salt: result.salt,
|
salt: result.salt,
|
||||||
verifier: result.verifier,
|
verifier: result.verifier,
|
||||||
token: verificationToken,
|
token: verificationToken
|
||||||
});
|
});
|
||||||
|
|
||||||
// if everything works, go the main dashboard page.
|
// if everything works, go the main dashboard page.
|
||||||
if (!errorCheck && response.status == "200") {
|
if (!errorCheck && response.status == '200') {
|
||||||
response = await response.json();
|
response = await response.json();
|
||||||
|
|
||||||
localStorage.setItem("publicKey", PUBLIC_KEY);
|
localStorage.setItem('publicKey', PUBLIC_KEY);
|
||||||
localStorage.setItem("encryptedPrivateKey", ciphertext);
|
localStorage.setItem('encryptedPrivateKey', ciphertext);
|
||||||
localStorage.setItem("iv", iv);
|
localStorage.setItem('iv', iv);
|
||||||
localStorage.setItem("tag", tag);
|
localStorage.setItem('tag', tag);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await attemptLogin(
|
await attemptLogin(
|
||||||
@@ -126,7 +127,7 @@ export default function SignupInvite() {
|
|||||||
setStep(3);
|
setStep(3);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
console.log("Error", error);
|
console.log('Error', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -155,14 +156,14 @@ export default function SignupInvite() {
|
|||||||
onButtonPressed={async () => {
|
onButtonPressed={async () => {
|
||||||
const response = await verifySignupInvite({
|
const response = await verifySignupInvite({
|
||||||
email,
|
email,
|
||||||
code: token,
|
code: token
|
||||||
});
|
});
|
||||||
if (response.status == 200) {
|
if (response.status == 200) {
|
||||||
setVerificationToken((await response.json()).token);
|
setVerificationToken((await response.json()).token);
|
||||||
setStep(2);
|
setStep(2);
|
||||||
} else {
|
} else {
|
||||||
console.log("ERROR", response);
|
console.log('ERROR', response);
|
||||||
router.push("/requestnewinvite");
|
router.push('/requestnewinvite');
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
size="lg"
|
size="lg"
|
||||||
@@ -211,7 +212,7 @@ export default function SignupInvite() {
|
|||||||
setPasswordErrorLength,
|
setPasswordErrorLength,
|
||||||
setPasswordErrorNumber,
|
setPasswordErrorNumber,
|
||||||
setPasswordErrorLowerCase,
|
setPasswordErrorLowerCase,
|
||||||
currentErrorCheck: false,
|
currentErrorCheck: false
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
type="password"
|
type="password"
|
||||||
@@ -244,7 +245,7 @@ export default function SignupInvite() {
|
|||||||
)}
|
)}
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
passwordErrorLength ? "text-gray-400" : "text-gray-600"
|
passwordErrorLength ? 'text-gray-400' : 'text-gray-600'
|
||||||
} text-sm`}
|
} text-sm`}
|
||||||
>
|
>
|
||||||
14 characters
|
14 characters
|
||||||
@@ -264,7 +265,7 @@ export default function SignupInvite() {
|
|||||||
)}
|
)}
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
passwordErrorLowerCase ? "text-gray-400" : "text-gray-600"
|
passwordErrorLowerCase ? 'text-gray-400' : 'text-gray-600'
|
||||||
} text-sm`}
|
} text-sm`}
|
||||||
>
|
>
|
||||||
1 lowercase character
|
1 lowercase character
|
||||||
@@ -284,7 +285,7 @@ export default function SignupInvite() {
|
|||||||
)}
|
)}
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
passwordErrorNumber ? "text-gray-400" : "text-gray-600"
|
passwordErrorNumber ? 'text-gray-400' : 'text-gray-600'
|
||||||
} text-sm`}
|
} text-sm`}
|
||||||
>
|
>
|
||||||
1 number
|
1 number
|
||||||
@@ -335,11 +336,11 @@ export default function SignupInvite() {
|
|||||||
await issueBackupKey({
|
await issueBackupKey({
|
||||||
email,
|
email,
|
||||||
password,
|
password,
|
||||||
personalName: firstName + " " + lastName,
|
personalName: firstName + ' ' + lastName,
|
||||||
setBackupKeyError,
|
setBackupKeyError,
|
||||||
setBackupKeyIssued,
|
setBackupKeyIssued
|
||||||
});
|
});
|
||||||
router.push("/dashboard/");
|
router.push('/dashboard/');
|
||||||
}}
|
}}
|
||||||
size="lg"
|
size="lg"
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user