From d6d816233d11238738ebbf3b3bf3348b78434c82 Mon Sep 17 00:00:00 2001 From: Angelo Veltens Date: Mon, 4 Jul 2022 17:08:24 +0200 Subject: [PATCH] WIP: PoC demo app auth works with oidc-client-ts --- .../AuthorizationCodeWithPkceOidcHandler.ts | 8 +- packages/oidc/package-lock.json | 172 +++++------------- packages/oidc/package.json | 4 +- packages/oidc/src/cleanup/cleanup.spec.ts | 7 +- packages/oidc/src/cleanup/cleanup.ts | 7 +- packages/oidc/src/dpop/tokenExchange.ts | 10 +- packages/oidc/src/index.ts | 5 +- 7 files changed, 66 insertions(+), 147 deletions(-) diff --git a/packages/browser/src/login/oidc/oidcHandlers/AuthorizationCodeWithPkceOidcHandler.ts b/packages/browser/src/login/oidc/oidcHandlers/AuthorizationCodeWithPkceOidcHandler.ts index df16f2b4fa..3a1fea7a50 100644 --- a/packages/browser/src/login/oidc/oidcHandlers/AuthorizationCodeWithPkceOidcHandler.ts +++ b/packages/browser/src/login/oidc/oidcHandlers/AuthorizationCodeWithPkceOidcHandler.ts @@ -85,7 +85,7 @@ export default class AuthorizationCodeWithPkceOidcHandler const storage = this.storageUtility; try { - const signingRequest = await oidcClientLibrary.createSigninRequest(); + const signingRequest = await oidcClientLibrary.createSigninRequest({}); await Promise.all([ // We use the OAuth 'state' value (which should be crypto-random) as // the key in our storage to store our actual SessionID. We do this @@ -96,8 +96,7 @@ export default class AuthorizationCodeWithPkceOidcHandler // that session ID can be any developer-specified value, and therefore // may not be appropriate (since the OAuth 'state' value should really // be an unguessable crypto-random value). - // eslint-disable-next-line no-underscore-dangle - storage.setForUser(signingRequest.state._id, { + storage.setForUser(signingRequest.state.id, { sessionId: oidcLoginOptions.sessionId, }), @@ -106,8 +105,7 @@ export default class AuthorizationCodeWithPkceOidcHandler // our session ID is unnecessary, but it provides a slightly cleaner // separation of concerns. storage.setForUser(oidcLoginOptions.sessionId, { - // eslint-disable-next-line no-underscore-dangle - codeVerifier: signingRequest.state._code_verifier, + codeVerifier: signingRequest.state.code_verifier ?? "", issuer: oidcLoginOptions.issuer.toString(), // The redirect URL is read after redirect, so it must be stored now. redirectUrl: oidcLoginOptions.redirectUrl, diff --git a/packages/oidc/package-lock.json b/packages/oidc/package-lock.json index 31e99c952a..86b60ae951 100644 --- a/packages/oidc/package-lock.json +++ b/packages/oidc/package-lock.json @@ -9,38 +9,26 @@ "version": "1.12.1", "license": "MIT", "dependencies": { - "@inrupt/oidc-client": "^1.11.6", - "@inrupt/solid-client-authn-core": "^1.11.8", + "@inrupt/solid-client-authn-core": "^1.12.1", "@types/jest": "^27.0.3", "@types/uuid": "^8.3.0", "jose": "^4.3.7", + "oidc-client-ts": "^2.0.5", "uuid": "^8.3.1" }, "devDependencies": { "cross-fetch": "^3.1.5" } }, - "node_modules/@inrupt/oidc-client": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@inrupt/oidc-client/-/oidc-client-1.11.6.tgz", - "integrity": "sha512-1rCTk1T6pdm/7gKozutZutk7jwmYBADlnkGGoI5ypke099NOCa5KFXjkQpbjsps0PRkKZ+0EaR70XN5+xqmViA==", - "dependencies": { - "acorn": "^7.4.1", - "base64-js": "^1.5.1", - "core-js": "^3.8.3", - "crypto-js": "^4.0.0", - "serialize-javascript": "^4.0.0" - } - }, "node_modules/@inrupt/solid-client-authn-core": { - "version": "1.11.8", - "resolved": "https://registry.npmjs.org/@inrupt/solid-client-authn-core/-/solid-client-authn-core-1.11.8.tgz", - "integrity": "sha512-D7IZn/kBAl1/pC1WVY57FFesVa2fBVScBU6NNqhk9g3m4Hs9vCI1Q51Mi08/9LqYrm/soeNSiIlGWSGJXsC2HQ==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@inrupt/solid-client-authn-core/-/solid-client-authn-core-1.12.1.tgz", + "integrity": "sha512-Pneh+jMls/R0I0MTZTTjJq4zjQ5OwNP0shE+p9WHQEviwBMZYCuiLN5jQGKLe0b39Nie0c+6KdYJ0xZPleUB4w==", "dependencies": { "@inrupt/solid-common-vocab": "^1.0.0", "@types/lodash.clonedeep": "^4.5.6", "@types/uuid": "^8.3.0", - "cross-fetch": "^3.0.6", + "cross-fetch": "^3.1.5", "events": "^3.3.0", "jose": "^4.3.7", "lodash.clonedeep": "^4.5.0", @@ -79,17 +67,6 @@ "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==" }, - "node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -112,25 +89,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -162,16 +120,6 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "node_modules/core-js": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.21.1.tgz", - "integrity": "sha512-FRq5b/VMrWlrmCzwRrpDYNxyHP9BcAZC+xHJaqTgIE5091ZV1NTmyh0sGOg5XqpnHvR0svdy0sv1gWA1zmhxig==", - "hasInstallScript": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, "node_modules/cross-fetch": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", @@ -253,6 +201,11 @@ "url": "https://github.com/sponsors/panva" } }, + "node_modules/jwt-decode": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", + "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" + }, "node_modules/lodash.clonedeep": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", @@ -296,6 +249,18 @@ "webidl-conversions": "^3.0.0" } }, + "node_modules/oidc-client-ts": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/oidc-client-ts/-/oidc-client-ts-2.0.5.tgz", + "integrity": "sha512-OXIuuLU2iSEtLblM+xR6+SE0GWjyUMVH6HtKpvZnV2AQt0irWZ+yAXGVB8EgNBu0lAQ/UN40EIme+uC0p7WwKw==", + "dependencies": { + "crypto-js": "^4.1.1", + "jwt-decode": "^3.1.2" + }, + "engines": { + "node": ">=12.13.0" + } + }, "node_modules/pretty-format": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", @@ -320,32 +285,11 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/serialize-javascript": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", - "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", - "dependencies": { - "randombytes": "^2.1.0" - } - }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -367,27 +311,15 @@ } }, "dependencies": { - "@inrupt/oidc-client": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@inrupt/oidc-client/-/oidc-client-1.11.6.tgz", - "integrity": "sha512-1rCTk1T6pdm/7gKozutZutk7jwmYBADlnkGGoI5ypke099NOCa5KFXjkQpbjsps0PRkKZ+0EaR70XN5+xqmViA==", - "requires": { - "acorn": "^7.4.1", - "base64-js": "^1.5.1", - "core-js": "^3.8.3", - "crypto-js": "^4.0.0", - "serialize-javascript": "^4.0.0" - } - }, "@inrupt/solid-client-authn-core": { - "version": "1.11.8", - "resolved": "https://registry.npmjs.org/@inrupt/solid-client-authn-core/-/solid-client-authn-core-1.11.8.tgz", - "integrity": "sha512-D7IZn/kBAl1/pC1WVY57FFesVa2fBVScBU6NNqhk9g3m4Hs9vCI1Q51Mi08/9LqYrm/soeNSiIlGWSGJXsC2HQ==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@inrupt/solid-client-authn-core/-/solid-client-authn-core-1.12.1.tgz", + "integrity": "sha512-Pneh+jMls/R0I0MTZTTjJq4zjQ5OwNP0shE+p9WHQEviwBMZYCuiLN5jQGKLe0b39Nie0c+6KdYJ0xZPleUB4w==", "requires": { "@inrupt/solid-common-vocab": "^1.0.0", "@types/lodash.clonedeep": "^4.5.6", "@types/uuid": "^8.3.0", - "cross-fetch": "^3.0.6", + "cross-fetch": "^3.1.5", "events": "^3.3.0", "jose": "^4.3.7", "lodash.clonedeep": "^4.5.0", @@ -426,11 +358,6 @@ "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==" }, - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" - }, "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -444,11 +371,6 @@ "color-convert": "^2.0.1" } }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -471,11 +393,6 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "core-js": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.21.1.tgz", - "integrity": "sha512-FRq5b/VMrWlrmCzwRrpDYNxyHP9BcAZC+xHJaqTgIE5091ZV1NTmyh0sGOg5XqpnHvR0svdy0sv1gWA1zmhxig==" - }, "cross-fetch": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", @@ -536,6 +453,11 @@ "resolved": "https://registry.npmjs.org/jose/-/jose-4.8.1.tgz", "integrity": "sha512-+/hpTbRcCw9YC0TOfN1W47pej4a9lRmltdOVdRLz5FP5UvUq3CenhXjQK7u/8NdMIIShMXYAh9VLPhc7TjhvFw==" }, + "jwt-decode": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", + "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" + }, "lodash.clonedeep": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", @@ -570,6 +492,15 @@ } } }, + "oidc-client-ts": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/oidc-client-ts/-/oidc-client-ts-2.0.5.tgz", + "integrity": "sha512-OXIuuLU2iSEtLblM+xR6+SE0GWjyUMVH6HtKpvZnV2AQt0irWZ+yAXGVB8EgNBu0lAQ/UN40EIme+uC0p7WwKw==", + "requires": { + "crypto-js": "^4.1.1", + "jwt-decode": "^3.1.2" + } + }, "pretty-format": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", @@ -587,32 +518,11 @@ } } }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "requires": { - "safe-buffer": "^5.1.0" - } - }, "react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "serialize-javascript": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", - "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", - "requires": { - "randombytes": "^2.1.0" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", diff --git a/packages/oidc/package.json b/packages/oidc/package.json index 253de6fd15..3659d71af4 100644 --- a/packages/oidc/package.json +++ b/packages/oidc/package.json @@ -1,7 +1,7 @@ { "name": "@inrupt/oidc-client-ext", "version": "1.12.1", - "description": "A module extending oidc-client-js with new features, such as dynamic client registration and DPoP support.", + "description": "A module extending oidc-client-ts with new features, such as dynamic client registration and DPoP support.", "homepage": "https://github.com/inrupt/solid-client-authn-js/tree/main/packages/oidc/", "bugs": "https://github.com/inrupt/solid-client-authn-js/issues", "main": "dist/index.js", @@ -29,11 +29,11 @@ "cross-fetch": "^3.1.5" }, "dependencies": { - "@inrupt/oidc-client": "^1.11.6", "@inrupt/solid-client-authn-core": "^1.12.1", "@types/jest": "^27.0.3", "@types/uuid": "^8.3.0", "jose": "^4.3.7", + "oidc-client-ts": "^2.0.5", "uuid": "^8.3.1" }, "publishConfig": { diff --git a/packages/oidc/src/cleanup/cleanup.spec.ts b/packages/oidc/src/cleanup/cleanup.spec.ts index 081dae45de..ce70b66ab5 100644 --- a/packages/oidc/src/cleanup/cleanup.spec.ts +++ b/packages/oidc/src/cleanup/cleanup.spec.ts @@ -20,7 +20,7 @@ */ import { jest, it, describe, expect } from "@jest/globals"; -import { OidcClient } from "@inrupt/oidc-client"; +import { OidcClient, OidcClientSettings } from "oidc-client-ts"; import { removeOidcQueryParam, clearOidcPersistentStorage } from "./cleanup"; jest.mock("@inrupt/oidc-client", () => { @@ -71,7 +71,10 @@ describe("clearOidcPersistentStorage", () => { it("clears oidc-client storage", async () => { // This is a bad test, but we can only test for internal behaviour of oidc-client, // or test that the 'clearStaleState' function is called, which is done here. - const clearSpy = jest.spyOn(new OidcClient({}), "clearStaleState"); + const clearSpy = jest.spyOn( + new OidcClient({} as OidcClientSettings), + "clearStaleState" + ); await clearOidcPersistentStorage(); expect(clearSpy).toHaveBeenCalled(); }); diff --git a/packages/oidc/src/cleanup/cleanup.ts b/packages/oidc/src/cleanup/cleanup.ts index ed635c7bb3..369933ce8a 100644 --- a/packages/oidc/src/cleanup/cleanup.ts +++ b/packages/oidc/src/cleanup/cleanup.ts @@ -19,7 +19,7 @@ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { OidcClient, WebStorageStateStore } from "@inrupt/oidc-client"; +import { OidcClient } from "oidc-client-ts"; /** * Removes OIDC-specific query parameters from a given URL (state, code...), and @@ -52,8 +52,11 @@ export async function clearOidcPersistentStorage(): Promise { // for a hash '#' fragment!). // eslint-disable-next-line camelcase response_mode: "query", + redirect_uri: "", + authority: "", + client_id: "", }); - await client.clearStaleState(new WebStorageStateStore({})); + await client.clearStaleState(); const myStorage = window.localStorage; const itemsToRemove = []; for (let i = 0; i <= myStorage.length; i += 1) { diff --git a/packages/oidc/src/dpop/tokenExchange.ts b/packages/oidc/src/dpop/tokenExchange.ts index d1048441ff..a5df07b907 100644 --- a/packages/oidc/src/dpop/tokenExchange.ts +++ b/packages/oidc/src/dpop/tokenExchange.ts @@ -19,7 +19,7 @@ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { OidcClient } from "@inrupt/oidc-client"; +import { OidcClient } from "oidc-client-ts"; import { IClient, IIssuerConfig, @@ -304,6 +304,9 @@ export async function getBearerToken( // against NSS, and not in general. // Issue tracker: https://github.com/solid/node-solid-server/issues/1490 loadUserInfo: false, + authority: "", + client_id: "", + redirect_uri: redirectUrl, }); signinResponse = await client.processSigninResponse(redirectUrl); if (client.settings.metadata === undefined) { @@ -326,6 +329,11 @@ export async function getBearerToken( "Missing some client information in storage: 'client_id' is undefined" ); } + if (signinResponse.id_token === undefined) { + throw new Error( + "Missing some information in sign-in response: 'id_token' is undefined" + ); + } const webId = await getWebidFromTokenPayload( signinResponse.id_token, client.settings.metadata.jwks_uri, diff --git a/packages/oidc/src/index.ts b/packages/oidc/src/index.ts index f297967a8b..2a2f6e272f 100644 --- a/packages/oidc/src/index.ts +++ b/packages/oidc/src/index.ts @@ -29,17 +29,14 @@ export { UserManager, AccessTokenEvents, MetadataService, - CordovaPopupNavigator, - CordovaIFrameNavigator, CheckSessionIFrame, - SigninRequest, SigninResponse, // TODO: Investigate why this fails // TokenRevocationClient, SessionMonitor, // Global, User, -} from "@inrupt/oidc-client"; +} from "oidc-client-ts"; export { registerClient } from "./dcr/clientRegistrar"; export {