fix: harden public routine trigger auth

This commit is contained in:
dotta
2026-03-20 13:23:31 -05:00
parent 13fd656e2b
commit a62c264ddf
2 changed files with 10 additions and 3 deletions

View File

@@ -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,

View File

@@ -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 {