@muze-nl/metro-oidc 0.1.5 → 0.3.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.
package/dist/browser.js CHANGED
@@ -107,12 +107,7 @@
107
107
  }
108
108
  const metrofetch = async function browserFetch(req2) {
109
109
  if (req2[Symbol.metroProxy]) {
110
- if (req2.body && req2.body[Symbol.metroSource]) {
111
- let body = req2.body[Symbol.metroSource];
112
- req2 = new Request(req2[Symbol.metroSource], { body });
113
- } else {
114
- req2 = req2[Symbol.metroSource];
115
- }
110
+ req2 = req2[Symbol.metroSource];
116
111
  }
117
112
  const res = await fetch(req2);
118
113
  return response(res);
@@ -149,103 +144,6 @@
149
144
  function client(...options) {
150
145
  return new Client(...options);
151
146
  }
152
- function bodyProxy(body, r) {
153
- let source = r.body;
154
- if (!source) {
155
- if (body === null) {
156
- source = new ReadableStream();
157
- } else if (body instanceof ReadableStream) {
158
- source = body;
159
- } else if (body instanceof Blob) {
160
- source = body.stream();
161
- } else {
162
- source = new ReadableStream({
163
- start(controller) {
164
- let chunk;
165
- switch (typeof body) {
166
- case "object":
167
- if (typeof body.toString == "function") {
168
- chunk = body.toString();
169
- } else if (body instanceof FormData) {
170
- chunk = new URLSearchParams(body).toString();
171
- } else if (body instanceof ArrayBuffer || ArrayBuffer.isView(body)) {
172
- chunk = body;
173
- } else {
174
- throw metroError("Cannot convert body to ReadableStream", body);
175
- }
176
- break;
177
- case "string":
178
- case "number":
179
- case "boolean":
180
- chunk = body;
181
- break;
182
- default:
183
- throw metroError("Cannot convert body to ReadableStream", body);
184
- break;
185
- }
186
- controller.enqueue(chunk);
187
- controller.close();
188
- }
189
- });
190
- }
191
- }
192
- return new Proxy(source, {
193
- get(target, prop, receiver) {
194
- switch (prop) {
195
- case Symbol.metroProxy:
196
- return true;
197
- break;
198
- case Symbol.metroSource:
199
- return body;
200
- break;
201
- case "toString":
202
- return function() {
203
- return "" + body;
204
- };
205
- break;
206
- }
207
- if (body && typeof body == "object") {
208
- if (prop in body) {
209
- if (typeof body[prop] == "function") {
210
- return function(...args) {
211
- return body[prop].apply(body, args);
212
- };
213
- }
214
- return body[prop];
215
- }
216
- }
217
- if (prop in target && prop != "toString") {
218
- if (typeof target[prop] == "function") {
219
- return function(...args) {
220
- return target[prop].apply(target, args);
221
- };
222
- }
223
- return target[prop];
224
- }
225
- },
226
- has(target, prop) {
227
- if (body && typeof body == "object") {
228
- return prop in body;
229
- } else {
230
- return prop in target;
231
- }
232
- },
233
- ownKeys(target) {
234
- if (body && typeof body == "object") {
235
- return Reflect.ownKeys(body);
236
- } else {
237
- return Reflect.ownKeys(target);
238
- }
239
- },
240
- getOwnPropertyDescriptor(target, prop) {
241
- if (body && typeof body == "object") {
242
- return Object.getOwnPropertyDescriptor(body, prop);
243
- } else {
244
- return Object.getOwnPropertyDescriptor(target, prop);
245
- }
246
- }
247
- });
248
- }
249
147
  function getRequestParams(req, current) {
250
148
  let params2 = current || {};
251
149
  if (!params2.url && current.url) {
@@ -275,7 +173,7 @@
275
173
  value = value[Symbol.metroSource];
276
174
  }
277
175
  if (typeof value == "function") {
278
- value(params2[prop], params2);
176
+ params2[prop] = value(params2[prop], params2);
279
177
  } else {
280
178
  if (prop == "url") {
281
179
  params2.url = url(params2.url, value);
@@ -292,6 +190,9 @@
292
190
  }
293
191
  }
294
192
  }
193
+ if (req instanceof Request && req.data) {
194
+ params2.body = req.data;
195
+ }
295
196
  return params2;
296
197
  }
297
198
  function request(...options) {
@@ -309,10 +210,10 @@
309
210
  Object.assign(requestParams, getRequestParams(option, requestParams));
310
211
  }
311
212
  }
