From 9304373c0210f65af792535457fa68424b376987 Mon Sep 17 00:00:00 2001 From: einaralex Date: Mon, 6 Nov 2023 17:14:37 +0000 Subject: [PATCH] fix: queryparams clean f nextjs + move async logic from constructor --- src/client.ts | 42 +++++++++++++++++++++++++------------ src/helpers/auth.helpers.ts | 4 ++-- test/client.test.ts | 37 ++++++++++++++++---------------- 3 files changed, 50 insertions(+), 33 deletions(-) diff --git a/src/client.ts b/src/client.ts index 71c6063..84961a9 100644 --- a/src/client.ts +++ b/src/client.ts @@ -70,10 +70,6 @@ export class MoneriumClient { /** Constructor with {@link ClassOptions} */ constructor(options: ClassOptions); constructor(envOrOptions?: ENV | ClassOptions) { - // TODO: CHECK HERE IF REFRESH TOKEN EXISTS - // TODO: CHECK HERE IF REFRESH TOKEN EXISTS - // TODO: CHECK HERE IF REFRESH TOKEN EXISTS - // TODO: CHECK HERE IF REFRESH TOKEN EXISTS // No arguments, default to sandbox if (!envOrOptions) { this.#env = MONERIUM_CONFIG.environments['sandbox']; @@ -92,14 +88,12 @@ export class MoneriumClient { clientId: clientId as string, redirectUrl: redirectUrl as string, }; - this.connect(this.#client); } else { const { clientId, clientSecret } = envOrOptions as ClientCredentials; this.#client = { clientId: clientId as string, clientSecret: clientSecret as string, }; - this.#clientCredentialsAuthorization(this.#client); } } } @@ -136,12 +130,23 @@ export class MoneriumClient { } // TODO: TEST auto link & manual link + address - async connect(client: AuthorizationCodeCredentials) { - const clientId = - client?.clientId || - (this.#client as AuthorizationCodeCredentials)?.clientId; + async connect(client: AuthorizationCodeCredentials | ClientCredentials) { + const clientId = client?.clientId || this.#client?.clientId; + const clientSecret = + (client as ClientCredentials)?.clientSecret || + (this.#client as ClientCredentials)?.clientSecret; + + if (clientSecret) { + if (!isServer) { + throw new Error('Only use client credentials on server side'); + } + return this.#clientCredentialsAuthorization( + this.#client as ClientCredentials, + ); + } + const redirectUrl = - client?.redirectUrl || + (client as AuthorizationCodeCredentials)?.redirectUrl || (this.#client as AuthorizationCodeCredentials)?.redirectUrl; if (!clientId) { @@ -226,6 +231,15 @@ export class MoneriumClient { // } }); + /** + * Remove auth code from URL. + * Make sure this is the last action before returning the bearer profile + * NextJS seems to overwrite this if there is data fetching in the background + */ + if (isAuthCode(args)) { + cleanQueryString(); + } + return this.bearerProfile as BearerProfile; } @@ -359,13 +373,15 @@ export class MoneriumClient { ) => { const codeVerifier = sessionStorage.getItem(STORAGE_CODE_VERIFIER) || ''; + if (!codeVerifier) { + throw new Error('Code verifier not found'); + } + /** @deprecated, use sessionStorage */ this.codeVerifier = codeVerifier; sessionStorage.removeItem(STORAGE_CODE_VERIFIER); // Remove auth code from URL. - cleanQueryString(); - return await this.getBearerToken({ code: authCode, redirect_uri: redirectUrl as string, diff --git a/src/helpers/auth.helpers.ts b/src/helpers/auth.helpers.ts index 30e6cd0..49819b3 100644 --- a/src/helpers/auth.helpers.ts +++ b/src/helpers/auth.helpers.ts @@ -5,8 +5,8 @@ import { PKCERequest, PKCERequestArgs, RefreshTokenRequest, -} from 'types'; -import { getChain, getNetwork, urlEncoded } from 'utils'; +} from '../types'; +import { getChain, getNetwork, urlEncoded } from '../utils'; import encodeBase64Url from 'crypto-js/enc-base64url'; import SHA256 from 'crypto-js/sha256'; import { STORAGE_CODE_VERIFIER } from '../constants'; diff --git a/test/client.test.ts b/test/client.test.ts index 5ffe28e..e07ba0a 100644 --- a/test/client.test.ts +++ b/test/client.test.ts @@ -89,24 +89,25 @@ describe('MoneriumClient', () => { replaceMock.mockRestore(); }); - test('class instance with refresh_token', async () => { - const connectMock = jest - .spyOn(MoneriumClient.prototype, 'connect') - .mockImplementation(); - const client = new MoneriumClient({ - env: 'production', - clientId: 'testClientId', - clientSecret: 'testSecret', - }); - - expect(connectMock).toHaveBeenCalled(); - expect(client.getEnvironment()).toEqual({ - api: 'https://api.monerium.app', - web: 'https://monerium.app', - wss: 'wss://api.monerium.app', - }); - connectMock.mockRestore(); - }); + // This is no longer valid, we were calling connect on the constructor, but there was no way to wait for the promise to resolve + // test('class instance with refresh_token', async () => { + // const connectMock = jest + // .spyOn(MoneriumClient.prototype, 'connect') + // .mockImplementation(); + // const client = new MoneriumClient({ + // env: 'production', + // clientId: 'testClientId', + // clientSecret: 'testSecret', + // }); + + // expect(connectMock).toHaveBeenCalled(); + // expect(client.getEnvironment()).toEqual({ + // api: 'https://api.monerium.app', + // web: 'https://monerium.app', + // wss: 'wss://api.monerium.app', + // }); + // connectMock.mockRestore(); + // }); test('authenticate with client credentials', async () => { const client = new MoneriumClient();