Files
NODEDC_PLATFORM/device-plane/services/device-control-core/src/sensitive-reference-management.mjs
T

98 lines
2.7 KiB
JavaScript

import {
normalizeNdcCredentialReference,
} from "./credential-reference.mjs";
export const DEVICE_SENSITIVE_REFERENCE_COMMAND_KINDS = Object.freeze([
"device_credential_binding.upsert",
"device_credential_binding.revoke",
]);
const commandKindSet = new Set(DEVICE_SENSITIVE_REFERENCE_COMMAND_KINDS);
const purposePattern = /^[a-z][a-z0-9._-]{1,63}$/;
const resolutionPattern = /^[a-z][a-z0-9._-]{1,63}$/;
export function isSensitiveReferenceManagementCommand(kind) {
return commandKindSet.has(kind);
}
export function normalizeSensitiveReferenceManagementCommand(kind, input) {
if (!commandKindSet.has(kind)) {
throw new TypeError("device_sensitive_reference_command_kind_invalid");
}
assertPlainObject(input);
if (kind === "device_credential_binding.upsert") {
assertAllowedKeys(input, [
"projectRef",
"deviceRef",
"purpose",
"credentialRef",
]);
return Object.freeze({
projectId: normalizeEntityRef(input.projectRef, "project"),
deviceId: normalizeEntityRef(input.deviceRef, "device"),
purpose: normalizePattern(
input.purpose,
purposePattern,
"device_credential_purpose_invalid",
),
credentialRef: normalizeNdcCredentialReference(input.credentialRef),
});
}
assertAllowedKeys(input, [
"projectRef",
"deviceRef",
"purpose",
"resolutionCode",
]);
return Object.freeze({
projectId: normalizeEntityRef(input.projectRef, "project"),
deviceId: normalizeEntityRef(input.deviceRef, "device"),
purpose: normalizePattern(
input.purpose,
purposePattern,
"device_credential_purpose_invalid",
),
resolutionCode: normalizePattern(
input.resolutionCode,
resolutionPattern,
"device_credential_resolution_code_invalid",
),
});
}
function normalizeEntityRef(value, prefix) {
if (typeof value !== "string") {
throw new TypeError(`device_${prefix}_ref_invalid`);
}
const match = value.match(new RegExp(
`^${prefix}:([0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})$`,
"i",
));
if (!match) throw new TypeError(`device_${prefix}_ref_invalid`);
return match[1].toLowerCase();
}
function normalizePattern(value, pattern, code) {
if (typeof value !== "string" || !pattern.test(value)) {
throw new TypeError(code);
}
return value;
}
function assertPlainObject(value) {
if (!value || typeof value !== "object" || Array.isArray(value)) {
throw new TypeError("device_sensitive_reference_command_invalid");
}
}
function assertAllowedKeys(input, allowed) {
const allowedSet = new Set(allowed);
for (const key of Object.keys(input)) {
if (!allowedSet.has(key)) {
throw new TypeError(`device_management_command_field_unexpected:${key}`);
}
}
}