312
- let body = requestParams.body;
313
- if (body) {
314
- if (typeof body == "object" && !(body instanceof String) && !(body instanceof ReadableStream) && !(body instanceof Blob) && !(body instanceof ArrayBuffer) && !(body instanceof DataView) && !(body instanceof FormData) && !(body instanceof URLSearchParams) && (typeof TypedArray == "undefined" || !(body instanceof TypedArray))) {
315
- requestParams.body = JSON.stringify(body);
213
+ let data = requestParams.body;
214
+ if (data) {
215
+ if (typeof data == "object" && !(data instanceof String) && !(data instanceof ReadableStream) && !(data instanceof Blob) && !(data instanceof ArrayBuffer) && !(data instanceof DataView) && !(data instanceof FormData) && !(data instanceof URLSearchParams) && (typeof TypedArray == "undefined" || !(data instanceof TypedArray))) {
216
+ requestParams.body = JSON.stringify(data);
316
217
  }
317
218
  }
318
219
  let r = new Request(requestParams.url, requestParams);
@@ -328,25 +229,21 @@
328
229
  break;
329
230
  case "with":
330
231
  return function(...options2) {
331
- if (body) {
332
- options2.unshift({ body });
232
+ if (data) {
233
+ options2.unshift({ body: data });
333
234
  }
334
235
  return request(target, ...options2);
335
236
  };
336
237
  break;
337
238
  case "body":
338
- if (!body) {
339
- body = target.body;
340
- }
341
- if (body) {
342
- if (body[Symbol.metroProxy]) {
343
- return body;
344
- }
345
- return bodyProxy(body, target);
346
- }
239
+ break;
240
+ case "data":
241
+ return data;
347
242
  break;
348
243
  }
349
244
  if (target[prop] instanceof Function) {
245
+ if (prop === "clone") {
246
+ }
350
247
  return target[prop].bind(target);
351
248
  }
352
249
  return target[prop];
@@ -367,7 +264,7 @@
367
264
  value = value[Symbol.metroSource];
368
265
  }
369
266
  if (typeof value == "function") {
370
- value(params2[prop], params2);
267
+ params2[prop] = value(params2[prop], params2);
371
268
  } else {
372
269
  if (prop == "url") {
373
270
  params2.url = new URL(value, params2.url || "https://localhost/");
@@ -376,6 +273,9 @@
376
273
  }
377
274
  }
378
275
  }
276
+ if (res instanceof Response && res.data) {
277
+ params2.body = res.data;
278
+ }
379
279
  return params2;
380
280
  }
381
281
  function response(...options) {
@@ -393,6 +293,10 @@
393
293
  }
394
294
  }
395
295
  }
296
+ let data = void 0;
297
+ if (responseParams.body) {
298
+ data = responseParams.body;
299
+ }
396
300
  let r = new Response(responseParams.body, responseParams);
397
301
  Object.freeze(r);
398
302
  return new Proxy(r, {
@@ -409,37 +313,17 @@
409
313
  return response(target, ...options2);
410
314
  };
411
315
  break;
412
- case "body":
413
- if (responseParams.body) {
414
- if (responseParams.body[Symbol.metroProxy]) {
415
- return responseParams.body;
416
- }
417
- return bodyProxy(responseParams.body, target);
418
- } else {
419
- return bodyProxy("", target);
420
- }
316
+ case "data":
317
+ return data;
421
318
  break;
422
319
  case "ok":
423
320
  return target.status >= 200 && target.status < 400;
424
321
  break;
425
- case "headers":
426
- return target.headers;
427
- break;
428
- default:
429
- if (prop in responseParams && prop != "toString") {
430
- return responseParams[prop];
431
- }
432
- if (prop in target && prop != "toString") {
433
- if (typeof target[prop] == "function") {
434
- return function(...args) {
435
- return target[prop].apply(target, args);
436
- };
437
- }
438
- return target[prop];
439
- }
440
- break;
441
322
  }
442
- return void 0;
323
+ if (typeof target[prop] == "function") {
324
+ return target[prop].bind(target);
325
+ }
326
+ return target[prop];
443
327
  }
444
328
  });
445
329
  }
@@ -648,9 +532,9 @@
648
532
  "Accept": "application/json"
649
533
  }
650
534
  });
