Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
3.7 kB · 131 lines
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132import { ConfigurationError, record, text } from "./validation.ts";
// These are Flarebot deployment operations, NOT Cloudflare OAuth scope IDs.export const DEPLOYMENT_CAPABILITIES = [ "identity", "account-selection", "worker-upload", "asset-upload", "workers-dev", "container-application", "container-rollout", "model-gateway",] as const;// Optional capabilities must be explicitly catalog-reviewed before domain setup.// Existing installations and sign-ins do not acquire extra permissions by default.export const DOMAIN_CAPABILITIES = ["domain-zones", "domain-routing"] as const;export type DeploymentCapability = | (typeof DEPLOYMENT_CAPABILITIES)[number] | (typeof DOMAIN_CAPABILITIES)[number];const field = "FLAREBOT_CONTROL_PLANE.oauthCapabilities";function invalid(): never { throw new ConfigurationError( field, "supply a catalog-reviewed manifest covering the complete release and verified registered client; see docs/oauth-onboarding.md", );}function strings(value: unknown): string[] { if (!Array.isArray(value) || value.length > 32) invalid(); return value.map((item) => text(item, field));}export function parseCapabilities(value: unknown) { const data = record( value, [ "schemaVersion", "artifactVersion", "reviewedAt", "registeredClient", "scopes", ], field, ); if ( data.schemaVersion !== 1 || typeof data.reviewedAt !== "string" || !/^\d{4}-\d{2}-\d{2}$/.test(data.reviewedAt) || !Number.isFinite(Date.parse(data.reviewedAt)) ) invalid(); const client = record( data.registeredClient, [ "clientId", "redirectUri", "tokenAuthMethod", "scopeIds", "userinfoVerified", ], field, ); if ( client.userinfoVerified !== true || !["none", "client_secret_basic", "client_secret_post"].includes( String(client.tokenAuthMethod), ) ) invalid(); if ( !Array.isArray(data.scopes) || !data.scopes.length || data.scopes.length > 32 ) invalid(); const scopes = data.scopes.map((input) => { const scope = record( input, ["id", "name", "category", "resourceScopes", "capabilities"], field, ); const id = text(scope.id, field); if ( !/^[a-z][a-z0-9_-]*(\.[a-z][a-z0-9_-]*)*$/.test(id) || ["offline", "offline_access"].includes(id) ) invalid(); const capabilities = strings(scope.capabilities); if ( !capabilities.length || capabilities.some( (item) => !( [ ...DEPLOYMENT_CAPABILITIES, ...DOMAIN_CAPABILITIES, ] as readonly string[] ).includes(item), ) ) invalid(); return { id, name: text(scope.name, field), ...(scope.category === undefined ? {} : { category: text(scope.category, field) }), resourceScopes: strings(scope.resourceScopes), capabilities: capabilities as DeploymentCapability[], }; }); if ( new Set(scopes.map((s) => s.id)).size !== scopes.length || DEPLOYMENT_CAPABILITIES.some( (capability) => !scopes.some((s) => s.capabilities.includes(capability)), ) ) invalid(); return { schemaVersion: 1 as const, artifactVersion: text(data.artifactVersion, field), reviewedAt: data.reviewedAt, registeredClient: { clientId: text(client.clientId, field), redirectUri: text(client.redirectUri, field), tokenAuthMethod: client.tokenAuthMethod as "none" | "client_secret_basic" | "client_secret_post", scopeIds: strings(client.scopeIds), userinfoVerified: true as const, }, scopes, };}