mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-06 18:27:19 +00:00
feat(infisical-pg): fixed radix issue, bugs in oauth and tag cascade on
This commit is contained in:
Vendored
+1
-1
@@ -59,7 +59,7 @@ declare module "fastify" {
|
|||||||
};
|
};
|
||||||
// passport data
|
// passport data
|
||||||
passportUser: {
|
passportUser: {
|
||||||
isCompleted: string;
|
isUserCompleted: string;
|
||||||
providerAuthToken: string;
|
providerAuthToken: string;
|
||||||
};
|
};
|
||||||
auditLogInfo: Pick<TCreateAuditLogDTO, "userAgent" | "userAgentType" | "ipAddress" | "actor">;
|
auditLogInfo: Pick<TCreateAuditLogDTO, "userAgent" | "userAgentType" | "ipAddress" | "actor">;
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ export const createJunctionTable = (
|
|||||||
table.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
table.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
table.uuid(`${table1Name}Id`).unsigned().notNullable(); // Foreign key for table1
|
table.uuid(`${table1Name}Id`).unsigned().notNullable(); // Foreign key for table1
|
||||||
table.uuid(`${table2Name}Id`).unsigned().notNullable(); // Foreign key for table2
|
table.uuid(`${table2Name}Id`).unsigned().notNullable(); // Foreign key for table2
|
||||||
table.foreign(`${table1Name}Id`).references("id").inTable(table1Name);
|
table.foreign(`${table1Name}Id`).references("id").inTable(table1Name).onDelete("CASCADE");
|
||||||
table.foreign(`${table2Name}Id`).references("id").inTable(table2Name);
|
table.foreign(`${table2Name}Id`).references("id").inTable(table2Name).onDelete("CASCADE");
|
||||||
});
|
});
|
||||||
|
|
||||||
// one time logic
|
// one time logic
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ import {
|
|||||||
projectAdminPermissions,
|
projectAdminPermissions,
|
||||||
projectMemberPermissions,
|
projectMemberPermissions,
|
||||||
projectNoAccessPermissions,
|
projectNoAccessPermissions,
|
||||||
ProjectPermissionSet
|
ProjectPermissionSet,
|
||||||
|
projectViewerPermission
|
||||||
} from "./project-permission";
|
} from "./project-permission";
|
||||||
|
|
||||||
type TPermissionServiceFactoryDep = {
|
type TPermissionServiceFactoryDep = {
|
||||||
@@ -74,6 +75,8 @@ export const permissionServiceFactory = ({
|
|||||||
return projectAdminPermissions;
|
return projectAdminPermissions;
|
||||||
case ProjectMembershipRole.Member:
|
case ProjectMembershipRole.Member:
|
||||||
return projectMemberPermissions;
|
return projectMemberPermissions;
|
||||||
|
case ProjectMembershipRole.Viewer:
|
||||||
|
return projectViewerPermission;
|
||||||
case ProjectMembershipRole.NoAccess:
|
case ProjectMembershipRole.NoAccess:
|
||||||
return projectNoAccessPermissions;
|
return projectNoAccessPermissions;
|
||||||
case ProjectMembershipRole.Custom:
|
case ProjectMembershipRole.Custom:
|
||||||
|
|||||||
@@ -114,6 +114,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
|
|||||||
authMethod: AuthMethod.GITLAB,
|
authMethod: AuthMethod.GITLAB,
|
||||||
callbackPort: req.query.state as string
|
callbackPort: req.query.state as string
|
||||||
});
|
});
|
||||||
|
console.log({ isUserCompleted, providerAuthToken });
|
||||||
|
|
||||||
return cb(null, { isUserCompleted, providerAuthToken });
|
return cb(null, { isUserCompleted, providerAuthToken });
|
||||||
}
|
}
|
||||||
@@ -152,7 +153,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
|
|||||||
// this is due to zod type difference
|
// this is due to zod type difference
|
||||||
}) as any,
|
}) as any,
|
||||||
handler: (req, res) => {
|
handler: (req, res) => {
|
||||||
if (req.passportUser.isCompleted) {
|
if (req.passportUser.isUserCompleted) {
|
||||||
return res.redirect(
|
return res.redirect(
|
||||||
`${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(
|
`${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(
|
||||||
req.passportUser.providerAuthToken
|
req.passportUser.providerAuthToken
|
||||||
@@ -197,7 +198,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
|
|||||||
// this is due to zod type difference
|
// this is due to zod type difference
|
||||||
}) as any,
|
}) as any,
|
||||||
handler: (req, res) => {
|
handler: (req, res) => {
|
||||||
if (req.passportUser.isCompleted) {
|
if (req.passportUser.isUserCompleted) {
|
||||||
return res.redirect(
|
return res.redirect(
|
||||||
`${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(
|
`${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(
|
||||||
req.passportUser.providerAuthToken
|
req.passportUser.providerAuthToken
|
||||||
@@ -242,7 +243,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
|
|||||||
// this is due to zod type difference
|
// this is due to zod type difference
|
||||||
}) as any,
|
}) as any,
|
||||||
handler: (req, res) => {
|
handler: (req, res) => {
|
||||||
if (req.passportUser.isCompleted) {
|
if (req.passportUser.isUserCompleted) {
|
||||||
return res.redirect(
|
return res.redirect(
|
||||||
`${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(
|
`${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(
|
||||||
req.passportUser.providerAuthToken
|
req.passportUser.providerAuthToken
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ export const registerLoginRouter = async (server: FastifyZodProvider) => {
|
|||||||
email: req.body.email,
|
email: req.body.email,
|
||||||
ip: req.realIp,
|
ip: req.realIp,
|
||||||
userAgent,
|
userAgent,
|
||||||
|
providerAuthToken: req.body.providerAuthToken,
|
||||||
clientProof: req.body.clientProof
|
clientProof: req.body.clientProof
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -86,7 +86,8 @@ export const registerSignupRouter = async (server: FastifyZodProvider) => {
|
|||||||
await server.services.signup.completeEmailAccountSignup({
|
await server.services.signup.completeEmailAccountSignup({
|
||||||
...req.body,
|
...req.body,
|
||||||
ip: req.realIp,
|
ip: req.realIp,
|
||||||
userAgent
|
userAgent,
|
||||||
|
authorization: req.headers.authorization
|
||||||
});
|
});
|
||||||
|
|
||||||
res.setCookie("jid", refreshToken, {
|
res.setCookie("jid", refreshToken, {
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import { getConfig } from "@app/lib/config/env";
|
||||||
|
import jwt from "jsonwebtoken";
|
||||||
|
import {
|
||||||
|
AuthModeProviderJwtTokenPayload,
|
||||||
|
AuthModeProviderSignUpTokenPayload,
|
||||||
|
AuthTokenType
|
||||||
|
} from "./auth-type";
|
||||||
|
import { BadRequestError, UnauthorizedError } from "@app/lib/errors";
|
||||||
|
|
||||||
|
export const validateProviderAuthToken = (providerToken: string, email: string) => {
|
||||||
|
if (!providerToken) throw new UnauthorizedError();
|
||||||
|
const appCfg = getConfig();
|
||||||
|
const decodedToken = jwt.verify(
|
||||||
|
providerToken,
|
||||||
|
appCfg.JWT_AUTH_SECRET
|
||||||
|
) as AuthModeProviderJwtTokenPayload;
|
||||||
|
|
||||||
|
console.log(decodedToken);
|
||||||
|
if (decodedToken.authTokenType !== AuthTokenType.PROVIDER_TOKEN) throw new UnauthorizedError();
|
||||||
|
if (decodedToken.email !== email) throw new Error("Invalid auth credentials");
|
||||||
|
};
|
||||||
|
|
||||||
|
export const validateSignUpAuthorization = async (token: string, userId: string) => {
|
||||||
|
const appCfg = getConfig();
|
||||||
|
const [AUTH_TOKEN_TYPE, AUTH_TOKEN_VALUE] = <[string, string]>token?.split(" ", 2) ?? [
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
];
|
||||||
|
if (AUTH_TOKEN_TYPE === null) {
|
||||||
|
throw new BadRequestError({ message: "Missing Authorization Header in the request header." });
|
||||||
|
}
|
||||||
|
if (AUTH_TOKEN_TYPE.toLowerCase() !== "bearer") {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: `The provided authentication type '${AUTH_TOKEN_TYPE}' is not supported.`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (AUTH_TOKEN_VALUE === null) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Missing Authorization Body in the request header"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const decodedToken = jwt.verify(
|
||||||
|
AUTH_TOKEN_VALUE,
|
||||||
|
appCfg.JWT_AUTH_SECRET
|
||||||
|
) as AuthModeProviderSignUpTokenPayload;
|
||||||
|
|
||||||
|
if (decodedToken.authTokenType !== AuthTokenType.SIGNUP_TOKEN) throw new UnauthorizedError();
|
||||||
|
if (decodedToken.userId !== userId) throw new UnauthorizedError();
|
||||||
|
};
|
||||||
@@ -16,15 +16,7 @@ import {
|
|||||||
TVerifyMfaTokenDTO
|
TVerifyMfaTokenDTO
|
||||||
} from "./auth-login-type";
|
} from "./auth-login-type";
|
||||||
import { AuthMethod, AuthTokenType } from "./auth-type";
|
import { AuthMethod, AuthTokenType } from "./auth-type";
|
||||||
|
import { validateProviderAuthToken } from "./auth-fns";
|
||||||
const isValidProviderAuthToken = (email: string, jwtSecret: string, providerAuthToken?: string) => {
|
|
||||||
if (!providerAuthToken) return false;
|
|
||||||
const decodedToken = jwt.verify(providerAuthToken, jwtSecret) as jwt.JwtPayload;
|
|
||||||
|
|
||||||
if (decodedToken.authTokenType !== AuthTokenType.PROVIDER_TOKEN) return false;
|
|
||||||
if (decodedToken.email !== email) return false;
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
type TAuthLoginServiceFactoryDep = {
|
type TAuthLoginServiceFactoryDep = {
|
||||||
userDal: TUserDalFactory;
|
userDal: TUserDalFactory;
|
||||||
@@ -136,13 +128,10 @@ export const authLoginServiceFactory = ({
|
|||||||
if (!userEnc || (userEnc && !userEnc.isAccepted)) {
|
if (!userEnc || (userEnc && !userEnc.isAccepted)) {
|
||||||
throw new Error("Failed to find user");
|
throw new Error("Failed to find user");
|
||||||
}
|
}
|
||||||
const cfg = getConfig();
|
if (!userEnc.authMethods?.includes(AuthMethod.EMAIL)) {
|
||||||
if (
|
validateProviderAuthToken(providerAuthToken as string, email);
|
||||||
!userEnc.authMethods?.includes(AuthMethod.EMAIL) &&
|
|
||||||
!isValidProviderAuthToken(email, cfg.JWT_AUTH_SECRET, providerAuthToken)
|
|
||||||
) {
|
|
||||||
throw new Error("Invalid authorization request");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const serverSrpKey = await generateSrpServerKey(userEnc.salt, userEnc.verifier);
|
const serverSrpKey = await generateSrpServerKey(userEnc.salt, userEnc.verifier);
|
||||||
const userEncKeys = await userDal.updateUserEncryptionByUserId(userEnc.userId, {
|
const userEncKeys = await userDal.updateUserEncryptionByUserId(userEnc.userId, {
|
||||||
clientPublicKey,
|
clientPublicKey,
|
||||||
@@ -166,11 +155,8 @@ export const authLoginServiceFactory = ({
|
|||||||
if (!userEnc) throw new Error("Failed to find user");
|
if (!userEnc) throw new Error("Failed to find user");
|
||||||
const cfg = getConfig();
|
const cfg = getConfig();
|
||||||
|
|
||||||
if (
|
if (!userEnc.authMethods?.includes(AuthMethod.EMAIL)) {
|
||||||
!userEnc.authMethods?.includes(AuthMethod.EMAIL) &&
|
validateProviderAuthToken(providerAuthToken as string, email);
|
||||||
!isValidProviderAuthToken(email, cfg.JWT_AUTH_SECRET, providerAuthToken)
|
|
||||||
) {
|
|
||||||
throw new Error("Invalid authorization request");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!userEnc.serverPrivateKey || !userEnc.clientPublicKey)
|
if (!userEnc.serverPrivateKey || !userEnc.clientPublicKey)
|
||||||
@@ -252,7 +238,6 @@ export const authLoginServiceFactory = ({
|
|||||||
}
|
}
|
||||||
const isLinkingRequired = !user?.authMethods?.includes(authMethod);
|
const isLinkingRequired = !user?.authMethods?.includes(authMethod);
|
||||||
const isUserCompleted = user.isAccepted;
|
const isUserCompleted = user.isAccepted;
|
||||||
|
|
||||||
const providerAuthToken = jwt.sign(
|
const providerAuthToken = jwt.sign(
|
||||||
{
|
{
|
||||||
authTokenType: AuthTokenType.PROVIDER_TOKEN,
|
authTokenType: AuthTokenType.PROVIDER_TOKEN,
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { TUserDalFactory } from "../user/user-dal";
|
|||||||
import { TAuthDalFactory } from "./auth-dal";
|
import { TAuthDalFactory } from "./auth-dal";
|
||||||
import { TCompleteAccountInviteDTO, TCompleteAccountSignupDTO } from "./auth-signup-type";
|
import { TCompleteAccountInviteDTO, TCompleteAccountSignupDTO } from "./auth-signup-type";
|
||||||
import { AuthMethod, AuthTokenType } from "./auth-type";
|
import { AuthMethod, AuthTokenType } from "./auth-type";
|
||||||
|
import { validateProviderAuthToken, validateSignUpAuthorization } from "./auth-fns";
|
||||||
|
|
||||||
type TAuthSignupDep = {
|
type TAuthSignupDep = {
|
||||||
authDal: TAuthDalFactory;
|
authDal: TAuthDalFactory;
|
||||||
@@ -98,7 +99,7 @@ export const authSignupServiceFactory = ({
|
|||||||
email,
|
email,
|
||||||
firstName,
|
firstName,
|
||||||
lastName,
|
lastName,
|
||||||
// providerAuthToken,
|
providerAuthToken,
|
||||||
salt,
|
salt,
|
||||||
verifier,
|
verifier,
|
||||||
publicKey,
|
publicKey,
|
||||||
@@ -111,13 +112,20 @@ export const authSignupServiceFactory = ({
|
|||||||
encryptedPrivateKeyIV,
|
encryptedPrivateKeyIV,
|
||||||
encryptedPrivateKeyTag,
|
encryptedPrivateKeyTag,
|
||||||
ip,
|
ip,
|
||||||
userAgent
|
userAgent,
|
||||||
|
authorization
|
||||||
}: TCompleteAccountSignupDTO) => {
|
}: TCompleteAccountSignupDTO) => {
|
||||||
const user = await userDal.findUserByEmail(email);
|
const user = await userDal.findUserByEmail(email);
|
||||||
if (!user || (user && user.isAccepted)) {
|
if (!user || (user && user.isAccepted)) {
|
||||||
throw new Error("Failed to complete account for complete user");
|
throw new Error("Failed to complete account for complete user");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (providerAuthToken) {
|
||||||
|
validateProviderAuthToken(providerAuthToken, user.email);
|
||||||
|
} else {
|
||||||
|
validateSignUpAuthorization(authorization, user.id);
|
||||||
|
}
|
||||||
|
|
||||||
const updateduser = await authDal.transaction(async (tx) => {
|
const updateduser = await authDal.transaction(async (tx) => {
|
||||||
const us = await userDal.updateById(user.id, { firstName, lastName, isAccepted: true }, tx);
|
const us = await userDal.updateById(user.id, { firstName, lastName, isAccepted: true }, tx);
|
||||||
if (!us) throw new Error("User not found");
|
if (!us) throw new Error("User not found");
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ export type TCompleteAccountSignupDTO = {
|
|||||||
attributionSource?: string | undefined;
|
attributionSource?: string | undefined;
|
||||||
ip: string;
|
ip: string;
|
||||||
userAgent: string;
|
userAgent: string;
|
||||||
|
authorization: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TCompleteAccountInviteDTO = {
|
export type TCompleteAccountInviteDTO = {
|
||||||
|
|||||||
@@ -47,3 +47,13 @@ export type AuthModeRefreshJwtTokenPayload = {
|
|||||||
tokenVersionId: string;
|
tokenVersionId: string;
|
||||||
refreshVersion: number;
|
refreshVersion: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type AuthModeProviderJwtTokenPayload = {
|
||||||
|
authTokenType: AuthTokenType.PROVIDER_TOKEN;
|
||||||
|
email: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AuthModeProviderSignUpTokenPayload = {
|
||||||
|
authTokenType: AuthTokenType.SIGNUP_TOKEN;
|
||||||
|
userId: string;
|
||||||
|
};
|
||||||
|
|||||||
Generated
+4703
-44580
File diff suppressed because it is too large
Load Diff
+10
-13
@@ -12,9 +12,6 @@
|
|||||||
"storybook": "storybook dev -p 6006 -s ./public",
|
"storybook": "storybook dev -p 6006 -s ./public",
|
||||||
"build-storybook": "storybook build"
|
"build-storybook": "storybook build"
|
||||||
},
|
},
|
||||||
"overrides": {
|
|
||||||
"@radix-ui/react-focus-scope": "1.0.4"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@casl/ability": "^6.5.0",
|
"@casl/ability": "^6.5.0",
|
||||||
"@casl/react": "^3.1.0",
|
"@casl/react": "^3.1.0",
|
||||||
@@ -34,19 +31,19 @@
|
|||||||
"@octokit/rest": "^19.0.7",
|
"@octokit/rest": "^19.0.7",
|
||||||
"@radix-ui/react-accordion": "^1.1.2",
|
"@radix-ui/react-accordion": "^1.1.2",
|
||||||
"@radix-ui/react-alert-dialog": "^1.0.5",
|
"@radix-ui/react-alert-dialog": "^1.0.5",
|
||||||
"@radix-ui/react-checkbox": "^1.0.1",
|
"@radix-ui/react-checkbox": "^1.0.4",
|
||||||
"@radix-ui/react-dialog": "^1.0.5",
|
"@radix-ui/react-dialog": "^1.0.5",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.0.6",
|
"@radix-ui/react-dropdown-menu": "^2.0.6",
|
||||||
"@radix-ui/react-hover-card": "^1.0.3",
|
"@radix-ui/react-hover-card": "^1.0.7",
|
||||||
"@radix-ui/react-label": "^2.0.0",
|
"@radix-ui/react-label": "^2.0.2",
|
||||||
"@radix-ui/react-popover": "^1.0.3",
|
"@radix-ui/react-popover": "^1.0.7",
|
||||||
"@radix-ui/react-popper": "^1.1.1",
|
"@radix-ui/react-popper": "^1.1.3",
|
||||||
"@radix-ui/react-progress": "^1.0.1",
|
"@radix-ui/react-progress": "^1.0.3",
|
||||||
"@radix-ui/react-select": "^2.0.0",
|
"@radix-ui/react-select": "^2.0.0",
|
||||||
"@radix-ui/react-switch": "^1.0.1",
|
"@radix-ui/react-switch": "^1.0.3",
|
||||||
"@radix-ui/react-tabs": "^1.0.2",
|
"@radix-ui/react-tabs": "^1.0.4",
|
||||||
"@radix-ui/react-toast": "^1.1.2",
|
"@radix-ui/react-toast": "^1.1.5",
|
||||||
"@radix-ui/react-tooltip": "^1.0.4",
|
"@radix-ui/react-tooltip": "^1.0.7",
|
||||||
"@reduxjs/toolkit": "^1.8.3",
|
"@reduxjs/toolkit": "^1.8.3",
|
||||||
"@stripe/react-stripe-js": "^1.16.3",
|
"@stripe/react-stripe-js": "^1.16.3",
|
||||||
"@stripe/stripe-js": "^1.46.0",
|
"@stripe/stripe-js": "^1.46.0",
|
||||||
|
|||||||
@@ -6,14 +6,22 @@ export const createJunctionTable = (
|
|||||||
knex: Knex,
|
knex: Knex,
|
||||||
tableName: TableName,
|
tableName: TableName,
|
||||||
table1Name: TableName,
|
table1Name: TableName,
|
||||||
table2Name: TableName
|
table2Name: TableName,
|
||||||
) =>
|
) =>
|
||||||
knex.schema.createTable(tableName, (table) => {
|
knex.schema.createTable(tableName, (table) => {
|
||||||
table.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
table.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
table.uuid(`${table1Name}Id`).unsigned().notNullable(); // Foreign key for table1
|
table.uuid(`${table1Name}Id`).unsigned().notNullable(); // Foreign key for table1
|
||||||
table.uuid(`${table2Name}Id`).unsigned().notNullable(); // Foreign key for table2
|
table.uuid(`${table2Name}Id`).unsigned().notNullable(); // Foreign key for table2
|
||||||
table.foreign(`${table1Name}Id`).references("id").inTable(table1Name);
|
table
|
||||||
table.foreign(`${table2Name}Id`).references("id").inTable(table2Name);
|
.foreign(`${table1Name}Id`)
|
||||||
|
.references("id")
|
||||||
|
.inTable(table1Name)
|
||||||
|
.onDelete("CASCADE");
|
||||||
|
table
|
||||||
|
.foreign(`${table2Name}Id`)
|
||||||
|
.references("id")
|
||||||
|
.inTable(table2Name)
|
||||||
|
.onDelete("CASCADE");
|
||||||
});
|
});
|
||||||
|
|
||||||
// one time logic
|
// one time logic
|
||||||
|
|||||||
Reference in New Issue
Block a user