fix: harden public routine trigger auth
This commit is contained in:
@@ -17,7 +17,7 @@ export function routineRoutes(db: Db) {
|
|||||||
const router = Router();
|
const router = Router();
|
||||||
const svc = routineService(db);
|
const svc = routineService(db);
|
||||||
|
|
||||||
async function assertCanManageCompanyRoutine(req: Request, companyId: string, assigneeAgentId?: string | null) {
|
function assertCanManageCompanyRoutine(req: Request, companyId: string, assigneeAgentId?: string | null) {
|
||||||
assertCompanyAccess(req, companyId);
|
assertCompanyAccess(req, companyId);
|
||||||
if (req.actor.type === "board") return;
|
if (req.actor.type === "board") return;
|
||||||
if (req.actor.type !== "agent" || !req.actor.agentId) throw unauthorized();
|
if (req.actor.type !== "agent" || !req.actor.agentId) throw unauthorized();
|
||||||
@@ -47,7 +47,7 @@ export function routineRoutes(db: Db) {
|
|||||||
|
|
||||||
router.post("/companies/:companyId/routines", validate(createRoutineSchema), async (req, res) => {
|
router.post("/companies/:companyId/routines", validate(createRoutineSchema), async (req, res) => {
|
||||||
const companyId = req.params.companyId as string;
|
const companyId = req.params.companyId as string;
|
||||||
await assertCanManageCompanyRoutine(req, companyId, req.body.assigneeAgentId);
|
assertCanManageCompanyRoutine(req, companyId, req.body.assigneeAgentId);
|
||||||
const created = await svc.create(companyId, req.body, {
|
const created = await svc.create(companyId, req.body, {
|
||||||
agentId: req.actor.type === "agent" ? req.actor.agentId : null,
|
agentId: req.actor.type === "agent" ? req.actor.agentId : null,
|
||||||
userId: req.actor.type === "board" ? req.actor.userId ?? "board" : null,
|
userId: req.actor.type === "board" ? req.actor.userId ?? "board" : null,
|
||||||
|
|||||||
@@ -1016,7 +1016,14 @@ export function routineService(db: Db, deps: { heartbeat?: IssueAssignmentWakeup
|
|||||||
const secretValue = await resolveTriggerSecret(trigger, routine.companyId);
|
const secretValue = await resolveTriggerSecret(trigger, routine.companyId);
|
||||||
if (trigger.signingMode === "bearer") {
|
if (trigger.signingMode === "bearer") {
|
||||||
const expected = `Bearer ${secretValue}`;
|
const expected = `Bearer ${secretValue}`;
|
||||||
if (!input.authorizationHeader || input.authorizationHeader.trim() !== expected) {
|
const provided = input.authorizationHeader?.trim() ?? "";
|
||||||
|
const expectedBuf = Buffer.from(expected);
|
||||||
|
const providedBuf = Buffer.alloc(expectedBuf.length);
|
||||||
|
providedBuf.write(provided.slice(0, expectedBuf.length));
|
||||||
|
const valid =
|
||||||
|
provided.length === expected.length &&
|
||||||
|
crypto.timingSafeEqual(providedBuf, expectedBuf);
|
||||||
|
if (!valid) {
|
||||||
throw unauthorized();
|
throw unauthorized();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user