651
- if (req.body && typeof req.body[Symbol.metroSource] == "object") {
535
+ if (req.data && typeof req.data == "object" && !(req.data instanceof ReadableStream)) {
652
536
  req = req.with({
653
- body: JSON.stringify(req.body[Symbol.metroSource], options.replacer, options.space)
537
+ body: JSON.stringify(req.data, options.replacer, options.space)
654
538
  });
655
539
  }
656
540
  } else {
@@ -1000,7 +884,7 @@
1000
884
  // note: this allows path components in the options.issuer url
1001
885
  configURL
1002
886
  );
1003
- const openid_config = response2.body[Symbol.metroSource];
887
+ const openid_config = response2.data;
1004
888
  assert(openid_config, openid_provider_metadata);
1005
889
  assert(openid_config.issuer, options.issuer);
1006
890
  return openid_config;
@@ -1053,7 +937,7 @@
1053
937
  let response2 = await options.client.post(options.registration_endpoint, {
1054
938
  body: options.client_info
1055
939
  });
1056
- let info = response2.body;
940
+ let info = response2.data;
1057
941
  if (!info.client_id || !info.client_secret) {
1058
942
  throw everything_default.metroError("metro.oidc: Error: dynamic registration of client failed, no client_id or client_secret returned", response2);
1059
943
  }
@@ -1382,7 +1266,7 @@
1382
1266
  }
1383
1267
  async function fetchAccessToken() {
1384
1268
  if (oauth22.grant_type === "authorization_code" && !options.tokens.has("authorization_code")) {
1385
- let authReqURL = getAuthorizationCodeURL();
1269
+ let authReqURL = await getAuthorizationCodeURL();
1386
1270
  if (!options.callbacks.authorize || typeof options.callbacks.authorize !== "function") {
1387
1271
  throw everything_default.metroError("oauth2mw: oauth2 with grant_type:authorization_code requires a callback function in client options.options.callbacks.authorize");
1388
1272
  }
@@ -1437,7 +1321,7 @@
1437
1321
  }
1438
1322
  return data;
1439
1323
  }
1440
- function getAuthorizationCodeURL() {
1324
+ async function getAuthorizationCodeURL() {
1441
1325
  if (!oauth22.authorization_endpoint) {
1442
1326
  throw everything_default.metroError("oauth2mw: Missing options.oauth2_configuration.authorization_endpoint");
1443
1327
  }
@@ -1455,17 +1339,26 @@
1455
1339
  state: oauth22.state || createState(40)
1456
1340
  // OAuth2.1 RFC says optional, but its a good idea to always add/check it
1457
1341
  };
1342
+ if (oauth22.response_type) {
1343
+ search.response_type = oauth22.response_type;
1344
+ }
1345
+ if (oauth22.response_mode) {
1346
+ search.response_mode = oauth22.response_mode;
1347
+ }
1458
1348
  options.state.set(search.state);
1459
1349
  if (oauth22.client_secret) {
1460
1350
  search.client_secret = oauth22.client_secret;
1461
1351
  }
1462
1352
  if (oauth22.code_verifier) {
1463
- search.code_challenge = generateCodeChallenge(oauth22.code_verifier);
1353
+ search.code_challenge = base64url_encode(await generateCodeChallenge(oauth22.code_verifier));
1464
1354
  search.code_challenge_method = "S256";
1465
1355
  }
1466
1356
  if (oauth22.scope) {
1467
1357
  search.scope = oauth22.scope;
1468
1358
  }
1359
+ if (oauth22.prompt) {
1360
+ search.prompt = oauth22.prompt;
1361
+ }
1469
1362
  return everything_default.url(url2, { search });
1470
1363
  }
1471
1364
  function getAccessTokenRequest(grant_type = null) {
@@ -1629,22 +1522,22 @@
1629
1522
  });
1630
1523
  break;
1631
1524
  case "/token/":
