@undefineds.co/xpod 0.4.2 → 0.4.3

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.
Files changed (113) hide show
  1. package/config/xpod.base.json +69 -1
  2. package/dist/components/components.jsonld +3 -0
  3. package/dist/components/context.jsonld +45 -0
  4. package/dist/identity/oidc/RememberedClientGrantStore.d.ts +18 -0
  5. package/dist/identity/oidc/RememberedClientGrantStore.js +38 -0
  6. package/dist/identity/oidc/RememberedClientGrantStore.jsonld +61 -0
  7. package/dist/identity/oidc/RememberedClientPromptFactory.d.ts +10 -0
  8. package/dist/identity/oidc/RememberedClientPromptFactory.js +45 -0
  9. package/dist/identity/oidc/RememberedClientPromptFactory.jsonld +54 -0
  10. package/dist/identity/oidc/RememberedConsentHandler.d.ts +11 -0
  11. package/dist/identity/oidc/RememberedConsentHandler.js +51 -0
  12. package/dist/identity/oidc/RememberedConsentHandler.jsonld +69 -0
  13. package/dist/identity/oidc/ScopedPickWebIdHandler.d.ts +4 -0
  14. package/dist/identity/oidc/ScopedPickWebIdHandler.js +25 -1
  15. package/dist/identity/oidc/ScopedPickWebIdHandler.jsonld +26 -0
  16. package/dist/index.d.ts +4 -1
  17. package/dist/index.js +8 -2
  18. package/package.json +2 -2
  19. package/static/app/assets/main.css +1 -1
  20. package/static/app/assets/main.js +8 -8
  21. package/static/app/xpod-desktop-client.json +14 -0
  22. package/static/auth-callback/assets/{AiConfigContext-CUjvHWwm.js → AiConfigContext-DrCH6ckh.js} +1 -1
  23. package/static/auth-callback/assets/{AiConfigPage-CTqNUQGp.js → AiConfigPage-DVrlSSdA.js} +1 -1
  24. package/static/auth-callback/assets/{DocumentProcessingPanel-CHSLcxxU.js → DocumentProcessingPanel-_Md-v2R2.js} +1 -1
  25. package/static/auth-callback/assets/{IndexLifecyclePanel-Cn11cEng.js → IndexLifecyclePanel-BbWwe23H.js} +1 -1
  26. package/static/auth-callback/assets/{IndexSubjectPanel-C9lLiF6_.js → IndexSubjectPanel-upH9MjU-.js} +1 -1
  27. package/static/auth-callback/assets/{ModelAssignmentsPanel-D0iiOmK7.js → ModelAssignmentsPanel-CVGH4t4g.js} +1 -1
  28. package/static/auth-callback/assets/{ModelsPage-sLumlx6c.js → ModelsPage-BpkVFKbf.js} +1 -1
  29. package/static/auth-callback/assets/{NetworkPage-Zst-vF-i.js → NetworkPage-Dcbrb1fd.js} +1 -1
  30. package/static/auth-callback/assets/{PaneListHeader-DCWzgI2Q.js → PaneListHeader-DrY-1wBq.js} +1 -1
  31. package/static/auth-callback/assets/{SearchIndexingPanel-BslPlvbX.js → SearchIndexingPanel-Dw25y53v.js} +1 -1
  32. package/static/auth-callback/assets/{StatusSubjectPanel-B180IJBq.js → StatusSubjectPanel-BHlz9rNF.js} +1 -1
  33. package/static/auth-callback/assets/{StatusWorkspace-PYnfVen5.js → StatusWorkspace-BH7exQP5.js} +1 -1
  34. package/static/auth-callback/assets/{SystemSettingsPage-i8Rp1f4E.js → SystemSettingsPage-BYLKnM9f.js} +1 -1
  35. package/static/auth-callback/assets/{SystemSettingsSubjectPanel-C19oU6DT.js → SystemSettingsSubjectPanel-DT34LKku.js} +1 -1
  36. package/static/auth-callback/assets/{activity-DBAcu9vM.js → activity-DdULRcSI.js} +1 -1
  37. package/static/auth-callback/assets/auth-callback-01yz-UDU.css +1 -0
  38. package/static/auth-callback/assets/{auth-callback-CGaAymMQ.js → auth-callback-D7l2P25I.js} +14 -14
  39. package/static/auth-callback/assets/{badge-Bam6VAk0.js → badge-j4zjFnmg.js} +1 -1
  40. package/static/auth-callback/assets/{download-DS0bFJRx.js → download-DGXoks01.js} +1 -1
  41. package/static/auth-callback/assets/{external-link-DexzrPwI.js → external-link-CvbgXXaI.js} +1 -1
  42. package/static/auth-callback/assets/{index-DQdWIkbj.js → index-BOK3j1dz.js} +1 -1
  43. package/static/auth-callback/assets/{index-BTDt1S5b.js → index-LRWvKJ2i.js} +1 -1
  44. package/static/auth-callback/assets/{index-browser-BX1idNBt.js → index-browser-C1Qpe0g4.js} +1 -1
  45. package/static/auth-callback/assets/{key-round-C85nwlgu.js → key-round-CmgS5UdQ.js} +1 -1
  46. package/static/auth-callback/assets/{rotate-ccw-A6Oag9av.js → rotate-ccw-c4CSG6Rq.js} +1 -1
  47. package/static/auth-callback/assets/{skeleton-BvfTlNEO.js → skeleton-ZPMTiRSM.js} +1 -1
  48. package/static/auth-callback/assets/{waypoints-DYFRaCfm.js → waypoints-xjyBflU5.js} +1 -1
  49. package/static/auth-callback/assets/{workspace-layout-DVR1e0R8.js → workspace-layout-B9nj6F5J.js} +1 -1
  50. package/static/auth-callback/auth-callback.html +2 -2
  51. package/static/auth-callback/xpod-desktop-client.json +14 -0
  52. package/static/dashboard/assets/{AiConfigContext-BM7FM2GL.js → AiConfigContext-BWOOSYNr.js} +1 -1
  53. package/static/dashboard/assets/{AiConfigPage-p-MraOBM.js → AiConfigPage-CG2kQ9Wy.js} +1 -1
  54. package/static/dashboard/assets/{DocumentProcessingPanel-Bl4EjKWL.js → DocumentProcessingPanel-B4VXajfj.js} +1 -1
  55. package/static/dashboard/assets/{IndexLifecyclePanel-DmHVRAdn.js → IndexLifecyclePanel-CWCy0CC8.js} +1 -1
  56. package/static/dashboard/assets/{IndexSubjectPanel-D-499Oas.js → IndexSubjectPanel-CSgyQnG_.js} +1 -1
  57. package/static/dashboard/assets/{ModelAssignmentsPanel-C_DUiLUl.js → ModelAssignmentsPanel-CdGIGidT.js} +1 -1
  58. package/static/dashboard/assets/{ModelsPage-BVV05BCL.js → ModelsPage-Chd5UK0D.js} +1 -1
  59. package/static/dashboard/assets/{NetworkPage-BmBWZoAI.js → NetworkPage-COia9NCH.js} +1 -1
  60. package/static/dashboard/assets/{PaneListHeader--7L-IICs.js → PaneListHeader-SZWyr602.js} +1 -1
  61. package/static/dashboard/assets/{SearchIndexingPanel-Bh69WHlh.js → SearchIndexingPanel-D6PZtG6k.js} +1 -1
  62. package/static/dashboard/assets/{StatusSubjectPanel-CXv7MD5a.js → StatusSubjectPanel-CxRD4kv0.js} +1 -1
  63. package/static/dashboard/assets/{StatusWorkspace-CmxTTkN7.js → StatusWorkspace-D3PfmY9-.js} +1 -1
  64. package/static/dashboard/assets/{SystemSettingsPage-euiBZgKr.js → SystemSettingsPage-COg1MmMj.js} +1 -1
  65. package/static/dashboard/assets/{SystemSettingsSubjectPanel-ro5iHev6.js → SystemSettingsSubjectPanel-BSVVB9Ol.js} +1 -1
  66. package/static/dashboard/assets/{activity-BJNDE3Gu.js → activity-BJJx5cN-.js} +1 -1
  67. package/static/dashboard/assets/{badge-BQKmk0KN.js → badge-elmrFSCj.js} +1 -1
  68. package/static/dashboard/assets/dashboard-01yz-UDU.css +1 -0
  69. package/static/dashboard/assets/{dashboard-DQTxcZiM.js → dashboard-IvQrNmru.js} +12 -12
  70. package/static/dashboard/assets/{download-GGpeN6-S.js → download-C3FH2KzG.js} +1 -1
  71. package/static/dashboard/assets/{external-link-Bv544qbJ.js → external-link-Bx7F0uKb.js} +1 -1
  72. package/static/dashboard/assets/{index-7YFh1X7m.js → index-M4-kWiGz.js} +1 -1
  73. package/static/dashboard/assets/{index-7AbzZfy2.js → index-liRoRIP1.js} +1 -1
  74. package/static/dashboard/assets/{key-round-BiB32Awf.js → key-round-CXg0bKAj.js} +1 -1
  75. package/static/dashboard/assets/{rotate-ccw-CZDUJt1v.js → rotate-ccw-yxJKOBrX.js} +1 -1
  76. package/static/dashboard/assets/{skeleton-C3J1hqN6.js → skeleton-x9jNGrQT.js} +1 -1
  77. package/static/dashboard/assets/{waypoints-CWFNKzHo.js → waypoints-CTKeRsGp.js} +1 -1
  78. package/static/dashboard/assets/{workspace-layout-D1i1FDM0.js → workspace-layout--YkgkS38.js} +1 -1
  79. package/static/dashboard/dashboard.html +2 -2
  80. package/static/dashboard/xpod-desktop-client.json +14 -0
  81. package/static/settings/assets/{AiConfigContext-B-tqFX8i.js → AiConfigContext-CelxXFcQ.js} +1 -1
  82. package/static/settings/assets/{AiConfigPage-DSZ1qKpy.js → AiConfigPage-BaP-EovM.js} +1 -1
  83. package/static/settings/assets/{DocumentProcessingPanel-BHO57iMD.js → DocumentProcessingPanel-DzLZluFv.js} +1 -1
  84. package/static/settings/assets/{IndexLifecyclePanel-DhB4LMHO.js → IndexLifecyclePanel-Bzj1-_oI.js} +1 -1
  85. package/static/settings/assets/{IndexSubjectPanel-zMtMv4nP.js → IndexSubjectPanel-B263QLUh.js} +1 -1
  86. package/static/settings/assets/{ModelAssignmentsPanel-4tMp-t3N.js → ModelAssignmentsPanel-BAdT4UR0.js} +1 -1
  87. package/static/settings/assets/{ModelsPage-CcuEwXHK.js → ModelsPage-C0NFa1zq.js} +1 -1
  88. package/static/settings/assets/{NetworkPage-jzhVzoPR.js → NetworkPage-BK6a7l4g.js} +1 -1
  89. package/static/settings/assets/{PaneListHeader-Cme9dy-w.js → PaneListHeader-BAS2ICPq.js} +1 -1
  90. package/static/settings/assets/{SearchIndexingPanel-gH1IcePJ.js → SearchIndexingPanel-Cb_p-NgW.js} +1 -1
  91. package/static/settings/assets/{StatusSubjectPanel-DX8jsVt3.js → StatusSubjectPanel-CcjqUua6.js} +1 -1
  92. package/static/settings/assets/{StatusWorkspace-CurRswDE.js → StatusWorkspace-7Ibty3_k.js} +1 -1
  93. package/static/settings/assets/{SystemSettingsPage-Do6AeOlg.js → SystemSettingsPage-DPSz4dg4.js} +1 -1
  94. package/static/settings/assets/{SystemSettingsSubjectPanel-Di4d8GGL.js → SystemSettingsSubjectPanel-Cb4HkKT5.js} +1 -1
  95. package/static/settings/assets/{activity-BndZTWqr.js → activity-Qhsr5Pxu.js} +1 -1
  96. package/static/settings/assets/{badge-bTZd84Yz.js → badge-B1vf2qCl.js} +1 -1
  97. package/static/settings/assets/{download-CTB6SCCX.js → download-CYNt0aZ-.js} +1 -1
  98. package/static/settings/assets/{external-link-VXD7cKP1.js → external-link-ClKb39NT.js} +1 -1
  99. package/static/settings/assets/{index-DlaUNsAu.js → index-BgiIDSch.js} +1 -1
  100. package/static/settings/assets/{index-browser-BC1kWYXi.js → index-browser-DJhvgpNI.js} +1 -1
  101. package/static/settings/assets/{index-BJTTGdJu.js → index-y8ew3MLM.js} +1 -1
  102. package/static/settings/assets/{key-round-Cgukkv9x.js → key-round-5d-DrJz-.js} +1 -1
  103. package/static/settings/assets/{rotate-ccw-kBanAhWZ.js → rotate-ccw-CHZY7kS5.js} +1 -1
  104. package/static/settings/assets/settings-01yz-UDU.css +1 -0
  105. package/static/settings/assets/{settings-B_NbAVC_.js → settings-D5VRWyx6.js} +13 -13
  106. package/static/settings/assets/{skeleton-0nvLWr59.js → skeleton-FNabNxNE.js} +1 -1
  107. package/static/settings/assets/{waypoints-DUjkmIoD.js → waypoints-BnL_8ljo.js} +1 -1
  108. package/static/settings/assets/{workspace-layout-5fe0Mvbk.js → workspace-layout-D5q3F59S.js} +1 -1
  109. package/static/settings/settings.html +2 -2
  110. package/static/settings/xpod-desktop-client.json +14 -0
  111. package/static/auth-callback/assets/auth-callback-yyFdkaKq.css +0 -1
  112. package/static/dashboard/assets/dashboard-yyFdkaKq.css +0 -1
  113. package/static/settings/assets/settings-yyFdkaKq.css +0 -1
