mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-08 22:13:59 +01:00
feat(server): bind idle credential eligibility to incoming wake proof (#18639)
Reviewed and verified at d1e3afa4af.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
0b87308d5d
commit
5877d751c0
31 files changed
+2071
-53
No files matched your search
@@ -1,3 +1,4 @@
|
||||
import { idleApiActivity } from "../services/idle-api-activity.js";
|
||||
import { createHash, timingSafeEqual } from "node:crypto";
|
||||
import type { Request, RequestHandler } from "express";
|
||||
import { and, eq, isNull, sql } from "drizzle-orm";
|
||||
@@ -43,7 +44,7 @@ import { ensureHumanRoleDefaultGrants } from "../services/principal-access-compa
|
||||
import { forbidden, unauthorized, unprocessable } from "../errors.js";
|
||||
|
||||
export { isCloudManagedInstance } from "../services/cloud-instance.js";
|
||||
import { cloudTenantPrimaryCompanyId } from "../services/cloud-instance.js";
|
||||
import { cloudTenantPrimaryCompanyId, isCloudManagedInstance } from "../services/cloud-instance.js";
|
||||
|
||||
function hashToken(token: string) {
|
||||
return createHash("sha256").update(token).digest("hex");
|
||||
@@ -329,6 +330,9 @@ export function actorMiddleware(db: Db, opts: ActorMiddlewareOptions): RequestHa
|
||||
runId: runIdHeader || undefined,
|
||||
source: "board_key",
|
||||
};
|
||||
if (isCloudManagedInstance() && (access.isInstanceAdmin || access.companyIds.length)) {
|
||||
_res.once("finish", () => { if (_res.statusCode >= 200 && _res.statusCode < 400) idleApiActivity.record(); });
|
||||
}
|
||||
next();
|
||||
return;
|
||||
}
|
||||
@@ -521,7 +525,9 @@ export function actorMiddleware(db: Db, opts: ActorMiddlewareOptions): RequestHa
|
||||
runId: runIdHeader || undefined,
|
||||
source: "agent_key",
|
||||
};
|
||||
|
||||
if (isCloudManagedInstance() && req.actor.onBehalfOfMemberships?.length) {
|
||||
_res.once("finish", () => { if (_res.statusCode >= 200 && _res.statusCode < 400) idleApiActivity.record(); });
|
||||
}
|
||||
next();
|
||||
};
|
||||
return async (req, res, next) => {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import type { Request } from "express";
|
||||
import type { VerifiedIdleCapabilities } from "../services/idle-incoming-wake-capability.js";
|
||||
import type { RequestHandler } from "express";
|
||||
import { logger } from "./logger.js";
|
||||
import {
|
||||
@@ -6,6 +8,12 @@ import {
|
||||
type CloudControlAction,
|
||||
} from "../services/cloud-runtime-identity.js";
|
||||
|
||||
const idleCapabilities = new WeakMap<Request, VerifiedIdleCapabilities>();
|
||||
/** Only this middleware's verified assertion can install request capabilities. */
|
||||
export function verifiedIdleCapabilities(req: Request): VerifiedIdleCapabilities | undefined {
|
||||
return idleCapabilities.get(req);
|
||||
}
|
||||
|
||||
/** Endpoint → method → the one action a control assertion must name to take it. */
|
||||
const ACTIONS_BY_ENDPOINT: Record<string, Record<string, CloudControlAction>> = {
|
||||
"/api/instance/connector-events/wake": { POST: "connector-events:wake" },
|
||||
@@ -50,7 +58,8 @@ export function cloudControlMiddleware(): RequestHandler {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
verifyCloudControlAssertion({ compactJws: assertion, expectedAction });
|
||||
const claims = verifyCloudControlAssertion({ compactJws: assertion, expectedAction });
|
||||
if (claims.idleCapabilities) idleCapabilities.set(req, claims.idleCapabilities as VerifiedIdleCapabilities);
|
||||
} catch (error) {
|
||||
logger.warn({ err: error }, "Rejected Cloud control assertion");
|
||||
res.status(401).json({ error: "invalid_cloud_control_assertion" });
|
||||
|
||||
Reference in new issue
Block a user