spaps
Version:
Sweet Potato Authentication & Payment Service CLI - Docker Compose orchestrator for local Python/FastAPI SPAPS server with built-in admin middleware
79 lines (72 loc) • 3.02 kB
JavaScript
const { authFetch } = require('./client');
const { extractApiError } = require('./http');
function required(value, option) {
const resolved = typeof value === 'string' ? value.trim() : value;
if (!resolved || (Array.isArray(resolved) && resolved.length === 0)) {
const error = new Error(`${option} is required`);
error.code = 'MISSING_ARGUMENT';
throw error;
}
return resolved;
}
async function requestPasskeyProfile(options, request = authFetch) {
const action = String(options.subcommand || '').split('.')[1];
const applicationId = required(
options.applicationId || process.env.SPAPS_APPLICATION_ID,
'--application-id (or SPAPS_APPLICATION_ID)'
);
const basePath = `/admin/apps/${encodeURIComponent(applicationId)}/auth/passkeys`;
let method = 'GET';
let path = basePath;
let body = null;
if (action === 'show') {
if (options.rpId) path += `?rp_id=${encodeURIComponent(options.rpId)}`;
} else if (action === 'configure' || action === 'validate') {
method = action === 'configure' ? 'PUT' : 'POST';
if (action === 'validate') path += '/validate';
body = {
rp_id: required(options.rpId, '--rp-id'),
rp_display_name: required(options.displayName, '--display-name'),
allowed_origins: required(options.allowedOrigins, '--allowed-origin'),
environment: options.environment || 'production',
policy_version: options.policyVersion || 1,
};
if (action === 'configure') body.confirm_disruptive = Boolean(options.confirmDisruptive);
} else if (action === 'disable') {
method = 'POST';
path += '/disable';
body = {
rp_id: required(options.rpId, '--rp-id'),
confirm_disruptive: Boolean(options.confirmDisruptive),
};
} else {
const error = new Error('Unknown passkeys action');
error.code = 'UNKNOWN_AUTH_SUBCOMMAND';
throw error;
}
const response = await request(path, { serverUrl: options.serverUrl, method, body });
if (response.status < 200 || response.status >= 300) {
const details = extractApiError(response.raw, response.status);
const error = new Error(details.message);
error.code = details.code;
throw error;
}
return response.data;
}
function renderPasskeyProfile(action, result) {
const profile = result.profile || result;
console.log();
console.log(`Passkey profile ${action}`);
console.log(` RP ID: ${profile.rp_id}`);
console.log(` display name: ${profile.rp_display_name}`);
console.log(` origins: ${(profile.allowed_origins || []).join(', ')}`);
console.log(` environment: ${profile.environment}`);
console.log(` policy version: ${profile.policy_version}`);
console.log(` enabled: ${profile.enabled}`);
if (typeof profile.affected_credentials === 'number') {
console.log(` affected credentials: ${profile.affected_credentials}`);
}
for (const diagnostic of result.diagnostics || []) console.log(` - ${diagnostic}`);
console.log();
}
module.exports = { renderPasskeyProfile, requestPasskeyProfile };