@undefineds.co/xpod 0.3.35 → 0.3.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -14,6 +14,7 @@ export interface PodWebIdLookupRepository {
14
14
  findByWebId: (webId: string) => Promise<PodLookupResult | undefined>;
15
15
  findAllByWebId?: (webId: string) => Promise<PodLookupResult[]>;
16
16
  findByWebIds?: (webIds: string[]) => Promise<PodLookupResult[]>;
17
+ listByAccountId?: (accountId: string) => Promise<PodLookupResult[]>;
17
18
  }
18
19
  /**
19
20
  * CSS-compatible WebID picker scoped to the current storage provider.
@@ -33,6 +34,8 @@ export declare class ScopedPickWebIdHandler extends JsonInteractionHandler imple
33
34
  getView({ accountId, oidcInteraction }: JsonInteractionHandlerInput): Promise<JsonRepresentation>;
34
35
  handle({ oidcInteraction, accountId, json }: JsonInteractionHandlerInput): Promise<never>;
35
36
  private resolveScopedEntries;
37
+ private resolveCandidateWebIds;
38
+ private isLinkedToAccount;
36
39
  private isResolvableByCurrentSp;
37
40
  private findSpPod;
38
41
  private resolveTargetStorage;
@@ -49,7 +49,7 @@ class ScopedPickWebIdHandler extends community_server_1.JsonInteractionHandler {
49
49
  const { webId, remember } = await (0, community_server_1.validateWithError)(inSchema, json);
50
50
  const provider = await this.providerFactory.getProvider();
51
51
  const target = await this.resolveTargetStorage(provider, oidcInteraction);
52
- if (!await this.webIdStore.isLinked(webId, accountId)) {
52
+ if (!await this.isLinkedToAccount(webId, accountId)) {
53
53
  this.logger.warn(`Trying to pick WebID ${webId} which does not belong to account ${accountId}`);
54
54
  throw new community_server_1.BadRequestHttpError('WebID does not belong to this account.');
55
55
  }
@@ -67,7 +67,7 @@ class ScopedPickWebIdHandler extends community_server_1.JsonInteractionHandler {
67
67
  throw new community_server_1.FoundHttpError(location);
68
68
  }
69
69
  async resolveScopedEntries(accountId, target) {
70
- const webIds = (await this.webIdStore.findLinks(accountId)).map((link) => link.webId);
70
+ const webIds = await this.resolveCandidateWebIds(accountId);
71
71
  if (target.serviceToken) {
72
72
  return this.resolveRemoteSpEntries(webIds, target);
73
73
  }
@@ -86,6 +86,39 @@ class ScopedPickWebIdHandler extends community_server_1.JsonInteractionHandler {
86
86
  }
87
87
  return entries;
88
88
  }
89
+ async resolveCandidateWebIds(accountId) {
90
+ const linkedWebIds = (await this.webIdStore.findLinks(accountId)).map((link) => link.webId);
91
+ if (linkedWebIds.length > 0) {
92
+ return dedupeStrings(linkedWebIds);
93
+ }
94
+ if (!this.podLookupRepository?.listByAccountId) {
95
+ return [];
96
+ }
97
+ try {
98
+ const pods = await this.podLookupRepository.listByAccountId(accountId);
99
+ return dedupeStrings(pods.flatMap(getPodCandidateWebIds));
100
+ }
101
+ catch (error) {
102
+ this.logger.warn(`Pod lookup unavailable for account ${accountId}: ${error}`);
103
+ return [];
104
+ }
105
+ }
106
+ async isLinkedToAccount(webId, accountId) {
107
+ if (await this.webIdStore.isLinked(webId, accountId)) {
108
+ return true;
109
+ }
110
+ if (!this.podLookupRepository?.listByAccountId) {
111
+ return false;
112
+ }
113
+ try {
114
+ const pods = await this.podLookupRepository.listByAccountId(accountId);
115
+ return pods.some((pod) => getPodCandidateWebIds(pod).includes(webId));
116
+ }
117
+ catch (error) {
118
+ this.logger.warn(`Pod lookup unavailable for account ${accountId}: ${error}`);
119
+ return false;
120
+ }
121
+ }
89
122
  async isResolvableByCurrentSp(webId, target) {
90
123
  if (target.serviceToken) {
91
124
  return (await this.resolveRemoteSpEntries([webId], target)).some((entry) => entry.webId === webId);
@@ -198,6 +231,15 @@ function normalizeOptionalUrl(url) {
198
231
  const trimmed = url?.trim();
199
232
  return trimmed ? trimmed : undefined;
200
233
  }
234
+ function dedupeStrings(values) {
235
+ return [...new Set(values)];
236
+ }
237
+ function getPodCandidateWebIds(pod) {
238
+ return dedupeStrings([
239
+ pod.webId,
240
+ ...(pod.webIds ?? []),
241
+ ].filter((value) => typeof value === 'string' && value.length > 0));
242
+ }
201
243
  function matchesTargetStorage(pod, targetStorageUrl) {
202
244
  const candidateUrls = (pod.storageUrl ? [pod.storageUrl] : [pod.baseUrl])
203
245
  .filter((value) => typeof value === 'string' && value.length > 0);
@@ -1 +1 @@
1
- {"version":3,"file":"ScopedPickWebIdHandler.js","sourceRoot":"","sources":["../../../src/identity/oidc/ScopedPickWebIdHandler.ts"],"names":[],"mappings":"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","sourcesContent":["import { boolean, object, string } from 'yup';\nimport { getLoggerFor } from 'global-logger-factory';\nimport {\n BadRequestHttpError,\n FoundHttpError,\n JsonInteractionHandler,\n assertAccountId,\n assertOidcInteraction,\n finishInteraction,\n forgetWebId,\n parseSchema,\n validateWithError,\n} from '@solid/community-server';\nimport type {\n Json,\n JsonInteractionHandlerInput,\n JsonRepresentation,\n JsonView,\n ProviderFactory,\n WebIdStore,\n} from '@solid/community-server';\nimport { getIdentityDatabase } from '../drizzle/db';\nimport { PodLookupRepository, type PodLookupResult } from '../drizzle/PodLookupRepository';\nimport { ProvisionCodeCodec } from '../../provision/ProvisionCodeCodec';\n\ntype FetchLike = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;\n\nconst inSchema = object({\n webId: string().trim().required(),\n remember: boolean().default(false),\n});\n\nexport interface ScopedPickWebIdHandlerOptions {\n webIdStore: WebIdStore;\n providerFactory: ProviderFactory;\n identityDbUrl?: string;\n provisionBaseUrl?: string;\n podLookupRepository?: PodWebIdLookupRepository;\n fetch?: FetchLike;\n}\n\nexport interface PodWebIdLookupRepository {\n findByWebId: (webId: string) => Promise<PodLookupResult | undefined>;\n findAllByWebId?: (webId: string) => Promise<PodLookupResult[]>;\n findByWebIds?: (webIds: string[]) => Promise<PodLookupResult[]>;\n}\n\ninterface WebIdEntry extends Record<string, Json | undefined> {\n webId: string;\n storageUrl?: string;\n storageMode?: 'cloud' | 'local' | 'custom';\n}\n\n/**\n * CSS-compatible WebID picker scoped to the current storage provider.\n *\n * The upstream handler lists every WebID linked to the IdP account. In an\n * IDP/SP split flow that lets a Local SP login pick a Cloud Pod again, so this\n * replacement keeps consent choices constrained by the selected SP's Pod facts.\n */\nexport class ScopedPickWebIdHandler extends JsonInteractionHandler implements JsonView {\n private readonly logger = getLoggerFor(this);\n private readonly webIdStore: WebIdStore;\n private readonly providerFactory: ProviderFactory;\n private readonly provisionBaseUrl?: string;\n private readonly podLookupRepository?: PodWebIdLookupRepository;\n private readonly fetch: FetchLike;\n\n public constructor(options: ScopedPickWebIdHandlerOptions) {\n super();\n this.webIdStore = options.webIdStore;\n this.providerFactory = options.providerFactory;\n this.provisionBaseUrl = normalizeOptionalUrl(options.provisionBaseUrl);\n this.podLookupRepository = options.podLookupRepository ??\n (options.identityDbUrl ? new PodLookupRepository(getIdentityDatabase(options.identityDbUrl)) : undefined);\n this.fetch = options.fetch ?? globalThis.fetch.bind(globalThis);\n }\n\n public async getView({ accountId, oidcInteraction }: JsonInteractionHandlerInput): Promise<JsonRepresentation> {\n assertAccountId(accountId);\n const provider = await this.providerFactory.getProvider();\n const description = parseSchema(inSchema);\n const target = await this.resolveTargetStorage(provider, oidcInteraction);\n const entries = await this.resolveScopedEntries(accountId, target);\n\n return {\n json: {\n ...description,\n webIds: entries.map((entry) => entry.webId),\n entries,\n },\n };\n }\n\n public async handle({ oidcInteraction, accountId, json }: JsonInteractionHandlerInput): Promise<never> {\n assertOidcInteraction(oidcInteraction);\n assertAccountId(accountId);\n const { webId, remember } = await validateWithError(inSchema, json);\n const provider = await this.providerFactory.getProvider();\n const target = await this.resolveTargetStorage(provider, oidcInteraction);\n\n if (!await this.webIdStore.isLinked(webId, accountId)) {\n this.logger.warn(`Trying to pick WebID ${webId} which does not belong to account ${accountId}`);\n throw new BadRequestHttpError('WebID does not belong to this account.');\n }\n\n if (!await this.isResolvableByCurrentSp(webId, target)) {\n this.logger.warn(`Trying to pick WebID ${webId} which does not belong to this storage provider`);\n throw new BadRequestHttpError('WebID does not belong to this storage provider.');\n }\n\n await forgetWebId(provider, oidcInteraction);\n const location = await finishInteraction(oidcInteraction, {\n login: {\n accountId: webId,\n remember,\n },\n }, true);\n throw new FoundHttpError(location);\n }\n\n private async resolveScopedEntries(accountId: string, target: TargetStorage): Promise<WebIdEntry[]> {\n const webIds = (await this.webIdStore.findLinks(accountId)).map((link) => link.webId);\n if (target.serviceToken) {\n return this.resolveRemoteSpEntries(webIds, target);\n }\n\n const entries: WebIdEntry[] = [];\n for (const webId of webIds) {\n const pod = await this.findSpPod(webId, target.storageUrl);\n if (!pod) {\n continue;\n }\n const storageUrl = ensureTrailingSlash(pod.storageUrl ?? pod.baseUrl);\n entries.push({\n webId,\n storageUrl,\n storageMode: deriveStorageMode(webId, storageUrl),\n });\n }\n return entries;\n }\n\n private async isResolvableByCurrentSp(webId: string, target: TargetStorage): Promise<boolean> {\n if (target.serviceToken) {\n return (await this.resolveRemoteSpEntries([webId], target)).some((entry) => entry.webId === webId);\n }\n return Boolean(await this.findSpPod(webId, target.storageUrl));\n }\n\n private async findSpPod(webId: string, targetStorageUrl: string): Promise<PodLookupResult | undefined> {\n if (!this.podLookupRepository) {\n this.logger.warn('No PodLookupRepository configured; refusing to expose unscoped WebID choices');\n return undefined;\n }\n\n try {\n if (this.podLookupRepository.findAllByWebId) {\n const pods = await this.podLookupRepository.findAllByWebId(webId);\n return pods.find((pod) => matchesTargetStorage(pod, targetStorageUrl));\n }\n\n if (this.podLookupRepository.findByWebIds) {\n const pods = await this.podLookupRepository.findByWebIds([webId]);\n return pods.find((pod) => matchesTargetStorage(pod, targetStorageUrl));\n }\n\n const pod = await this.podLookupRepository.findByWebId(webId);\n return pod && matchesTargetStorage(pod, targetStorageUrl) ? pod : undefined;\n } catch (error) {\n this.logger.warn(`Pod lookup unavailable for WebID ${webId}: ${error}`);\n return undefined;\n }\n }\n\n private async resolveTargetStorage(\n provider: { issuer: string },\n oidcInteraction?: JsonInteractionHandlerInput['oidcInteraction'],\n ): Promise<TargetStorage> {\n const provisionCode = extractProvisionCode(oidcInteraction);\n if (!provisionCode) {\n return { storageUrl: ensureTrailingSlash(provider.issuer) };\n }\n\n const payload = new ProvisionCodeCodec(this.provisionBaseUrl ?? provider.issuer).decode(provisionCode);\n if (!payload) {\n throw new BadRequestHttpError('Invalid or expired provisionCode.');\n }\n\n const targetUrl = payload.spDomain\n ? `https://${payload.spDomain}`\n : payload.spUrl;\n return {\n storageUrl: ensureTrailingSlash(targetUrl),\n lookupUrl: ensureTrailingSlash(payload.spUrl),\n serviceToken: payload.serviceToken,\n };\n }\n\n private async resolveRemoteSpEntries(webIds: string[], target: TargetStorage): Promise<WebIdEntry[]> {\n if (!target.lookupUrl || !target.serviceToken || webIds.length === 0) {\n return [];\n }\n\n const response = await this.fetch(new URL('/provision/webids', target.lookupUrl).toString(), {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${target.serviceToken}`,\n 'Content-Type': 'application/json',\n 'Accept': 'application/json',\n },\n body: JSON.stringify({ webIds }),\n });\n\n if (!response.ok) {\n this.logger.warn(`Remote SP WebID lookup failed: HTTP ${response.status}`);\n return [];\n }\n\n const body = await response.json().catch(() => null) as { entries?: RemoteSpWebIdEntry[] } | null;\n if (!Array.isArray(body?.entries)) {\n return [];\n }\n\n const allowedWebIds = new Set(webIds);\n return body.entries\n .filter((entry) => typeof entry.webId === 'string' && allowedWebIds.has(entry.webId))\n .filter((entry) => typeof entry.storageUrl === 'string' && matchesTargetStorage(\n {\n podId: '',\n accountId: '',\n baseUrl: entry.podUrl ?? entry.storageUrl,\n storageUrl: entry.storageUrl,\n },\n target.storageUrl,\n ))\n .map((entry) => ({\n webId: entry.webId,\n storageUrl: ensureTrailingSlash(entry.storageUrl),\n storageMode: deriveStorageMode(entry.webId, entry.storageUrl),\n }));\n }\n}\n\ninterface TargetStorage {\n storageUrl: string;\n lookupUrl?: string;\n serviceToken?: string;\n}\n\ninterface RemoteSpWebIdEntry {\n webId: string;\n podUrl?: string;\n storageUrl: string;\n}\n\nfunction deriveStorageMode(webId: string, storageUrl: string): 'cloud' | 'local' | 'custom' {\n const webIdRoot = deriveStorageRoot(webId);\n const storageRoot = deriveStorageRoot(storageUrl);\n if (!webIdRoot || !storageRoot) {\n return 'custom';\n }\n return webIdRoot === storageRoot ? 'cloud' : 'local';\n}\n\nfunction deriveStorageRoot(url: string): string | undefined {\n try {\n const parsed = new URL(url);\n const segments = parsed.pathname.split('/').filter(Boolean);\n if (segments.length === 0) {\n return ensureTrailingSlash(parsed.origin);\n }\n\n return ensureTrailingSlash(new URL(`/${segments[0]}/`, parsed.origin).toString());\n } catch {\n return undefined;\n }\n}\n\nfunction ensureTrailingSlash(url: string): string {\n return url.replace(/\\/+$/u, '') + '/';\n}\n\nfunction normalizeOptionalUrl(url: string | undefined): string | undefined {\n const trimmed = url?.trim();\n return trimmed ? trimmed : undefined;\n}\n\nfunction matchesTargetStorage(pod: PodLookupResult, targetStorageUrl: string): boolean {\n const candidateUrls = (pod.storageUrl ? [pod.storageUrl] : [pod.baseUrl])\n .filter((value): value is string => typeof value === 'string' && value.length > 0);\n const targetRoot = deriveStorageRoot(targetStorageUrl);\n if (!targetRoot) {\n return false;\n }\n\n for (const candidate of candidateUrls) {\n const candidateRoot = deriveStorageRoot(candidate);\n if (candidateRoot && candidateRoot === targetRoot) {\n return true;\n }\n\n const candidateUrl = ensureTrailingSlash(candidate);\n if (candidateUrl.startsWith(targetRoot) || targetRoot.startsWith(candidateUrl)) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction extractProvisionCode(oidcInteraction: JsonInteractionHandlerInput['oidcInteraction']): string | undefined {\n const params = oidcInteraction?.params as Record<string, unknown> | undefined;\n const value = params?.provisionCode;\n return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;\n}\n"]}
1
+ {"version":3,"file":"ScopedPickWebIdHandler.js","sourceRoot":"","sources":["../../../src/identity/oidc/ScopedPickWebIdHandler.ts"],"names":[],"mappings":"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","sourcesContent":["import { boolean, object, string } from 'yup';\nimport { getLoggerFor } from 'global-logger-factory';\nimport {\n BadRequestHttpError,\n FoundHttpError,\n JsonInteractionHandler,\n assertAccountId,\n assertOidcInteraction,\n finishInteraction,\n forgetWebId,\n parseSchema,\n validateWithError,\n} from '@solid/community-server';\nimport type {\n Json,\n JsonInteractionHandlerInput,\n JsonRepresentation,\n JsonView,\n ProviderFactory,\n WebIdStore,\n} from '@solid/community-server';\nimport { getIdentityDatabase } from '../drizzle/db';\nimport { PodLookupRepository, type PodLookupResult } from '../drizzle/PodLookupRepository';\nimport { ProvisionCodeCodec } from '../../provision/ProvisionCodeCodec';\n\ntype FetchLike = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;\n\nconst inSchema = object({\n webId: string().trim().required(),\n remember: boolean().default(false),\n});\n\nexport interface ScopedPickWebIdHandlerOptions {\n webIdStore: WebIdStore;\n providerFactory: ProviderFactory;\n identityDbUrl?: string;\n provisionBaseUrl?: string;\n podLookupRepository?: PodWebIdLookupRepository;\n fetch?: FetchLike;\n}\n\nexport interface PodWebIdLookupRepository {\n findByWebId: (webId: string) => Promise<PodLookupResult | undefined>;\n findAllByWebId?: (webId: string) => Promise<PodLookupResult[]>;\n findByWebIds?: (webIds: string[]) => Promise<PodLookupResult[]>;\n listByAccountId?: (accountId: string) => Promise<PodLookupResult[]>;\n}\n\ninterface WebIdEntry extends Record<string, Json | undefined> {\n webId: string;\n storageUrl?: string;\n storageMode?: 'cloud' | 'local' | 'custom';\n}\n\n/**\n * CSS-compatible WebID picker scoped to the current storage provider.\n *\n * The upstream handler lists every WebID linked to the IdP account. In an\n * IDP/SP split flow that lets a Local SP login pick a Cloud Pod again, so this\n * replacement keeps consent choices constrained by the selected SP's Pod facts.\n */\nexport class ScopedPickWebIdHandler extends JsonInteractionHandler implements JsonView {\n private readonly logger = getLoggerFor(this);\n private readonly webIdStore: WebIdStore;\n private readonly providerFactory: ProviderFactory;\n private readonly provisionBaseUrl?: string;\n private readonly podLookupRepository?: PodWebIdLookupRepository;\n private readonly fetch: FetchLike;\n\n public constructor(options: ScopedPickWebIdHandlerOptions) {\n super();\n this.webIdStore = options.webIdStore;\n this.providerFactory = options.providerFactory;\n this.provisionBaseUrl = normalizeOptionalUrl(options.provisionBaseUrl);\n this.podLookupRepository = options.podLookupRepository ??\n (options.identityDbUrl ? new PodLookupRepository(getIdentityDatabase(options.identityDbUrl)) : undefined);\n this.fetch = options.fetch ?? globalThis.fetch.bind(globalThis);\n }\n\n public async getView({ accountId, oidcInteraction }: JsonInteractionHandlerInput): Promise<JsonRepresentation> {\n assertAccountId(accountId);\n const provider = await this.providerFactory.getProvider();\n const description = parseSchema(inSchema);\n const target = await this.resolveTargetStorage(provider, oidcInteraction);\n const entries = await this.resolveScopedEntries(accountId, target);\n\n return {\n json: {\n ...description,\n webIds: entries.map((entry) => entry.webId),\n entries,\n },\n };\n }\n\n public async handle({ oidcInteraction, accountId, json }: JsonInteractionHandlerInput): Promise<never> {\n assertOidcInteraction(oidcInteraction);\n assertAccountId(accountId);\n const { webId, remember } = await validateWithError(inSchema, json);\n const provider = await this.providerFactory.getProvider();\n const target = await this.resolveTargetStorage(provider, oidcInteraction);\n\n if (!await this.isLinkedToAccount(webId, accountId)) {\n this.logger.warn(`Trying to pick WebID ${webId} which does not belong to account ${accountId}`);\n throw new BadRequestHttpError('WebID does not belong to this account.');\n }\n\n if (!await this.isResolvableByCurrentSp(webId, target)) {\n this.logger.warn(`Trying to pick WebID ${webId} which does not belong to this storage provider`);\n throw new BadRequestHttpError('WebID does not belong to this storage provider.');\n }\n\n await forgetWebId(provider, oidcInteraction);\n const location = await finishInteraction(oidcInteraction, {\n login: {\n accountId: webId,\n remember,\n },\n }, true);\n throw new FoundHttpError(location);\n }\n\n private async resolveScopedEntries(accountId: string, target: TargetStorage): Promise<WebIdEntry[]> {\n const webIds = await this.resolveCandidateWebIds(accountId);\n if (target.serviceToken) {\n return this.resolveRemoteSpEntries(webIds, target);\n }\n\n const entries: WebIdEntry[] = [];\n for (const webId of webIds) {\n const pod = await this.findSpPod(webId, target.storageUrl);\n if (!pod) {\n continue;\n }\n const storageUrl = ensureTrailingSlash(pod.storageUrl ?? pod.baseUrl);\n entries.push({\n webId,\n storageUrl,\n storageMode: deriveStorageMode(webId, storageUrl),\n });\n }\n return entries;\n }\n\n private async resolveCandidateWebIds(accountId: string): Promise<string[]> {\n const linkedWebIds = (await this.webIdStore.findLinks(accountId)).map((link) => link.webId);\n if (linkedWebIds.length > 0) {\n return dedupeStrings(linkedWebIds);\n }\n\n if (!this.podLookupRepository?.listByAccountId) {\n return [];\n }\n\n try {\n const pods = await this.podLookupRepository.listByAccountId(accountId);\n return dedupeStrings(pods.flatMap(getPodCandidateWebIds));\n } catch (error) {\n this.logger.warn(`Pod lookup unavailable for account ${accountId}: ${error}`);\n return [];\n }\n }\n\n private async isLinkedToAccount(webId: string, accountId: string): Promise<boolean> {\n if (await this.webIdStore.isLinked(webId, accountId)) {\n return true;\n }\n\n if (!this.podLookupRepository?.listByAccountId) {\n return false;\n }\n\n try {\n const pods = await this.podLookupRepository.listByAccountId(accountId);\n return pods.some((pod) => getPodCandidateWebIds(pod).includes(webId));\n } catch (error) {\n this.logger.warn(`Pod lookup unavailable for account ${accountId}: ${error}`);\n return false;\n }\n }\n\n private async isResolvableByCurrentSp(webId: string, target: TargetStorage): Promise<boolean> {\n if (target.serviceToken) {\n return (await this.resolveRemoteSpEntries([webId], target)).some((entry) => entry.webId === webId);\n }\n return Boolean(await this.findSpPod(webId, target.storageUrl));\n }\n\n private async findSpPod(webId: string, targetStorageUrl: string): Promise<PodLookupResult | undefined> {\n if (!this.podLookupRepository) {\n this.logger.warn('No PodLookupRepository configured; refusing to expose unscoped WebID choices');\n return undefined;\n }\n\n try {\n if (this.podLookupRepository.findAllByWebId) {\n const pods = await this.podLookupRepository.findAllByWebId(webId);\n return pods.find((pod) => matchesTargetStorage(pod, targetStorageUrl));\n }\n\n if (this.podLookupRepository.findByWebIds) {\n const pods = await this.podLookupRepository.findByWebIds([webId]);\n return pods.find((pod) => matchesTargetStorage(pod, targetStorageUrl));\n }\n\n const pod = await this.podLookupRepository.findByWebId(webId);\n return pod && matchesTargetStorage(pod, targetStorageUrl) ? pod : undefined;\n } catch (error) {\n this.logger.warn(`Pod lookup unavailable for WebID ${webId}: ${error}`);\n return undefined;\n }\n }\n\n private async resolveTargetStorage(\n provider: { issuer: string },\n oidcInteraction?: JsonInteractionHandlerInput['oidcInteraction'],\n ): Promise<TargetStorage> {\n const provisionCode = extractProvisionCode(oidcInteraction);\n if (!provisionCode) {\n return { storageUrl: ensureTrailingSlash(provider.issuer) };\n }\n\n const payload = new ProvisionCodeCodec(this.provisionBaseUrl ?? provider.issuer).decode(provisionCode);\n if (!payload) {\n throw new BadRequestHttpError('Invalid or expired provisionCode.');\n }\n\n const targetUrl = payload.spDomain\n ? `https://${payload.spDomain}`\n : payload.spUrl;\n return {\n storageUrl: ensureTrailingSlash(targetUrl),\n lookupUrl: ensureTrailingSlash(payload.spUrl),\n serviceToken: payload.serviceToken,\n };\n }\n\n private async resolveRemoteSpEntries(webIds: string[], target: TargetStorage): Promise<WebIdEntry[]> {\n if (!target.lookupUrl || !target.serviceToken || webIds.length === 0) {\n return [];\n }\n\n const response = await this.fetch(new URL('/provision/webids', target.lookupUrl).toString(), {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${target.serviceToken}`,\n 'Content-Type': 'application/json',\n 'Accept': 'application/json',\n },\n body: JSON.stringify({ webIds }),\n });\n\n if (!response.ok) {\n this.logger.warn(`Remote SP WebID lookup failed: HTTP ${response.status}`);\n return [];\n }\n\n const body = await response.json().catch(() => null) as { entries?: RemoteSpWebIdEntry[] } | null;\n if (!Array.isArray(body?.entries)) {\n return [];\n }\n\n const allowedWebIds = new Set(webIds);\n return body.entries\n .filter((entry) => typeof entry.webId === 'string' && allowedWebIds.has(entry.webId))\n .filter((entry) => typeof entry.storageUrl === 'string' && matchesTargetStorage(\n {\n podId: '',\n accountId: '',\n baseUrl: entry.podUrl ?? entry.storageUrl,\n storageUrl: entry.storageUrl,\n },\n target.storageUrl,\n ))\n .map((entry) => ({\n webId: entry.webId,\n storageUrl: ensureTrailingSlash(entry.storageUrl),\n storageMode: deriveStorageMode(entry.webId, entry.storageUrl),\n }));\n }\n}\n\ninterface TargetStorage {\n storageUrl: string;\n lookupUrl?: string;\n serviceToken?: string;\n}\n\ninterface RemoteSpWebIdEntry {\n webId: string;\n podUrl?: string;\n storageUrl: string;\n}\n\nfunction deriveStorageMode(webId: string, storageUrl: string): 'cloud' | 'local' | 'custom' {\n const webIdRoot = deriveStorageRoot(webId);\n const storageRoot = deriveStorageRoot(storageUrl);\n if (!webIdRoot || !storageRoot) {\n return 'custom';\n }\n return webIdRoot === storageRoot ? 'cloud' : 'local';\n}\n\nfunction deriveStorageRoot(url: string): string | undefined {\n try {\n const parsed = new URL(url);\n const segments = parsed.pathname.split('/').filter(Boolean);\n if (segments.length === 0) {\n return ensureTrailingSlash(parsed.origin);\n }\n\n return ensureTrailingSlash(new URL(`/${segments[0]}/`, parsed.origin).toString());\n } catch {\n return undefined;\n }\n}\n\nfunction ensureTrailingSlash(url: string): string {\n return url.replace(/\\/+$/u, '') + '/';\n}\n\nfunction normalizeOptionalUrl(url: string | undefined): string | undefined {\n const trimmed = url?.trim();\n return trimmed ? trimmed : undefined;\n}\n\nfunction dedupeStrings(values: string[]): string[] {\n return [...new Set(values)];\n}\n\nfunction getPodCandidateWebIds(pod: PodLookupResult): string[] {\n return dedupeStrings([\n pod.webId,\n ...(pod.webIds ?? []),\n ].filter((value): value is string => typeof value === 'string' && value.length > 0));\n}\n\nfunction matchesTargetStorage(pod: PodLookupResult, targetStorageUrl: string): boolean {\n const candidateUrls = (pod.storageUrl ? [pod.storageUrl] : [pod.baseUrl])\n .filter((value): value is string => typeof value === 'string' && value.length > 0);\n const targetRoot = deriveStorageRoot(targetStorageUrl);\n if (!targetRoot) {\n return false;\n }\n\n for (const candidate of candidateUrls) {\n const candidateRoot = deriveStorageRoot(candidate);\n if (candidateRoot && candidateRoot === targetRoot) {\n return true;\n }\n\n const candidateUrl = ensureTrailingSlash(candidate);\n if (candidateUrl.startsWith(targetRoot) || targetRoot.startsWith(candidateUrl)) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction extractProvisionCode(oidcInteraction: JsonInteractionHandlerInput['oidcInteraction']): string | undefined {\n const params = oidcInteraction?.params as Record<string, unknown> | undefined;\n const value = params?.provisionCode;\n return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;\n}\n"]}
@@ -115,6 +115,14 @@
115
115
  "@id": "undefineds:dist/identity/oidc/ScopedPickWebIdHandler.jsonld#ScopedPickWebIdHandler__member_resolveScopedEntries",
116
116
  "memberFieldName": "resolveScopedEntries"
117
117
  },
118
+ {
119
+ "@id": "undefineds:dist/identity/oidc/ScopedPickWebIdHandler.jsonld#ScopedPickWebIdHandler__member_resolveCandidateWebIds",
120
+ "memberFieldName": "resolveCandidateWebIds"
121
+ },
122
+ {
123
+ "@id": "undefineds:dist/identity/oidc/ScopedPickWebIdHandler.jsonld#ScopedPickWebIdHandler__member_isLinkedToAccount",
124
+ "memberFieldName": "isLinkedToAccount"
125
+ },
118
126
  {
119
127
  "@id": "undefineds:dist/identity/oidc/ScopedPickWebIdHandler.jsonld#ScopedPickWebIdHandler__member_isResolvableByCurrentSp",
120
128
  "memberFieldName": "isResolvableByCurrentSp"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@undefineds.co/xpod",
3
- "version": "0.3.35",
3
+ "version": "0.3.37",
4
4
  "description": "Xpod is an extended Community Solid Server, offering rich-feature, production-level Solid Pod and identity management.",
5
5
  "repository": "https://github.com/undefinedsco/xpod",
6
6
  "author": "developer@undefineds.co",