Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | 2x 68x 68x 8x 8x 8x 8x 8x 26x 26x 26x 26x 26x 26x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x 8x 8x 8x 8x 8x 8x 8x 13x 12x 12x 3x 9x 8x 8x 8x 8x 9x 23x | import { getSecret, validateEnvVariable } from "shared-utils";
import { SECRET_CACHE_TTL_MS } from "./constants";
import {
ExternalAllowedLocation,
ExternalApiAuthConfig,
ExternalApiClient,
ExternalClientStatus,
} from "./types";
type CachedConfig = {
secretArn: string;
loadedAtMs: number;
config: ExternalApiAuthConfig;
};
let cachedConfig: CachedConfig | null = null;
function ensureNonEmptyString(value: unknown, fieldName: string): string {
Iif (typeof value !== "string" || value.trim() === "") {
throw new Error(`Invalid external auth config: ${fieldName} must be a non-empty string.`);
}
return value.trim();
}
function parseHex(value: unknown, fieldName: string): Buffer {
const parsedValue = ensureNonEmptyString(value, fieldName);
Iif (!/^[0-9a-f]+$/i.test(parsedValue) || parsedValue.length % 2 !== 0) {
throw new Error(`Invalid external auth config: ${fieldName} must be a valid hex string.`);
}
const asBuffer = Buffer.from(parsedValue, "hex");
Iif (asBuffer.length === 0) {
throw new Error(`Invalid external auth config: ${fieldName} cannot be empty.`);
}
return asBuffer;
}
function parseBase64(value: unknown, fieldName: string): Buffer {
const parsedValue = ensureNonEmptyString(value, fieldName);
const normalized = parsedValue.replace(/-/g, "+").replace(/_/g, "/");
Iif (!/^[A-Za-z0-9+/=]+$/.test(normalized)) {
throw new Error(`Invalid external auth config: ${fieldName} must be base64 encoded.`);
}
const asBuffer = Buffer.from(normalized, "base64");
Iif (asBuffer.length === 0) {
throw new Error(`Invalid external auth config: ${fieldName} cannot decode to an empty value.`);
}
return asBuffer;
}
function parseAllowedLocations(rawAllowedLocations: unknown): ExternalAllowedLocation[] {
Iif (!Array.isArray(rawAllowedLocations)) {
throw new Error("Invalid external auth config: client.allowedLocations must be an array.");
}
return rawAllowedLocations.map((location, index) => {
Iif (!location || typeof location !== "object") {
throw new Error(
`Invalid external auth config: client.allowedLocations[${index}] must be an object.`,
);
}
const typedLocation = location as Record<string, unknown>;
return {
bucket: ensureNonEmptyString(
typedLocation.bucket,
`client.allowedLocations[${index}].bucket`,
),
prefix:
typeof typedLocation.prefix === "string" && typedLocation.prefix.trim().length > 0
? typedLocation.prefix
: "",
};
});
}
function parseStatus(value: unknown): ExternalClientStatus {
Eif (value === "ACTIVE" || value === "INACTIVE") {
return value;
}
throw new Error("Invalid external auth config: client.status must be ACTIVE or INACTIVE.");
}
function parseClient(client: unknown, index: number): ExternalApiClient {
Iif (!client || typeof client !== "object") {
throw new Error(`Invalid external auth config: clients[${index}] must be an object.`);
}
const typedClient = client as Record<string, unknown>;
const grants = typedClient.grants;
Iif (!Array.isArray(grants) || grants.some((grant) => typeof grant !== "string")) {
throw new Error(`Invalid external auth config: clients[${index}].grants must be string[].`);
}
return {
clientId: ensureNonEmptyString(typedClient.clientId, `clients[${index}].clientId`),
status: parseStatus(typedClient.status),
grants: grants as string[],
secretSalt: parseBase64(typedClient.secretSalt, `clients[${index}].secretSalt`),
secretHash: parseBase64(typedClient.secretHash, `clients[${index}].secretHash`),
allowedLocations: parseAllowedLocations(typedClient.allowedLocations),
};
}
function parseConfig(configString: string): ExternalApiAuthConfig {
let parsedConfig: unknown;
try {
parsedConfig = JSON.parse(configString);
} catch {
throw new Error("Invalid external auth config: secret value must be valid JSON.");
}
Iif (!parsedConfig || typeof parsedConfig !== "object") {
throw new Error("Invalid external auth config: root value must be an object.");
}
const typedConfig = parsedConfig as Record<string, unknown>;
const clients = typedConfig.clients;
Iif (!Array.isArray(clients)) {
throw new Error("Invalid external auth config: clients must be an array.");
}
return {
issuer: ensureNonEmptyString(typedConfig.issuer, "issuer"),
jwtSigningKey: parseHex(typedConfig.jwtSigningSecretHex, "jwtSigningSecretHex"),
clients: clients.map((client, index) => parseClient(client, index)),
};
}
export async function getExternalApiAuthConfig(): Promise<ExternalApiAuthConfig> {
const secretArn = validateEnvVariable("externalApiAuthSecretArn");
if (
cachedConfig &&
cachedConfig.secretArn === secretArn &&
Date.now() - cachedConfig.loadedAtMs < SECRET_CACHE_TTL_MS
) {
return cachedConfig.config;
}
const secretValue = await getSecret(secretArn);
const config = parseConfig(secretValue);
cachedConfig = {
secretArn,
loadedAtMs: Date.now(),
config,
};
return config;
}
export function getActiveClient(
config: ExternalApiAuthConfig,
clientId: string,
): ExternalApiClient | undefined {
return config.clients.find(
(client) => client.clientId === clientId && client.status === "ACTIVE",
);
}
export function resetExternalApiAuthConfigCache() {
cachedConfig = null;
}
|