@ajna-inc/openbadges 0.1.0

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 (224) hide show
  1. package/LICENSE +202 -0
  2. package/build/OpenBadgesModule.d.ts +10 -0
  3. package/build/OpenBadgesModule.js +75 -0
  4. package/build/OpenBadgesModule.js.map +1 -0
  5. package/build/OpenBadgesModuleConfig.d.ts +96 -0
  6. package/build/OpenBadgesModuleConfig.js +50 -0
  7. package/build/OpenBadgesModuleConfig.js.map +1 -0
  8. package/build/api/OpenBadgesApi.d.ts +48 -0
  9. package/build/api/OpenBadgesApi.js +81 -0
  10. package/build/api/OpenBadgesApi.js.map +1 -0
  11. package/build/api/index.d.ts +1 -0
  12. package/build/api/index.js +18 -0
  13. package/build/api/index.js.map +1 -0
  14. package/build/constants.d.ts +12 -0
  15. package/build/constants.js +27 -0
  16. package/build/constants.js.map +1 -0
  17. package/build/cryptosuites/EcdsaSd2023.d.ts +143 -0
  18. package/build/cryptosuites/EcdsaSd2023.js +518 -0
  19. package/build/cryptosuites/EcdsaSd2023.js.map +1 -0
  20. package/build/cryptosuites/EddsaRdfc2022.d.ts +112 -0
  21. package/build/cryptosuites/EddsaRdfc2022.js +356 -0
  22. package/build/cryptosuites/EddsaRdfc2022.js.map +1 -0
  23. package/build/cryptosuites/constants.d.ts +14 -0
  24. package/build/cryptosuites/constants.js +22 -0
  25. package/build/cryptosuites/constants.js.map +1 -0
  26. package/build/cryptosuites/contextPreprocessor.d.ts +24 -0
  27. package/build/cryptosuites/contextPreprocessor.js +127 -0
  28. package/build/cryptosuites/contextPreprocessor.js.map +1 -0
  29. package/build/cryptosuites/dataIntegrityV2Context.d.ts +144 -0
  30. package/build/cryptosuites/dataIntegrityV2Context.js +86 -0
  31. package/build/cryptosuites/dataIntegrityV2Context.js.map +1 -0
  32. package/build/cryptosuites/index.d.ts +11 -0
  33. package/build/cryptosuites/index.js +33 -0
  34. package/build/cryptosuites/index.js.map +1 -0
  35. package/build/http/OpenBadgesHttpModule.d.ts +9 -0
  36. package/build/http/OpenBadgesHttpModule.js +120 -0
  37. package/build/http/OpenBadgesHttpModule.js.map +1 -0
  38. package/build/http/OpenBadgesHttpModuleConfig.d.ts +55 -0
  39. package/build/http/OpenBadgesHttpModuleConfig.js +78 -0
  40. package/build/http/OpenBadgesHttpModuleConfig.js.map +1 -0
  41. package/build/http/endpoints/authorize.d.ts +3 -0
  42. package/build/http/endpoints/authorize.js +79 -0
  43. package/build/http/endpoints/authorize.js.map +1 -0
  44. package/build/http/endpoints/consent.d.ts +3 -0
  45. package/build/http/endpoints/consent.js +25 -0
  46. package/build/http/endpoints/consent.js.map +1 -0
  47. package/build/http/endpoints/credentials.d.ts +4 -0
  48. package/build/http/endpoints/credentials.js +85 -0
  49. package/build/http/endpoints/credentials.js.map +1 -0
  50. package/build/http/endpoints/did.d.ts +3 -0
  51. package/build/http/endpoints/did.js +48 -0
  52. package/build/http/endpoints/did.js.map +1 -0
  53. package/build/http/endpoints/introspect.d.ts +3 -0
  54. package/build/http/endpoints/introspect.js +37 -0
  55. package/build/http/endpoints/introspect.js.map +1 -0
  56. package/build/http/endpoints/jwks.d.ts +3 -0
  57. package/build/http/endpoints/jwks.js +46 -0
  58. package/build/http/endpoints/jwks.js.map +1 -0
  59. package/build/http/endpoints/profile.d.ts +4 -0
  60. package/build/http/endpoints/profile.js +58 -0
  61. package/build/http/endpoints/profile.js.map +1 -0
  62. package/build/http/endpoints/refresh.d.ts +15 -0
  63. package/build/http/endpoints/refresh.js +134 -0
  64. package/build/http/endpoints/refresh.js.map +1 -0
  65. package/build/http/endpoints/registration.d.ts +3 -0
  66. package/build/http/endpoints/registration.js +42 -0
  67. package/build/http/endpoints/registration.js.map +1 -0
  68. package/build/http/endpoints/revoke.d.ts +3 -0
  69. package/build/http/endpoints/revoke.js +38 -0
  70. package/build/http/endpoints/revoke.js.map +1 -0
  71. package/build/http/endpoints/serviceDescription.d.ts +3 -0
  72. package/build/http/endpoints/serviceDescription.js +52 -0
  73. package/build/http/endpoints/serviceDescription.js.map +1 -0
  74. package/build/http/endpoints/statusList.d.ts +10 -0
  75. package/build/http/endpoints/statusList.js +95 -0
  76. package/build/http/endpoints/statusList.js.map +1 -0
  77. package/build/http/endpoints/token.d.ts +3 -0
  78. package/build/http/endpoints/token.js +147 -0
  79. package/build/http/endpoints/token.js.map +1 -0
  80. package/build/http/middleware/auth.d.ts +5 -0
  81. package/build/http/middleware/auth.js +48 -0
  82. package/build/http/middleware/auth.js.map +1 -0
  83. package/build/http/router.d.ts +13 -0
  84. package/build/http/router.js +36 -0
  85. package/build/http/router.js.map +1 -0
  86. package/build/http/tenants.d.ts +2 -0
  87. package/build/http/tenants.js +20 -0
  88. package/build/http/tenants.js.map +1 -0
  89. package/build/http/util/auth.d.ts +8 -0
  90. package/build/http/util/auth.js +43 -0
  91. package/build/http/util/auth.js.map +1 -0
  92. package/build/index.d.ts +46 -0
  93. package/build/index.js +71 -0
  94. package/build/index.js.map +1 -0
  95. package/build/models/ClrCredential.d.ts +112 -0
  96. package/build/models/ClrCredential.js +52 -0
  97. package/build/models/ClrCredential.js.map +1 -0
  98. package/build/models/EndorsementCredential.d.ts +89 -0
  99. package/build/models/EndorsementCredential.js +11 -0
  100. package/build/models/EndorsementCredential.js.map +1 -0
  101. package/build/models/StatusListCredential.d.ts +81 -0
  102. package/build/models/StatusListCredential.js +28 -0
  103. package/build/models/StatusListCredential.js.map +1 -0
  104. package/build/models/index.d.ts +8 -0
  105. package/build/models/index.js +25 -0
  106. package/build/models/index.js.map +1 -0
  107. package/build/repository/OpenBadgeCredentialRecord.d.ts +44 -0
  108. package/build/repository/OpenBadgeCredentialRecord.js +46 -0
  109. package/build/repository/OpenBadgeCredentialRecord.js.map +1 -0
  110. package/build/repository/OpenBadgeCredentialRepository.d.ts +8 -0
  111. package/build/repository/OpenBadgeCredentialRepository.js +38 -0
  112. package/build/repository/OpenBadgeCredentialRepository.js.map +1 -0
  113. package/build/repository/OpenBadgesAuthCodeRecord.d.ts +35 -0
  114. package/build/repository/OpenBadgesAuthCodeRecord.js +28 -0
  115. package/build/repository/OpenBadgesAuthCodeRecord.js.map +1 -0
  116. package/build/repository/OpenBadgesAuthCodeRepository.d.ts +6 -0
  117. package/build/repository/OpenBadgesAuthCodeRepository.js +32 -0
  118. package/build/repository/OpenBadgesAuthCodeRepository.js.map +1 -0
  119. package/build/repository/OpenBadgesConsentRecord.d.ts +24 -0
  120. package/build/repository/OpenBadgesConsentRecord.js +23 -0
  121. package/build/repository/OpenBadgesConsentRecord.js.map +1 -0
  122. package/build/repository/OpenBadgesConsentRepository.d.ts +6 -0
  123. package/build/repository/OpenBadgesConsentRepository.js +32 -0
  124. package/build/repository/OpenBadgesConsentRepository.js.map +1 -0
  125. package/build/repository/OpenBadgesKeyBindingRecord.d.ts +24 -0
  126. package/build/repository/OpenBadgesKeyBindingRecord.js +32 -0
  127. package/build/repository/OpenBadgesKeyBindingRecord.js.map +1 -0
  128. package/build/repository/OpenBadgesKeyBindingRepository.d.ts +7 -0
  129. package/build/repository/OpenBadgesKeyBindingRepository.js +35 -0
  130. package/build/repository/OpenBadgesKeyBindingRepository.js.map +1 -0
  131. package/build/repository/OpenBadgesOAuthRecord.d.ts +35 -0
  132. package/build/repository/OpenBadgesOAuthRecord.js +25 -0
  133. package/build/repository/OpenBadgesOAuthRecord.js.map +1 -0
  134. package/build/repository/OpenBadgesOAuthRepository.d.ts +8 -0
  135. package/build/repository/OpenBadgesOAuthRepository.js +38 -0
  136. package/build/repository/OpenBadgesOAuthRepository.js.map +1 -0
  137. package/build/repository/OpenBadgesProfileRecord.d.ts +21 -0
  138. package/build/repository/OpenBadgesProfileRecord.js +22 -0
  139. package/build/repository/OpenBadgesProfileRecord.js.map +1 -0
  140. package/build/repository/OpenBadgesProfileRepository.d.ts +6 -0
  141. package/build/repository/OpenBadgesProfileRepository.js +32 -0
  142. package/build/repository/OpenBadgesProfileRepository.js.map +1 -0
  143. package/build/repository/OpenBadgesRevocationCacheRecord.d.ts +23 -0
  144. package/build/repository/OpenBadgesRevocationCacheRecord.js +23 -0
  145. package/build/repository/OpenBadgesRevocationCacheRecord.js.map +1 -0
  146. package/build/repository/OpenBadgesRevocationCacheRepository.d.ts +6 -0
  147. package/build/repository/OpenBadgesRevocationCacheRepository.js +32 -0
  148. package/build/repository/OpenBadgesRevocationCacheRepository.js.map +1 -0
  149. package/build/repository/OpenBadgesServiceDescriptionRecord.d.ts +21 -0
  150. package/build/repository/OpenBadgesServiceDescriptionRecord.js +22 -0
  151. package/build/repository/OpenBadgesServiceDescriptionRecord.js.map +1 -0
  152. package/build/repository/OpenBadgesServiceDescriptionRepository.d.ts +6 -0
  153. package/build/repository/OpenBadgesServiceDescriptionRepository.js +32 -0
  154. package/build/repository/OpenBadgesServiceDescriptionRepository.js.map +1 -0
  155. package/build/repository/OpenBadgesTokenRecord.d.ts +39 -0
  156. package/build/repository/OpenBadgesTokenRecord.js +36 -0
  157. package/build/repository/OpenBadgesTokenRecord.js.map +1 -0
  158. package/build/repository/OpenBadgesTokenRepository.d.ts +9 -0
  159. package/build/repository/OpenBadgesTokenRepository.js +45 -0
  160. package/build/repository/OpenBadgesTokenRepository.js.map +1 -0
  161. package/build/repository/StatusListRecord.d.ts +49 -0
  162. package/build/repository/StatusListRecord.js +47 -0
  163. package/build/repository/StatusListRecord.js.map +1 -0
  164. package/build/repository/StatusListRepository.d.ts +24 -0
  165. package/build/repository/StatusListRepository.js +52 -0
  166. package/build/repository/StatusListRepository.js.map +1 -0
  167. package/build/repository/index.d.ts +18 -0
  168. package/build/repository/index.js +35 -0
  169. package/build/repository/index.js.map +1 -0
  170. package/build/services/AchievementValidator.d.ts +158 -0
  171. package/build/services/AchievementValidator.js +238 -0
  172. package/build/services/AchievementValidator.js.map +1 -0
  173. package/build/services/ConsumerService.d.ts +24 -0
  174. package/build/services/ConsumerService.js +143 -0
  175. package/build/services/ConsumerService.js.map +1 -0
  176. package/build/services/ContextService.d.ts +14 -0
  177. package/build/services/ContextService.js +54 -0
  178. package/build/services/ContextService.js.map +1 -0
  179. package/build/services/DataIntegrityService.d.ts +51 -0
  180. package/build/services/DataIntegrityService.js +134 -0
  181. package/build/services/DataIntegrityService.js.map +1 -0
  182. package/build/services/DidCommLinkService.d.ts +7 -0
  183. package/build/services/DidCommLinkService.js +20 -0
  184. package/build/services/DidCommLinkService.js.map +1 -0
  185. package/build/services/DisplayMapper.d.ts +9 -0
  186. package/build/services/DisplayMapper.js +26 -0
  187. package/build/services/DisplayMapper.js.map +1 -0
  188. package/build/services/IssuerService.d.ts +38 -0
  189. package/build/services/IssuerService.js +225 -0
  190. package/build/services/IssuerService.js.map +1 -0
  191. package/build/services/JwtService.d.ts +19 -0
  192. package/build/services/JwtService.js +229 -0
  193. package/build/services/JwtService.js.map +1 -0
  194. package/build/services/KeyService.d.ts +102 -0
  195. package/build/services/KeyService.js +439 -0
  196. package/build/services/KeyService.js.map +1 -0
  197. package/build/services/OAuthClient.d.ts +26 -0
  198. package/build/services/OAuthClient.js +127 -0
  199. package/build/services/OAuthClient.js.map +1 -0
  200. package/build/services/ProofService.d.ts +15 -0
  201. package/build/services/ProofService.js +43 -0
  202. package/build/services/ProofService.js.map +1 -0
  203. package/build/services/RevocationService.d.ts +59 -0
  204. package/build/services/RevocationService.js +319 -0
  205. package/build/services/RevocationService.js.map +1 -0
  206. package/build/services/VerifyService.d.ts +17 -0
  207. package/build/services/VerifyService.js +54 -0
  208. package/build/services/VerifyService.js.map +1 -0
  209. package/build/services/crypto/CryptoDriver.d.ts +9 -0
  210. package/build/services/crypto/CryptoDriver.js +7 -0
  211. package/build/services/crypto/CryptoDriver.js.map +1 -0
  212. package/build/services/crypto/JsonLdCryptoDriver.d.ts +17 -0
  213. package/build/services/crypto/JsonLdCryptoDriver.js +45 -0
  214. package/build/services/crypto/JsonLdCryptoDriver.js.map +1 -0
  215. package/build/services/crypto/JwtCryptoDriver.d.ts +13 -0
  216. package/build/services/crypto/JwtCryptoDriver.js +42 -0
  217. package/build/services/crypto/JwtCryptoDriver.js.map +1 -0
  218. package/build/services/index.d.ts +12 -0
  219. package/build/services/index.js +29 -0
  220. package/build/services/index.js.map +1 -0
  221. package/build/utils/validate.d.ts +17 -0
  222. package/build/utils/validate.js +107 -0
  223. package/build/utils/validate.js.map +1 -0
  224. package/package.json +57 -0
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.configureRefreshEndpoint = configureRefreshEndpoint;
4
+ const auth_1 = require("../middleware/auth");
5
+ const router_1 = require("../router");
6
+ const OpenBadgeCredentialRepository_1 = require("../../repository/OpenBadgeCredentialRepository");
7
+ const OpenBadgeCredentialRecord_1 = require("../../repository/OpenBadgeCredentialRecord");
8
+ const ProofService_1 = require("../../services/ProofService");
9
+ const KeyService_1 = require("../../services/KeyService");
10
+ const RevocationService_1 = require("../../services/RevocationService");
11
+ const constants_1 = require("../../constants");
12
+ const OB_READ = 'https://purl.imsglobal.org/spec/ob/v3p0/scope/readonly';
13
+ const OB_WRITE = 'https://purl.imsglobal.org/spec/ob/v3p0/scope/replace';
14
+ /**
15
+ * Credential Refresh Endpoint
16
+ *
17
+ * Allows holders to request a refreshed (renewed) version of their credential.
18
+ * The issuer may update validity dates or other information.
19
+ *
20
+ * POST /ims/ob/v3p0/credentials/refresh
21
+ * Body: { credentialId: string } or the full credential
22
+ *
23
+ * Returns: refreshed credential with new proof and updated dates
24
+ */
25
+ function configureRefreshEndpoint(router, config, module) {
26
+ router.post(config.refreshPath, (0, auth_1.bearerAuth)(module), (0, auth_1.requireScopes)([OB_WRITE]), async (req, res) => {
27
+ try {
28
+ const { agentContext } = (0, router_1.getRequestContext)(req);
29
+ const body = req.body;
30
+ if (!body.credentialId && !body.credential) {
31
+ return (0, router_1.sendError)(res, 400, 'invalid_request', 'Missing credentialId or credential in request body');
32
+ }
33
+ const repo = agentContext.dependencyManager.resolve(OpenBadgeCredentialRepository_1.OpenBadgeCredentialRepository);
34
+ const proofService = agentContext.dependencyManager.resolve(ProofService_1.ProofService);
35
+ const keyService = agentContext.dependencyManager.resolve(KeyService_1.KeyService);
36
+ const revocationService = agentContext.dependencyManager.resolve(RevocationService_1.RevocationService);
37
+ let originalCredential;
38
+ let recordId;
39
+ // Find the original credential
40
+ if (body.credentialId) {
41
+ // Look up by credential ID in stored records
42
+ const records = await repo.getAll(agentContext);
43
+ const matchingRecord = records.find((r) => {
44
+ const cred = r.credential;
45
+ return cred?.id === body.credentialId;
46
+ });
47
+ if (!matchingRecord) {
48
+ return (0, router_1.sendError)(res, 404, 'not_found', `Credential not found: ${body.credentialId}`);
49
+ }
50
+ originalCredential = matchingRecord.credential;
51
+ recordId = matchingRecord.id;
52
+ }
53
+ else {
54
+ originalCredential = body.credential;
55
+ }
56
+ // Check if credential is revoked
57
+ const isRevoked = await revocationService.isRevoked(agentContext, originalCredential);
58
+ if (isRevoked) {
59
+ return (0, router_1.sendError)(res, 400, 'invalid_request', 'Cannot refresh a revoked credential');
60
+ }
61
+ // Extract issuer info for signing
62
+ const issuer = originalCredential.issuer;
63
+ const issuerId = typeof issuer === 'string' ? issuer : issuer?.id;
64
+ if (!issuerId) {
65
+ return (0, router_1.sendError)(res, 400, 'invalid_request', 'Could not determine issuer from credential');
66
+ }
67
+ // Create refreshed credential with updated dates
68
+ const now = new Date();
69
+ const refreshedCredential = {
70
+ ...originalCredential,
71
+ // Update validity dates
72
+ validFrom: now.toISOString(),
73
+ // Extend validity by 1 year if original had validUntil
74
+ ...(originalCredential.validUntil
75
+ ? { validUntil: new Date(now.getTime() + 365 * 24 * 60 * 60 * 1000).toISOString() }
76
+ : {}),
77
+ // Add refresh metadata
78
+ refreshService: {
79
+ type: 'RefreshService2023',
80
+ refreshedAt: now.toISOString(),
81
+ previousId: originalCredential.id,
82
+ },
83
+ };
84
+ // Remove old proof
85
+ delete refreshedCredential.proof;
86
+ // Ensure contexts are correct
87
+ const contexts = Array.isArray(refreshedCredential['@context'])
88
+ ? refreshedCredential['@context']
89
+ : [refreshedCredential['@context']];
90
+ if (!contexts.includes(constants_1.VC_V2_CONTEXT)) {
91
+ refreshedCredential['@context'] = [constants_1.VC_V2_CONTEXT, ...contexts.filter((c) => c !== constants_1.VC_V2_CONTEXT)];
92
+ }
93
+ // Sign the refreshed credential
94
+ const verificationMethod = `${issuerId}#key-1`;
95
+ try {
96
+ await keyService.ensureBinding(agentContext, { controller: issuerId, vmId: verificationMethod });
97
+ }
98
+ catch {
99
+ // Key binding may already exist
100
+ }
101
+ const signedCredential = await proofService.sign(agentContext, refreshedCredential, {
102
+ id: verificationMethod,
103
+ controller: issuerId,
104
+ });
105
+ // Save the refreshed credential
106
+ const newRecord = new OpenBadgeCredentialRecord_1.OpenBadgeCredentialRecord({
107
+ credential: signedCredential,
108
+ derived: undefined,
109
+ status: 'unknown',
110
+ });
111
+ await repo.save(agentContext, newRecord);
112
+ // Optionally mark old credential as superseded (soft update)
113
+ if (recordId) {
114
+ try {
115
+ const oldRecord = await repo.getById(agentContext, recordId);
116
+ if (oldRecord) {
117
+ oldRecord.status = 'superseded';
118
+ await repo.update(agentContext, oldRecord);
119
+ }
120
+ }
121
+ catch {
122
+ // Ignore update errors
123
+ }
124
+ }
125
+ console.log('[OB][Refresh] Credential refreshed, new record id:', newRecord.id);
126
+ return (0, router_1.sendJson)(res, signedCredential, 200, 'application/vc+ld+json');
127
+ }
128
+ catch (e) {
129
+ console.error('[OB][Refresh] Error:', e?.message || e);
130
+ return (0, router_1.sendError)(res, 500, 'server_error', e?.message || 'Unexpected error');
131
+ }
132
+ });
133
+ }
134
+ //# sourceMappingURL=refresh.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refresh.js","sourceRoot":"","sources":["../../../src/http/endpoints/refresh.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Router } from 'express';
2
+ import type { OpenBadgesHttpModuleConfig } from '../OpenBadgesHttpModuleConfig';
3
+ export declare function configureRegistrationEndpoint(router: Router, config: OpenBadgesHttpModuleConfig): void;
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.configureRegistrationEndpoint = configureRegistrationEndpoint;
4
+ const router_1 = require("../router");
5
+ const OpenBadgesOAuthRepository_1 = require("../../repository/OpenBadgesOAuthRepository");
6
+ const OpenBadgesOAuthRecord_1 = require("../../repository/OpenBadgesOAuthRecord");
7
+ function randomId(prefix = '') {
8
+ return prefix + Math.random().toString(36).slice(2) + Math.random().toString(36).slice(2);
9
+ }
10
+ function configureRegistrationEndpoint(router, config) {
11
+ router.post(config.registrationPath, async (req, res) => {
12
+ const { agentContext } = (0, router_1.getRequestContext)(req);
13
+ const oauthRepo = agentContext.dependencyManager.resolve(OpenBadgesOAuthRepository_1.OpenBadgesOAuthRepository);
14
+ const body = req.body || {};
15
+ if (!body.client_name) {
16
+ return (0, router_1.sendError)(res, 400, 'invalid_client_metadata', 'client_name is required');
17
+ }
18
+ const client_id = randomId('ob_');
19
+ const client_secret = randomId('sec_');
20
+ const registration = {
21
+ client_id,
22
+ client_secret,
23
+ client_id_issued_at: Math.floor(Date.now() / 1000),
24
+ client_secret_expires_at: 0,
25
+ token_endpoint_auth_method: 'client_secret_basic',
26
+ client_name: body.client_name,
27
+ redirect_uris: body.redirect_uris ?? [],
28
+ scope: body.scope ?? '',
29
+ grant_types: body.grant_types ?? ['authorization_code', 'refresh_token'],
30
+ response_types: body.response_types ?? ['code'],
31
+ application_type: body.application_type ?? 'web',
32
+ };
33
+ const rec = new OpenBadgesOAuthRecord_1.OpenBadgesOAuthRecord({
34
+ host: new URL(config.baseUrl).origin,
35
+ clientRegistration: registration,
36
+ tokens: {},
37
+ });
38
+ await oauthRepo.save(agentContext, rec);
39
+ (0, router_1.sendJson)(res, registration, 201);
40
+ });
41
+ }
42
+ //# sourceMappingURL=registration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registration.js","sourceRoot":"","sources":["../../../src/http/endpoints/registration.ts"],"names":[],"mappings":";;AAYA,sEAoCC;AA5CD,sCAAkE;AAClE,0FAAsF;AACtF,kFAA8E;AAE9E,SAAS,QAAQ,CAAC,MAAM,GAAG,EAAE;IAC3B,OAAO,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;AAC3F,CAAC;AAED,SAAgB,6BAA6B,CAAC,MAAc,EAAE,MAAkC;IAC9F,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,gBAAgB,EAAE,KAAK,EAAE,GAAc,EAAE,GAAa,EAAE,EAAE;QAC3E,MAAM,EAAE,YAAY,EAAE,GAAG,IAAA,0BAAiB,EAAC,GAAG,CAAC,CAAA;QAC/C,MAAM,SAAS,GAAG,YAAY,CAAC,iBAAiB,CAAC,OAAO,CAAC,qDAAyB,CAAC,CAAA;QAEnF,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,IAAI,EAAE,CAAA;QAC3B,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACtB,OAAO,IAAA,kBAAS,EAAC,GAAG,EAAE,GAAG,EAAE,yBAAyB,EAAE,yBAAyB,CAAC,CAAA;QAClF,CAAC;QAED,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;QACjC,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAA;QAEtC,MAAM,YAAY,GAAG;YACnB,SAAS;YACT,aAAa;YACb,mBAAmB,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;YAClD,wBAAwB,EAAE,CAAC;YAC3B,0BAA0B,EAAE,qBAAqB;YACjD,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,aAAa,EAAE,IAAI,CAAC,aAAa,IAAI,EAAE;YACvC,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,EAAE;YACvB,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,CAAC,oBAAoB,EAAE,eAAe,CAAC;YACxE,cAAc,EAAE,IAAI,CAAC,cAAc,IAAI,CAAC,MAAM,CAAC;YAC/C,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,IAAI,KAAK;SACjD,CAAA;QAED,MAAM,GAAG,GAAG,IAAI,6CAAqB,CAAC;YACpC,IAAI,EAAE,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM;YACpC,kBAAkB,EAAE,YAAY;YAChC,MAAM,EAAE,EAAE;SACX,CAAC,CAAA;QACF,MAAM,SAAS,CAAC,IAAI,CAAC,YAAY,EAAE,GAAG,CAAC,CAAA;QAEvC,IAAA,iBAAQ,EAAC,GAAG,EAAE,YAAY,EAAE,GAAG,CAAC,CAAA;IAClC,CAAC,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Router } from 'express';
2
+ import type { OpenBadgesHttpModule } from '../OpenBadgesHttpModule';
3
+ export declare function configureRevokeEndpoint(router: Router, module: OpenBadgesHttpModule): void;
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.configureRevokeEndpoint = configureRevokeEndpoint;
4
+ const router_1 = require("../router");
5
+ const OpenBadgesTokenRepository_1 = require("../../repository/OpenBadgesTokenRepository");
6
+ const OpenBadgesOAuthRepository_1 = require("../../repository/OpenBadgesOAuthRepository");
7
+ const auth_1 = require("../util/auth");
8
+ function configureRevokeEndpoint(router, module) {
9
+ router.post(module.config.revokePath, async (req, res) => {
10
+ const { agentContext } = (0, router_1.getRequestContext)(req);
11
+ // Client auth required
12
+ const basic = (0, auth_1.parseBasicAuth)(req) ?? (0, auth_1.parseBodyClientAuth)(req);
13
+ if (!basic)
14
+ return (0, router_1.sendError)(res, 401, 'invalid_client', 'Client authentication required');
15
+ const oauthRepo = agentContext.dependencyManager.resolve(OpenBadgesOAuthRepository_1.OpenBadgesOAuthRepository);
16
+ const clientRec = await oauthRepo.findByClientId(agentContext, basic.clientId);
17
+ const reg = clientRec?.clientRegistration || {};
18
+ if (!clientRec || reg.client_secret !== basic.clientSecret)
19
+ return (0, router_1.sendError)(res, 401, 'invalid_client', 'Invalid client credentials');
20
+ const token = String(req.body?.token ?? '');
21
+ if (!token)
22
+ return (0, router_1.sendError)(res, 400, 'invalid_request', 'token is required');
23
+ const tokenRepo = agentContext.dependencyManager.resolve(OpenBadgesTokenRepository_1.OpenBadgesTokenRepository);
24
+ const tokenRec = await tokenRepo.findByToken(agentContext, token);
25
+ if (tokenRec) {
26
+ if (tokenRec.clientId !== basic.clientId)
27
+ return (0, router_1.sendError)(res, 400, 'invalid_request', 'client mismatch');
28
+ // delete all tokens in the pair
29
+ const pair = await tokenRepo.findByPairId(agentContext, tokenRec.pairId);
30
+ for (const t of pair) {
31
+ await tokenRepo.deleteById(agentContext, t.id);
32
+ }
33
+ }
34
+ // Per RFC7009, successful revocation returns 200 even if token was unknown
35
+ return (0, router_1.sendJson)(res, { revoked: true });
36
+ });
37
+ }
38
+ //# sourceMappingURL=revoke.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"revoke.js","sourceRoot":"","sources":["../../../src/http/endpoints/revoke.ts"],"names":[],"mappings":";;AASA,0DA4BC;AAjCD,sCAAkE;AAClE,0FAAsF;AACtF,0FAAsF;AACtF,uCAAkE;AAElE,SAAgB,uBAAuB,CAAC,MAAc,EAAE,MAA4B;IAClF,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,KAAK,EAAE,GAAc,EAAE,GAAa,EAAE,EAAE;QAC5E,MAAM,EAAE,YAAY,EAAE,GAAG,IAAA,0BAAiB,EAAC,GAAG,CAAC,CAAA;QAC/C,uBAAuB;QACvB,MAAM,KAAK,GAAG,IAAA,qBAAc,EAAC,GAAG,CAAC,IAAI,IAAA,0BAAmB,EAAC,GAAG,CAAC,CAAA;QAC7D,IAAI,CAAC,KAAK;YAAE,OAAO,IAAA,kBAAS,EAAC,GAAG,EAAE,GAAG,EAAE,gBAAgB,EAAE,gCAAgC,CAAC,CAAA;QAC1F,MAAM,SAAS,GAAG,YAAY,CAAC,iBAAiB,CAAC,OAAO,CAAC,qDAAyB,CAAC,CAAA;QACnF,MAAM,SAAS,GAAG,MAAM,SAAS,CAAC,cAAc,CAAC,YAAY,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAA;QAC9E,MAAM,GAAG,GAAI,SAAS,EAAE,kBAA0B,IAAI,EAAE,CAAA;QACxD,IAAI,CAAC,SAAS,IAAI,GAAG,CAAC,aAAa,KAAK,KAAK,CAAC,YAAY;YACxD,OAAO,IAAA,kBAAS,EAAC,GAAG,EAAE,GAAG,EAAE,gBAAgB,EAAE,4BAA4B,CAAC,CAAA;QAE5E,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAA;QAC3C,IAAI,CAAC,KAAK;YAAE,OAAO,IAAA,kBAAS,EAAC,GAAG,EAAE,GAAG,EAAE,iBAAiB,EAAE,mBAAmB,CAAC,CAAA;QAE9E,MAAM,SAAS,GAAG,YAAY,CAAC,iBAAiB,CAAC,OAAO,CAAC,qDAAyB,CAAC,CAAA;QACnF,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,WAAW,CAAC,YAAY,EAAE,KAAK,CAAC,CAAA;QACjE,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,QAAQ,CAAC,QAAQ,KAAK,KAAK,CAAC,QAAQ;gBAAE,OAAO,IAAA,kBAAS,EAAC,GAAG,EAAE,GAAG,EAAE,iBAAiB,EAAE,iBAAiB,CAAC,CAAA;YAC1G,gCAAgC;YAChC,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAA;YACxE,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;gBACrB,MAAM,SAAS,CAAC,UAAU,CAAC,YAAY,EAAE,CAAC,CAAC,EAAE,CAAC,CAAA;YAChD,CAAC;QACH,CAAC;QACD,2EAA2E;QAC3E,OAAO,IAAA,iBAAQ,EAAC,GAAG,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;IACzC,CAAC,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Router } from 'express';
2
+ import type { OpenBadgesHttpModuleConfig } from '../OpenBadgesHttpModuleConfig';
3
+ export declare function configureServiceDescriptionEndpoint(router: Router, config: OpenBadgesHttpModuleConfig): void;
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.configureServiceDescriptionEndpoint = configureServiceDescriptionEndpoint;
4
+ const router_1 = require("../router");
5
+ function configureServiceDescriptionEndpoint(router, config) {
6
+ router.get(config.discoveryPath, async (req, res) => {
7
+ const { agentContext } = (0, router_1.getRequestContext)(req);
8
+ const base = new URL(config.baseUrl);
9
+ const authUrl = new URL(config.authorizePath, config.baseUrl).toString();
10
+ const tokenUrl = new URL(config.tokenPath, config.baseUrl).toString();
11
+ const registrationUrl = new URL(config.registrationPath, config.baseUrl).toString();
12
+ const response = {
13
+ openapi: '3.0.0',
14
+ info: {
15
+ title: 'Open Badges 3.0 / CLR 2.0 API',
16
+ version: '1.0.0',
17
+ },
18
+ servers: [{ url: `${base.origin}` }],
19
+ components: {
20
+ securitySchemes: {
21
+ OAuth2ACG: {
22
+ type: 'oauth2',
23
+ description: 'OAuth 2.0 Authorization Code Grant authorization',
24
+ 'x-imssf-name': config.providerName ?? agentContext.config.label ?? 'Provider',
25
+ 'x-imssf-privacyPolicyUrl': config.privacyPolicyUrl,
26
+ 'x-imssf-termsOfServiceUrl': config.termsOfServiceUrl,
27
+ 'x-imssf-registrationUrl': registrationUrl,
28
+ 'x-oauth-revocationUrl': new URL(config.revokePath, config.baseUrl).toString(),
29
+ 'x-oauth-introspectionUrl': new URL(config.introspectPath, config.baseUrl).toString(),
30
+ 'x-oauth-jwksUrl': new URL(config.jwksPath, config.baseUrl).toString(),
31
+ flows: {
32
+ authorizationCode: {
33
+ authorizationUrl: authUrl,
34
+ tokenUrl: tokenUrl,
35
+ refreshUrl: tokenUrl,
36
+ scopes: {
37
+ 'https://purl.imsglobal.org/spec/ob/v3p0/scope/readonly': 'Read-only access to credentials and profile',
38
+ 'https://purl.imsglobal.org/spec/ob/v3p0/scope/replace': 'Write/update access to credentials and profile',
39
+ 'https://purl.imsglobal.org/spec/ob/v3p0/scope/delete': 'Delete access to credentials and profile',
40
+ 'https://purl.imsglobal.org/spec/clr/v2p0/scope/readonly': 'Read-only CLR scope',
41
+ 'https://purl.imsglobal.org/spec/clr/v2p0/scope/replace': 'Write/replace CLR scope',
42
+ },
43
+ },
44
+ },
45
+ },
46
+ },
47
+ },
48
+ };
49
+ (0, router_1.sendJson)(res, response);
50
+ });
51
+ }
52
+ //# sourceMappingURL=serviceDescription.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serviceDescription.js","sourceRoot":"","sources":["../../../src/http/endpoints/serviceDescription.ts"],"names":[],"mappings":";;AAMA,kFAiDC;AAnDD,sCAAuD;AAEvD,SAAgB,mCAAmC,CAAC,MAAc,EAAE,MAAkC;IACpG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,aAAa,EAAE,KAAK,EAAE,GAAc,EAAE,GAAa,EAAE,EAAE;QACvE,MAAM,EAAE,YAAY,EAAE,GAAG,IAAA,0BAAiB,EAAC,GAAG,CAAC,CAAA;QAE/C,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;QACpC,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAA;QACxE,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAA;QACrE,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAA;QAEnF,MAAM,QAAQ,GAAG;YACf,OAAO,EAAE,OAAO;YAChB,IAAI,EAAE;gBACJ,KAAK,EAAE,+BAA+B;gBACtC,OAAO,EAAE,OAAO;aACjB;YACD,OAAO,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;YACpC,UAAU,EAAE;gBACV,eAAe,EAAE;oBACf,SAAS,EAAE;wBACT,IAAI,EAAE,QAAQ;wBACd,WAAW,EAAE,kDAAkD;wBAC/D,cAAc,EAAE,MAAM,CAAC,YAAY,IAAI,YAAY,CAAC,MAAM,CAAC,KAAK,IAAI,UAAU;wBAC9E,0BAA0B,EAAE,MAAM,CAAC,gBAAgB;wBACnD,2BAA2B,EAAE,MAAM,CAAC,iBAAiB;wBACrD,yBAAyB,EAAE,eAAe;wBAC1C,uBAAuB,EAAE,IAAI,GAAG,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE;wBAC9E,0BAA0B,EAAE,IAAI,GAAG,CAAC,MAAM,CAAC,cAAc,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE;wBACrF,iBAAiB,EAAE,IAAI,GAAG,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE;wBACtE,KAAK,EAAE;4BACL,iBAAiB,EAAE;gCACjB,gBAAgB,EAAE,OAAO;gCACzB,QAAQ,EAAE,QAAQ;gCAClB,UAAU,EAAE,QAAQ;gCACpB,MAAM,EAAE;oCACN,wDAAwD,EAAE,6CAA6C;oCACvG,uDAAuD,EAAE,gDAAgD;oCACzG,sDAAsD,EAAE,0CAA0C;oCAClG,yDAAyD,EAAE,qBAAqB;oCAChF,wDAAwD,EAAE,yBAAyB;iCACpF;6BACF;yBACF;qBACF;iBACF;aACF;SACF,CAAA;QAED,IAAA,iBAAQ,EAAC,GAAG,EAAE,QAAQ,CAAC,CAAA;IACzB,CAAC,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { Router } from 'express';
2
+ import type { OpenBadgesHttpModuleConfig } from '../OpenBadgesHttpModuleConfig';
3
+ import type { OpenBadgesHttpModule } from '../OpenBadgesHttpModule';
4
+ /**
5
+ * Configure the StatusList2021 endpoint
6
+ *
7
+ * GET /status-list/:id - Returns a signed StatusList2021Credential
8
+ * POST /status-list/:id/status - Update status for a credential index (issuer only)
9
+ */
10
+ export declare function configureStatusListEndpoint(router: Router, config: OpenBadgesHttpModuleConfig, _module: OpenBadgesHttpModule): void;
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.configureStatusListEndpoint = configureStatusListEndpoint;
4
+ const router_1 = require("../router");
5
+ const RevocationService_1 = require("../../services/RevocationService");
6
+ const ProofService_1 = require("../../services/ProofService");
7
+ /**
8
+ * Configure the StatusList2021 endpoint
9
+ *
10
+ * GET /status-list/:id - Returns a signed StatusList2021Credential
11
+ * POST /status-list/:id/status - Update status for a credential index (issuer only)
12
+ */
13
+ function configureStatusListEndpoint(router, config, _module) {
14
+ const basePath = config.statusListPath;
15
+ // GET /status-list/:id - Return signed StatusList2021Credential
16
+ router.get(`${basePath}/:id`, async (req, res) => {
17
+ try {
18
+ const { agentContext } = (0, router_1.getRequestContext)(req);
19
+ const listId = String(req.params.id);
20
+ const revocationService = agentContext.dependencyManager.resolve(RevocationService_1.RevocationService);
21
+ const proofService = agentContext.dependencyManager.resolve(ProofService_1.ProofService);
22
+ // Get the status list record
23
+ const record = await revocationService.getStatusList(agentContext, listId);
24
+ if (!record) {
25
+ return (0, router_1.sendError)(res, 404, 'not_found', `Status list not found: ${listId}`);
26
+ }
27
+ // Build the unsigned StatusList2021Credential
28
+ const unsignedCredential = revocationService.buildStatusListCredential(record);
29
+ // Sign the credential
30
+ const verificationMethod = `${record.issuerDid}#key-1`;
31
+ const signedCredential = await proofService.sign(agentContext, unsignedCredential, {
32
+ id: verificationMethod,
33
+ controller: record.issuerDid,
34
+ });
35
+ // Return with proper content type
36
+ return (0, router_1.sendJson)(res, signedCredential, 200, 'application/vc+ld+json');
37
+ }
38
+ catch (e) {
39
+ console.error('[OB][StatusList] GET error:', e?.message || e);
40
+ return (0, router_1.sendError)(res, 500, 'server_error', e?.message || 'Unexpected error');
41
+ }
42
+ });
43
+ // POST /status-list/:id/status - Update status for an index (issuer operation)
44
+ router.post(`${basePath}/:id/status`, async (req, res) => {
45
+ try {
46
+ const { agentContext } = (0, router_1.getRequestContext)(req);
47
+ const listId = String(req.params.id);
48
+ const { index, status } = req.body;
49
+ if (typeof index !== 'number' || typeof status !== 'boolean') {
50
+ return (0, router_1.sendError)(res, 400, 'invalid_request', 'Missing required fields: index (number), status (boolean)');
51
+ }
52
+ const revocationService = agentContext.dependencyManager.resolve(RevocationService_1.RevocationService);
53
+ // Update the status
54
+ await revocationService.setStatus(agentContext, { listId, index, status });
55
+ return (0, router_1.sendJson)(res, { success: true, listId, index, status: status ? 'revoked' : 'active' });
56
+ }
57
+ catch (e) {
58
+ console.error('[OB][StatusList] POST error:', e?.message || e);
59
+ if (e?.message?.includes('not found')) {
60
+ return (0, router_1.sendError)(res, 404, 'not_found', e.message);
61
+ }
62
+ return (0, router_1.sendError)(res, 500, 'server_error', e?.message || 'Unexpected error');
63
+ }
64
+ });
65
+ // POST /status-list - Create a new status list
66
+ router.post(basePath, async (req, res) => {
67
+ try {
68
+ const { agentContext } = (0, router_1.getRequestContext)(req);
69
+ const { listId, issuerDid, purpose, capacity } = req.body;
70
+ if (!listId || !issuerDid) {
71
+ return (0, router_1.sendError)(res, 400, 'invalid_request', 'Missing required fields: listId, issuerDid');
72
+ }
73
+ const revocationService = agentContext.dependencyManager.resolve(RevocationService_1.RevocationService);
74
+ const record = await revocationService.createStatusList(agentContext, {
75
+ listId,
76
+ issuerDid,
77
+ purpose: purpose || 'revocation',
78
+ capacity,
79
+ baseUrl: config.baseUrl,
80
+ });
81
+ return (0, router_1.sendJson)(res, {
82
+ success: true,
83
+ listId: record.listId,
84
+ purpose: record.purpose,
85
+ capacity: record.capacity,
86
+ statusListCredentialUrl: `${config.baseUrl}${basePath}/${listId}`,
87
+ }, 201);
88
+ }
89
+ catch (e) {
90
+ console.error('[OB][StatusList] POST create error:', e?.message || e);
91
+ return (0, router_1.sendError)(res, 500, 'server_error', e?.message || 'Unexpected error');
92
+ }
93
+ });
94
+ }
95
+ //# sourceMappingURL=statusList.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"statusList.js","sourceRoot":"","sources":["../../../src/http/endpoints/statusList.ts"],"names":[],"mappings":";;AAeA,kEAuGC;AAjHD,sCAAkE;AAClE,wEAAoE;AACpE,8DAA0D;AAE1D;;;;;GAKG;AACH,SAAgB,2BAA2B,CACzC,MAAc,EACd,MAAkC,EAClC,OAA6B;IAE7B,MAAM,QAAQ,GAAG,MAAM,CAAC,cAAc,CAAA;IAEtC,gEAAgE;IAChE,MAAM,CAAC,GAAG,CAAC,GAAG,QAAQ,MAAM,EAAE,KAAK,EAAE,GAAc,EAAE,GAAa,EAAE,EAAE;QACpE,IAAI,CAAC;YACH,MAAM,EAAE,YAAY,EAAE,GAAG,IAAA,0BAAiB,EAAC,GAAG,CAAC,CAAA;YAC/C,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;YAEpC,MAAM,iBAAiB,GAAG,YAAY,CAAC,iBAAiB,CAAC,OAAO,CAAC,qCAAiB,CAAC,CAAA;YACnF,MAAM,YAAY,GAAG,YAAY,CAAC,iBAAiB,CAAC,OAAO,CAAC,2BAAY,CAAC,CAAA;YAEzE,6BAA6B;YAC7B,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,aAAa,CAAC,YAAY,EAAE,MAAM,CAAC,CAAA;YAC1E,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,OAAO,IAAA,kBAAS,EAAC,GAAG,EAAE,GAAG,EAAE,WAAW,EAAE,0BAA0B,MAAM,EAAE,CAAC,CAAA;YAC7E,CAAC;YAED,8CAA8C;YAC9C,MAAM,kBAAkB,GAAG,iBAAiB,CAAC,yBAAyB,CAAC,MAAM,CAAC,CAAA;YAE9E,sBAAsB;YACtB,MAAM,kBAAkB,GAAG,GAAG,MAAM,CAAC,SAAS,QAAQ,CAAA;YACtD,MAAM,gBAAgB,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,YAAY,EAAE,kBAAkB,EAAE;gBACjF,EAAE,EAAE,kBAAkB;gBACtB,UAAU,EAAE,MAAM,CAAC,SAAS;aAC7B,CAAC,CAAA;YAEF,kCAAkC;YAClC,OAAO,IAAA,iBAAQ,EAAC,GAAG,EAAE,gBAAgB,EAAE,GAAG,EAAE,wBAAwB,CAAC,CAAA;QACvE,CAAC;QAAC,OAAO,CAAM,EAAE,CAAC;YAChB,OAAO,CAAC,KAAK,CAAC,6BAA6B,EAAE,CAAC,EAAE,OAAO,IAAI,CAAC,CAAC,CAAA;YAC7D,OAAO,IAAA,kBAAS,EAAC,GAAG,EAAE,GAAG,EAAE,cAAc,EAAE,CAAC,EAAE,OAAO,IAAI,kBAAkB,CAAC,CAAA;QAC9E,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,+EAA+E;IAC/E,MAAM,CAAC,IAAI,CAAC,GAAG,QAAQ,aAAa,EAAE,KAAK,EAAE,GAAc,EAAE,GAAa,EAAE,EAAE;QAC5E,IAAI,CAAC;YACH,MAAM,EAAE,YAAY,EAAE,GAAG,IAAA,0BAAiB,EAAC,GAAG,CAAC,CAAA;YAC/C,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;YACpC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,IAA4C,CAAA;YAE1E,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,MAAM,KAAK,SAAS,EAAE,CAAC;gBAC7D,OAAO,IAAA,kBAAS,EAAC,GAAG,EAAE,GAAG,EAAE,iBAAiB,EAAE,2DAA2D,CAAC,CAAA;YAC5G,CAAC;YAED,MAAM,iBAAiB,GAAG,YAAY,CAAC,iBAAiB,CAAC,OAAO,CAAC,qCAAiB,CAAC,CAAA;YAEnF,oBAAoB;YACpB,MAAM,iBAAiB,CAAC,SAAS,CAAC,YAAY,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;YAE1E,OAAO,IAAA,iBAAQ,EAAC,GAAG,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAA;QAC/F,CAAC;QAAC,OAAO,CAAM,EAAE,CAAC;YAChB,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,CAAC,EAAE,OAAO,IAAI,CAAC,CAAC,CAAA;YAC9D,IAAI,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;gBACtC,OAAO,IAAA,kBAAS,EAAC,GAAG,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,CAAA;YACpD,CAAC;YACD,OAAO,IAAA,kBAAS,EAAC,GAAG,EAAE,GAAG,EAAE,cAAc,EAAE,CAAC,EAAE,OAAO,IAAI,kBAAkB,CAAC,CAAA;QAC9E,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,+CAA+C;IAC/C,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,GAAc,EAAE,GAAa,EAAE,EAAE;QAC5D,IAAI,CAAC;YACH,MAAM,EAAE,YAAY,EAAE,GAAG,IAAA,0BAAiB,EAAC,GAAG,CAAC,CAAA;YAC/C,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,GAAG,CAAC,IAKpD,CAAA;YAED,IAAI,CAAC,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;gBAC1B,OAAO,IAAA,kBAAS,EAAC,GAAG,EAAE,GAAG,EAAE,iBAAiB,EAAE,4CAA4C,CAAC,CAAA;YAC7F,CAAC;YAED,MAAM,iBAAiB,GAAG,YAAY,CAAC,iBAAiB,CAAC,OAAO,CAAC,qCAAiB,CAAC,CAAA;YAEnF,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,gBAAgB,CAAC,YAAY,EAAE;gBACpE,MAAM;gBACN,SAAS;gBACT,OAAO,EAAE,OAAO,IAAI,YAAY;gBAChC,QAAQ;gBACR,OAAO,EAAE,MAAM,CAAC,OAAO;aACxB,CAAC,CAAA;YAEF,OAAO,IAAA,iBAAQ,EAAC,GAAG,EAAE;gBACnB,OAAO,EAAE,IAAI;gBACb,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,uBAAuB,EAAE,GAAG,MAAM,CAAC,OAAO,GAAG,QAAQ,IAAI,MAAM,EAAE;aAClE,EAAE,GAAG,CAAC,CAAA;QACT,CAAC;QAAC,OAAO,CAAM,EAAE,CAAC;YAChB,OAAO,CAAC,KAAK,CAAC,qCAAqC,EAAE,CAAC,EAAE,OAAO,IAAI,CAAC,CAAC,CAAA;YACrE,OAAO,IAAA,kBAAS,EAAC,GAAG,EAAE,GAAG,EAAE,cAAc,EAAE,CAAC,EAAE,OAAO,IAAI,kBAAkB,CAAC,CAAA;QAC9E,CAAC;IACH,CAAC,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Router } from 'express';
2
+ import type { OpenBadgesHttpModule } from '../OpenBadgesHttpModule';
3
+ export declare function configureTokenEndpoint(router: Router, module: OpenBadgesHttpModule): void;
@@ -0,0 +1,147 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.configureTokenEndpoint = configureTokenEndpoint;
4
+ const router_1 = require("../router");
5
+ const OpenBadgesAuthCodeRepository_1 = require("../../repository/OpenBadgesAuthCodeRepository");
6
+ const OpenBadgesTokenRepository_1 = require("../../repository/OpenBadgesTokenRepository");
7
+ const OpenBadgesTokenRecord_1 = require("../../repository/OpenBadgesTokenRecord");
8
+ const OpenBadgesOAuthRepository_1 = require("../../repository/OpenBadgesOAuthRepository");
9
+ const auth_1 = require("../util/auth");
10
+ function randomToken(prefix = '') {
11
+ return prefix + Math.random().toString(36).slice(2) + Math.random().toString(36).slice(2);
12
+ }
13
+ function configureTokenEndpoint(router, module) {
14
+ router.post(module.config.tokenPath, async (req, res) => {
15
+ const { agentContext } = (0, router_1.getRequestContext)(req);
16
+ const grant_type = String(req.body?.grant_type ?? '');
17
+ if (grant_type === 'authorization_code') {
18
+ // Client auth
19
+ const basic = (0, auth_1.parseBasicAuth)(req) ?? (0, auth_1.parseBodyClientAuth)(req);
20
+ if (!basic)
21
+ return (0, router_1.sendError)(res, 401, 'invalid_client', 'Client authentication required');
22
+ const oauthRepo = agentContext.dependencyManager.resolve(OpenBadgesOAuthRepository_1.OpenBadgesOAuthRepository);
23
+ const clientRec = await oauthRepo.findByClientId(agentContext, basic.clientId);
24
+ const reg = clientRec?.clientRegistration || {};
25
+ if (!clientRec || reg.client_secret !== basic.clientSecret)
26
+ return (0, router_1.sendError)(res, 401, 'invalid_client', 'Invalid client credentials');
27
+ const code = String(req.body?.code ?? '');
28
+ const redirect_uri = String(req.body?.redirect_uri ?? '');
29
+ const code_verifier = req.body?.code_verifier ? String(req.body.code_verifier) : undefined;
30
+ if (!code || !redirect_uri)
31
+ return (0, router_1.sendError)(res, 400, 'invalid_request', 'code and redirect_uri required');
32
+ const codeRepo = agentContext.dependencyManager.resolve(OpenBadgesAuthCodeRepository_1.OpenBadgesAuthCodeRepository);
33
+ const entry = await codeRepo.findByCode(agentContext, code);
34
+ if (!entry || entry.expiresAt.getTime() < Date.now())
35
+ return (0, router_1.sendError)(res, 400, 'invalid_grant', 'Invalid or expired code');
36
+ if (entry.redirectUri !== redirect_uri)
37
+ return (0, router_1.sendError)(res, 400, 'invalid_grant', 'redirect_uri mismatch');
38
+ if (entry.clientId !== basic.clientId)
39
+ return (0, router_1.sendError)(res, 400, 'invalid_grant', 'client mismatch');
40
+ // PKCE check when a code_challenge was provided
41
+ if (entry.codeChallenge) {
42
+ if (!code_verifier)
43
+ return (0, router_1.sendError)(res, 400, 'invalid_request', 'code_verifier required');
44
+ const { createHash } = require('crypto');
45
+ const b64url = (buf) => buf
46
+ .toString('base64')
47
+ .replace(/=/g, '')
48
+ .replace(/\+/g, '-')
49
+ .replace(/\//g, '_');
50
+ if (entry.codeChallengeMethod === 'S256') {
51
+ const expected = b64url(createHash('sha256').update(code_verifier).digest());
52
+ if (expected !== entry.codeChallenge)
53
+ return (0, router_1.sendError)(res, 400, 'invalid_grant', 'PKCE verification failed');
54
+ }
55
+ else {
56
+ // plain
57
+ if (code_verifier !== entry.codeChallenge)
58
+ return (0, router_1.sendError)(res, 400, 'invalid_grant', 'PKCE verification failed');
59
+ }
60
+ }
61
+ const accessToken = randomToken('at_');
62
+ const refreshToken = randomToken('rt_');
63
+ const expiresIn = 3 * 60;
64
+ const pairId = randomToken('pair_');
65
+ const tokenRepo = agentContext.dependencyManager.resolve(OpenBadgesTokenRepository_1.OpenBadgesTokenRepository);
66
+ await tokenRepo.save(agentContext, new OpenBadgesTokenRecord_1.OpenBadgesTokenRecord({
67
+ token: accessToken,
68
+ tokenType: 'access',
69
+ clientId: entry.clientId,
70
+ subject: entry.subject,
71
+ scope: entry.scope,
72
+ expiresAt: new Date(Date.now() + expiresIn * 1000),
73
+ pairId,
74
+ host: new URL(module.config.baseUrl).origin,
75
+ }));
76
+ await tokenRepo.save(agentContext, new OpenBadgesTokenRecord_1.OpenBadgesTokenRecord({
77
+ token: refreshToken,
78
+ tokenType: 'refresh',
79
+ clientId: entry.clientId,
80
+ subject: entry.subject,
81
+ scope: entry.scope,
82
+ expiresAt: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000),
83
+ pairId,
84
+ host: new URL(module.config.baseUrl).origin,
85
+ }));
86
+ await codeRepo.deleteById(agentContext, entry.id);
87
+ return (0, router_1.sendJson)(res, {
88
+ access_token: accessToken,
89
+ token_type: 'Bearer',
90
+ expires_in: expiresIn,
91
+ refresh_token: refreshToken,
92
+ scope: entry.scope,
93
+ });
94
+ }
95
+ if (grant_type === 'refresh_token') {
96
+ const basic = (0, auth_1.parseBasicAuth)(req) ?? (0, auth_1.parseBodyClientAuth)(req);
97
+ if (!basic)
98
+ return (0, router_1.sendError)(res, 401, 'invalid_client', 'Client authentication required');
99
+ const oauthRepo = agentContext.dependencyManager.resolve(OpenBadgesOAuthRepository_1.OpenBadgesOAuthRepository);
100
+ const clientRec = await oauthRepo.findByClientId(agentContext, basic.clientId);
101
+ const reg = clientRec?.clientRegistration || {};
102
+ if (!clientRec || reg.client_secret !== basic.clientSecret)
103
+ return (0, router_1.sendError)(res, 401, 'invalid_client', 'Invalid client credentials');
104
+ const refresh_token = String(req.body?.refresh_token ?? '');
105
+ const tokenRepo = agentContext.dependencyManager.resolve(OpenBadgesTokenRepository_1.OpenBadgesTokenRepository);
106
+ const stored = await tokenRepo.findByToken(agentContext, refresh_token);
107
+ if (!stored || stored.tokenType !== 'refresh' || stored.expiresAt.getTime() < Date.now())
108
+ return (0, router_1.sendError)(res, 400, 'invalid_grant', 'Invalid or expired refresh token');
109
+ if (stored.clientId !== basic.clientId)
110
+ return (0, router_1.sendError)(res, 400, 'invalid_grant', 'client mismatch');
111
+ const accessToken = randomToken('at_');
112
+ const newRefreshToken = randomToken('rt_');
113
+ const expiresIn = 3 * 60;
114
+ await tokenRepo.save(agentContext, new OpenBadgesTokenRecord_1.OpenBadgesTokenRecord({
115
+ token: accessToken,
116
+ tokenType: 'access',
117
+ clientId: stored.clientId,
118
+ subject: stored.subject,
119
+ scope: stored.scope,
120
+ expiresAt: new Date(Date.now() + expiresIn * 1000),
121
+ pairId: stored.pairId,
122
+ host: stored.host,
123
+ }));
124
+ // Rotate refresh token: delete old, create new one
125
+ await tokenRepo.deleteById(agentContext, stored.id);
126
+ await tokenRepo.save(agentContext, new OpenBadgesTokenRecord_1.OpenBadgesTokenRecord({
127
+ token: newRefreshToken,
128
+ tokenType: 'refresh',
129
+ clientId: stored.clientId,
130
+ subject: stored.subject,
131
+ scope: stored.scope,
132
+ expiresAt: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000),
133
+ pairId: stored.pairId,
134
+ host: stored.host,
135
+ }));
136
+ return (0, router_1.sendJson)(res, {
137
+ access_token: accessToken,
138
+ token_type: 'Bearer',
139
+ expires_in: expiresIn,
140
+ refresh_token: newRefreshToken,
141
+ scope: stored.scope,
142
+ });
143
+ }
144
+ return (0, router_1.sendError)(res, 400, 'unsupported_grant_type', 'Only authorization_code and refresh_token supported');
145
+ });
146
+ }
147
+ //# sourceMappingURL=token.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token.js","sourceRoot":"","sources":["../../../src/http/endpoints/token.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { NextFunction, Response } from 'express';
2
+ import type { ObRequest } from '../router';
3
+ import type { OpenBadgesHttpModule } from '../OpenBadgesHttpModule';
4
+ export declare function bearerAuth(module: OpenBadgesHttpModule): (req: ObRequest, res: Response, next: NextFunction) => Promise<void>;
5
+ export declare function requireScopes(required: string[]): (req: ObRequest, res: Response, next: NextFunction) => void;