mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
feat(infisical-pg): auth injection completed and validation in password router
This commit is contained in:
@@ -18,6 +18,7 @@ module.exports = {
|
||||
"import/first": "error",
|
||||
"import/newline-after-import": "error",
|
||||
"import/no-duplicates": "error",
|
||||
"consistent-return": "off",
|
||||
"simple-import-sort/imports": [
|
||||
"warn",
|
||||
{
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"lint:fix": "eslint --fix 'src/**/*.ts'",
|
||||
"lint": "eslint 'src/**/*.ts'",
|
||||
"generate:component": "tsx ./scripts/create-backend-file.ts",
|
||||
"generate:schema": "tsx ./scripts/generate-schema-types.ts",
|
||||
"migration:new": "tsx ./scripts/create-migration.ts",
|
||||
"migration:up": "knex --knexfile ./src/db/knexfile.ts --client pg migrate:up",
|
||||
"migration:down": "knex --knexfile ./src/db/knexfile.ts --client pg migrate:down",
|
||||
|
||||
@@ -10,7 +10,6 @@ console.log(`
|
||||
Component List
|
||||
--------------
|
||||
1. Service component
|
||||
2. Schema file
|
||||
`);
|
||||
const componentType = parseInt(prompt("Select a component: "), 10);
|
||||
|
||||
@@ -55,27 +54,4 @@ export const ${serviceName} = ({ ${componentName}Dal }: ${serviceTypeName}Dep) =
|
||||
`
|
||||
);
|
||||
writeFileSync(path.join(dir, `${componentName}-types.ts`), "");
|
||||
} else if (componentType === 2) {
|
||||
const componentName = prompt("Type component name in lowercase with space seperated: ");
|
||||
const dashcase = componentName.split(" ").join("-");
|
||||
const pascalCase = componentName
|
||||
.split(" ")
|
||||
.reduce(
|
||||
(prev, curr) => prev + `${curr.at(0)?.toUpperCase()}${curr.slice(1).toLowerCase()}`,
|
||||
""
|
||||
);
|
||||
writeFileSync(
|
||||
path.join(__dirname, "../src/db/schemas", `${dashcase}.ts`),
|
||||
`
|
||||
import { z } from "zod";
|
||||
|
||||
import { TImmutableDBKeys } from "./models";
|
||||
|
||||
export const ${pascalCase}Schema = z.object({});
|
||||
|
||||
export type T${pascalCase} = z.infer<typeof ${pascalCase}Schema>;
|
||||
export type T${pascalCase}Insert = Omit<T${pascalCase}, TImmutableDBKeys>;
|
||||
export type T${pascalCase}Update = Partial<Omit<T${pascalCase}, TImmutableDBKeys>>;
|
||||
`
|
||||
);
|
||||
}
|
||||
|
||||
163
backend-pg/scripts/generate-schema-types.ts
Normal file
163
backend-pg/scripts/generate-schema-types.ts
Normal file
@@ -0,0 +1,163 @@
|
||||
import dotenv from "dotenv";
|
||||
import path from "path";
|
||||
import knex from "knex";
|
||||
import { appendFileSync, readFileSync, writeFileSync } from "fs";
|
||||
import promptSync from "prompt-sync";
|
||||
|
||||
const prompt = promptSync();
|
||||
|
||||
dotenv.config({
|
||||
path: path.join(__dirname, "../.env"),
|
||||
debug: true
|
||||
});
|
||||
|
||||
const db = knex({
|
||||
client: "pg",
|
||||
connection: process.env.DB_CONNECTION_URI
|
||||
});
|
||||
|
||||
const getZodPrimitiveType = (type: string) => {
|
||||
switch (type) {
|
||||
case "uuid":
|
||||
return "z.string().uuid()";
|
||||
case "character varying":
|
||||
return "z.string()";
|
||||
case "ARRAY":
|
||||
return "z.string().array()";
|
||||
case "boolean":
|
||||
return "z.boolean()";
|
||||
case "jsonb":
|
||||
return "z.string()";
|
||||
case "json":
|
||||
return "z.string()";
|
||||
case "timestamp with time zone":
|
||||
return "z.string().datetime()";
|
||||
case "integer":
|
||||
return "z.number()";
|
||||
case "text":
|
||||
return "z.string()";
|
||||
default:
|
||||
throw new Error(`Invalid type: ${type}`);
|
||||
}
|
||||
};
|
||||
|
||||
const getZodDefaultValue = (type: unknown, value: string | number | boolean | Object) => {
|
||||
if (!value || value === "null") return;
|
||||
switch (type) {
|
||||
case "uuid":
|
||||
return;
|
||||
case "character varying": {
|
||||
if (typeof value === "string" && value.includes("::")) {
|
||||
return `.default(${value.split("::")[0]})`;
|
||||
}
|
||||
return `.default(${value})`;
|
||||
}
|
||||
case "ARRAY":
|
||||
return `.default(${value})`;
|
||||
case "boolean":
|
||||
return `.default(${value})`;
|
||||
case "jsonb":
|
||||
return "z.string()";
|
||||
case "json":
|
||||
return "z.string()";
|
||||
case "timestamp with time zone": {
|
||||
if (value === "CURRENT_TIMESTAMP") return;
|
||||
return "z.string().datetime()";
|
||||
}
|
||||
case "integer": {
|
||||
if ((value as string).includes("nextval")) return;
|
||||
return `.default(${value})`;
|
||||
}
|
||||
case "text":
|
||||
if (typeof value === "string" && value.includes("::")) {
|
||||
return `.default(${value.split("::")[0]})`;
|
||||
}
|
||||
return `.default(${value})`;
|
||||
default:
|
||||
throw new Error(`Invalid type: ${type}`);
|
||||
}
|
||||
};
|
||||
|
||||
const main = async () => {
|
||||
const tables = (
|
||||
await db("information_schema.tables")
|
||||
.whereRaw("table_schema = current_schema()")
|
||||
.select<{ tableName: string }[]>("table_name as tableName")
|
||||
.orderBy("table_name")
|
||||
).filter(
|
||||
(el) => el.tableName !== "infisical_migrations_lock" && el.tableName !== "infisical_migrations"
|
||||
);
|
||||
|
||||
console.log("Select a table to generate schema");
|
||||
console.table(tables);
|
||||
console.log("all: all tables");
|
||||
const selectedTables = prompt("Type table numbers comma seperated: ");
|
||||
const tableNumbers =
|
||||
selectedTables !== "all" ? selectedTables.split(",").map((el) => Number(el)) : [];
|
||||
|
||||
for (let i = 0; i < tables.length; i++) {
|
||||
// skip if not desired table
|
||||
if (selectedTables !== "all" && !tableNumbers.includes(i)) continue;
|
||||
|
||||
const tableName = tables[i].tableName;
|
||||
const columns = await db(tableName).columnInfo();
|
||||
const columnNames = Object.keys(columns);
|
||||
|
||||
let schema = "";
|
||||
for (let colNum = 0; colNum < columnNames.length; colNum++) {
|
||||
const columnName = columnNames[colNum];
|
||||
const colInfo = columns[columnName];
|
||||
let ztype = getZodPrimitiveType(colInfo.type);
|
||||
if (colInfo.defaultValue) {
|
||||
const defaultValue = colInfo.defaultValue;
|
||||
const zSchema = getZodDefaultValue(colInfo.type, defaultValue);
|
||||
if (zSchema) {
|
||||
ztype = ztype.concat(zSchema);
|
||||
}
|
||||
}
|
||||
if (colInfo.nullable) {
|
||||
ztype = ztype.concat(".nullable().optional()");
|
||||
}
|
||||
schema = schema.concat(`${!schema ? "\n" : ""} ${columnName}: ${ztype},\n`);
|
||||
}
|
||||
|
||||
const dashcase = tableName.split("_").join("-");
|
||||
const pascalCase = tableName
|
||||
.split("_")
|
||||
.reduce(
|
||||
(prev, curr) => prev + `${curr.at(0)?.toUpperCase()}${curr.slice(1).toLowerCase()}`,
|
||||
""
|
||||
);
|
||||
writeFileSync(
|
||||
path.join(__dirname, "../src/db/schemas", `${dashcase}.ts`),
|
||||
`// Code generated by automation script, DO NOT EDIT.
|
||||
// Automated by pulling database and generating zod schema
|
||||
// To update. Just run npm run generate:schema
|
||||
// Written by akhilmhdh.
|
||||
|
||||
import { z } from "zod";
|
||||
|
||||
import { TImmutableDBKeys } from "./models";
|
||||
|
||||
export const ${pascalCase}Schema = z.object({${schema}});
|
||||
|
||||
export type T${pascalCase} = z.infer<typeof ${pascalCase}Schema>;
|
||||
export type T${pascalCase}Insert = Omit<T${pascalCase}, TImmutableDBKeys>;
|
||||
export type T${pascalCase}Update = Partial<Omit<T${pascalCase}, TImmutableDBKeys>>;
|
||||
`
|
||||
);
|
||||
|
||||
// const file = readFileSync(path.join(__dirname, "../src/db/schemas/index.ts"), "utf8");
|
||||
// if (!file.includes(`export * from "./${dashcase};"`)) {
|
||||
// appendFileSync(
|
||||
// path.join(__dirname, "../src/db/schemas/index.ts"),
|
||||
// `\nexport * from "./${dashcase}";`,
|
||||
// "utf8"
|
||||
// );
|
||||
// }
|
||||
}
|
||||
|
||||
process.exit(0);
|
||||
};
|
||||
|
||||
main();
|
||||
9
backend-pg/src/@types/fastify.d.ts
vendored
9
backend-pg/src/@types/fastify.d.ts
vendored
@@ -3,6 +3,8 @@ import { TAuthDalFactory } from "@app/services/auth/auth-dal";
|
||||
import { TAuthLoginFactory } from "@app/services/auth/auth-login-service";
|
||||
import { TAuthPasswordFactory } from "@app/services/auth/auth-password-service";
|
||||
import { TAuthSignupFactory } from "@app/services/auth/auth-signup-service";
|
||||
import { AuthMode } from "@app/services/auth/auth-signup-type";
|
||||
import { TAuthTokenServiceFactory } from "@app/services/token/token-service";
|
||||
|
||||
import "fastify";
|
||||
|
||||
@@ -14,6 +16,12 @@ declare module "fastify" {
|
||||
userId: string;
|
||||
user: TUser;
|
||||
};
|
||||
// identity injection. depending on which kinda of token the information is filled in auth
|
||||
auth: {
|
||||
authMode: AuthMode.JWT | AuthMode.API_KEY_V2 | AuthMode.API_KEY;
|
||||
userId: string;
|
||||
user: TUser;
|
||||
};
|
||||
}
|
||||
|
||||
interface FastifyInstance {
|
||||
@@ -21,6 +29,7 @@ declare module "fastify" {
|
||||
login: TAuthLoginFactory;
|
||||
password: TAuthPasswordFactory;
|
||||
signup: TAuthSignupFactory;
|
||||
authToken: TAuthTokenServiceFactory;
|
||||
};
|
||||
|
||||
// this is exclusive use for middlewares in which we need to inject data
|
||||
|
||||
62
backend-pg/src/@types/knex.d.ts
vendored
62
backend-pg/src/@types/knex.d.ts
vendored
@@ -2,42 +2,58 @@ import { Knex } from "knex";
|
||||
|
||||
import {
|
||||
TableName,
|
||||
TAuthTokens,
|
||||
TAuthTokenSessions,
|
||||
TAuthTokenSessionsInsert,
|
||||
TAuthTokenSessionsUpdate,
|
||||
TAuthTokensUpdate,
|
||||
TBackupPrivateKey,
|
||||
TBackupPrivateKeyInsert,
|
||||
TToken,
|
||||
TTokenInsert,
|
||||
TTokenUpdate,
|
||||
TUser,
|
||||
TUserEncryptionKey,
|
||||
TUserEncryptionKeyInsert,
|
||||
TUserEncryptionKeyUpdate,
|
||||
TUserInsert,
|
||||
TUserUpdate
|
||||
TBackupPrivateKeyUpdate,
|
||||
TOrganizationMemberships,
|
||||
TOrganizations,
|
||||
TOrganizationsInsert,
|
||||
TOrganizationsUpdate,
|
||||
TUserEncryptionKeys,
|
||||
TUserEncryptionKeysInsert,
|
||||
TUserEncryptionKeysUpdate,
|
||||
TUsers,
|
||||
TUsersInsert,
|
||||
TUsersUpdate
|
||||
} from "@app/db/schemas";
|
||||
import {
|
||||
TTokenSession,
|
||||
TTokenSessionInsert,
|
||||
TTokenSessionUpdate
|
||||
} from "@app/db/schemas/token-session";
|
||||
|
||||
declare module "knex/types/tables" {
|
||||
interface Tables extends { [key in TableName]: Knex.CompositeTableType<any> } {
|
||||
[TableName.Users]: Knex.CompositeTableType<TUser, TUserInsert, TUserUpdate>;
|
||||
[TableName.Users]: Knex.CompositeTableType<TUsers, TUsersInsert, TUsersUpdate>;
|
||||
[TableName.UserEncryptionKey]: Knex.CompositeTableType<
|
||||
TUserEncryptionKey,
|
||||
TUserEncryptionKeyInsert,
|
||||
TUserEncryptionKeyUpdate
|
||||
TUserEncryptionKeys,
|
||||
TUserEncryptionKeysInsert,
|
||||
TUserEncryptionKeysUpdate
|
||||
>;
|
||||
[TableName.AuthTokens]: Knex.CompositeTableType<
|
||||
TAuthTokens,
|
||||
TAuthTokensInsert,
|
||||
TAuthTokensUpdate
|
||||
>;
|
||||
[TableName.AuthTokens]: Knex.CompositeTableType<TToken, TTokenInsert, TTokenUpdate>;
|
||||
[TableName.AuthTokenSession]: Knex.CompositeTableType<
|
||||
TTokenSession,
|
||||
TTokenSessionInsert,
|
||||
TTokenSessionUpdate
|
||||
TAuthTokenSessions,
|
||||
TAuthTokenSessionsInsert,
|
||||
TAuthTokenSessionsUpdate
|
||||
>;
|
||||
[TableName.BackupPrivateKey]: Knex.CompositeTableType<
|
||||
TBackupPrivateKey,
|
||||
TBackupPrivateKeyInsert,
|
||||
TTokenSessionUpdate
|
||||
TBackupPrivateKeyUpdate
|
||||
>;
|
||||
[TableName.Organization]: Knex.CompositeTableType<
|
||||
TOrganizations,
|
||||
TOrganizationsInsert,
|
||||
TOrganizationsUpdate
|
||||
>;
|
||||
[TableName.OrgMembership]: Knex.CompositeTableType<
|
||||
TOrganizationMemberships,
|
||||
TOrganizationsInsert,
|
||||
TOrganizationsUpdate
|
||||
>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ export async function up(knex: Knex): Promise<void> {
|
||||
const isTablePresent = await knex.schema.hasTable(TableName.Users);
|
||||
if (!isTablePresent) {
|
||||
await knex.schema.createTable(TableName.Users, (t) => {
|
||||
t.uuid("id").primary().defaultTo(knex.fn.uuid());
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("email").notNullable();
|
||||
t.specificType("authMethods", "text[]");
|
||||
t.boolean("superAdmin").defaultTo(false);
|
||||
|
||||
@@ -6,10 +6,10 @@ export async function up(knex: Knex): Promise<void> {
|
||||
const isTablePresent = await knex.schema.hasTable(TableName.UserEncryptionKey);
|
||||
if (!isTablePresent) {
|
||||
await knex.schema.createTable(TableName.UserEncryptionKey, (t) => {
|
||||
t.increments().primary();
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.text("clientPublicKey");
|
||||
t.text("serverPrivateKey");
|
||||
t.text("encryptionVersion").defaultTo(1);
|
||||
t.integer("encryptionVersion").defaultTo(1);
|
||||
t.text("protectedKey").notNullable();
|
||||
t.text("protectedKeyIV").notNullable();
|
||||
t.text("protectedKeyTag").notNullable();
|
||||
|
||||
@@ -6,6 +6,7 @@ export async function up(knex: Knex): Promise<void> {
|
||||
const isTablePresent = await knex.schema.hasTable(TableName.AuthTokens);
|
||||
if (!isTablePresent) {
|
||||
await knex.schema.createTable(TableName.AuthTokens, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("type").notNullable();
|
||||
t.string("phoneNumber");
|
||||
t.string("tokenHash").notNullable();
|
||||
|
||||
@@ -7,7 +7,7 @@ export async function up(knex: Knex): Promise<void> {
|
||||
const isTablePresent = await knex.schema.hasTable(TableName.AuthTokenSession);
|
||||
if (!isTablePresent) {
|
||||
await knex.schema.createTable(TableName.AuthTokenSession, (t) => {
|
||||
t.increments();
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("ip").notNullable();
|
||||
t.string("userAgent");
|
||||
t.integer("refreshVersion").notNullable().defaultTo(1);
|
||||
|
||||
@@ -6,7 +6,7 @@ export async function up(knex: Knex): Promise<void> {
|
||||
const doesTableExist = await knex.schema.hasTable(TableName.BackupPrivateKey);
|
||||
if (!doesTableExist) {
|
||||
await knex.schema.createTable(TableName.BackupPrivateKey, (t) => {
|
||||
t.increments();
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("encryptedPrivateKey").notNullable();
|
||||
t.string("iv").notNullable();
|
||||
t.string("tag").notNullable();
|
||||
|
||||
24
backend-pg/src/db/migrations/20231204092737_organization.ts
Normal file
24
backend-pg/src/db/migrations/20231204092737_organization.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
const isTablePresent = await knex.schema.hasTable(TableName.Organization);
|
||||
if (!isTablePresent) {
|
||||
await knex.schema.createTable(TableName.Organization, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("name").notNullable();
|
||||
t.string("customerId");
|
||||
// does not need update trigger we will do it manually
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
}
|
||||
// this is a one time function
|
||||
await createOnUpdateTrigger(knex, TableName.Organization);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.Organization);
|
||||
await dropOnUpdateTrigger(knex, TableName.Organization);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
import { OrgMembershipStatus } from "../schemas/models";
|
||||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
const isTablePresent = await knex.schema.hasTable(TableName.OrgMembership);
|
||||
if (!isTablePresent) {
|
||||
await knex.schema.createTable(TableName.OrgMembership, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("role").notNullable();
|
||||
t.string("status").notNullable().defaultTo(OrgMembershipStatus.Invited);
|
||||
t.string("inviteEmail");
|
||||
// does not need update trigger we will do it manually
|
||||
t.timestamps(true, true, true);
|
||||
t.uuid("userId").notNullable();
|
||||
t.foreign("userId").references("id").inTable(TableName.Users).onDelete("CASCADE");
|
||||
t.uuid("orgId").notNullable();
|
||||
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||
});
|
||||
}
|
||||
// this is a one time function
|
||||
await createOnUpdateTrigger(knex, TableName.OrgMembership);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.OrgMembership);
|
||||
await dropOnUpdateTrigger(knex, TableName.OrgMembership);
|
||||
}
|
||||
24
backend-pg/src/db/schemas/auth-token-sessions.ts
Normal file
24
backend-pg/src/db/schemas/auth-token-sessions.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
// Code generated by automation script, DO NOT EDIT.
|
||||
// Automated by pulling database and generating zod schema
|
||||
// To update. Just run npm run generate:schema
|
||||
// Written by akhilmhdh.
|
||||
|
||||
import { z } from "zod";
|
||||
|
||||
import { TImmutableDBKeys } from "./models";
|
||||
|
||||
export const AuthTokenSessionsSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
ip: z.string(),
|
||||
userAgent: z.string().nullable().optional(),
|
||||
refreshVersion: z.number().default(1),
|
||||
accessVersion: z.number().default(1),
|
||||
lastUsed: z.string().datetime(),
|
||||
createdAt: z.string().datetime(),
|
||||
updatedAt: z.string().datetime(),
|
||||
userId: z.string().uuid(),
|
||||
});
|
||||
|
||||
export type TAuthTokenSessions = z.infer<typeof AuthTokenSessionsSchema>;
|
||||
export type TAuthTokenSessionsInsert = Omit<TAuthTokenSessions, TImmutableDBKeys>;
|
||||
export type TAuthTokenSessionsUpdate = Partial<Omit<TAuthTokenSessions, TImmutableDBKeys>>;
|
||||
24
backend-pg/src/db/schemas/auth-tokens.ts
Normal file
24
backend-pg/src/db/schemas/auth-tokens.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
// Code generated by automation script, DO NOT EDIT.
|
||||
// Automated by pulling database and generating zod schema
|
||||
// To update. Just run npm run generate:schema
|
||||
// Written by akhilmhdh.
|
||||
|
||||
import { z } from "zod";
|
||||
|
||||
import { TImmutableDBKeys } from "./models";
|
||||
|
||||
export const AuthTokensSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
type: z.string(),
|
||||
phoneNumber: z.string().nullable().optional(),
|
||||
tokenHash: z.string(),
|
||||
triesLeft: z.number().nullable().optional(),
|
||||
expiresAt: z.string().datetime(),
|
||||
createdAt: z.string().datetime(),
|
||||
updatedAt: z.string().datetime(),
|
||||
userId: z.string().uuid().nullable().optional(),
|
||||
});
|
||||
|
||||
export type TAuthTokens = z.infer<typeof AuthTokensSchema>;
|
||||
export type TAuthTokensInsert = Omit<TAuthTokens, TImmutableDBKeys>;
|
||||
export type TAuthTokensUpdate = Partial<Omit<TAuthTokens, TImmutableDBKeys>>;
|
||||
@@ -1,19 +1,24 @@
|
||||
// Code generated by automation script, DO NOT EDIT.
|
||||
// Automated by pulling database and generating zod schema
|
||||
// To update. Just run npm run generate:schema
|
||||
// Written by akhilmhdh.
|
||||
|
||||
import { z } from "zod";
|
||||
|
||||
import { SecretEncryptionAlgo, SecretKeyEncoding, TImmutableDBKeys } from "./models";
|
||||
import { TImmutableDBKeys } from "./models";
|
||||
|
||||
export const BackupPrivateKeySchema = z.object({
|
||||
id: z.string(),
|
||||
userId: z.string(),
|
||||
id: z.string().uuid(),
|
||||
encryptedPrivateKey: z.string(),
|
||||
iv: z.string(),
|
||||
tag: z.string(),
|
||||
algorithm: z.nativeEnum(SecretEncryptionAlgo),
|
||||
keyEncoding: z.nativeEnum(SecretKeyEncoding),
|
||||
algorithm: z.string(),
|
||||
keyEncoding: z.string(),
|
||||
salt: z.string(),
|
||||
verifier: z.string(),
|
||||
createdAt: z.string().datetime(),
|
||||
updatedAt: z.string().datetime()
|
||||
updatedAt: z.string().datetime(),
|
||||
userId: z.string().uuid(),
|
||||
});
|
||||
|
||||
export type TBackupPrivateKey = z.infer<typeof BackupPrivateKeySchema>;
|
||||
|
||||
@@ -1,15 +1,8 @@
|
||||
export {
|
||||
BackupPrivateKeySchema,
|
||||
TBackupPrivateKey,
|
||||
TBackupPrivateKeyInsert,
|
||||
TBackupPrivateKeyUpdate
|
||||
} from "./backup-private-key";
|
||||
export { TableName } from "./models";
|
||||
export { TokenSchema, TToken, TTokenInsert, TTokenUpdate } from "./token";
|
||||
export { AuthMethod, TUser, TUserInsert, TUserUpdate, UserSchema } from "./user";
|
||||
export {
|
||||
TUserEncryptionKey,
|
||||
TUserEncryptionKeyInsert,
|
||||
TUserEncryptionKeyUpdate,
|
||||
UserEncryptionKey
|
||||
} from "./user-encryption-key";
|
||||
export * from "./auth-token-sessions";
|
||||
export * from "./auth-tokens";
|
||||
export * from "./backup-private-key";
|
||||
export * from "./models";
|
||||
export * from "./organization-memberships";
|
||||
export * from "./organizations";
|
||||
export * from "./user-encryption-keys";
|
||||
export * from "./users";
|
||||
|
||||
@@ -1,13 +1,36 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export enum TableName {
|
||||
Users = "users",
|
||||
UserEncryptionKey = "user_encryption_keys",
|
||||
AuthTokens = "auth_tokens",
|
||||
AuthTokenSession = "auth_token_sessions",
|
||||
BackupPrivateKey = "backup_private_key"
|
||||
BackupPrivateKey = "backup_private_key",
|
||||
Organization = "organizations",
|
||||
OrgMembership = "organization_memberships"
|
||||
}
|
||||
|
||||
export type TImmutableDBKeys = "id" | "createdAt" | "updatedAt";
|
||||
|
||||
export const UserDeviceSchema = z
|
||||
.object({
|
||||
ip: z.string(),
|
||||
userAgent: z.string()
|
||||
})
|
||||
.array()
|
||||
.default([]);
|
||||
|
||||
export enum OrgMembershipRole {
|
||||
Admin = "admin",
|
||||
Member = "member",
|
||||
Custom = "custom"
|
||||
}
|
||||
|
||||
export enum OrgMembershipStatus {
|
||||
Invited = "invited",
|
||||
Accepted = "accepted"
|
||||
}
|
||||
|
||||
export enum SecretEncryptionAlgo {
|
||||
AES_256_GCM = "aes-256-gcm"
|
||||
}
|
||||
|
||||
23
backend-pg/src/db/schemas/organization-memberships.ts
Normal file
23
backend-pg/src/db/schemas/organization-memberships.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
// Code generated by automation script, DO NOT EDIT.
|
||||
// Automated by pulling database and generating zod schema
|
||||
// To update. Just run npm run generate:schema
|
||||
// Written by akhilmhdh.
|
||||
|
||||
import { z } from "zod";
|
||||
|
||||
import { TImmutableDBKeys } from "./models";
|
||||
|
||||
export const OrganizationMembershipsSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
role: z.string(),
|
||||
status: z.string().default('invited'),
|
||||
inviteEmail: z.string().nullable().optional(),
|
||||
createdAt: z.string().datetime(),
|
||||
updatedAt: z.string().datetime(),
|
||||
userId: z.string().uuid(),
|
||||
orgId: z.string().uuid(),
|
||||
});
|
||||
|
||||
export type TOrganizationMemberships = z.infer<typeof OrganizationMembershipsSchema>;
|
||||
export type TOrganizationMembershipsInsert = Omit<TOrganizationMemberships, TImmutableDBKeys>;
|
||||
export type TOrganizationMembershipsUpdate = Partial<Omit<TOrganizationMemberships, TImmutableDBKeys>>;
|
||||
20
backend-pg/src/db/schemas/organizations.ts
Normal file
20
backend-pg/src/db/schemas/organizations.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
// Code generated by automation script, DO NOT EDIT.
|
||||
// Automated by pulling database and generating zod schema
|
||||
// To update. Just run npm run generate:schema
|
||||
// Written by akhilmhdh.
|
||||
|
||||
import { z } from "zod";
|
||||
|
||||
import { TImmutableDBKeys } from "./models";
|
||||
|
||||
export const OrganizationsSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
name: z.string(),
|
||||
customerId: z.string().nullable().optional(),
|
||||
createdAt: z.string().datetime(),
|
||||
updatedAt: z.string().datetime(),
|
||||
});
|
||||
|
||||
export type TOrganizations = z.infer<typeof OrganizationsSchema>;
|
||||
export type TOrganizationsInsert = Omit<TOrganizations, TImmutableDBKeys>;
|
||||
export type TOrganizationsUpdate = Partial<Omit<TOrganizations, TImmutableDBKeys>>;
|
||||
@@ -1,17 +0,0 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { TImmutableDBKeys } from "./models";
|
||||
|
||||
export const TokenSessionSchema = z.object({
|
||||
id: z.string(),
|
||||
userId: z.string(),
|
||||
ip: z.string(),
|
||||
userAgent: z.string(),
|
||||
refreshVersion: z.number().default(1),
|
||||
accessVersion: z.number().default(1),
|
||||
lastUsed: z.string().datetime()
|
||||
});
|
||||
|
||||
export type TTokenSession = z.infer<typeof TokenSessionSchema>;
|
||||
export type TTokenSessionInsert = Omit<TTokenSession, TImmutableDBKeys>;
|
||||
export type TTokenSessionUpdate = Partial<Omit<TTokenSession, TImmutableDBKeys>>;
|
||||
@@ -1,19 +0,0 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { TImmutableDBKeys } from "./models";
|
||||
|
||||
export const TokenSchema = z.object({
|
||||
id: z.number(),
|
||||
type: z.enum(["emailConfirmation", "emailMfa", "organizationInvitation", "passwordReset"]),
|
||||
phoneNumber: z.string().optional(),
|
||||
tokenHash: z.string(),
|
||||
triesLeft: z.number().optional(),
|
||||
expiresAt: z.string().datetime().optional(),
|
||||
createdAt: z.string().datetime(),
|
||||
updatedAt: z.string().datetime(),
|
||||
userId: z.string().optional()
|
||||
});
|
||||
|
||||
export type TToken = z.infer<typeof TokenSchema>;
|
||||
export type TTokenInsert = Omit<TToken, TImmutableDBKeys>;
|
||||
export type TTokenUpdate = Partial<Omit<TToken, TImmutableDBKeys>>;
|
||||
@@ -1,26 +0,0 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { PickRequired } from "@app/lib/types";
|
||||
|
||||
import { TImmutableDBKeys } from "./models";
|
||||
|
||||
export const UserEncryptionKey = z.object({
|
||||
id: z.number(),
|
||||
userId: z.string(),
|
||||
serverPrivateKey: z.string().optional().nullable(),
|
||||
clientPublicKey: z.string().optional().nullable(),
|
||||
encryptionVersion: z.number().default(1).optional(),
|
||||
protectedKey: z.string(),
|
||||
protectedKeyIV: z.string(),
|
||||
protectedKeyTag: z.string(),
|
||||
publicKey: z.string(),
|
||||
encryptedPrivateKey: z.string(),
|
||||
iv: z.string(),
|
||||
tag: z.string(),
|
||||
salt: z.string(),
|
||||
verifier: z.string()
|
||||
});
|
||||
|
||||
export type TUserEncryptionKey = z.infer<typeof UserEncryptionKey>;
|
||||
export type TUserEncryptionKeyInsert = Omit<PickRequired<TUserEncryptionKey>, TImmutableDBKeys>;
|
||||
export type TUserEncryptionKeyUpdate = Partial<Omit<TUserEncryptionKey, TImmutableDBKeys>>;
|
||||
29
backend-pg/src/db/schemas/user-encryption-keys.ts
Normal file
29
backend-pg/src/db/schemas/user-encryption-keys.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
// Code generated by automation script, DO NOT EDIT.
|
||||
// Automated by pulling database and generating zod schema
|
||||
// To update. Just run npm run generate:schema
|
||||
// Written by akhilmhdh.
|
||||
|
||||
import { z } from "zod";
|
||||
|
||||
import { TImmutableDBKeys } from "./models";
|
||||
|
||||
export const UserEncryptionKeysSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
clientPublicKey: z.string().nullable().optional(),
|
||||
serverPrivateKey: z.string().nullable().optional(),
|
||||
encryptionVersion: z.number().default(1).nullable().optional(),
|
||||
protectedKey: z.string(),
|
||||
protectedKeyIV: z.string(),
|
||||
protectedKeyTag: z.string(),
|
||||
publicKey: z.string(),
|
||||
encryptedPrivateKey: z.string(),
|
||||
iv: z.string(),
|
||||
tag: z.string(),
|
||||
salt: z.string(),
|
||||
verifier: z.string(),
|
||||
userId: z.string().uuid(),
|
||||
});
|
||||
|
||||
export type TUserEncryptionKeys = z.infer<typeof UserEncryptionKeysSchema>;
|
||||
export type TUserEncryptionKeysInsert = Omit<TUserEncryptionKeys, TImmutableDBKeys>;
|
||||
export type TUserEncryptionKeysUpdate = Partial<Omit<TUserEncryptionKeys, TImmutableDBKeys>>;
|
||||
@@ -1,38 +0,0 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { TImmutableDBKeys } from "./models";
|
||||
|
||||
export enum AuthMethod {
|
||||
EMAIL = "email",
|
||||
GOOGLE = "google",
|
||||
GITHUB = "github",
|
||||
GITLAB = "gitlab",
|
||||
OKTA_SAML = "okta-saml",
|
||||
AZURE_SAML = "azure-saml",
|
||||
JUMPCLOUD_SAML = "jumpcloud-saml"
|
||||
}
|
||||
|
||||
export const UserSchema = z.object({
|
||||
id: z.string(),
|
||||
authMethods: z.nativeEnum(AuthMethod).array().default([AuthMethod.EMAIL]).optional().nullable(),
|
||||
email: z.string(),
|
||||
isSuperAdmin: z.boolean().default(false).optional(),
|
||||
firstName: z.string().optional().nullable(),
|
||||
lastName: z.string().optional().nullable(),
|
||||
isMfaEnabled: z.boolean().default(false).optional(),
|
||||
mfaMethods: z.string().array().default([]).optional().nullable(),
|
||||
isAccepted: z.boolean().default(false).optional(),
|
||||
devices: z.string().nullable().optional()
|
||||
});
|
||||
|
||||
export const UserDeviceSchema = z
|
||||
.object({
|
||||
ip: z.string(),
|
||||
userAgent: z.string()
|
||||
})
|
||||
.array()
|
||||
.default([]);
|
||||
|
||||
export type TUser = z.infer<typeof UserSchema>;
|
||||
export type TUserInsert = Omit<TUser, TImmutableDBKeys>;
|
||||
export type TUserUpdate = Partial<Omit<TUser, "id" | "email">>;
|
||||
27
backend-pg/src/db/schemas/users.ts
Normal file
27
backend-pg/src/db/schemas/users.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
// Code generated by automation script, DO NOT EDIT.
|
||||
// Automated by pulling database and generating zod schema
|
||||
// To update. Just run npm run generate:schema
|
||||
// Written by akhilmhdh.
|
||||
|
||||
import { z } from "zod";
|
||||
|
||||
import { TImmutableDBKeys } from "./models";
|
||||
|
||||
export const UsersSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
email: z.string(),
|
||||
authMethods: z.string().array().nullable().optional(),
|
||||
superAdmin: z.boolean().default(false).nullable().optional(),
|
||||
firstName: z.string().nullable().optional(),
|
||||
lastName: z.string().nullable().optional(),
|
||||
isAccepted: z.boolean().default(false).nullable().optional(),
|
||||
isMfaEnabled: z.boolean().default(false).nullable().optional(),
|
||||
mfaMethods: z.string().array().nullable().optional(),
|
||||
devices: z.string().nullable().optional(),
|
||||
createdAt: z.string().datetime(),
|
||||
updatedAt: z.string().datetime(),
|
||||
});
|
||||
|
||||
export type TUsers = z.infer<typeof UsersSchema>;
|
||||
export type TUsersInsert = Omit<TUsers, TImmutableDBKeys>;
|
||||
export type TUsersUpdate = Partial<Omit<TUsers, TImmutableDBKeys>>;
|
||||
@@ -16,7 +16,7 @@ export class UnauthorizedError extends Error {
|
||||
|
||||
error: unknown;
|
||||
|
||||
constructor({ name, error, message }: { message?: string; 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;
|
||||
|
||||
10
backend-pg/src/lib/knex/index.ts
Normal file
10
backend-pg/src/lib/knex/index.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
export const withTransaction = <K extends object>(db: Knex, dal: K) => ({
|
||||
transaction: async <T>(cb: (tx: Knex) => T) =>
|
||||
db.transaction(async (trx) => {
|
||||
const res = await cb(trx);
|
||||
return res;
|
||||
}),
|
||||
...dal
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
import { z } from "zod";
|
||||
import { z,ZodTypeAny } from "zod";
|
||||
|
||||
// this is a patched zod string to remove empty string to undefined
|
||||
export const zpStr = <T extends z.ZodString>(
|
||||
export const zpStr = <T extends ZodTypeAny>(
|
||||
schema: T,
|
||||
opt: { stripNull: boolean } = { stripNull: true }
|
||||
) =>
|
||||
|
||||
75
backend-pg/src/server/plugins/auth/inject-identity.ts
Normal file
75
backend-pg/src/server/plugins/auth/inject-identity.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { FastifyRequest } from "fastify";
|
||||
import jwt, { JwtPayload } from "jsonwebtoken";
|
||||
|
||||
import { getConfig } from "@app/lib/config/env";
|
||||
import { UnauthorizedError } from "@app/lib/errors";
|
||||
import { AuthMode, AuthModeJwtTokenPayload, AuthTokenType } from "@app/services/auth/auth-type";
|
||||
|
||||
const extractAuth = async (req: FastifyRequest, jwtSecret: string) => {
|
||||
const apiKey = req.headers?.["x-api-key"];
|
||||
if (apiKey) {
|
||||
return { authMode: AuthMode.API_KEY, token: apiKey };
|
||||
}
|
||||
const authHeader = req.headers?.authorization;
|
||||
if (!authHeader) return { authMode: null, token: null };
|
||||
|
||||
const authTokenValue = authHeader.slice(7); // slice of after Bearer
|
||||
if (authTokenValue.startsWith("st.")) {
|
||||
return { authMode: AuthMode.SERVICE_TOKEN, token: authTokenValue } as const;
|
||||
}
|
||||
|
||||
const decodedToken = jwt.verify(authTokenValue, jwtSecret) as JwtPayload;
|
||||
switch (decodedToken.authTokenType) {
|
||||
case AuthTokenType.ACCESS_TOKEN:
|
||||
return { authMode: AuthMode.JWT, token: decodedToken as AuthModeJwtTokenPayload } as const;
|
||||
case AuthTokenType.API_KEY:
|
||||
return { authMode: AuthMode.API_KEY_V2, token: decodedToken } as const;
|
||||
case AuthMode.SERVICE_ACCESS_TOKEN:
|
||||
return { authMode: AuthMode.SERVICE_ACCESS_TOKEN, token: decodedToken } as const;
|
||||
default:
|
||||
throw new UnauthorizedError({ name: "Invalid token type" });
|
||||
}
|
||||
};
|
||||
|
||||
const getJwtIdentity = async (server: FastifyZodProvider, token: AuthModeJwtTokenPayload) => {
|
||||
const session = await server.services.authToken.getUserTokenSessionById(
|
||||
token.tokenVersionId,
|
||||
token.userId
|
||||
);
|
||||
|
||||
if (!session) throw new UnauthorizedError({ name: "Session not found" });
|
||||
if (token.accessVersion !== session.accessVersion)
|
||||
throw new UnauthorizedError({ name: "Stale session" });
|
||||
|
||||
const user = await server.store.user.getUserById(session.userId);
|
||||
if (!user || !user.isAccepted) throw new UnauthorizedError({ name: "Token user not found" });
|
||||
|
||||
return user;
|
||||
};
|
||||
|
||||
export const injectIdentity = (server: FastifyZodProvider) => {
|
||||
server.decorateRequest("auth", null);
|
||||
server.addHook("onRequest", async (req) => {
|
||||
const appCfg = getConfig();
|
||||
const { authMode, token } = await extractAuth(req, appCfg.JWT_AUTH_SECRET);
|
||||
if (!authMode) return;
|
||||
// TODO(akhilmhdh-pg): fill in rest of auth mode logic
|
||||
switch (authMode) {
|
||||
case AuthMode.JWT: {
|
||||
const user = await getJwtIdentity(server, token as AuthModeJwtTokenPayload);
|
||||
req.auth = { authMode: AuthMode.JWT, user, userId: user.id };
|
||||
break;
|
||||
}
|
||||
case AuthMode.SERVICE_TOKEN:
|
||||
break;
|
||||
case AuthMode.SERVICE_ACCESS_TOKEN:
|
||||
break;
|
||||
case AuthMode.API_KEY:
|
||||
break;
|
||||
case AuthMode.API_KEY_V2:
|
||||
break;
|
||||
default:
|
||||
throw new UnauthorizedError({ name: "Unknown token strategy" });
|
||||
}
|
||||
});
|
||||
};
|
||||
17
backend-pg/src/server/plugins/auth/verify-auth.ts
Normal file
17
backend-pg/src/server/plugins/auth/verify-auth.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { FastifyRequest } from "fastify";
|
||||
|
||||
import { UnauthorizedError } from "@app/lib/errors";
|
||||
import { AuthMode } from "@app/services/auth/auth-type";
|
||||
|
||||
export const verifyAuth =
|
||||
<T extends FastifyRequest>(authStrats: AuthMode[]) =>
|
||||
(req: T) => {
|
||||
if (!Array.isArray(authStrats)) throw new Error("Auth strategy must be array");
|
||||
if (!req.auth)
|
||||
throw new UnauthorizedError({ name: "Unauthorized access", message: "Token missing" });
|
||||
|
||||
const isAccessAllowed = authStrats.some((strat) => strat === req.auth.authMode);
|
||||
if (!isAccessAllowed) {
|
||||
throw new UnauthorizedError({ name: `${req.url} Unauthorized Access` });
|
||||
}
|
||||
};
|
||||
@@ -11,6 +11,7 @@ import { tokenServiceFactory } from "@app/services/token/token-service";
|
||||
import { registerV1Routes } from "./v1";
|
||||
import { registerV2Routes } from "./v2";
|
||||
import { registerV3Routes } from "./v3";
|
||||
import { injectIdentity } from "../plugins/auth/inject-identity";
|
||||
|
||||
export const registerRoutes = async (
|
||||
server: FastifyZodProvider,
|
||||
@@ -37,6 +38,8 @@ export const registerRoutes = async (
|
||||
user: authDal
|
||||
} as FastifyZodProvider["store"]);
|
||||
|
||||
await server.register(injectIdentity);
|
||||
|
||||
// register routes for v1
|
||||
await server.register(registerV1Routes, { prefix: "/v1" });
|
||||
await server.register(registerV2Routes, { prefix: "/v2" });
|
||||
|
||||
@@ -2,6 +2,8 @@ import { z } from "zod";
|
||||
|
||||
import { BackupPrivateKeySchema } from "@app/db/schemas";
|
||||
import { getConfig } from "@app/lib/config/env";
|
||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||
import { AuthMode } from "@app/services/auth/auth-type";
|
||||
|
||||
export const registerPasswordRouter = async (server: FastifyZodProvider) => {
|
||||
server.route({
|
||||
@@ -18,6 +20,7 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => {
|
||||
})
|
||||
}
|
||||
},
|
||||
onRequest: verifyAuth([AuthMode.JWT]),
|
||||
handler: async (req) => {
|
||||
const { salt, serverPublicKey } = await server.services.password.generateServerPubKey(
|
||||
req.auth.userId,
|
||||
@@ -48,6 +51,7 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => {
|
||||
})
|
||||
}
|
||||
},
|
||||
onRequest: verifyAuth([AuthMode.JWT]),
|
||||
handler: async (req, res) => {
|
||||
const appCfg = getConfig();
|
||||
await server.services.password.changePassword({ ...req.body, userId: req.auth.userId });
|
||||
@@ -65,6 +69,7 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => {
|
||||
server.route({
|
||||
method: "POST",
|
||||
url: "/backup-private-key",
|
||||
onRequest: verifyAuth([AuthMode.JWT]),
|
||||
schema: {
|
||||
body: z.object({
|
||||
clientProof: z.string().trim(),
|
||||
@@ -95,6 +100,7 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => {
|
||||
server.route({
|
||||
method: "GET",
|
||||
url: "/backup-private-key",
|
||||
onRequest: verifyAuth([AuthMode.JWT]),
|
||||
schema: {
|
||||
response: {
|
||||
200: z.object({
|
||||
|
||||
@@ -2,20 +2,24 @@ import jwt, { JwtPayload } from "jsonwebtoken";
|
||||
import { z } from "zod";
|
||||
|
||||
import { getConfig } from "@app/lib/config/env";
|
||||
import { AuthTokenType } from "@app/services/auth/auth-signup-type";
|
||||
import { AuthTokenType } from "@app/services/auth/auth-type";
|
||||
|
||||
export const registerMfaRouter = async (server: FastifyZodProvider) => {
|
||||
const cfg = getConfig();
|
||||
|
||||
server.decorateRequest("mfa", null);
|
||||
server.addHook("preParsing", async (req, res) => {
|
||||
const authorizationHeader = req.headers.authorization;
|
||||
|
||||
if (!authorizationHeader || !authorizationHeader.startsWith("Bearer ")) {
|
||||
res.status(401).send({ error: "Missing bearer token" });
|
||||
return;
|
||||
return res;
|
||||
}
|
||||
const token = authorizationHeader.split(" ")[1];
|
||||
if (!token) res.status(401).send({ error: "Missing bearer token" });
|
||||
if (!token) {
|
||||
res.status(401).send({ error: "Missing bearer token" });
|
||||
return res;
|
||||
}
|
||||
|
||||
const decodedToken = jwt.verify(token, cfg.JWT_AUTH_SECRET) as JwtPayload;
|
||||
if (decodedToken.authTokenType !== AuthTokenType.MFA_TOKEN)
|
||||
@@ -23,8 +27,7 @@ export const registerMfaRouter = async (server: FastifyZodProvider) => {
|
||||
|
||||
const user = await server.store.user.getUserById(decodedToken.userId);
|
||||
if (!user) throw new Error("User not found");
|
||||
req.mfa.userId = user.id;
|
||||
req.mfa.user = user;
|
||||
req.mfa = { userId: user.id, user };
|
||||
});
|
||||
|
||||
server.route({
|
||||
@@ -52,7 +55,7 @@ export const registerMfaRouter = async (server: FastifyZodProvider) => {
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
encryptionVersion: z.number().default(1).optional(),
|
||||
encryptionVersion: z.number().default(1).nullable().optional(),
|
||||
protectedKey: z.string(),
|
||||
protectedKeyIV: z.string(),
|
||||
protectedKeyTag: z.string(),
|
||||
|
||||
@@ -44,7 +44,7 @@ export const registerLoginRouter = async (server: FastifyZodProvider) => {
|
||||
z.object({ mfaEnabled: z.literal(true), token: z.string() }),
|
||||
z.object({
|
||||
mfaEnabled: z.literal(false),
|
||||
encryptionVersion: z.number().default(1).optional(),
|
||||
encryptionVersion: z.number().default(1).nullable().optional(),
|
||||
protectedKey: z.string(),
|
||||
protectedKeyIV: z.string(),
|
||||
protectedKeyTag: z.string(),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { UserSchema } from "@app/db/schemas";
|
||||
import { UsersSchema } from "@app/db/schemas";
|
||||
import { getConfig } from "@app/lib/config/env";
|
||||
|
||||
export const registerSignupRouter = async (server: FastifyZodProvider) => {
|
||||
@@ -35,7 +35,7 @@ export const registerSignupRouter = async (server: FastifyZodProvider) => {
|
||||
200: z.object({
|
||||
message: z.string(),
|
||||
token: z.string(),
|
||||
user: UserSchema
|
||||
user: UsersSchema
|
||||
})
|
||||
}
|
||||
},
|
||||
@@ -72,7 +72,7 @@ export const registerSignupRouter = async (server: FastifyZodProvider) => {
|
||||
response: {
|
||||
200: z.object({
|
||||
message: z.string(),
|
||||
user: UserSchema,
|
||||
user: UsersSchema,
|
||||
token: z.string()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TDbClient } from "@app/db";
|
||||
import { TableName, TBackupPrivateKey, TUser, TUserEncryptionKey } from "@app/db/schemas";
|
||||
import { TableName, TBackupPrivateKey, TUserEncryptionKeys, TUsers } from "@app/db/schemas";
|
||||
import { withTransaction } from "@app/lib/knex";
|
||||
|
||||
export type TAuthDalFactory = ReturnType<typeof authDalFactory>;
|
||||
|
||||
export const authDalFactory = (db: TDbClient) => {
|
||||
// getters
|
||||
const getUserByEmail = async (email: string): Promise<TUser | undefined> =>
|
||||
const getUserByEmail = async (email: string): Promise<TUsers | undefined> =>
|
||||
db(TableName.Users).where({ email }).select("*").first();
|
||||
|
||||
const getUserById = async (userId: string): Promise<TUser | undefined> =>
|
||||
const getUserById = async (userId: string): Promise<TUsers | undefined> =>
|
||||
db(TableName.Users).where({ id: userId }).select("*").first();
|
||||
|
||||
const getUserEncKeyByEmail = async (email: string) =>
|
||||
@@ -39,8 +40,8 @@ export const authDalFactory = (db: TDbClient) => {
|
||||
// all inserts and updates
|
||||
const createUser = async (
|
||||
email: string,
|
||||
data: Partial<TUser> = {}
|
||||
): Promise<TUser | undefined> => {
|
||||
data: Partial<TUsers> = {}
|
||||
): Promise<TUsers | undefined> => {
|
||||
const [user] = await db(TableName.Users)
|
||||
.insert({ email, ...data })
|
||||
.returning("*");
|
||||
@@ -49,8 +50,8 @@ export const authDalFactory = (db: TDbClient) => {
|
||||
|
||||
const updateUser = async (
|
||||
email: string,
|
||||
data: Partial<TUser> = {}
|
||||
): Promise<TUser | undefined> => {
|
||||
data: Partial<TUsers> = {}
|
||||
): Promise<TUsers | undefined> => {
|
||||
const [user] = await db(TableName.Users)
|
||||
.where({ email })
|
||||
.update({ ...data })
|
||||
@@ -60,9 +61,9 @@ export const authDalFactory = (db: TDbClient) => {
|
||||
|
||||
const updateUserById = async (
|
||||
id: string,
|
||||
data: Partial<TUser> = {},
|
||||
data: Partial<TUsers> = {},
|
||||
tx?: Knex
|
||||
): Promise<TUser | undefined> => {
|
||||
): Promise<TUsers | undefined> => {
|
||||
const [user] = await (tx ? tx(TableName.Users) : db(TableName.Users))
|
||||
.where({ id })
|
||||
.update({ ...data })
|
||||
@@ -72,9 +73,9 @@ export const authDalFactory = (db: TDbClient) => {
|
||||
|
||||
const updateUserEncryptionByUserId = async (
|
||||
userId: string,
|
||||
data: Partial<TUserEncryptionKey> = {},
|
||||
data: Partial<TUserEncryptionKeys> = {},
|
||||
tx?: Knex
|
||||
): Promise<TUserEncryptionKey | undefined> => {
|
||||
): Promise<TUserEncryptionKeys | undefined> => {
|
||||
const [userEnc] = await (tx ? tx(TableName.UserEncryptionKey) : db(TableName.UserEncryptionKey))
|
||||
.where({ userId })
|
||||
.update({ ...data })
|
||||
@@ -85,12 +86,12 @@ export const authDalFactory = (db: TDbClient) => {
|
||||
// all upserts
|
||||
const upsertUserEncryptionKey = async (
|
||||
userId: string,
|
||||
data: Partial<TUserEncryptionKey>,
|
||||
data: Partial<TUserEncryptionKeys>,
|
||||
tx?: Knex
|
||||
) => {
|
||||
const [userEnc] = await (tx ? tx(TableName.UserEncryptionKey) : db(TableName.UserEncryptionKey))
|
||||
// if user insert make sure to pass all required data
|
||||
.insert({ userId, ...data } as TUserEncryptionKey)
|
||||
.insert({ userId, ...data } as TUserEncryptionKeys)
|
||||
.onConflict("userId")
|
||||
.merge()
|
||||
.returning("*");
|
||||
@@ -110,12 +111,7 @@ export const authDalFactory = (db: TDbClient) => {
|
||||
return backupKey;
|
||||
};
|
||||
|
||||
return {
|
||||
transaction: async <T>(cb: (tx: Knex) => T) =>
|
||||
db.transaction(async (trx) => {
|
||||
const res = await cb(trx);
|
||||
return res;
|
||||
}),
|
||||
return withTransaction(db, {
|
||||
getUserByEmail,
|
||||
getUserById,
|
||||
getUserEncKeyByEmail,
|
||||
@@ -127,5 +123,5 @@ export const authDalFactory = (db: TDbClient) => {
|
||||
updateUserEncryptionByUserId,
|
||||
upsertUserEncryptionKey,
|
||||
upsertBackupKey
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import jwt from "jsonwebtoken";
|
||||
|
||||
import { AuthMethod, TUser } from "@app/db/schemas";
|
||||
import { UserDeviceSchema } from "@app/db/schemas/user";
|
||||
import { TUsers, UserDeviceSchema } from "@app/db/schemas";
|
||||
import { getConfig } from "@app/lib/config/env";
|
||||
import { generateSrpServerKey, srpCheckClientProof } from "@app/lib/crypto";
|
||||
|
||||
import { SmtpTemplates, TSmtpService } from "../smtp/smtp-service";
|
||||
import { TTokenServiceFactory } from "../token/token-service";
|
||||
import { TAuthTokenServiceFactory } from "../token/token-service";
|
||||
import { TokenType } from "../token/token-types";
|
||||
import { TAuthDalFactory } from "./auth-dal";
|
||||
import {
|
||||
@@ -14,7 +13,7 @@ import {
|
||||
TLoginGenServerPublicKeyDTO,
|
||||
TVerifyMfaTokenDTO
|
||||
} from "./auth-login-type";
|
||||
import { AuthTokenType } from "./auth-signup-type";
|
||||
import { AuthMethod, AuthTokenType } from "./auth-type";
|
||||
|
||||
const isValidProviderAuthToken = (email: string, jwtSecret: string, providerAuthToken?: string) => {
|
||||
if (!providerAuthToken) return false;
|
||||
@@ -27,7 +26,7 @@ const isValidProviderAuthToken = (email: string, jwtSecret: string, providerAuth
|
||||
|
||||
type TAuthLoginServiceFactoryDep = {
|
||||
authDal: TAuthDalFactory;
|
||||
tokenService: TTokenServiceFactory;
|
||||
tokenService: TAuthTokenServiceFactory;
|
||||
smtpService: TSmtpService;
|
||||
};
|
||||
|
||||
@@ -42,7 +41,7 @@ export const authLoginServiceFactory = ({
|
||||
* Not exported. This is to update user device list
|
||||
* If new device is found. Will be saved and a mail will be send
|
||||
*/
|
||||
const updateUserDeviceSession = async (user: TUser, ip: string, userAgent: string) => {
|
||||
const updateUserDeviceSession = async (user: TUsers, ip: string, userAgent: string) => {
|
||||
const devices = await UserDeviceSchema.parseAsync(JSON.parse(user.devices || "[]"));
|
||||
const isDeviceSeen = devices.some(
|
||||
(device) => device.ip === ip && device.userAgent === userAgent
|
||||
@@ -69,7 +68,7 @@ export const authLoginServiceFactory = ({
|
||||
* Private
|
||||
* Send mfa code via email
|
||||
* */
|
||||
const sendUserMfaCode = async (user: TUser) => {
|
||||
const sendUserMfaCode = async (user: TUsers) => {
|
||||
const code = await tokenService.createTokenForUser({
|
||||
type: TokenType.TOKEN_EMAIL_MFA,
|
||||
userId: user.id
|
||||
@@ -89,7 +88,7 @@ export const authLoginServiceFactory = ({
|
||||
* Check user device and send mail if new device
|
||||
* generate the auth and refresh token. fn shared by mfa verification and login verification with mfa disabled
|
||||
*/
|
||||
const generateUserTokens = async (user: TUser, ip: string, userAgent: string) => {
|
||||
const generateUserTokens = async (user: TUsers, ip: string, userAgent: string) => {
|
||||
const cfg = getConfig();
|
||||
await updateUserDeviceSession(user, ip, userAgent);
|
||||
const tokenSession = await tokenService.getUserTokenSession({
|
||||
|
||||
@@ -4,7 +4,7 @@ import { getConfig } from "@app/lib/config/env";
|
||||
import { generateSrpServerKey, srpCheckClientProof } from "@app/lib/crypto";
|
||||
|
||||
import { SmtpTemplates, TSmtpService } from "../smtp/smtp-service";
|
||||
import { TTokenServiceFactory } from "../token/token-service";
|
||||
import { TAuthTokenServiceFactory } from "../token/token-service";
|
||||
import { TokenType } from "../token/token-types";
|
||||
import { TAuthDalFactory } from "./auth-dal";
|
||||
import {
|
||||
@@ -12,11 +12,11 @@ import {
|
||||
TCreateBackupPrivateKeyDTO,
|
||||
TResetPasswordViaBackupKeyDTO
|
||||
} from "./auth-password-type";
|
||||
import { AuthTokenType } from "./auth-signup-type";
|
||||
import { AuthTokenType } from "./auth-type";
|
||||
|
||||
type TAuthPasswordServiceFactoryDep = {
|
||||
authDal: TAuthDalFactory;
|
||||
tokenService: TTokenServiceFactory;
|
||||
tokenService: TAuthTokenServiceFactory;
|
||||
smtpService: TSmtpService;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
import { AuthMethod } from "@app/db/schemas";
|
||||
import jwt from "jsonwebtoken";
|
||||
|
||||
import { getConfig } from "@app/lib/config/env";
|
||||
import { isDisposableEmail } from "@app/lib/validator";
|
||||
|
||||
import { SmtpTemplates, TSmtpService } from "../smtp/smtp-service";
|
||||
import { TTokenServiceFactory } from "../token/token-service";
|
||||
import { TAuthTokenServiceFactory } from "../token/token-service";
|
||||
import { TokenType } from "../token/token-types";
|
||||
import { TAuthDalFactory } from "./auth-dal";
|
||||
import { AuthTokenType, TCompleteAccountSignupDTO } from "./auth-signup-type";
|
||||
import { TCompleteAccountSignupDTO } from "./auth-signup-type";
|
||||
import { AuthMethod, AuthTokenType } from "./auth-type";
|
||||
|
||||
type TAuthSignupDep = {
|
||||
authDal: TAuthDalFactory;
|
||||
tokenService: TTokenServiceFactory;
|
||||
tokenService: TAuthTokenServiceFactory;
|
||||
smtpService: TSmtpService;
|
||||
};
|
||||
|
||||
@@ -66,7 +68,7 @@ export const authSignupServiceFactory = ({
|
||||
});
|
||||
|
||||
// generate jwt token this is a temporary token
|
||||
const jwtToken = tokenService.createJwtToken(
|
||||
const jwtToken = jwt.sign(
|
||||
{
|
||||
authTokenType: AuthTokenType.SIGNUP_TOKEN,
|
||||
userId: user.id.toString()
|
||||
@@ -136,7 +138,7 @@ export const authSignupServiceFactory = ({
|
||||
if (!tokenSession) throw new Error("Failed to create token");
|
||||
const appCfg = getConfig();
|
||||
|
||||
const accessToken = tokenService.createJwtToken(
|
||||
const accessToken = jwt.sign(
|
||||
{
|
||||
authTokenType: AuthTokenType.ACCESS_TOKEN,
|
||||
userId: updateduser.info.id,
|
||||
@@ -147,7 +149,7 @@ export const authSignupServiceFactory = ({
|
||||
{ expiresIn: appCfg.JWT_SIGNUP_LIFETIME }
|
||||
);
|
||||
|
||||
const refreshToken = tokenService.createJwtToken(
|
||||
const refreshToken = jwt.sign(
|
||||
{
|
||||
authTokenType: AuthTokenType.REFRESH_TOKEN,
|
||||
userId: updateduser.info.id,
|
||||
|
||||
@@ -1,22 +1,3 @@
|
||||
export enum AuthTokenType {
|
||||
ACCESS_TOKEN = "accessToken",
|
||||
REFRESH_TOKEN = "refreshToken",
|
||||
SIGNUP_TOKEN = "signupToken", // TODO: remove in favor of claim
|
||||
MFA_TOKEN = "mfaToken", // TODO: remove in favor of claim
|
||||
PROVIDER_TOKEN = "providerToken", // TODO: remove in favor of claim
|
||||
API_KEY = "apiKey",
|
||||
SERVICE_ACCESS_TOKEN = "serviceAccessToken",
|
||||
SERVICE_REFRESH_TOKEN = "serviceRefreshToken"
|
||||
}
|
||||
|
||||
export enum AuthMode {
|
||||
JWT = "jwt",
|
||||
SERVICE_TOKEN = "serviceToken",
|
||||
SERVICE_ACCESS_TOKEN = "serviceAccessToken",
|
||||
API_KEY = "apiKey",
|
||||
API_KEY_V2 = "apiKeyV2"
|
||||
}
|
||||
|
||||
export type TCompleteAccountSignupDTO = {
|
||||
email: string;
|
||||
firstName: string;
|
||||
|
||||
35
backend-pg/src/services/auth/auth-type.ts
Normal file
35
backend-pg/src/services/auth/auth-type.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
export enum AuthMethod {
|
||||
EMAIL = "email",
|
||||
GOOGLE = "google",
|
||||
GITHUB = "github",
|
||||
GITLAB = "gitlab",
|
||||
OKTA_SAML = "okta-saml",
|
||||
AZURE_SAML = "azure-saml",
|
||||
JUMPCLOUD_SAML = "jumpcloud-saml"
|
||||
}
|
||||
|
||||
export enum AuthTokenType {
|
||||
ACCESS_TOKEN = "accessToken",
|
||||
REFRESH_TOKEN = "refreshToken",
|
||||
SIGNUP_TOKEN = "signupToken", // TODO: remove in favor of claim
|
||||
MFA_TOKEN = "mfaToken", // TODO: remove in favor of claim
|
||||
PROVIDER_TOKEN = "providerToken", // TODO: remove in favor of claim
|
||||
API_KEY = "apiKey",
|
||||
SERVICE_ACCESS_TOKEN = "serviceAccessToken",
|
||||
SERVICE_REFRESH_TOKEN = "serviceRefreshToken"
|
||||
}
|
||||
|
||||
export enum AuthMode {
|
||||
JWT = "jwt",
|
||||
SERVICE_TOKEN = "serviceToken",
|
||||
SERVICE_ACCESS_TOKEN = "serviceAccessToken",
|
||||
API_KEY = "apiKey",
|
||||
API_KEY_V2 = "apiKeyV2"
|
||||
}
|
||||
|
||||
export type AuthModeJwtTokenPayload = {
|
||||
authTokenType: AuthTokenType.ACCESS_TOKEN;
|
||||
userId: string;
|
||||
tokenVersionId: string;
|
||||
accessVersion: number;
|
||||
};
|
||||
@@ -1,6 +1,5 @@
|
||||
import { TDbClient } from "@app/db";
|
||||
import { TableName, TToken } from "@app/db/schemas";
|
||||
import { TTokenSession } from "@app/db/schemas/token-session";
|
||||
import { TableName, TAuthTokens, TAuthTokenSessions } from "@app/db/schemas";
|
||||
|
||||
import {
|
||||
TDeleteTokenForUserDalDTO,
|
||||
@@ -19,7 +18,7 @@ export const tokenDalFactory = (db: TDbClient) => {
|
||||
userId,
|
||||
type,
|
||||
triesLeft
|
||||
}: TUpsertTokenForUserDalDTO): Promise<TToken | undefined> => {
|
||||
}: TUpsertTokenForUserDalDTO): Promise<TAuthTokens | undefined> => {
|
||||
const token = await db.transaction(async (tx) => {
|
||||
await tx(TableName.AuthTokens).where({ userId, type }).delete().returning("*");
|
||||
const [newToken] = await tx(TableName.AuthTokens)
|
||||
@@ -33,13 +32,23 @@ export const tokenDalFactory = (db: TDbClient) => {
|
||||
const getTokenForUser = async ({
|
||||
userId,
|
||||
type
|
||||
}: TGetTokenForUserDalDTO): Promise<TToken | undefined> =>
|
||||
}: TGetTokenForUserDalDTO): Promise<TAuthTokens | undefined> =>
|
||||
db(TableName.AuthTokens).where({ userId, type }).first();
|
||||
|
||||
const getTokenSession = async (
|
||||
userId: string,
|
||||
ip: string,
|
||||
userAgent: string
|
||||
): Promise<TAuthTokenSessions | undefined> =>
|
||||
db(TableName.AuthTokenSession).where({ userId, ip, userAgent }).first();
|
||||
|
||||
const getTokenSessionById = async (id: string, userId: string) =>
|
||||
db(TableName.AuthTokenSession).where({ id, userId }).first();
|
||||
|
||||
const deleteTokenForUser = async ({
|
||||
userId,
|
||||
type
|
||||
}: TDeleteTokenForUserDalDTO): Promise<TToken[] | undefined> =>
|
||||
}: TDeleteTokenForUserDalDTO): Promise<TAuthTokens[] | undefined> =>
|
||||
db(TableName.AuthTokens).where({ userId, type }).delete().returning("*");
|
||||
|
||||
const decrementTriesField = async ({
|
||||
@@ -49,18 +58,11 @@ export const tokenDalFactory = (db: TDbClient) => {
|
||||
await db(TableName.AuthTokens).where({ userId, type }).decrement("triesLeft", 1);
|
||||
};
|
||||
|
||||
const getTokenSession = async (
|
||||
userId: string,
|
||||
ip: string,
|
||||
userAgent: string
|
||||
): Promise<TTokenSession | undefined> =>
|
||||
db(TableName.AuthTokenSession).where({ userId, ip, userAgent }).first();
|
||||
|
||||
const insertTokenSession = async (
|
||||
userId: string,
|
||||
ip: string,
|
||||
userAgent: string
|
||||
): Promise<TTokenSession | undefined> => {
|
||||
): Promise<TAuthTokenSessions | undefined> => {
|
||||
const [session] = await db(TableName.AuthTokenSession)
|
||||
.insert({
|
||||
userId,
|
||||
@@ -77,7 +79,7 @@ export const tokenDalFactory = (db: TDbClient) => {
|
||||
const incrementVersion = async (
|
||||
userId: string,
|
||||
sessionId: string
|
||||
): Promise<TTokenSession | undefined> => {
|
||||
): Promise<TAuthTokenSessions | undefined> => {
|
||||
const [session] = await db(TableName.AuthTokenSession)
|
||||
.where({ userId, id: sessionId })
|
||||
.increment("accessVersion", 1)
|
||||
@@ -87,8 +89,9 @@ export const tokenDalFactory = (db: TDbClient) => {
|
||||
};
|
||||
|
||||
return {
|
||||
upsertTokenForUser,
|
||||
getTokenForUser,
|
||||
getTokenSessionById,
|
||||
upsertTokenForUser,
|
||||
deleteTokenForUser,
|
||||
decrementTriesField,
|
||||
getTokenSession,
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import crypto from "node:crypto";
|
||||
import bcrypt from "bcrypt";
|
||||
import jwt, { SignOptions } from "jsonwebtoken";
|
||||
|
||||
import { TToken } from "@app/db/schemas";
|
||||
import { TTokenSession } from "@app/db/schemas/token-session";
|
||||
import { TAuthTokens, TAuthTokenSessions } from "@app/db/schemas";
|
||||
import { getConfig } from "@app/lib/config/env";
|
||||
|
||||
import { TTokenDalFactory } from "./token-dal";
|
||||
@@ -14,11 +12,11 @@ import {
|
||||
TValidateTokenForUserDTO
|
||||
} from "./token-types";
|
||||
|
||||
type TTokenServiceFactoryDep = {
|
||||
type TAuthTokenServiceFactoryDep = {
|
||||
tokenDal: TTokenDalFactory;
|
||||
// adjust the expiry from env through here
|
||||
};
|
||||
export type TTokenServiceFactory = ReturnType<typeof tokenServiceFactory>;
|
||||
export type TAuthTokenServiceFactory = ReturnType<typeof tokenServiceFactory>;
|
||||
|
||||
export const getTokenConfig = (tokenType: TokenType) => {
|
||||
// generate random token based on specified token use-case
|
||||
@@ -57,7 +55,7 @@ export const getTokenConfig = (tokenType: TokenType) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const tokenServiceFactory = ({ tokenDal }: TTokenServiceFactoryDep) => {
|
||||
export const tokenServiceFactory = ({ tokenDal }: TAuthTokenServiceFactoryDep) => {
|
||||
const createTokenForUser = async ({ type, userId }: TCreateTokenForUserDTO) => {
|
||||
const { token, ...tkCfg } = getTokenConfig(type);
|
||||
const appCfg = getConfig();
|
||||
@@ -76,7 +74,7 @@ export const tokenServiceFactory = ({ tokenDal }: TTokenServiceFactoryDep) => {
|
||||
type,
|
||||
userId,
|
||||
code
|
||||
}: TValidateTokenForUserDTO): Promise<TToken | undefined> => {
|
||||
}: TValidateTokenForUserDTO): Promise<TAuthTokens | undefined> => {
|
||||
const token = await tokenDal.getTokenForUser({ type, userId });
|
||||
// validate token
|
||||
if (!token) throw new Error("Failed to find token");
|
||||
@@ -105,7 +103,7 @@ export const tokenServiceFactory = ({ tokenDal }: TTokenServiceFactoryDep) => {
|
||||
userId,
|
||||
ip,
|
||||
userAgent
|
||||
}: TIssueAuthTokenDTO): Promise<TTokenSession | undefined> => {
|
||||
}: TIssueAuthTokenDTO): Promise<TAuthTokenSessions | undefined> => {
|
||||
let session = await tokenDal.getTokenSession(userId, ip, userAgent);
|
||||
if (!session) {
|
||||
session = await tokenDal.insertTokenSession(userId, ip, userAgent);
|
||||
@@ -113,22 +111,19 @@ export const tokenServiceFactory = ({ tokenDal }: TTokenServiceFactoryDep) => {
|
||||
return session;
|
||||
};
|
||||
|
||||
const getUserTokenSessionById = async (id: string, userId: string) =>
|
||||
tokenDal.getTokenSessionById(id, userId);
|
||||
|
||||
const clearTokenSessionById = async (
|
||||
userId: string,
|
||||
sessionId: string
|
||||
): Promise<TTokenSession | undefined> => tokenDal.incrementVersion(userId, sessionId);
|
||||
|
||||
const createJwtToken = (
|
||||
payload: string | Buffer | object,
|
||||
secret: string,
|
||||
options?: SignOptions
|
||||
) => jwt.sign(payload, secret, options);
|
||||
): Promise<TAuthTokenSessions | undefined> => tokenDal.incrementVersion(userId, sessionId);
|
||||
|
||||
return {
|
||||
createTokenForUser,
|
||||
validateTokenForUser,
|
||||
createJwtToken,
|
||||
getUserTokenSession,
|
||||
clearTokenSessionById
|
||||
clearTokenSessionById,
|
||||
getUserTokenSessionById
|
||||
};
|
||||
};
|
||||
|
||||
@@ -16,19 +16,19 @@ import { getUserAgentType } from "../../posthog";
|
||||
export * from "./authDataExtractors";
|
||||
|
||||
interface ExtractAuthModeParams {
|
||||
headers: { [key: string]: string | string[] | undefined }
|
||||
headers: { [key: string]: string | string[] | undefined };
|
||||
}
|
||||
|
||||
interface ExtractAuthModeReturn {
|
||||
authMode: AuthMode;
|
||||
authTokenValue: string;
|
||||
authMode: AuthMode;
|
||||
authTokenValue: string;
|
||||
}
|
||||
|
||||
interface GetAuthDataParams {
|
||||
authMode: AuthMode;
|
||||
authTokenValue: string;
|
||||
ipAddress: string;
|
||||
userAgent: string;
|
||||
authMode: AuthMode;
|
||||
authTokenValue: string;
|
||||
ipAddress: string;
|
||||
userAgent: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -44,33 +44,30 @@ interface GetAuthDataParams {
|
||||
* @throws {UnauthorizedError} Throws an error if no applicable authMode is found.
|
||||
*/
|
||||
export const extractAuthMode = async ({
|
||||
headers
|
||||
headers
|
||||
}: ExtractAuthModeParams): Promise<ExtractAuthModeReturn> => {
|
||||
const apiKey = headers["x-api-key"] as string;
|
||||
const authHeader = headers["authorization"] as string;
|
||||
|
||||
const apiKey = headers["x-api-key"] as string;
|
||||
const authHeader = headers["authorization"] as string;
|
||||
|
||||
if (apiKey) {
|
||||
return { authMode: AuthMode.API_KEY, authTokenValue: apiKey };
|
||||
}
|
||||
|
||||
if (!authHeader) throw UnauthorizedRequestError({
|
||||
message: "Failed to authenticate unknown authentication method"
|
||||
if (apiKey) {
|
||||
return { authMode: AuthMode.API_KEY, authTokenValue: apiKey };
|
||||
}
|
||||
|
||||
if (!authHeader)
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed to authenticate unknown authentication method"
|
||||
});
|
||||
|
||||
if (!authHeader.startsWith("Bearer ")) throw UnauthorizedRequestError({
|
||||
message: "Failed to authenticate unknown authentication method"
|
||||
if (!authHeader.startsWith("Bearer "))
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed to authenticate unknown authentication method"
|
||||
});
|
||||
|
||||
const authTokenValue = authHeader.slice(7);
|
||||
|
||||
if (authTokenValue.startsWith("st.")) {
|
||||
return { authMode: AuthMode.SERVICE_TOKEN, authTokenValue };
|
||||
}
|
||||
const authTokenValue = authHeader.slice(7);
|
||||
|
||||
const decodedToken = <jwt.AuthnJwtPayload>(
|
||||
jwt.verify(authTokenValue, await getAuthSecret())
|
||||
);
|
||||
if (authTokenValue.startsWith("st.")) {
|
||||
return { authMode: AuthMode.SERVICE_TOKEN, authTokenValue };
|
||||
}
|
||||
|
||||
switch (decodedToken.authTokenType) {
|
||||
case AuthTokenType.ACCESS_TOKEN:
|
||||
@@ -87,13 +84,18 @@ export const extractAuthMode = async ({
|
||||
}
|
||||
|
||||
export const getAuthData = async ({
|
||||
authMode,
|
||||
authTokenValue,
|
||||
ipAddress,
|
||||
userAgent
|
||||
authMode,
|
||||
authTokenValue,
|
||||
ipAddress,
|
||||
userAgent
|
||||
}: GetAuthDataParams): Promise<AuthData> => {
|
||||
const userAgentType = getUserAgentType(userAgent);
|
||||
|
||||
const userAgentType = getUserAgentType(userAgent);
|
||||
switch (authMode) {
|
||||
case AuthMode.SERVICE_TOKEN: {
|
||||
const serviceTokenData = await validateServiceTokenV2({
|
||||
authTokenValue
|
||||
});
|
||||
|
||||
switch (authMode) {
|
||||
case AuthMode.SERVICE_TOKEN: {
|
||||
@@ -193,4 +195,81 @@ export const getAuthData = async ({
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case AuthMode.SERVICE_ACCESS_TOKEN: {
|
||||
const serviceTokenData = await validateServiceTokenV3({
|
||||
authTokenValue
|
||||
});
|
||||
|
||||
return {
|
||||
actor: {
|
||||
type: ActorType.SERVICE_V3,
|
||||
metadata: {
|
||||
serviceId: serviceTokenData._id.toString(),
|
||||
name: serviceTokenData.name
|
||||
}
|
||||
},
|
||||
authPayload: serviceTokenData,
|
||||
ipAddress,
|
||||
userAgent,
|
||||
userAgentType
|
||||
};
|
||||
}
|
||||
case AuthMode.API_KEY: {
|
||||
const user = await validateAPIKey({
|
||||
authTokenValue
|
||||
});
|
||||
|
||||
return {
|
||||
actor: {
|
||||
type: ActorType.USER,
|
||||
metadata: {
|
||||
userId: user._id.toString(),
|
||||
email: user.email
|
||||
}
|
||||
},
|
||||
authPayload: user,
|
||||
ipAddress,
|
||||
userAgent,
|
||||
userAgentType
|
||||
};
|
||||
}
|
||||
case AuthMode.API_KEY_V2: {
|
||||
const user = await validateAPIKeyV2({
|
||||
authTokenValue
|
||||
});
|
||||
|
||||
return {
|
||||
actor: {
|
||||
type: ActorType.USER,
|
||||
metadata: {
|
||||
userId: user._id.toString(),
|
||||
email: user.email
|
||||
}
|
||||
},
|
||||
authPayload: user,
|
||||
ipAddress,
|
||||
userAgent,
|
||||
userAgentType
|
||||
};
|
||||
}
|
||||
case AuthMode.JWT: {
|
||||
const user = await validateJWT({
|
||||
authTokenValue
|
||||
});
|
||||
|
||||
return {
|
||||
actor: {
|
||||
type: ActorType.USER,
|
||||
metadata: {
|
||||
userId: user._id.toString(),
|
||||
email: user.email
|
||||
}
|
||||
},
|
||||
authPayload: user,
|
||||
ipAddress,
|
||||
userAgent,
|
||||
userAgentType
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -41,7 +41,7 @@ const AddTagPopoverContent = ({
|
||||
<div className="flex flex-col space-y-1.5">
|
||||
{wsTags?.map((wsTag: WsTag) => (
|
||||
<div
|
||||
key={`tag-${wsTag._id}`}
|
||||
key={`tag-${wsTag.id}`}
|
||||
className="mt-4 h-[32px] relative flex items-center justify-start hover:border-mineshaft-600 hover:border hover:bg-mineshaft-700 p-2 rounded-md hover:text-bunker-200 bg-none"
|
||||
onClick={() => handleSelectTag(wsTag)}
|
||||
onMouseEnter={() => handleTagOnMouseEnter(wsTag)}
|
||||
|
||||
@@ -64,7 +64,7 @@ const UpgradePlanModal = ({
|
||||
<button
|
||||
type='button'
|
||||
className='inline-flex justify-center rounded-md border border-transparent bg-primary opacity-80 hover:opacity-100 px-4 py-2 text-sm font-medium text-black hover:text-semibold duration-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2'
|
||||
onClick={() => router.push(`/org/${currentOrg?._id}/billing`)}
|
||||
onClick={() => router.push(`/org/${currentOrg?.id}/billing`)}
|
||||
>
|
||||
Upgrade Now
|
||||
</button>
|
||||
|
||||
@@ -41,7 +41,7 @@ type EnvironmentProps = {
|
||||
const ProjectUsersTable = ({ userData, changeData, myUser, filter, isUserListLoading }: Props) => {
|
||||
const { currentWorkspace } = useWorkspace();
|
||||
const { subscription } = useSubscription();
|
||||
const { data: wsKey } = useGetUserWsKey(currentWorkspace?._id ?? "");
|
||||
const { data: wsKey } = useGetUserWsKey(currentWorkspace?.id ?? "");
|
||||
|
||||
const { mutateAsync: deleteUserFromWorkspaceMutateAsync } = useDeleteUserFromWorkspace();
|
||||
const { mutateAsync: uploadWsKeyMutateAsync } = useUploadWsKey();
|
||||
|
||||
@@ -37,7 +37,7 @@ const AddTagsMenu = ({ allTags, currentTags, modifyTags, id }: { allTags: Tag[];
|
||||
>
|
||||
<Menu.Items className="absolute z-[90] text-sm drop-shadow-xl right-0 mt-0.5 w-[12rem] origin-top-right rounded-md bg-mineshaft-600 border border-mineshaft-500 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none p-1 space-y-1">
|
||||
{allTags?.map((tag) => { return (
|
||||
<Menu.Item key={tag._id}>
|
||||
<Menu.Item key={tag.id}>
|
||||
<button
|
||||
type="button"
|
||||
className={`${currentTags?.map(currentTag => currentTag.name).includes(tag.name) ? "opacity-30 cursor-default" : "hover:bg-mineshaft-700"} w-full text-left bg-mineshaft-800 px-2 py-0.5 text-bunker-200 rounded-sm flex items-center`}
|
||||
|
||||
@@ -147,9 +147,9 @@ const KeyPair = ({
|
||||
<div className="w-2/12 h-10 flex items-center overflow-visible overflow-r-scroll no-scrollbar no-scrollbar::-webkit-scrollbar">
|
||||
<div className="flex items-center max-h-16">
|
||||
{keyPair.tags?.map((tag, index) => (
|
||||
index < 2 && <div key={keyPair.pos} className={`ml-2 px-1.5 ${tagData.filter(tagDp => tagDp._id === tag._id)[0]?.color} rounded-sm text-sm ${tagData.filter(tagDp => tagDp._id === tag._id)[0]?.colorText} flex items-center`}>
|
||||
index < 2 && <div key={keyPair.pos} className={`ml-2 px-1.5 ${tagData.filter(tagDp => tagDp.id === tag.id)[0]?.color} rounded-sm text-sm ${tagData.filter(tagDp => tagDp.id === tag.id)[0]?.colorText} flex items-center`}>
|
||||
<span className='mb-0.5 cursor-default'>{tag.name}</span>
|
||||
<FontAwesomeIcon icon={faXmark} className="ml-1 cursor-pointer p-1" onClick={() => modifyTags(keyPair.tags.filter(ttag => ttag._id !== tag._id), keyPair.id)}/>
|
||||
<FontAwesomeIcon icon={faXmark} className="ml-1 cursor-pointer p-1" onClick={() => modifyTags(keyPair.tags.filter(ttag => ttag.id !== tag.id), keyPair.id)}/>
|
||||
</div>
|
||||
))}
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ export default function NavHeader({
|
||||
<div className="mr-2 flex h-5 w-5 items-center justify-center rounded-md bg-primary text-sm text-black">
|
||||
{currentOrg?.name?.charAt(0)}
|
||||
</div>
|
||||
<Link passHref legacyBehavior href={`/org/${currentOrg?._id}/overview`}>
|
||||
<Link passHref legacyBehavior href={`/org/${currentOrg?.id}/overview`}>
|
||||
<a className="pl-0.5 text-sm font-semibold text-primary/80 hover:text-primary">
|
||||
{currentOrg?.name}
|
||||
</a>
|
||||
|
||||
@@ -191,14 +191,14 @@ export default function UserInfoStep({
|
||||
|
||||
const userOrgs = await fetchOrganizations();
|
||||
|
||||
const orgId = userOrgs[0]?._id;
|
||||
const orgId = userOrgs[0]?.id;
|
||||
const project = await ProjectService.initProject({
|
||||
organizationId: orgId,
|
||||
projectName: "Example Project"
|
||||
});
|
||||
|
||||
localStorage.setItem("orgData.id", orgId);
|
||||
localStorage.setItem("projectData.id", project._id);
|
||||
localStorage.setItem("projectData.id", project.id);
|
||||
|
||||
incrementStep();
|
||||
} catch (error) {
|
||||
|
||||
@@ -112,7 +112,7 @@ export const CreateTagModal = ({ isOpen, onToggle }: Props): JSX.Element => {
|
||||
});
|
||||
const { createNotification } = useNotificationContext();
|
||||
const { currentWorkspace } = useWorkspace();
|
||||
const workspaceId = currentWorkspace?._id || "";
|
||||
const workspaceId = currentWorkspace?.id || "";
|
||||
|
||||
const { mutateAsync: createWsTag } = useCreateWsTag();
|
||||
|
||||
|
||||
@@ -2,11 +2,11 @@ const ENV = process.env.NEXT_PUBLIC_ENV! || "development"; // investigate
|
||||
const POSTHOG_API_KEY = process.env.NEXT_PUBLIC_POSTHOG_API_KEY!;
|
||||
const POSTHOG_HOST =
|
||||
process.env.NEXT_PUBLIC_POSTHOG_HOST! || "https://app.posthog.com";
|
||||
const INTERCOM_ID = process.env.NEXT_PUBLIC_INTERCOM_ID!;
|
||||
const INTERCOMid = process.env.NEXT_PUBLIC_INTERCOMid!;
|
||||
|
||||
export {
|
||||
ENV,
|
||||
INTERCOM_ID,
|
||||
INTERCOMid,
|
||||
POSTHOG_API_KEY,
|
||||
POSTHOG_HOST
|
||||
};
|
||||
@@ -9,7 +9,7 @@
|
||||
/* eslint-disable func-names */
|
||||
// @ts-nocheck
|
||||
|
||||
import { INTERCOM_ID as APP_ID } from "@app/components/utilities/config";
|
||||
import { INTERCOMid as APPid } from "@app/components/utilities/config";
|
||||
|
||||
// Loads Intercom with the snippet
|
||||
// This must be run before boot, it initializes window.Intercom
|
||||
@@ -37,7 +37,7 @@ export const load = () => {
|
||||
var s=d.createElement("script");
|
||||
s.type="text/javascript";
|
||||
s.async=true;
|
||||
s.src="https://widget.intercom.io/widget/" + APP_ID;
|
||||
s.src="https://widget.intercom.io/widget/" + APPid;
|
||||
var x=d.getElementsByTagName("script")[0];
|
||||
x.parentNode.insertBefore(s, x);
|
||||
};
|
||||
@@ -56,7 +56,7 @@ export const load = () => {
|
||||
export const boot = (options = {}) => {
|
||||
window &&
|
||||
window.Intercom &&
|
||||
window.Intercom("boot", { app_id: APP_ID, ...options });
|
||||
window.Intercom("boot", { appid: APPid, ...options });
|
||||
};
|
||||
|
||||
export const update = () => {
|
||||
|
||||
@@ -16,7 +16,7 @@ export const UpgradePlanModal = ({ text, isOpen, onOpenChange }: Props): JSX.Ele
|
||||
const { mutateAsync, isLoading } = useGetOrgTrialUrl();
|
||||
const link =
|
||||
subscription && subscription.slug !== null
|
||||
? `/org/${currentOrg?._id}/billing`
|
||||
? `/org/${currentOrg?.id}/billing`
|
||||
: "https://infisical.com/scheduledemo";
|
||||
|
||||
const handleUpgradeBtnClick = async () => {
|
||||
@@ -27,7 +27,7 @@ export const UpgradePlanModal = ({ text, isOpen, onOpenChange }: Props): JSX.Ele
|
||||
// direct user to start pro trial
|
||||
|
||||
const url = await mutateAsync({
|
||||
orgId: currentOrg._id,
|
||||
orgId: currentOrg.id,
|
||||
success_url: window.location.href
|
||||
});
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ const OrgPermissionContext = createContext<null | {
|
||||
|
||||
export const OrgPermissionProvider = ({ children }: Props): JSX.Element => {
|
||||
const { currentOrg } = useOrganization();
|
||||
const orgId = currentOrg?._id || "";
|
||||
const orgId = currentOrg?.id || "";
|
||||
const { data: permission, isLoading } = useGetUserOrgPermissions({ orgId });
|
||||
|
||||
if (isLoading) {
|
||||
|
||||
@@ -26,7 +26,7 @@ export const OrgProvider = ({ children }: Props): JSX.Element => {
|
||||
const value = useMemo<TOrgContext>(
|
||||
() => ({
|
||||
orgs: userOrgs,
|
||||
currentOrg: (userOrgs || []).find(({ _id }) => _id === currentWsOrgID) || (userOrgs || [])[0],
|
||||
currentOrg: (userOrgs || []).find(({ id }) => id === currentWsOrgID) || (userOrgs || [])[0],
|
||||
isLoading
|
||||
}),
|
||||
[currentWsOrgID, userOrgs, isLoading]
|
||||
|
||||
@@ -13,7 +13,7 @@ const ProjectPermissionContext = createContext<null | TProjectPermission>(null);
|
||||
|
||||
export const ProjectPermissionProvider = ({ children }: Props): JSX.Element => {
|
||||
const { currentWorkspace, isLoading: isWsLoading } = useWorkspace();
|
||||
const workspaceId = currentWorkspace?._id || "";
|
||||
const workspaceId = currentWorkspace?.id || "";
|
||||
const { data: permission, isLoading } = useGetUserProjectPermissions({ workspaceId });
|
||||
|
||||
if ((isLoading && currentWorkspace) || isWsLoading) {
|
||||
|
||||
@@ -20,7 +20,7 @@ export const SubscriptionProvider = ({ children }: Props): JSX.Element => {
|
||||
const { currentOrg } = useOrganization();
|
||||
|
||||
const { data, isLoading } = useGetOrgSubscription({
|
||||
orgID: currentOrg?._id || ""
|
||||
orgID: currentOrg?.id || ""
|
||||
});
|
||||
|
||||
// memorize the workspace details for the context
|
||||
|
||||
@@ -26,7 +26,7 @@ export const WorkspaceProvider = ({ children }: Props): JSX.Element => {
|
||||
const wsId = workspaceId || localStorage.getItem("projectData.id");
|
||||
return {
|
||||
workspaces: ws || [],
|
||||
currentWorkspace: (ws || []).find(({ _id: id }) => id === wsId),
|
||||
currentWorkspace: (ws || []).find(({ id: id }) => id === wsId),
|
||||
isLoading
|
||||
};
|
||||
}, [ws, workspaceId, isLoading]);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export type APIKeyDataV2 = {
|
||||
_id: string;
|
||||
id: string;
|
||||
name: string;
|
||||
user: string;
|
||||
lastUsed?: string;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export type TBot = {
|
||||
_id: string;
|
||||
id: string;
|
||||
name: string;
|
||||
workspace: string;
|
||||
isActive: boolean;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export type IncidentContact = {
|
||||
_id: string;
|
||||
id: string;
|
||||
email: string;
|
||||
organization: string;
|
||||
__v: number;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export type IntegrationAuth = {
|
||||
_id: string;
|
||||
id: string;
|
||||
integration: string;
|
||||
workspace: string;
|
||||
__v: number;
|
||||
|
||||
@@ -10,7 +10,7 @@ export type TCloudIntegration = {
|
||||
};
|
||||
|
||||
export type TIntegration = {
|
||||
_id: string;
|
||||
id: string;
|
||||
workspace: string;
|
||||
environment: string;
|
||||
isActive: boolean;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export type UserWsKeyPair = {
|
||||
_id: string;
|
||||
id: string;
|
||||
encryptedKey: string;
|
||||
nonce: string;
|
||||
sender: Sender;
|
||||
@@ -11,7 +11,7 @@ export type UserWsKeyPair = {
|
||||
};
|
||||
|
||||
export type Sender = {
|
||||
_id: string;
|
||||
id: string;
|
||||
email: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export type Organization = {
|
||||
_id: string;
|
||||
id: string;
|
||||
name: string;
|
||||
createAt: string;
|
||||
updatedAt: string;
|
||||
@@ -25,7 +25,7 @@ export type PlanBillingInfo = {
|
||||
}
|
||||
|
||||
export type Invoice = {
|
||||
_id: string;
|
||||
id: string;
|
||||
created: number;
|
||||
invoice_pdf: string;
|
||||
number: string;
|
||||
@@ -34,7 +34,7 @@ export type Invoice = {
|
||||
}
|
||||
|
||||
export type PmtMethod = {
|
||||
_id: string;
|
||||
id: string;
|
||||
brand: string;
|
||||
exp_month: number;
|
||||
exp_year: number;
|
||||
@@ -43,14 +43,14 @@ export type PmtMethod = {
|
||||
}
|
||||
|
||||
export type TaxID = {
|
||||
_id: string;
|
||||
id: string;
|
||||
country: string;
|
||||
type: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export type License = {
|
||||
_id: string;
|
||||
id: string;
|
||||
customerId: string;
|
||||
prefix: string;
|
||||
licenseKey: string;
|
||||
|
||||
@@ -4,7 +4,7 @@ export type TGetRolesDTO = {
|
||||
};
|
||||
|
||||
export type TRole<T extends string | undefined> = {
|
||||
_id: string;
|
||||
id: string;
|
||||
organization: string;
|
||||
workspace: T;
|
||||
name: string;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export type TSecretApprovalPolicy = {
|
||||
_id: string;
|
||||
id: string;
|
||||
workspace: string;
|
||||
name: string;
|
||||
environment: string;
|
||||
|
||||
@@ -78,7 +78,7 @@ export const decryptSecretApprovalSecret = (
|
||||
key
|
||||
});
|
||||
return {
|
||||
_id: encSecret._id,
|
||||
id: encSecret.id,
|
||||
version: encSecret.version,
|
||||
secretKey,
|
||||
secretValue,
|
||||
|
||||
@@ -16,7 +16,7 @@ export enum CommitType {
|
||||
}
|
||||
|
||||
export type TSecretApprovalSecChangeData = {
|
||||
_id: string;
|
||||
id: string;
|
||||
secretKeyCiphertext: string;
|
||||
secretKeyIV: string;
|
||||
secretKeyTag: string;
|
||||
@@ -34,7 +34,7 @@ export type TSecretApprovalSecChangeData = {
|
||||
};
|
||||
|
||||
export type TSecretApprovalSecChange = {
|
||||
_id: string;
|
||||
id: string;
|
||||
version: number;
|
||||
secretKey: string;
|
||||
secretValue: string;
|
||||
@@ -46,7 +46,7 @@ export type TSecretApprovalRequest<
|
||||
T extends unknown = TSecretApprovalSecChangeData,
|
||||
J extends unknown = EncryptedSecret
|
||||
> = {
|
||||
_id: string;
|
||||
id: string;
|
||||
slug: string;
|
||||
createdAt: string;
|
||||
committer: string;
|
||||
|
||||
@@ -142,7 +142,7 @@ export const useGetImportedSecrets = ({
|
||||
});
|
||||
|
||||
return {
|
||||
_id: encSecret._id,
|
||||
id: encSecret.id,
|
||||
env: encSecret.environment,
|
||||
key: secretKey,
|
||||
value: secretValue,
|
||||
|
||||
@@ -2,7 +2,7 @@ import { UserWsKeyPair } from "../keys/types";
|
||||
import { EncryptedSecret } from "../secrets/types";
|
||||
|
||||
export type TSecretImports = {
|
||||
_id: string;
|
||||
id: string;
|
||||
workspaceId: string;
|
||||
environment: string;
|
||||
folderId: string;
|
||||
|
||||
@@ -71,7 +71,7 @@ export type TProviderTemplate = {
|
||||
};
|
||||
|
||||
export type TSecretRotation<T extends unknown = EncryptedSecret> = {
|
||||
_id: string;
|
||||
id: string;
|
||||
interval: number;
|
||||
provider: string;
|
||||
customProvider: string;
|
||||
|
||||
@@ -102,7 +102,7 @@ export const useGetSnapshotSecrets = ({ decryptFileKey, env, snapshotId }: TSnap
|
||||
const secretComment = "";
|
||||
|
||||
const decryptedSecret = {
|
||||
_id: encSecret.secret,
|
||||
id: encSecret.secret,
|
||||
env: encSecret.environment,
|
||||
key: secretKey,
|
||||
value: secretValue,
|
||||
|
||||
@@ -2,7 +2,7 @@ import { UserWsKeyPair } from "../keys/types";
|
||||
import { EncryptedSecretVersion } from "../secrets/types";
|
||||
|
||||
export type TSecretSnapshot = {
|
||||
_id: string;
|
||||
id: string;
|
||||
workspace: string;
|
||||
version: number;
|
||||
secretVersions: string[];
|
||||
|
||||
@@ -63,7 +63,7 @@ export const decryptSecrets = (
|
||||
});
|
||||
|
||||
const decryptedSecret: DecryptedSecret = {
|
||||
_id: encSecret._id,
|
||||
id: encSecret.id,
|
||||
env: encSecret.environment,
|
||||
key: secretKey,
|
||||
value: secretValue,
|
||||
@@ -79,7 +79,7 @@ export const decryptSecrets = (
|
||||
|
||||
if (encSecret.type === "personal") {
|
||||
personalSecrets[decryptedSecret.key] = {
|
||||
id: encSecret._id,
|
||||
id: encSecret.id,
|
||||
value: secretValue
|
||||
};
|
||||
} else {
|
||||
@@ -225,7 +225,7 @@ export const useGetSecretVersion = (dto: GetSecretVersionsDTO) =>
|
||||
return data
|
||||
.map((el) => ({
|
||||
createdAt: el.createdAt,
|
||||
id: el._id,
|
||||
id: el.id,
|
||||
value: decryptSymmetric({
|
||||
ciphertext: el.secretValueCiphertext,
|
||||
iv: el.secretValueIV,
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { UserWsKeyPair } from "../keys/types";
|
||||
import type { WsTag } from "../tags/types";
|
||||
|
||||
export type EncryptedSecret = {
|
||||
_id: string;
|
||||
id: string;
|
||||
version: number;
|
||||
workspace: string;
|
||||
type: "shared" | "personal";
|
||||
@@ -26,7 +26,7 @@ export type EncryptedSecret = {
|
||||
};
|
||||
|
||||
export type DecryptedSecret = {
|
||||
_id: string;
|
||||
id: string;
|
||||
version: number;
|
||||
key: string;
|
||||
value: string;
|
||||
@@ -45,7 +45,7 @@ export type DecryptedSecret = {
|
||||
};
|
||||
|
||||
export type EncryptedSecretVersion = {
|
||||
_id: string;
|
||||
id: string;
|
||||
secret: string;
|
||||
version: number;
|
||||
workspace: string;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export type SubscriptionPlan = {
|
||||
_id: string;
|
||||
id: string;
|
||||
membersUsed: number;
|
||||
memberLimit: number;
|
||||
auditLogs: boolean;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export type UserWsTags = WsTag[];
|
||||
|
||||
export type WsTag = {
|
||||
_id: string;
|
||||
id: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
tagColor?: string;
|
||||
@@ -11,7 +11,7 @@ export type WsTag = {
|
||||
__v: number;
|
||||
}
|
||||
|
||||
export type WorkspaceTag = { _id: string; name: string; slug: string };
|
||||
export type WorkspaceTag = { id: string; name: string; slug: string };
|
||||
|
||||
export type CreateTagDTO = {
|
||||
workspaceID: string;
|
||||
@@ -27,7 +27,7 @@ export type CreateTagRes = {
|
||||
createdAt: string;
|
||||
tagColor?: string;
|
||||
user: string;
|
||||
_id: string;
|
||||
id: string;
|
||||
};
|
||||
|
||||
export type DeleteTagDTO = { tagID: string; };
|
||||
@@ -38,12 +38,12 @@ export type DeleteWsTagRes = {
|
||||
workspace: string;
|
||||
createdAt: string;
|
||||
user: string;
|
||||
_id: string;
|
||||
id: string;
|
||||
};
|
||||
|
||||
export type SecretTags = {
|
||||
id: string;
|
||||
_id: string;
|
||||
id: string;
|
||||
slug: string;
|
||||
tagColor: string;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export type TrustedIp = {
|
||||
_id: string;
|
||||
id: string;
|
||||
workspace: string;
|
||||
ipAddress: string;
|
||||
type: "ipv4" | "ipv6";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export type TWebhook = {
|
||||
_id: string;
|
||||
id: string;
|
||||
workspace: string;
|
||||
environment: string;
|
||||
secretPath: string;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export type Workspace = {
|
||||
__v: number;
|
||||
_id: string;
|
||||
id: string;
|
||||
name: string;
|
||||
organization: string;
|
||||
autoCapitalization: boolean;
|
||||
@@ -14,13 +14,13 @@ export type WorkspaceEnv = {
|
||||
isWriteDenied: boolean;
|
||||
};
|
||||
|
||||
export type WorkspaceTag = { _id: string; name: string; slug: string };
|
||||
export type WorkspaceTag = { id: string; name: string; slug: string };
|
||||
|
||||
export type NameWorkspaceSecretsDTO = {
|
||||
workspaceId: string;
|
||||
secretsToUpdate: {
|
||||
secretName: string;
|
||||
_id: string;
|
||||
id: string;
|
||||
}[];
|
||||
}
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ export const AdminLayout = ({ children }: LayoutProps) => {
|
||||
<div>
|
||||
{!router.asPath.includes("personal") && (
|
||||
<div className="flex h-12 cursor-default justify-between items-center px-3 pt-6">
|
||||
<Link href={`/org/${currentOrg?._id}/overview`}>
|
||||
<Link href={`/org/${currentOrg?.id}/overview`}>
|
||||
<div className="my-6 flex cursor-default items-center justify-center pr-2 text-sm text-mineshaft-300 hover:text-mineshaft-100">
|
||||
<FontAwesomeIcon icon={faArrowLeft} className="pr-3" />
|
||||
Back to organization
|
||||
@@ -264,7 +264,7 @@ export const AdminLayout = ({ children }: LayoutProps) => {
|
||||
|
||||
// direct user to start pro trial
|
||||
const url = await mutateAsync({
|
||||
orgId: currentOrg._id,
|
||||
orgId: currentOrg.id,
|
||||
success_url: window.location.href
|
||||
});
|
||||
|
||||
|
||||
@@ -267,15 +267,15 @@ export const Navbar = () => {
|
||||
</div>
|
||||
<div className="mt-3 mb-2 flex flex-col items-start px-1">
|
||||
{orgs
|
||||
?.filter((org: { _id: string }) => org._id !== currentOrg?._id)
|
||||
.map((org: { _id: string; name: string }) => (
|
||||
?.filter((org: { id: string }) => org.id !== currentOrg?.id)
|
||||
.map((org: { id: string; name: string }) => (
|
||||
<div
|
||||
onKeyDown={() => null}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
key={guidGenerator()}
|
||||
onClick={() => {
|
||||
localStorage.setItem("orgData.id", org._id);
|
||||
localStorage.setItem("orgData.id", org.id);
|
||||
router.reload();
|
||||
}}
|
||||
className="flex w-full cursor-pointer flex-row items-center justify-start rounded-md p-1.5 hover:bg-white/5"
|
||||
@@ -326,7 +326,7 @@ export const Navbar = () => {
|
||||
|
||||
// direct user to start pro trial
|
||||
const url = await mutateAsync({
|
||||
orgId: currentOrg._id,
|
||||
orgId: currentOrg.id,
|
||||
success_url: window.location.href
|
||||
});
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import SecurityClient from "@app/components/utilities/SecurityClient";
|
||||
|
||||
export type IGitRisks = {
|
||||
_id: string;
|
||||
id: string;
|
||||
description: string;
|
||||
startLine: string;
|
||||
endLine: string;
|
||||
|
||||
@@ -18,7 +18,7 @@ export default function DashboardRedirect() {
|
||||
if (localStorage.getItem("orgData.id")) {
|
||||
router.push(`/org/${localStorage.getItem("orgData.id")}/overview`);
|
||||
} else if (userOrgs) {
|
||||
userOrg = userOrgs[0]._id;
|
||||
userOrg = userOrgs[0].id;
|
||||
router.push(`/org/${userOrg}/overview`);
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
@@ -52,7 +52,7 @@ export default function AWSParameterStoreAuthorizeIntegrationPage() {
|
||||
setIsLoading(false);
|
||||
|
||||
router.push(
|
||||
`/integrations/aws-parameter-store/create?integrationAuthId=${integrationAuth._id}`
|
||||
`/integrations/aws-parameter-store/create?integrationAuthId=${integrationAuth.id}`
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
|
||||
@@ -95,12 +95,12 @@ export default function AWSParameterStoreCreateIntegrationPage() {
|
||||
}
|
||||
}
|
||||
|
||||
if (!integrationAuth?._id) return;
|
||||
if (!integrationAuth?.id) return;
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
await mutateAsync({
|
||||
integrationAuthId: integrationAuth?._id,
|
||||
integrationAuthId: integrationAuth?.id,
|
||||
isActive: true,
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
path,
|
||||
|
||||
@@ -50,7 +50,7 @@ export default function AWSSecretManagerCreateIntegrationPage() {
|
||||
setIsLoading(false);
|
||||
|
||||
router.push(
|
||||
`/integrations/aws-secret-manager/create?integrationAuthId=${integrationAuth._id}`
|
||||
`/integrations/aws-secret-manager/create?integrationAuthId=${integrationAuth.id}`
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
|
||||
@@ -94,12 +94,12 @@ export default function AWSSecretManagerCreateIntegrationPage() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!integrationAuth?._id) return;
|
||||
if (!integrationAuth?.id) return;
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
await mutateAsync({
|
||||
integrationAuthId: integrationAuth?._id,
|
||||
integrationAuthId: integrationAuth?.id,
|
||||
isActive: true,
|
||||
app: targetSecretName.trim(),
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
|
||||
@@ -53,11 +53,11 @@ export default function AzureKeyVaultCreateIntegrationPage() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!integrationAuth?._id) return;
|
||||
if (!integrationAuth?.id) return;
|
||||
|
||||
setIsLoading(true);
|
||||
await mutateAsync({
|
||||
integrationAuthId: integrationAuth?._id,
|
||||
integrationAuthId: integrationAuth?.id,
|
||||
isActive: true,
|
||||
app: vaultBaseUrl,
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
|
||||
@@ -26,7 +26,7 @@ export default function AzureKeyVaultOAuth2CallbackPage() {
|
||||
});
|
||||
|
||||
router.push(
|
||||
`/integrations/azure-key-vault/create?integrationAuthId=${integrationAuth._id}`
|
||||
`/integrations/azure-key-vault/create?integrationAuthId=${integrationAuth.id}`
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
|
||||
@@ -72,7 +72,7 @@ export default function BitBucketCreateIntegrationPage() {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
|
||||
if (!integrationAuth?._id) return;
|
||||
if (!integrationAuth?.id) return;
|
||||
|
||||
const targetApp = integrationAuthApps?.find(
|
||||
(integrationAuthApp) => integrationAuthApp.appId === targetAppId
|
||||
@@ -84,7 +84,7 @@ export default function BitBucketCreateIntegrationPage() {
|
||||
if (!targetApp || !targetApp.appId || !targetEnvironment) return;
|
||||
|
||||
await mutateAsync({
|
||||
integrationAuthId: integrationAuth?._id,
|
||||
integrationAuthId: integrationAuth?.id,
|
||||
isActive: true,
|
||||
app: targetApp.name,
|
||||
appId: targetApp.appId,
|
||||
|
||||
@@ -24,7 +24,7 @@ export default function BitBucketOAuth2CallbackPage() {
|
||||
integration: "bitbucket"
|
||||
});
|
||||
|
||||
router.push(`/integrations/bitbucket/create?integrationAuthId=${integrationAuth._id}`);
|
||||
router.push(`/integrations/bitbucket/create?integrationAuthId=${integrationAuth.id}`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ export default function ChecklyCreateIntegrationPage() {
|
||||
|
||||
setIsLoading(false);
|
||||
|
||||
router.push(`/integrations/checkly/create?integrationAuthId=${integrationAuth._id}`);
|
||||
router.push(`/integrations/checkly/create?integrationAuthId=${integrationAuth.id}`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ export default function ChecklyCreateIntegrationPage() {
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
if (!integrationAuth?._id) return;
|
||||
if (!integrationAuth?.id) return;
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
@@ -94,7 +94,7 @@ export default function ChecklyCreateIntegrationPage() {
|
||||
if (!targetApp) return;
|
||||
|
||||
await mutateAsync({
|
||||
integrationAuthId: integrationAuth?._id,
|
||||
integrationAuthId: integrationAuth?.id,
|
||||
isActive: true,
|
||||
app: targetApp?.name,
|
||||
appId: targetApp?.appId,
|
||||
|
||||
@@ -38,7 +38,7 @@ export default function CircleCICreateIntegrationPage() {
|
||||
|
||||
setIsLoading(false);
|
||||
|
||||
router.push(`/integrations/circleci/create?integrationAuthId=${integrationAuth._id}`);
|
||||
router.push(`/integrations/circleci/create?integrationAuthId=${integrationAuth.id}`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
@@ -63,12 +63,12 @@ export default function CircleCICreateIntegrationPage() {
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
if (!integrationAuth?._id) return;
|
||||
if (!integrationAuth?.id) return;
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
await mutateAsync({
|
||||
integrationAuthId: integrationAuth?._id,
|
||||
integrationAuthId: integrationAuth?.id,
|
||||
isActive: true,
|
||||
app: targetApp,
|
||||
appId: integrationAuthApps?.find((integrationAuthApp) => integrationAuthApp.name === targetApp)?.appId,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user