@@ -2,13 +2,80 @@
2
2
  "@context": [
3
3
  "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^8.0.0/components/context.jsonld",
4
4
  "https://linkedsoftwaredependencies.org/bundles/npm/@undefineds.co/xpod/^0.0.0/components/context.jsonld",
5
- "https://linkedsoftwaredependencies.org/bundles/npm/asynchronous-handlers/^1.0.0/components/context.jsonld"
5
+ "https://linkedsoftwaredependencies.org/bundles/npm/asynchronous-handlers/^1.0.0/components/context.jsonld",
6
+ {
7
+ "rememberedGrantStorage": "RememberedClientGrantStore:_storage",
8
+ "rememberedPromptSource": "RememberedClientPromptFactory:_source",
9
+ "rememberedPromptStore": "RememberedClientPromptFactory:_store",
10
+ "rememberedConsentSource": "RememberedConsentHandler:_source",
11
+ "rememberedConsentStore": "RememberedConsentHandler:_store",
12
+ "rememberedConsentProvider": "RememberedConsentHandler:_providerFactory",
13
+ "scopedRememberedGrantStore": "ScopedPickWebIdHandler:_options_rememberedClientGrantStore"
14
+ }
6
15
  ],
7
16
  "import": [
8
17
  "./cli.json",
9
18
  "./resolver.json"
10
19
  ],
