mirror of
https://github.com/fosrl/pangolin.git
synced 2026-05-21 16:25:19 +00:00
🚧 prepare tables for auth methods
This commit is contained in:
@@ -141,7 +141,10 @@ export enum ActionsEnum {
|
|||||||
listResourcePolicyRoles = "listResourcePolicyRoles",
|
listResourcePolicyRoles = "listResourcePolicyRoles",
|
||||||
setResourcePolicyRoles = "setResourcePolicyRoles",
|
setResourcePolicyRoles = "setResourcePolicyRoles",
|
||||||
listResourcePolicyUsers = "listResourcePolicyUsers",
|
listResourcePolicyUsers = "listResourcePolicyUsers",
|
||||||
setResourcePolicyUsers = "setResourcePolicyUsers"
|
setResourcePolicyUsers = "setResourcePolicyUsers",
|
||||||
|
setResourcePolicyPassword = "setResourcePolicyPassword",
|
||||||
|
setResourcePolicyPincode = "setResourcePolicyPincode",
|
||||||
|
setResourcePolicyHeaderAuth = "setResourcePolicyHeaderAuth"
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function checkUserActionPermission(
|
export async function checkUserActionPermission(
|
||||||
|
|||||||
@@ -516,11 +516,6 @@ export const resourceHeaderAuthExtendedCompatibility = pgTable(
|
|||||||
resourceId: integer("resourceId")
|
resourceId: integer("resourceId")
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => resources.resourceId, { onDelete: "cascade" }),
|
.references(() => resources.resourceId, { onDelete: "cascade" }),
|
||||||
resourcePolicyId: integer("resourcePolicyId")
|
|
||||||
.notNull()
|
|
||||||
.references(() => resourcePolicies.resourcePolicyId, {
|
|
||||||
onDelete: "cascade"
|
|
||||||
}),
|
|
||||||
extendedCompatibilityIsActivated: boolean(
|
extendedCompatibilityIsActivated: boolean(
|
||||||
"extendedCompatibilityIsActivated"
|
"extendedCompatibilityIsActivated"
|
||||||
)
|
)
|
||||||
@@ -571,9 +566,6 @@ export const resourcePolicyPassword = pgTable("resourcePolicyPassword", {
|
|||||||
|
|
||||||
export const resourcePolicyHeaderAuth = pgTable("resourcePolicyHeaderAuth", {
|
export const resourcePolicyHeaderAuth = pgTable("resourcePolicyHeaderAuth", {
|
||||||
headerAuthId: serial("headerAuthId").primaryKey(),
|
headerAuthId: serial("headerAuthId").primaryKey(),
|
||||||
resourceId: integer("resourceId")
|
|
||||||
.notNull()
|
|
||||||
.references(() => resources.resourceId, { onDelete: "cascade" }),
|
|
||||||
headerAuthHash: varchar("headerAuthHash").notNull(),
|
headerAuthHash: varchar("headerAuthHash").notNull(),
|
||||||
resourcePolicyId: integer("resourcePolicyId")
|
resourcePolicyId: integer("resourcePolicyId")
|
||||||
.notNull()
|
.notNull()
|
||||||
|
|||||||
@@ -734,6 +734,33 @@ authenticated.post(
|
|||||||
resource.setResourcePolicyUsers
|
resource.setResourcePolicyUsers
|
||||||
);
|
);
|
||||||
|
|
||||||
|
authenticated.post(
|
||||||
|
"/resource-policy/:resourcePolicyId/password",
|
||||||
|
verifyResourcePolicyAccess,
|
||||||
|
verifyLimits,
|
||||||
|
verifyUserHasAction(ActionsEnum.setResourcePolicyPassword),
|
||||||
|
logActionAudit(ActionsEnum.setResourcePolicyPassword),
|
||||||
|
policy.setResourcePolicyPassword
|
||||||
|
);
|
||||||
|
|
||||||
|
authenticated.post(
|
||||||
|
"/resource-policy/:resourcePolicyId/pincode",
|
||||||
|
verifyResourcePolicyAccess,
|
||||||
|
verifyLimits,
|
||||||
|
verifyUserHasAction(ActionsEnum.setResourcePolicyPincode),
|
||||||
|
logActionAudit(ActionsEnum.setResourcePolicyPincode),
|
||||||
|
policy.setResourcePolicyPincode
|
||||||
|
);
|
||||||
|
|
||||||
|
authenticated.post(
|
||||||
|
"/resource-policy/:resourcePolicyId/header-auth",
|
||||||
|
verifyResourcePolicyAccess,
|
||||||
|
verifyLimits,
|
||||||
|
verifyUserHasAction(ActionsEnum.setResourcePolicyHeaderAuth),
|
||||||
|
logActionAudit(ActionsEnum.setResourcePolicyHeaderAuth),
|
||||||
|
policy.setResourcePolicyHeaderAuth
|
||||||
|
);
|
||||||
|
|
||||||
authenticated.post(
|
authenticated.post(
|
||||||
`/resource/:resourceId/password`,
|
`/resource/:resourceId/password`,
|
||||||
verifyResourceAccess,
|
verifyResourceAccess,
|
||||||
|
|||||||
@@ -632,6 +632,33 @@ authenticated.put(
|
|||||||
policy.setResourcePolicyAccessControl
|
policy.setResourcePolicyAccessControl
|
||||||
);
|
);
|
||||||
|
|
||||||
|
authenticated.post(
|
||||||
|
"/resource-policy/:resourcePolicyId/password",
|
||||||
|
verifyApiKeyResourcePolicyAccess,
|
||||||
|
verifyLimits,
|
||||||
|
verifyApiKeyHasAction(ActionsEnum.setResourcePolicyPassword),
|
||||||
|
logActionAudit(ActionsEnum.setResourcePolicyPassword),
|
||||||
|
policy.setResourcePolicyPassword
|
||||||
|
);
|
||||||
|
|
||||||
|
authenticated.post(
|
||||||
|
"/resource-policy/:resourcePolicyId/pincode",
|
||||||
|
verifyApiKeyResourcePolicyAccess,
|
||||||
|
verifyLimits,
|
||||||
|
verifyApiKeyHasAction(ActionsEnum.setResourcePolicyPincode),
|
||||||
|
logActionAudit(ActionsEnum.setResourcePolicyPincode),
|
||||||
|
policy.setResourcePolicyPincode
|
||||||
|
);
|
||||||
|
|
||||||
|
authenticated.post(
|
||||||
|
"/resource-policy/:resourcePolicyId/header-auth",
|
||||||
|
verifyApiKeyResourcePolicyAccess,
|
||||||
|
verifyLimits,
|
||||||
|
verifyApiKeyHasAction(ActionsEnum.setResourcePolicyHeaderAuth),
|
||||||
|
logActionAudit(ActionsEnum.setResourcePolicyHeaderAuth),
|
||||||
|
policy.setResourcePolicyHeaderAuth
|
||||||
|
);
|
||||||
|
|
||||||
authenticated.post(
|
authenticated.post(
|
||||||
"/resource/:resourceId/roles/add",
|
"/resource/:resourceId/roles/add",
|
||||||
verifyApiKeyResourceAccess,
|
verifyApiKeyResourceAccess,
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
export * from "./getResourcePolicy";
|
export * from "./getResourcePolicy";
|
||||||
export * from "./updateResourcePolicy";
|
export * from "./updateResourcePolicy";
|
||||||
export * from "./setResourcePolicyAccessControl";
|
export * from "./setResourcePolicyAccessControl";
|
||||||
|
export * from "./setResourcePolicyPassword";
|
||||||
|
export * from "./setResourcePolicyPincode";
|
||||||
|
export * from "./setResourcePolicyHeaderAuth";
|
||||||
|
|||||||
130
server/routers/policy/setResourcePolicyHeaderAuth.ts
Normal file
130
server/routers/policy/setResourcePolicyHeaderAuth.ts
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
import { Request, Response, NextFunction } from "express";
|
||||||
|
import { z } from "zod";
|
||||||
|
import {
|
||||||
|
db,
|
||||||
|
resourcePolicyHeaderAuth,
|
||||||
|
resourcePolicyHeaderAuthExtendedCompatibility
|
||||||
|
} from "@server/db";
|
||||||
|
import { eq } from "drizzle-orm";
|
||||||
|
import HttpCode from "@server/types/HttpCode";
|
||||||
|
import createHttpError from "http-errors";
|
||||||
|
import { fromError } from "zod-validation-error";
|
||||||
|
import { response } from "@server/lib/response";
|
||||||
|
import logger from "@server/logger";
|
||||||
|
import { hashPassword } from "@server/auth/password";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
|
const setResourcePolicyHeaderAuthParamsSchema = z.object({
|
||||||
|
resourcePolicyId: z.string().transform(Number).pipe(z.int().positive())
|
||||||
|
});
|
||||||
|
|
||||||
|
const setResourcePolicyHeaderAuthBodySchema = z.strictObject({
|
||||||
|
user: z.string().min(4).max(100).nullable(),
|
||||||
|
password: z.string().min(4).max(100).nullable(),
|
||||||
|
extendedCompatibility: z.boolean().nullable()
|
||||||
|
});
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "post",
|
||||||
|
path: "/resource-policy/{resourcePolicyId}/header-auth",
|
||||||
|
description:
|
||||||
|
"Set or update the header authentication for a resource policy. If user and password is not provided, it will remove the header authentication.",
|
||||||
|
tags: [OpenAPITags.Resource],
|
||||||
|
request: {
|
||||||
|
params: setResourcePolicyHeaderAuthParamsSchema,
|
||||||
|
body: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: setResourcePolicyHeaderAuthBodySchema
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
export async function setResourcePolicyHeaderAuth(
|
||||||
|
req: Request,
|
||||||
|
res: Response,
|
||||||
|
next: NextFunction
|
||||||
|
): Promise<any> {
|
||||||
|
try {
|
||||||
|
const parsedParams = setResourcePolicyHeaderAuthParamsSchema.safeParse(
|
||||||
|
req.params
|
||||||
|
);
|
||||||
|
if (!parsedParams.success) {
|
||||||
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.BAD_REQUEST,
|
||||||
|
fromError(parsedParams.error).toString()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const parsedBody = setResourcePolicyHeaderAuthBodySchema.safeParse(
|
||||||
|
req.body
|
||||||
|
);
|
||||||
|
if (!parsedBody.success) {
|
||||||
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.BAD_REQUEST,
|
||||||
|
fromError(parsedBody.error).toString()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { resourcePolicyId } = parsedParams.data;
|
||||||
|
const { user, password, extendedCompatibility } = parsedBody.data;
|
||||||
|
|
||||||
|
await db.transaction(async (trx) => {
|
||||||
|
await trx
|
||||||
|
.delete(resourcePolicyHeaderAuth)
|
||||||
|
.where(
|
||||||
|
eq(
|
||||||
|
resourcePolicyHeaderAuth.resourcePolicyId,
|
||||||
|
resourcePolicyId
|
||||||
|
)
|
||||||
|
);
|
||||||
|
await trx
|
||||||
|
.delete(resourcePolicyHeaderAuthExtendedCompatibility)
|
||||||
|
.where(
|
||||||
|
eq(
|
||||||
|
resourcePolicyHeaderAuthExtendedCompatibility.resourcePolicyId,
|
||||||
|
resourcePolicyId
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (user && password && extendedCompatibility !== null) {
|
||||||
|
const headerAuthHash = await hashPassword(
|
||||||
|
Buffer.from(`${user}:${password}`).toString("base64")
|
||||||
|
);
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
trx
|
||||||
|
.insert(resourcePolicyHeaderAuth)
|
||||||
|
.values({ resourcePolicyId, headerAuthHash }),
|
||||||
|
trx
|
||||||
|
.insert(resourcePolicyHeaderAuthExtendedCompatibility)
|
||||||
|
.values({
|
||||||
|
resourcePolicyId,
|
||||||
|
extendedCompatibilityIsActivated:
|
||||||
|
extendedCompatibility
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return response(res, {
|
||||||
|
data: {},
|
||||||
|
success: true,
|
||||||
|
error: false,
|
||||||
|
message: "Header Authentication set successfully",
|
||||||
|
status: HttpCode.CREATED
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(error);
|
||||||
|
return next(
|
||||||
|
createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
106
server/routers/policy/setResourcePolicyPassword.ts
Normal file
106
server/routers/policy/setResourcePolicyPassword.ts
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
import { Request, Response, NextFunction } from "express";
|
||||||
|
import { z } from "zod";
|
||||||
|
import { db } from "@server/db";
|
||||||
|
import { resourcePolicyPassword } from "@server/db";
|
||||||
|
import { eq } from "drizzle-orm";
|
||||||
|
import HttpCode from "@server/types/HttpCode";
|
||||||
|
import createHttpError from "http-errors";
|
||||||
|
import { fromError } from "zod-validation-error";
|
||||||
|
import { response } from "@server/lib/response";
|
||||||
|
import logger from "@server/logger";
|
||||||
|
import { hashPassword } from "@server/auth/password";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
|
const setResourcePolicyPasswordParamsSchema = z.object({
|
||||||
|
resourcePolicyId: z.string().transform(Number).pipe(z.int().positive())
|
||||||
|
});
|
||||||
|
|
||||||
|
const setResourcePolicyPasswordBodySchema = z.strictObject({
|
||||||
|
password: z.string().min(4).max(100).nullable()
|
||||||
|
});
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "post",
|
||||||
|
path: "/resource-policy/{resourcePolicyId}/password",
|
||||||
|
description:
|
||||||
|
"Set the password for a resource policy. Setting the password to null will remove it.",
|
||||||
|
tags: [OpenAPITags.Resource],
|
||||||
|
request: {
|
||||||
|
params: setResourcePolicyPasswordParamsSchema,
|
||||||
|
body: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: setResourcePolicyPasswordBodySchema
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
export async function setResourcePolicyPassword(
|
||||||
|
req: Request,
|
||||||
|
res: Response,
|
||||||
|
next: NextFunction
|
||||||
|
): Promise<any> {
|
||||||
|
try {
|
||||||
|
const parsedParams = setResourcePolicyPasswordParamsSchema.safeParse(
|
||||||
|
req.params
|
||||||
|
);
|
||||||
|
if (!parsedParams.success) {
|
||||||
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.BAD_REQUEST,
|
||||||
|
fromError(parsedParams.error).toString()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const parsedBody = setResourcePolicyPasswordBodySchema.safeParse(
|
||||||
|
req.body
|
||||||
|
);
|
||||||
|
if (!parsedBody.success) {
|
||||||
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.BAD_REQUEST,
|
||||||
|
fromError(parsedBody.error).toString()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { resourcePolicyId } = parsedParams.data;
|
||||||
|
const { password } = parsedBody.data;
|
||||||
|
|
||||||
|
await db.transaction(async (trx) => {
|
||||||
|
await trx
|
||||||
|
.delete(resourcePolicyPassword)
|
||||||
|
.where(
|
||||||
|
eq(
|
||||||
|
resourcePolicyPassword.resourcePolicyId,
|
||||||
|
resourcePolicyId
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (password) {
|
||||||
|
const passwordHash = await hashPassword(password);
|
||||||
|
|
||||||
|
await trx
|
||||||
|
.insert(resourcePolicyPassword)
|
||||||
|
.values({ resourcePolicyId, passwordHash });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return response(res, {
|
||||||
|
data: {},
|
||||||
|
success: true,
|
||||||
|
error: false,
|
||||||
|
message: "Resource policy password set successfully",
|
||||||
|
status: HttpCode.CREATED
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(error);
|
||||||
|
return next(
|
||||||
|
createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
109
server/routers/policy/setResourcePolicyPincode.ts
Normal file
109
server/routers/policy/setResourcePolicyPincode.ts
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
import { Request, Response, NextFunction } from "express";
|
||||||
|
import { z } from "zod";
|
||||||
|
import { db } from "@server/db";
|
||||||
|
import { resourcePolicyPincode } from "@server/db";
|
||||||
|
import { eq } from "drizzle-orm";
|
||||||
|
import HttpCode from "@server/types/HttpCode";
|
||||||
|
import createHttpError from "http-errors";
|
||||||
|
import { fromError } from "zod-validation-error";
|
||||||
|
import { response } from "@server/lib/response";
|
||||||
|
import logger from "@server/logger";
|
||||||
|
import { hashPassword } from "@server/auth/password";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
|
const setResourcePolicyPincodeParamsSchema = z.object({
|
||||||
|
resourcePolicyId: z.string().transform(Number).pipe(z.int().positive())
|
||||||
|
});
|
||||||
|
|
||||||
|
const setResourcePolicyPincodeBodySchema = z.strictObject({
|
||||||
|
pincode: z
|
||||||
|
.string()
|
||||||
|
.regex(/^\d{6}$/)
|
||||||
|
.or(z.null())
|
||||||
|
});
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "post",
|
||||||
|
path: "/resource-policy/{resourcePolicyId}/pincode",
|
||||||
|
description:
|
||||||
|
"Set the PIN code for a resource policy. Setting the PIN code to null will remove it.",
|
||||||
|
tags: [OpenAPITags.Resource],
|
||||||
|
request: {
|
||||||
|
params: setResourcePolicyPincodeParamsSchema,
|
||||||
|
body: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: setResourcePolicyPincodeBodySchema
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
export async function setResourcePolicyPincode(
|
||||||
|
req: Request,
|
||||||
|
res: Response,
|
||||||
|
next: NextFunction
|
||||||
|
): Promise<any> {
|
||||||
|
try {
|
||||||
|
const parsedParams = setResourcePolicyPincodeParamsSchema.safeParse(
|
||||||
|
req.params
|
||||||
|
);
|
||||||
|
if (!parsedParams.success) {
|
||||||
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.BAD_REQUEST,
|
||||||
|
fromError(parsedParams.error).toString()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const parsedBody = setResourcePolicyPincodeBodySchema.safeParse(
|
||||||
|
req.body
|
||||||
|
);
|
||||||
|
if (!parsedBody.success) {
|
||||||
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.BAD_REQUEST,
|
||||||
|
fromError(parsedBody.error).toString()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { resourcePolicyId } = parsedParams.data;
|
||||||
|
const { pincode } = parsedBody.data;
|
||||||
|
|
||||||
|
await db.transaction(async (trx) => {
|
||||||
|
await trx
|
||||||
|
.delete(resourcePolicyPincode)
|
||||||
|
.where(
|
||||||
|
eq(
|
||||||
|
resourcePolicyPincode.resourcePolicyId,
|
||||||
|
resourcePolicyId
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (pincode) {
|
||||||
|
const pincodeHash = await hashPassword(pincode);
|
||||||
|
|
||||||
|
await trx
|
||||||
|
.insert(resourcePolicyPincode)
|
||||||
|
.values({ resourcePolicyId, pincodeHash, digitLength: 6 });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return response(res, {
|
||||||
|
data: {},
|
||||||
|
success: true,
|
||||||
|
error: false,
|
||||||
|
message: "Resource policy PIN code set successfully",
|
||||||
|
status: HttpCode.CREATED
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(error);
|
||||||
|
return next(
|
||||||
|
createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user