feat(device-core): protect enrollment identifiers
This commit is contained in:
@@ -4,7 +4,9 @@ import { createServer } from "node:http";
|
||||
import {
|
||||
assertSafeProjection,
|
||||
hashRestrictedIdentifier,
|
||||
maskRestrictedIdentifier,
|
||||
normalizeDiscoverySignal,
|
||||
normalizeRestrictedIdentifier,
|
||||
toSafeDiscoveryView,
|
||||
} from "../../../packages/device-protocol-contract/src/index.mjs";
|
||||
import {
|
||||
@@ -76,6 +78,9 @@ export function createControlCoreApp({
|
||||
if (typeof managementToken !== "string" || managementToken.length < 32) {
|
||||
throw new TypeError("device_management_token_invalid");
|
||||
}
|
||||
if (typeof identifierPepper !== "string" || identifierPepper.length < 32) {
|
||||
throw new TypeError("device_identifier_pepper_invalid");
|
||||
}
|
||||
}
|
||||
|
||||
const server = createServer(async (request, response) => {
|
||||
@@ -121,9 +126,12 @@ export function createControlCoreApp({
|
||||
);
|
||||
const actor = managementActorFromHeaders(request.headers);
|
||||
const input = await readJsonBody(request, 64 * 1024);
|
||||
const protectedInput = managementCommandKind === "enrollment_intent.ensure"
|
||||
? protectEnrollmentIdentifier(input, identifierPepper)
|
||||
: input;
|
||||
const command = normalizeDeviceManagementCommand(
|
||||
managementCommandKind,
|
||||
input,
|
||||
protectedInput,
|
||||
);
|
||||
const requestDigest = managementRequestDigest({
|
||||
actor,
|
||||
@@ -263,6 +271,38 @@ export function createControlCoreApp({
|
||||
return server;
|
||||
}
|
||||
|
||||
function protectEnrollmentIdentifier(input, identifierPepper) {
|
||||
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
||||
throw new TypeError("device_enrollment_input_invalid");
|
||||
}
|
||||
const allowedKeys = new Set([
|
||||
"projectRef",
|
||||
"enrollmentKey",
|
||||
"routeRef",
|
||||
"modelProfileRef",
|
||||
"displayName",
|
||||
"identifier",
|
||||
"expiresAt",
|
||||
]);
|
||||
for (const key of Object.keys(input)) {
|
||||
if (!allowedKeys.has(key)) {
|
||||
throw new TypeError("device_enrollment_input_field_unexpected");
|
||||
}
|
||||
}
|
||||
const identifier = normalizeRestrictedIdentifier(input.identifier);
|
||||
return Object.freeze({
|
||||
projectRef: input.projectRef,
|
||||
enrollmentKey: input.enrollmentKey,
|
||||
routeRef: input.routeRef,
|
||||
modelProfileRef: input.modelProfileRef,
|
||||
displayName: input.displayName,
|
||||
identifierKind: identifier.kind,
|
||||
identifierDigest: hashRestrictedIdentifier(identifier, identifierPepper),
|
||||
identifierMasked: maskRestrictedIdentifier(identifier),
|
||||
expiresAt: input.expiresAt,
|
||||
});
|
||||
}
|
||||
|
||||
function projectWorkspaceId(pathname) {
|
||||
const match = pathname.match(
|
||||
/^\/internal\/v1\/query\/projects\/([0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})\/workspace$/i,
|
||||
|
||||
Reference in New Issue
Block a user