11
20
  "@graph": [
21
+ {
22
+ "@id": "urn:undefineds:xpod:RememberedClientGrantStore",
23
+ "@type": "RememberedClientGrantStore",
24
+ "rememberedGrantStorage": {
25
+ "@type": "WrappedExpiringStorage",
26
+ "source": {
27
+ "@type": "ContainerPathStorage",
28
+ "relativePath": "/idp/remembered-clients/",
29
+ "source": { "@id": "urn:solid-server:default:KeyValueStorage" }
30
+ }
31
+ }
32
+ },
33
+ {
34
+ "comment": "Retain default account/WebID checks and restore explicitly remembered Desktop grants before consent.",
35
+ "@type": "Override",
36
+ "overrideInstance": { "@id": "urn:solid-server:default:PromptFactory" },
37
+ "overrideParameters": {
38
+ "@type": "RememberedClientPromptFactory",
39
+ "rememberedPromptSource": {
40
+ "@type": "AccountPromptFactory",
41
+ "webIdStore": { "@id": "urn:solid-server:default:WebIdStore" },
42
+ "cookieStore": { "@id": "urn:solid-server:default:CookieStore" },
43
+ "cookieName": { "@id": "urn:solid-server:default:value:accountCookieName" }
44
+ },
45
+ "rememberedPromptStore": { "@id": "urn:undefineds:xpod:RememberedClientGrantStore" }
46
+ }
47
+ },
48
+ {
49
+ "comment": "Keep CSS consent processing and persist the user's explicit remember-app choice.",
50
+ "@type": "Override",
51
+ "overrideInstance": { "@id": "urn:solid-server:default:ConsentHandler" },
52
+ "overrideParameters": {
53
+ "@type": "StatusWaterfallHandler",
54
+ "handlers": [
55
+ {
56
+ "@type": "MethodFilterHandler",
57
+ "methods": [ "GET" ],
58
+ "source": {
59
+ "@type": "ClientInfoHandler",
60
+ "providerFactory": { "@id": "urn:solid-server:default:IdentityProviderFactory" }
61
+ }
62
+ },
63
+ {
64
+ "@type": "MethodFilterHandler",
65
+ "methods": [ "POST" ],
66
+ "source": {
67
+ "@type": "RememberedConsentHandler",
68
+ "rememberedConsentProvider": { "@id": "urn:solid-server:default:IdentityProviderFactory" },
69
+ "rememberedConsentSource": {
70
+ "@type": "ConsentHandler",
71
+ "providerFactory": { "@id": "urn:solid-server:default:IdentityProviderFactory" }
72
+ },
73
+ "rememberedConsentStore": { "@id": "urn:undefineds:xpod:RememberedClientGrantStore" }
74
+ }
75
+ }
76
+ ]
77
+ }
78
+ },
12
79
  {
13
80
  "comment": "Close the profile-owned RDF authority after writes stop.",
14
81
  "@id": "urn:solid-server:default:CleanupFinalizer",
@@ -152,6 +219,7 @@
152
219
  },
153
220
  "overrideParameters": {
154
221
  "@type": "ScopedPickWebIdHandler",
222
+ "scopedRememberedGrantStore": { "@id": "urn:undefineds:xpod:RememberedClientGrantStore" },
155
223
  "ownershipResolver": {
156
224
  "@id": "urn:undefineds:xpod:PodOwnershipResolver"
157
225
  },
@@ -102,6 +102,9 @@
102
102
  "undefineds:dist/identity/oidc/AutoDetectOidcHandler.jsonld",
103
103
  "undefineds:dist/identity/oidc/AutoDetectIdentityProviderHandler.jsonld",
104
104
  "undefineds:dist/identity/oidc/LoopbackClientIdAdapterFactory.jsonld",
105
+ "undefineds:dist/identity/oidc/RememberedClientGrantStore.jsonld",
106
+ "undefineds:dist/identity/oidc/RememberedConsentHandler.jsonld",
107
+ "undefineds:dist/identity/oidc/RememberedClientPromptFactory.jsonld",
105
108
  "undefineds:dist/identity/oidc/ScopedPickWebIdHandler.jsonld",
106
109
  "undefineds:dist/authentication/ConfiguredLoopbackDPoPWebIdExtractor.jsonld",
107
110
  "undefineds:dist/identity/AccountStorageBindingsHandler.jsonld",
@@ -3102,6 +3102,45 @@
3102
3102
  }
3103
3103
  }