1632
- if (req.body[Symbol.metroSource] instanceof URLSearchParams) {
1525
+ if (req.data instanceof URLSearchParams) {
1633
1526
  let body = {};
1634
- req.body.forEach((value, key) => body[key] = value);
1527
+ req.data.forEach((value, key) => body[key] = value);
1635
1528
  req = req.with({ body });
1636
1529
  }
1637
1530
  if (error3 = fails2(req, {
1638
1531
  method: "POST",
1639
- body: {
1532
+ data: {
1640
1533
  grant_type: oneOf2("refresh_token", "authorization_code")
1641
1534
  }
1642
1535
  })) {
1643
1536
  return everything_default.response(badRequest(error3));
1644
1537
  }
1645
- switch (req.body.grant_type) {
1538
+ switch (req.data.grant_type) {
1646
1539
  case "refresh_token":
1647
- if (error3 = fails2(req.body, oneOf2({
1540
+ if (error3 = fails2(req.data, oneOf2({
1648
1541
  refresh_token: "mockRefreshToken",
1649
1542
  client_id: "mockClientId",
1650
1543
  client_secret: "mockClientSecret"
@@ -1657,7 +1550,7 @@
1657
1550
  }
1658
1551
  break;
1659
1552
  case "access_token":
1660
- if (error3 = fails2(req.body, oneOf2({
1553
+ if (error3 = fails2(req.data, oneOf2({
1661
1554
  client_id: "mockClientId",
1662
1555
  client_secret: "mockClientSecret"
1663
1556
  }, {
@@ -1782,6 +1675,57 @@
1782
1675
  throw everything_default.metroError("metro.oidcmw: Error while fetching " + issuer + ".wellknown/oauth_authorization_server", res);
1783
1676
  }
1784
1677
 
1678
+ // node_modules/@muze-nl/metro-oauth2/src/keysstore.mjs
1679
+ function keysStore() {
1680
+ return new Promise((resolve, reject) => {
1681
+ const request2 = globalThis.indexedDB.open("metro", 1);
1682
+ request2.onupgradeneeded = () => request2.result.createObjectStore("keyPairs", { keyPath: "domain" });
1683
+ request2.onerror = (event) => {
1684
+ reject(event);
1685
+ };
1686
+ request2.onsuccess = (event) => {
1687
+ const db = event.target.result;
1688
+ resolve({
1689
+ set: function(value, key) {
1690
+ return new Promise((resolve2, reject2) => {
1691
+ const tx = db.transaction("keyPairs", "readwrite", { durability: "strict" });
1692
+ const objectStore = tx.objectStore("keyPairs");
1693
+ tx.oncomplete = () => {
1694
+ resolve2();
1695
+ };
1696
+ tx.onerror = reject2;
1697
+ objectStore.put(value, key);
1698
+ });
1699
+ },
1700
+ get: function(key) {
1701
+ return new Promise((resolve2, reject2) => {
1702
+ const tx = db.transaction("keyPairs", "readonly");
1703
+ const objectStore = tx.objectStore("keyPairs");
1704
+ const request3 = objectStore.get(key);
1705
+ request3.onsuccess = () => {
1706
+ resolve2(request3.result);
1707
+ };
1708
+ request3.onerror = reject2;
1709
+ tx.onerror = reject2;
1710
+ });
1711
+ },
1712
+ clear: function() {
1713
+ return new Promise((resolve2, reject2) => {
1714
+ const tx = db.transaction("keyPairs", "readwrite");
1715
+ const objectStore = tx.objectStore("keyPairs");
1716
+ const request3 = objectStore.clear();
1717
+ request3.onsuccess = () => {
1718
+ resolve2();
1719
+ };
1720
+ request3.onerror = reject2;
1721
+ tx.onerror = reject2;
1722
+ });
1723
+ }
1724
+ });
1725
+ };
1726
+ });
1727
+ }
1728
+
1785
1729
  // node_modules/dpop/build/index.js
1786
1730
  var encoder = new TextEncoder();
1787
1731
  var decoder = new TextDecoder();
@@ -1982,62 +1926,24 @@
1982
1926
  return crypto.subtle.generateKey(algorithm, options?.extractable ?? false, ["sign", "verify"]);
1983
1927
  }
1984
1928
 
1985
- // node_modules/@muze-nl/metro-oauth2/src/keysstore.mjs
1986
- function keysStore() {
1987
- return new Promise((resolve, reject) => {
1988
- const request2 = globalThis.indexedDB.open("metro", 1);
1989
- request2.onupgradeneeded = () => request2.result.createObjectStore("keyPairs", { keyPath: "domain" });
1990
- request2.onerror = (event) => {
1991
- reject(event);
1992
- };
1993
- request2.onsuccess = (event) => {
1994
- const db = event.target.result;
1995
- resolve({
1996
- set: function(value, key) {
1997
- return new Promise((resolve2, reject2) => {
1998
- const tx = db.transaction("keyPairs", "readwriteflush", { durability: "strict" });
1999
- const objectStore = tx.objectStore("keyPairs");
2000
- tx.oncomplete = () => {
2001
- resolve2();
2002
- };
2003
- tx.onerror = reject2;
2004
- objectStore.put(value, key);
2005
- });
2006
- },
2007
- get: function(key) {
2008
- return new Promise((resolve2, reject2) => {
2009
- const tx = db.transaction("keyPairs", "readonly");
2010
- const objectStore = tx.objectStore("keyPairs");
2011
- const request3 = objectStore.get(key);
2012
- request3.onsuccess = () => {
2013
- resolve2(request3.result);
2014
- };
2015
- request3.onerror = reject2;
2016
- tx.onerror = reject2;
2017
- });
2018
- }
2019
- });
2020
- };
2021
- });
2022
- }
2023
-
2024
1929
  // node_modules/@muze-nl/metro-oauth2/src/oauth2.dpop.mjs
2025
1930
  function dpopmw(options) {
2026
1931
  assert2(options, {
1932
+ site: Required2(validURL2),
2027
1933
  authorization_endpoint: Required2(validURL2),
2028
1934
  token_endpoint: Required2(validURL2)
2029
1935
  // dpop_signing_alg_values_supported: Required([]) // this property is unfortunately rarely supported
2030
1936
  });
2031
1937
  return async (req, next) => {
2032
1938
  const keys = await keysStore();
2033
- const url2 = everything_default.url(req.url);
2034
- let keyInfo = await keys.get(url2.host);
1939
+ let keyInfo = await keys.get(options.site);
2035
1940
  if (!keyInfo) {
2036
1941
  let keyPair = await generateKeyPair("ES256");
2037
- keyInfo = { domain: url2.host, keyPair };
1942
+ keyInfo = { domain: options.site, keyPair };
2038
1943
  await keys.set(keyInfo);
2039
1944
  }
2040
- if (url2.href.startsWith(options.authorization_endpoint) || url2.href.startsWith(options.token_endpoint)) {
1945
+ const url2 = everything_default.url(req.url);
1946
+ if (req.url.startsWith(options.authorization_endpoint) || req.url.startsWith(options.token_endpoint)) {
2041
1947
  const dpopHeader = await DPoP(keyInfo.keyPair, req.url, req.method);
2042
1948
  req = req.with({
2043
1949
  headers: {
@@ -2050,6 +1956,8 @@
2050
1956
  const dpopHeader = await DPoP(keyInfo.keyPair, req.url, req.method, nonce, accessToken);
2051
1957
  req = req.with({
2052
1958
  headers: {
1959
+ "Authorization": "DPoP " + accessToken,
1960
+ //solidcommunity server sends accesstoken with type Bearer
2053
1961
  "DPoP": dpopHeader
2054
1962
  }
2055
1963
  });
@@ -2067,8 +1975,10 @@
2067
1975
  mockserver: oauth2_mockserver_exports,
2068
1976
  discovery: oauth2_discovery_exports,
2069
1977
  tokenstore: tokenStore,
2070
- dpopmw
1978
+ dpopmw,
1979
+ keysstore: keysStore
2071
1980
  });
1981
+ globalThis.oauth2 = oauth2;
2072
1982
  var browser_default = oauth2;
2073
1983
 
2074
1984
  // src/oidc.store.mjs
@@ -2146,6 +2056,7 @@
2146
2056
  });
2147
2057
  options.store.set("client_info", options.client_info);
2148
2058
  }
2059
+ const scope = options.scope || "openid";
2149
2060
  const oauth2Options = Object.assign(
2150
2061
  {
2151
2062
  site: options.issuer,
@@ -2154,12 +2065,13 @@
2154
2065
  oauth2_configuration: {
2155
2066
  client_id: options.client_info.client_id,
2156
2067
  client_secret: options.client_info.client_secret,
2157
- code_verifier: false,
2158
- //FIXME: detect pkce support
2159
2068
  grant_type: "authorization_code",
2069
+ response_type: "code",
2070
+ response_mode: "query",
2160
2071
  authorization_endpoint: options.openid_configuration.authorization_endpoint,
2161
2072
  token_endpoint: options.openid_configuration.token_endpoint,
2162
- scope: options.openid_configuration.scope || "openid",
2073
+ scope,
2074
+ //FIXME: should only use scopes supported by server
2163
2075
  redirect_uri: options.client_info.redirect_uris[0]
2164
2076
  //FIXME: find the best match?
2165
2077
  }
@@ -2167,6 +2079,7 @@
2167
2079
  //...
2168
2080
  );
2169
2081
  const dpopOptions = {
2082
+ site: options.issuer,
2170
2083
  authorization_endpoint: options.openid_configuration.authorization_endpoint,
2171
2084
  token_endpoint: options.openid_configuration.token_endpoint,
2172
2085
  dpop_signing_alg_values_supported: options.openid_configuration.dpop_signing_alg_values_supported