Files

29 lines
1.4 KiB
TypeScript

import { getPlugin } from '@/lib/admin/plugin-registry';
import { listApprovals } from '@/lib/admin/plugin-approvals';
import type { CredentialSpec, UserCredentialSpec } from './credentials';
/**
* The user-scope credential `credentialId` as the manifest of `pluginId`
* declares it, when this server knows that manifest: an installed (registry)
* plugin, or a user-uploaded package an admin approved.
*
* The connect dialog and the proxy used to take the plugin id at its word,
* so any signed-in user could store a credential under a made-up plugin id
* and relay requests through the server to any origin with it, and a
* plugin could reach for a credential declared by none. A credential is
* only ever for a plugin the server can name, and only on the server the
* manifest fixes, when it fixes one.
*/
export async function declaredUserCredential(pluginId: string, credentialId: string): Promise<UserCredentialSpec | null> {
const plugin = await getPlugin(pluginId);
const fromRegistry = (plugin as { credentials?: Record<string, CredentialSpec> } | null)?.credentials?.[credentialId];
if (plugin && plugin.enabled && fromRegistry?.scope === 'user') return fromRegistry;
if (plugin) return null;
for (const entry of await listApprovals()) {
if (entry.pluginId !== pluginId || entry.status !== 'approved') continue;
const spec = entry.manifest.credentials?.[credentialId];
if (spec?.scope === 'user') return spec;
}
return null;
}