3104
3104
  },
3105
+ "RememberedClientGrantStore": {
3106
+ "@id": "undefineds:dist/identity/oidc/RememberedClientGrantStore.jsonld#RememberedClientGrantStore",
3107
+ "@prefix": true,
3108
+ "@context": {
3109
+ "storage": {
3110
+ "@id": "undefineds:dist/identity/oidc/RememberedClientGrantStore.jsonld#RememberedClientGrantStore_storage"
3111
+ }
3112
+ }
3113
+ },
3114
+ "RememberedConsentHandler": {
3115
+ "@id": "undefineds:dist/identity/oidc/RememberedConsentHandler.jsonld#RememberedConsentHandler",
3116
+ "@prefix": true,
3117
+ "@context": {
3118
+ "store": {
3119
+ "@id": "undefineds:dist/identity/oidc/RememberedConsentHandler.jsonld#RememberedConsentHandler_store"
3120
+ },
3121
+ "providerFactory": {
3122
+ "@id": "undefineds:dist/identity/oidc/RememberedConsentHandler.jsonld#RememberedConsentHandler_providerFactory"
3123
+ },
3124
+ "source": {
3125
+ "@id": "undefineds:dist/identity/oidc/RememberedConsentHandler.jsonld#RememberedConsentHandler_source"
3126
+ },
3127
+ "rFactory": {
3128
+ "@id": "undefineds:dist/identity/oidc/RememberedConsentHandler.jsonld#RememberedConsentHandler_providerFactory"
3129
+ }
3130
+ }
3131
+ },
3132
+ "RememberedClientPromptFactory": {
3133
+ "@id": "undefineds:dist/identity/oidc/RememberedClientPromptFactory.jsonld#RememberedClientPromptFactory",
3134
+ "@prefix": true,
3135
+ "@context": {
3136
+ "store": {
3137
+ "@id": "undefineds:dist/identity/oidc/RememberedClientPromptFactory.jsonld#RememberedClientPromptFactory_store"
3138
+ },
3139
+ "source": {
3140
+ "@id": "undefineds:dist/identity/oidc/RememberedClientPromptFactory.jsonld#RememberedClientPromptFactory_source"
3141
+ }
3142
+ }
3143
+ },
3105
3144
  "ScopedPickWebIdHandler": {
3106
3145
  "@id": "undefineds:dist/identity/oidc/ScopedPickWebIdHandler.jsonld#ScopedPickWebIdHandler",
3107
3146
  "@prefix": true,
@@ -3118,6 +3157,9 @@
3118
3157
  "options_provisionBaseUrl": {
3119
3158
  "@id": "undefineds:dist/identity/oidc/ScopedPickWebIdHandler.jsonld#ScopedPickWebIdHandler_options_provisionBaseUrl"
3120
3159
  },
3160
+ "options_rememberedClientGrantStore": {
3161
+ "@id": "undefineds:dist/identity/oidc/ScopedPickWebIdHandler.jsonld#ScopedPickWebIdHandler_options_rememberedClientGrantStore"
3162
+ },
3121
3163
  "ownershipResolver": {
3122
3164
  "@id": "undefineds:dist/identity/oidc/ScopedPickWebIdHandler.jsonld#ScopedPickWebIdHandler_options_ownershipResolver"
3123
3165
  },
@@ -3129,6 +3171,9 @@
3129
3171
  },
3130
3172
  "provisionBaseUrl": {
3131
3173
  "@id": "undefineds:dist/identity/oidc/ScopedPickWebIdHandler.jsonld#ScopedPickWebIdHandler_options_provisionBaseUrl"
3174
+ },
3175
+ "rememberedClientGrantStore": {
3176
+ "@id": "undefineds:dist/identity/oidc/ScopedPickWebIdHandler.jsonld#ScopedPickWebIdHandler_options_rememberedClientGrantStore"
3132
3177
  }
3133
3178
  }
3134
3179
  },
