mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-21 05:00:56 +00:00
feat(infisical-pg): completed signup, login, password and backup key migration
This commit is contained in:
@@ -1,16 +1,39 @@
|
||||
import { Logger } from "pino";
|
||||
import { z } from "zod";
|
||||
|
||||
import { zpStr } from "../zod";
|
||||
|
||||
const zodStrBool = z
|
||||
.enum(["true", "false"])
|
||||
.optional()
|
||||
.transform((val) => val === "true");
|
||||
|
||||
const envSchema = z.object({
|
||||
PORT: z.coerce.number().default(4000),
|
||||
HOST: zpStr(z.string().default("localhost")),
|
||||
DB_CONNECTION_URI: zpStr(z.string().describe("Postgres database conntection string")),
|
||||
NODE_ENV: z.enum(["development", "test", "production"]).default("development"),
|
||||
SALT_ROUNDS: z.coerce.number().default(10),
|
||||
// TODO(akhilmhdh): will be changed to one
|
||||
ENCRYPTION_KEY: z.string().optional(),
|
||||
ROOT_ENCRYPTION_KEY: z.string().optional(),
|
||||
HTTPS_ENABLED: z
|
||||
.enum(["true", "false"])
|
||||
.optional()
|
||||
.transform((val) => val === "true")
|
||||
ENCRYPTION_KEY: zpStr(z.string().optional()),
|
||||
ROOT_ENCRYPTION_KEY: zpStr(z.string().optional()),
|
||||
HTTPS_ENABLED: zodStrBool,
|
||||
// smtp options
|
||||
SMTP_HOST: zpStr(z.string().optional()),
|
||||
SMTP_SECURE: zodStrBool,
|
||||
SMTP_PORT: z.coerce.number().default(587),
|
||||
SMTP_USERNAME: zpStr(z.string().optional()),
|
||||
SMTP_PASSWORD: zpStr(z.string().optional()),
|
||||
SMTP_FROM_ADDRESS: zpStr(z.string().optional()),
|
||||
SMTP_FROM_NAME: zpStr(z.string().optional().default("Infisical")),
|
||||
COOKIE_SECRET_SIGN_KEY: z.string().default("g5giLbOMpaJhqEogXApkiw2ZFW5Q0jvA"),
|
||||
SITE_URL: zpStr(z.string().optional()),
|
||||
// jwt options
|
||||
JWT_AUTH_SECRET: zpStr(z.string()),
|
||||
JWT_AUTH_LIFETIME: zpStr(z.string().default("10d")),
|
||||
JWT_SIGNUP_LIFETIME: zpStr(z.string().default("15m")),
|
||||
JWT_REFRESH_LIFETIME: zpStr(z.string().default("90d")),
|
||||
JWT_MFA_LIFETIME: zpStr(z.string().default("5m"))
|
||||
});
|
||||
|
||||
let envCfg: Readonly<z.infer<typeof envSchema>>;
|
||||
@@ -21,8 +44,20 @@ export const initEnvConfig = (logger: Logger) => {
|
||||
const parsedEnv = envSchema.safeParse(process.env);
|
||||
if (!parsedEnv.success) {
|
||||
logger.error("Invalid environment variables. Check the error below");
|
||||
logger.error(parsedEnv.error);
|
||||
logger.error(parsedEnv.error.issues);
|
||||
process.exit(-1);
|
||||
}
|
||||
envCfg = Object.freeze(parsedEnv.data);
|
||||
return envCfg;
|
||||
};
|
||||
|
||||
export const formatSmtpConfig = () => ({
|
||||
host: envCfg.SMTP_HOST,
|
||||
port: envCfg.SMTP_PORT,
|
||||
auth:
|
||||
envCfg.SMTP_USERNAME && envCfg.SMTP_PASSWORD
|
||||
? { user: envCfg.SMTP_USERNAME, pass: envCfg.SMTP_PASSWORD }
|
||||
: undefined,
|
||||
secure: envCfg.SMTP_SECURE,
|
||||
from: `"${envCfg.SMTP_FROM_NAME}" <${envCfg.SMTP_FROM_ADDRESS}>`
|
||||
});
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export { generateSrpServerKey, srpCheckClientProof } from "./srp";
|
||||
@@ -0,0 +1,26 @@
|
||||
import jsrp from "jsrp";
|
||||
|
||||
export const generateSrpServerKey = async (salt: string, verifier: string) => {
|
||||
// eslint-disable-next-line new-cap
|
||||
const server = new jsrp.server();
|
||||
await new Promise((resolve) => {
|
||||
server.init({ salt, verifier }, () => resolve(null));
|
||||
});
|
||||
return { pubKey: server.getPublicKey(), privateKey: server.getPrivateKey() };
|
||||
};
|
||||
|
||||
export const srpCheckClientProof = async (
|
||||
salt: string,
|
||||
verifier: string,
|
||||
serverPrivateKey: string,
|
||||
clientPublicKey: string,
|
||||
clientProof: string
|
||||
) => {
|
||||
// eslint-disable-next-line new-cap
|
||||
const server = new jsrp.server();
|
||||
await new Promise((resolve) => {
|
||||
server.init({ salt, verifier, b: serverPrivateKey }, () => resolve(null));
|
||||
});
|
||||
server.setClientPublicKey(clientPublicKey);
|
||||
return server.checkClientProof(clientProof);
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
/* eslint-disable max-classes-per-file */
|
||||
export class DatabaseError extends Error {
|
||||
name: string;
|
||||
|
||||
error: unknown;
|
||||
|
||||
constructor({ name, error, message }: { message?: string; name: string; error: unknown }) {
|
||||
super(message || "Failed to execute db ops");
|
||||
this.name = name;
|
||||
this.error = error;
|
||||
}
|
||||
}
|
||||
|
||||
export class UnauthorizedError extends Error {
|
||||
name: string;
|
||||
|
||||
error: unknown;
|
||||
|
||||
constructor({ name, error, message }: { message?: string; name: string; error: unknown }) {
|
||||
super(message ?? "You are not allowed to access this resourve");
|
||||
this.name = name;
|
||||
this.error = error;
|
||||
}
|
||||
}
|
||||
|
||||
export class BadRequestError extends Error {
|
||||
name: string;
|
||||
|
||||
error: unknown;
|
||||
|
||||
constructor({ name, error, message }: { message?: string; name: string; error: unknown }) {
|
||||
super(message ?? "The request is invalid");
|
||||
this.name = name;
|
||||
this.error = error;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export type RequiredKeys<T> = {
|
||||
[K in keyof T]-?: undefined extends T[K] ? never : K;
|
||||
}[keyof T];
|
||||
|
||||
export type PickRequired<T> = Pick<T, RequiredKeys<T>>;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1 @@
|
||||
export { isDisposableEmail } from "./validate-email";
|
||||
@@ -0,0 +1,10 @@
|
||||
import fs from "fs/promises";
|
||||
import path from "path";
|
||||
|
||||
export const isDisposableEmail = async (email: string) => {
|
||||
const emailDomain = email.split("@")[1];
|
||||
const disposableEmails = await fs.readFile(path.join(__dirname, "disposable_emails.txt"), "utf8");
|
||||
|
||||
if (disposableEmails.split("\n").includes(emailDomain)) return true;
|
||||
return false;
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
import { z } from "zod";
|
||||
|
||||
// this is a patched zod string to remove empty string to undefined
|
||||
export const zpStr = <T extends z.ZodString>(
|
||||
schema: T,
|
||||
opt: { stripNull: boolean } = { stripNull: true }
|
||||
) =>
|
||||
z.preprocess((val) => {
|
||||
if (opt.stripNull && val === null) return undefined;
|
||||
if (typeof val !== "string") return val;
|
||||
return val.trim() || undefined;
|
||||
}, schema);
|
||||
Reference in New Issue
Block a user