@@ -0,0 +1,18 @@
1
+ import type { ExpiringStorage } from '@solid/community-server';
2
+ import type { Grant, Provider } from 'oidc-provider';
3
+ export declare const XPOD_DESKTOP_CLIENT_ID = "https://id.undefineds.co/app/xpod-desktop-client.json";
4
+ export interface RememberedClientGrant {
5
+ accountId: string;
6
+ clientId: string;
7
+ grantId: string;
8
+ expires: number;
9
+ }
10
+ /** One authoritative account/client record, always validated against the provider's live grant. */
11
+ export declare class RememberedClientGrantStore {
12
+ private readonly storage;
13
+ constructor(storage: ExpiringStorage<string, RememberedClientGrant>);
14
+ remember(grant: Grant): Promise<void>;
15
+ forget(accountId: string, clientId: string): Promise<void>;
16
+ find(provider: Provider, accountId: string, clientId: string): Promise<Grant | undefined>;
17
+ private clientKey;
18
+ }
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RememberedClientGrantStore = exports.XPOD_DESKTOP_CLIENT_ID = void 0;
4
+ exports.XPOD_DESKTOP_CLIENT_ID = 'https://id.undefineds.co/app/xpod-desktop-client.json';
5
+ /** One authoritative account/client record, always validated against the provider's live grant. */
6
+ class RememberedClientGrantStore {
7
+ constructor(storage) {
8
+ this.storage = storage;
9
+ }
10
+ async remember(grant) {
11
+ const { accountId, clientId, jti: grantId, exp } = grant;
12
+ if (!accountId || !clientId || !grantId || !exp || exp * 1000 <= Date.now()) {
13
+ return;
14
+ }
15
+ const entry = { accountId, clientId, grantId, expires: exp * 1000 };
16
+ await this.storage.set(this.clientKey(accountId, clientId), entry, new Date(entry.expires));
17
+ }
18
+ async forget(accountId, clientId) {
19
+ await this.storage.delete(this.clientKey(accountId, clientId));
20
+ }
21
+ async find(provider, accountId, clientId) {
22
+ const entry = await this.storage.get(this.clientKey(accountId, clientId));
23
+ if (!entry || entry.accountId !== accountId || entry.clientId !== clientId || entry.expires <= Date.now()) {
24
+ return undefined;
25
+ }
26
+ const grant = await provider.Grant.find(entry.grantId);
27
+ if (!grant || grant.accountId !== accountId || grant.clientId !== clientId ||
28
+ !grant.exp || grant.exp * 1000 <= Date.now()) {
29
+ return undefined;
30
+ }
31
+ return grant;
32
+ }
33
+ clientKey(accountId, clientId) {
34
+ return encodeURIComponent(JSON.stringify(['remembered-client', accountId, clientId]));
35
+ }
36
+ }
37
+ exports.RememberedClientGrantStore = RememberedClientGrantStore;
38
+ //# sourceMappingURL=RememberedClientGrantStore.js.map
@@ -0,0 +1,61 @@
1
+ {
2
+ "@context": [
3
+ "https://linkedsoftwaredependencies.org/bundles/npm/@undefineds.co/xpod/^0.0.0/components/context.jsonld",
4
+ "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^8.0.0/components/context.jsonld"
5
+ ],
6
+ "@id": "npmd:@undefineds.co/xpod",
7
+ "components": [
8
+ {
9
+ "@id": "undefineds:dist/identity/oidc/RememberedClientGrantStore.jsonld#RememberedClientGrantStore",
10
+ "@type": "Class",
11
+ "requireElement": "RememberedClientGrantStore",
12
+ "comment": "One authoritative account/client record, always validated against the provider's live grant.",
13
+ "parameters": [
14
+ {
15
+ "@id": "undefineds:dist/identity/oidc/RememberedClientGrantStore.jsonld#RememberedClientGrantStore_storage",
16
+ "range": {
17
+ "@type": "ParameterRangeGenericComponent",
18
+ "component": "css:dist/storage/keyvalue/ExpiringStorage.jsonld#ExpiringStorage",
19
+ "genericTypeInstances": [
20
+ "xsd:string",
21
+ {
22
+ "@type": "ParameterRangeWildcard"
23
+ }
24
+ ]
25
+ }
26
+ }
27
+ ],
28
+ "memberFields": [
29
+ {
30
+ "@id": "undefineds:dist/identity/oidc/RememberedClientGrantStore.jsonld#RememberedClientGrantStore__member_storage",
31
+ "memberFieldName": "storage"
32
+ },
33
+ {
34
+ "@id": "undefineds:dist/identity/oidc/RememberedClientGrantStore.jsonld#RememberedClientGrantStore__member_constructor",
35
+ "memberFieldName": "constructor"
36
+ },
37
+ {
38
+ "@id": "undefineds:dist/identity/oidc/RememberedClientGrantStore.jsonld#RememberedClientGrantStore__member_remember",
39
+ "memberFieldName": "remember"
40
+ },
41
+ {
42
+ "@id": "undefineds:dist/identity/oidc/RememberedClientGrantStore.jsonld#RememberedClientGrantStore__member_forget",
43
+ "memberFieldName": "forget"
44
+ },
45
+ {
46
+ "@id": "undefineds:dist/identity/oidc/RememberedClientGrantStore.jsonld#RememberedClientGrantStore__member_find",
47
+ "memberFieldName": "find"
48
+ },
49
+ {
50
+ "@id": "undefineds:dist/identity/oidc/RememberedClientGrantStore.jsonld#RememberedClientGrantStore__member_clientKey",
51
+ "memberFieldName": "clientKey"
52
+ }
53
+ ],
54
+ "constructorArguments": [
55
+ {
56
+ "@id": "undefineds:dist/identity/oidc/RememberedClientGrantStore.jsonld#RememberedClientGrantStore_storage"
57
+ }
58
+ ]
59
+ }
60
+ ]
61
+ }
@@ -0,0 +1,10 @@
1
+ import { PromptFactory } from '@solid/community-server';
2
+ import { interactionPolicy } from 'oidc-provider';
3
+ import { RememberedClientGrantStore } from './RememberedClientGrantStore';
4
+ /** Runs after the existing account and WebID checks, before any consent checks. */
5
+ export declare class RememberedClientPromptFactory extends PromptFactory {
6
+ private readonly source;
7
+ private readonly store;
8
+ constructor(source: PromptFactory, store: RememberedClientGrantStore);
9
+ handle(policy: interactionPolicy.DefaultPolicy): Promise<void>;
10
+ }
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RememberedClientPromptFactory = void 0;
4
+ const community_server_1 = require("@solid/community-server");
5
+ const oidc_provider_1 = require("oidc-provider");
6
+ const RememberedClientGrantStore_1 = require("./RememberedClientGrantStore");
7
+ /** Runs after the existing account and WebID checks, before any consent checks. */
8
+ class RememberedClientPromptFactory extends community_server_1.PromptFactory {
9
+ constructor(source, store) {
10
+ super();
11
+ this.source = source;
12
+ this.store = store;
13
+ }
14
+ async handle(policy) {
15
+ await this.source.handleSafe(policy);
16
+ const consent = policy.get('consent');
17
+ const native = consent?.checks.get('native_client_prompt');
18
+ const consentIndex = policy.findIndex((prompt) => prompt.name === 'consent');
19
+ const loginIndex = policy.findIndex((prompt) => prompt.name === 'login');
20
+ if (!consent || !native || loginIndex < 0 || loginIndex >= consentIndex) {
21
+ throw new community_server_1.InternalServerError('Missing ordered default login and consent policies.');
22
+ }
23
+ const remembered = new WeakSet();
24
+ policy.add(new oidc_provider_1.interactionPolicy.Prompt({ name: 'restore_remembered_client', requestable: false }, new oidc_provider_1.interactionPolicy.Check('restore_remembered_client', 'Restore previously remembered consent.', async (ctx) => {
25
+ const { oidc } = ctx;
26
+ const accountId = oidc.session?.accountId;
27
+ const clientId = oidc.client?.clientId;
28
+ if (!accountId || clientId !== RememberedClientGrantStore_1.XPOD_DESKTOP_CLIENT_ID || oidc.result?.consent) {
29
+ return false;
30
+ }
31
+ const grant = await this.store.find(oidc.provider, accountId, clientId);
32
+ if (grant) {
33
+ oidc.session.ensureClientContainer(clientId);
34
+ oidc.session.grantIdFor(clientId, grant.jti);
35
+ oidc.entity('Grant', grant);
36
+ remembered.add(ctx);
37
+ }
38
+ return false;
39
+ })), consentIndex);
40
+ const originalCheck = native.check;
41
+ native.check = async (ctx) => remembered.has(ctx) ? false : originalCheck(ctx);
42
+ }
43
+ }
44
+ exports.RememberedClientPromptFactory = RememberedClientPromptFactory;
45
+ //# sourceMappingURL=RememberedClientPromptFactory.js.map
@@ -0,0 +1,54 @@
1
+ {
2
+ "@context": [
3
+ "https://linkedsoftwaredependencies.org/bundles/npm/@undefineds.co/xpod/^0.0.0/components/context.jsonld",
4
+ "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^8.0.0/components/context.jsonld"
5
+ ],
6
+ "@id": "npmd:@undefineds.co/xpod",
7
+ "components": [
8
+ {
9
+ "@id": "undefineds:dist/identity/oidc/RememberedClientPromptFactory.jsonld#RememberedClientPromptFactory",
10
+ "@type": "Class",
11
+ "requireElement": "RememberedClientPromptFactory",
12
+ "extends": [
13
+ "css:dist/identity/configuration/PromptFactory.jsonld#PromptFactory"
14
+ ],
15
+ "comment": "Runs after the existing account and WebID checks, before any consent checks.",
16
+ "parameters": [
17
+ {
18
+ "@id": "undefineds:dist/identity/oidc/RememberedClientPromptFactory.jsonld#RememberedClientPromptFactory_store",
19
+ "range": "undefineds:dist/identity/oidc/RememberedClientGrantStore.jsonld#RememberedClientGrantStore"
20
+ },
21
+ {
22
+ "@id": "undefineds:dist/identity/oidc/RememberedClientPromptFactory.jsonld#RememberedClientPromptFactory_source",
23
+ "range": "css:dist/identity/configuration/PromptFactory.jsonld#PromptFactory"
24
+ }
25
+ ],
26
+ "memberFields": [
27
+ {
28
+ "@id": "undefineds:dist/identity/oidc/RememberedClientPromptFactory.jsonld#RememberedClientPromptFactory__member_source",
29
+ "memberFieldName": "source"
30
+ },
31
+ {
32
+ "@id": "undefineds:dist/identity/oidc/RememberedClientPromptFactory.jsonld#RememberedClientPromptFactory__member_store",
33
+ "memberFieldName": "store"
34
+ },
35
+ {
36
+ "@id": "undefineds:dist/identity/oidc/RememberedClientPromptFactory.jsonld#RememberedClientPromptFactory__member_constructor",
37
+ "memberFieldName": "constructor"
38
+ },
39
+ {
40
+ "@id": "undefineds:dist/identity/oidc/RememberedClientPromptFactory.jsonld#RememberedClientPromptFactory__member_handle",
41
+ "memberFieldName": "handle"
42
+ }
43
+ ],
44
+ "constructorArguments": [
45
+ {
46
+ "@id": "undefineds:dist/identity/oidc/RememberedClientPromptFactory.jsonld#RememberedClientPromptFactory_source"
47
+ },
48
+ {
49
+ "@id": "undefineds:dist/identity/oidc/RememberedClientPromptFactory.jsonld#RememberedClientPromptFactory_store"
50
+ }
51
+ ]
52
+ }
53
+ ]
54
+ }
@@ -0,0 +1,11 @@
1
+ import { JsonInteractionHandler, type JsonInteractionHandlerInput, type JsonRepresentation, type ProviderFactory } from '@solid/community-server';
2
+ import { RememberedClientGrantStore } from './RememberedClientGrantStore';
3
+ /** Records successful CSS consent without replacing its grant or interaction handling. */
4
+ export declare class RememberedConsentHandler extends JsonInteractionHandler {
5
+ private readonly providerFactory;
6
+ private readonly source;
7
+ private readonly store;
8
+ constructor(providerFactory: ProviderFactory, source: JsonInteractionHandler, store: RememberedClientGrantStore);
9
+ canHandle(input: JsonInteractionHandlerInput): Promise<void>;
10
+ handle(input: JsonInteractionHandlerInput): Promise<JsonRepresentation>;
11
+ }
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RememberedConsentHandler = void 0;
4
+ const community_server_1 = require("@solid/community-server");
5
+ const yup_1 = require("yup");
6
+ const RememberedClientGrantStore_1 = require("./RememberedClientGrantStore");
7
+ const rememberSchema = (0, yup_1.object)({ remember: (0, yup_1.boolean)().default(false) });
8
+ /** Records successful CSS consent without replacing its grant or interaction handling. */
9
+ class RememberedConsentHandler extends community_server_1.JsonInteractionHandler {
10
+ constructor(providerFactory, source, store) {
11
+ super();
12
+ this.providerFactory = providerFactory;
13
+ this.source = source;
14
+ this.store = store;
15
+ }
16
+ async canHandle(input) {
17
+ await this.source.canHandle(input);
18
+ }
19
+ async handle(input) {
20
+ const interaction = input.oidcInteraction;
21
+ const previousResult = interaction?.result;
22
+ try {
23
+ return await this.source.handleSafe(input);
24
+ }
25
+ catch (error) {
26
+ if (!(error instanceof community_server_1.FoundHttpError) || !interaction?.result?.consent ||
27
+ interaction.result === previousResult) {
28
+ throw error;
29
+ }
30
+ const accountId = interaction.session?.accountId;
31
+ const clientId = interaction.params.client_id;
32
+ const grantId = interaction.result.consent.grantId ?? interaction.grantId;
33
+ if (accountId && clientId === RememberedClientGrantStore_1.XPOD_DESKTOP_CLIENT_ID && grantId) {
34
+ const provider = await this.providerFactory.getProvider();
35
+ const grant = await provider.Grant.find(grantId);
36
+ if (grant?.accountId === accountId && grant.clientId === clientId) {
37
+ const { remember } = await rememberSchema.validate(input.json);
38
+ if (remember) {
39
+ await this.store.remember(grant);
40
+ }
41
+ else {
42
+ await this.store.forget(accountId, clientId);
43
+ }
44
+ }
45
+ }
46
+ throw error;
47
+ }
48
+ }
49
+ }
50
+ exports.RememberedConsentHandler = RememberedConsentHandler;
51
+ //# sourceMappingURL=RememberedConsentHandler.js.map
@@ -0,0 +1,69 @@
1
+ {
2
+ "@context": [
3
+ "https://linkedsoftwaredependencies.org/bundles/npm/@undefineds.co/xpod/^0.0.0/components/context.jsonld",
4
+ "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^8.0.0/components/context.jsonld"
5
+ ],
6
+ "@id": "npmd:@undefineds.co/xpod",
7
+ "components": [
8
+ {
9
+ "@id": "undefineds:dist/identity/oidc/RememberedConsentHandler.jsonld#RememberedConsentHandler",
10
+ "@type": "Class",
11
+ "requireElement": "RememberedConsentHandler",
12
+ "extends": [
13
+ "css:dist/identity/interaction/JsonInteractionHandler.jsonld#JsonInteractionHandler"
14
+ ],
15
+ "comment": "Records successful CSS consent without replacing its grant or interaction handling.",
16
+ "parameters": [
17
+ {
18
+ "@id": "undefineds:dist/identity/oidc/RememberedConsentHandler.jsonld#RememberedConsentHandler_store",
19
+ "range": "undefineds:dist/identity/oidc/RememberedClientGrantStore.jsonld#RememberedClientGrantStore"
20
+ },
21
+ {
22
+ "@id": "undefineds:dist/identity/oidc/RememberedConsentHandler.jsonld#RememberedConsentHandler_providerFactory",
23
+ "range": "css:dist/identity/configuration/ProviderFactory.jsonld#ProviderFactory"
24
+ },
25
+ {
26
+ "@id": "undefineds:dist/identity/oidc/RememberedConsentHandler.jsonld#RememberedConsentHandler_source",
27
+ "range": "css:dist/identity/interaction/JsonInteractionHandler.jsonld#JsonInteractionHandler"
28
+ }
29
+ ],
30
+ "memberFields": [
31
+ {
32
+ "@id": "undefineds:dist/identity/oidc/RememberedConsentHandler.jsonld#RememberedConsentHandler__member_providerFactory",
33
+ "memberFieldName": "providerFactory"
34
+ },
35
+ {
36
+ "@id": "undefineds:dist/identity/oidc/RememberedConsentHandler.jsonld#RememberedConsentHandler__member_source",
37
+ "memberFieldName": "source"
38
+ },
39
+ {
40
+ "@id": "undefineds:dist/identity/oidc/RememberedConsentHandler.jsonld#RememberedConsentHandler__member_store",
41
+ "memberFieldName": "store"
42
+ },
43
+ {
44
+ "@id": "undefineds:dist/identity/oidc/RememberedConsentHandler.jsonld#RememberedConsentHandler__member_constructor",
45
+ "memberFieldName": "constructor"
46
+ },
47
+ {
48
+ "@id": "undefineds:dist/identity/oidc/RememberedConsentHandler.jsonld#RememberedConsentHandler__member_canHandle",
49
+ "memberFieldName": "canHandle"
50
+ },
51
+ {
52
+ "@id": "undefineds:dist/identity/oidc/RememberedConsentHandler.jsonld#RememberedConsentHandler__member_handle",
53
+ "memberFieldName": "handle"
54
+ }
55
+ ],
56
+ "constructorArguments": [
57
+ {
58
+ "@id": "undefineds:dist/identity/oidc/RememberedConsentHandler.jsonld#RememberedConsentHandler_providerFactory"
59
+ },
60
+ {
61
+ "@id": "undefineds:dist/identity/oidc/RememberedConsentHandler.jsonld#RememberedConsentHandler_source"
62
+ },
63
+ {
64
+ "@id": "undefineds:dist/identity/oidc/RememberedConsentHandler.jsonld#RememberedConsentHandler_store"
65
+ }
66
+ ]
67
+ }
68
+ ]
69
+ }
@@ -1,11 +1,13 @@
1
1
  import { JsonInteractionHandler } from '@solid/community-server';
2
2
  import type { JsonInteractionHandlerInput, JsonRepresentation, JsonView, ProviderFactory } from '@solid/community-server';
3
3
  import type { PodOwnershipResolver } from './PodOwnershipResolver';
4
+ import { RememberedClientGrantStore } from './RememberedClientGrantStore';
4
5
  export interface ScopedPickWebIdHandlerOptions {
5
6
  ownershipResolver: PodOwnershipResolver;
6
7
  providerFactory: ProviderFactory;
7
8
  storageBaseUrl?: string;
8
9
  provisionBaseUrl?: string;
10
+ rememberedClientGrantStore?: RememberedClientGrantStore;
9
11
  }
10
12
  /**
11
13
  * CSS-compatible WebID picker scoped to the current storage provider.
@@ -21,9 +23,11 @@ export declare class ScopedPickWebIdHandler extends JsonInteractionHandler imple
21
23
  private readonly providerFactory;
22
24
  private readonly storageBaseUrl?;
23
25
  private readonly provisionBaseUrl?;
26
+ private readonly rememberedClientGrantStore?;
24
27
  constructor(options: ScopedPickWebIdHandlerOptions);
25
28
  getView({ accountId, oidcInteraction }: JsonInteractionHandlerInput): Promise<JsonRepresentation>;
26
29
  handle({ oidcInteraction, accountId, json }: JsonInteractionHandlerInput): Promise<never>;
30
+ private clearSelectedWebId;
27
31
  private resolveScopedEntries;
28
32
  private resolveTargetStorage;
29
33
  }
@@ -5,6 +5,7 @@ const yup_1 = require("yup");
5
5
  const global_logger_factory_1 = require("global-logger-factory");
6
6
  const community_server_1 = require("@solid/community-server");
7
7
  const ProvisionCodeCodec_1 = require("../../provision/ProvisionCodeCodec");
8
+ const RememberedClientGrantStore_1 = require("./RememberedClientGrantStore");
8
9
  const inSchema = (0, yup_1.object)({
9
10
  webId: (0, yup_1.string)().trim().required(),
10
11
  remember: (0, yup_1.boolean)().default(false),
@@ -25,6 +26,7 @@ class ScopedPickWebIdHandler extends community_server_1.JsonInteractionHandler {
25
26
  this.providerFactory = options.providerFactory;
26
27
  this.storageBaseUrl = normalizeOptionalUrl(options.storageBaseUrl);
27
28
  this.provisionBaseUrl = normalizeOptionalUrl(options.provisionBaseUrl);
29
+ this.rememberedClientGrantStore = options.rememberedClientGrantStore;
28
30
  }
29
31
  async getView({ accountId, oidcInteraction }) {
30
32
  (0, community_server_1.assertAccountId)(accountId);
@@ -51,7 +53,7 @@ class ScopedPickWebIdHandler extends community_server_1.JsonInteractionHandler {
51
53
  this.logger.warn('Rejected an unverified WebID selection; ownership could not be established');
52
54
  throw new community_server_1.BadRequestHttpError('WebID does not belong to this storage provider.');
53
55
  }
54
- await (0, community_server_1.forgetWebId)(provider, oidcInteraction);
56
+ await this.clearSelectedWebId(provider, oidcInteraction);
55
57
  const location = await (0, community_server_1.finishInteraction)(oidcInteraction, {
56
58
  login: {
57
59
  accountId: webId,
@@ -60,6 +62,28 @@ class ScopedPickWebIdHandler extends community_server_1.JsonInteractionHandler {
60
62
  }, true);
61
63
  throw new community_server_1.FoundHttpError(location);
62
64
  }
65
+ async clearSelectedWebId(provider, interaction) {
66
+ const clientId = interaction.params.client_id;
67
+ const accountId = interaction.session?.accountId;
68
+ const remembered = accountId && clientId === RememberedClientGrantStore_1.XPOD_DESKTOP_CLIENT_ID && interaction.grantId
69
+ ? await this.rememberedClientGrantStore?.find(provider, accountId, clientId)
70
+ : undefined;
71
+ if (!remembered || remembered.jti !== interaction.grantId) {
72
+ await (0, community_server_1.forgetWebId)(provider, interaction);
73
+ return;
74
+ }
75
+ // Preserve only explicitly remembered consent. Detach every current grant
76
+ // reference so oidc-provider can establish the selected WebID's own grant.
77
+ const session = await provider.Session.find(interaction.session.cookie);
78
+ if (session) {
79
+ delete session.accountId;
80
+ delete session.authorizationFor(RememberedClientGrantStore_1.XPOD_DESKTOP_CLIENT_ID).grantId;
81
+ await session.persist();
82
+ }
83
+ delete interaction.grantId;
84
+ delete interaction.result?.consent;
85
+ delete interaction.lastSubmission?.consent;
86
+ }
63
87
  async resolveScopedEntries(accountId, target) {
64
88
  try {
65
89
  const candidateWebIds = await this.ownershipResolver.listAccountWebIds(accountId);