-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
/** | ||
* @jest-environment node | ||
*/ | ||
/* eslint header/header: "off", max-lines:"off" */ | ||
/* | ||
* Copyright (c) 2022, salesforce.com, inc. | ||
* All rights reserved. | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause | ||
*/ | ||
|
||
import nock from 'nock'; | ||
import {ShopperLogin} from '../../lib/shopperLogin'; | ||
import * as slasHelper from './slasHelper'; | ||
import { | ||
authorizePasswordless, | ||
getPasswordLessAccessToken, | ||
} from './passwordlessHelper'; | ||
|
||
type slasHelperType = typeof slasHelper; | ||
// Mock the module | ||
jest.mock('./slasHelper', () => { | ||
const actualUtils = jest.requireActual<slasHelperType>('./slasHelper'); | ||
Check warning on line 23 in src/static/helpers/passwordlessHelper.test.ts GitHub Actions / linux-tests (12)
Check warning on line 23 in src/static/helpers/passwordlessHelper.test.ts GitHub Actions / linux-tests (14)
Check warning on line 23 in src/static/helpers/passwordlessHelper.test.ts GitHub Actions / linux-tests (16)
|
||
const createCodeVerifierMock = jest.fn(() => 'code_verifier') | ||
Check warning on line 24 in src/static/helpers/passwordlessHelper.test.ts GitHub Actions / linux-tests (12)
Check warning on line 24 in src/static/helpers/passwordlessHelper.test.ts GitHub Actions / linux-tests (14)
Check warning on line 24 in src/static/helpers/passwordlessHelper.test.ts GitHub Actions / linux-tests (16)
|
||
return { | ||
Check warning on line 25 in src/static/helpers/passwordlessHelper.test.ts GitHub Actions / linux-tests (12)
Check warning on line 25 in src/static/helpers/passwordlessHelper.test.ts GitHub Actions / linux-tests (14)
Check warning on line 25 in src/static/helpers/passwordlessHelper.test.ts GitHub Actions / linux-tests (16)
|
||
...actualUtils, | ||
Check warning on line 26 in src/static/helpers/passwordlessHelper.test.ts GitHub Actions / linux-tests (12)
Check warning on line 26 in src/static/helpers/passwordlessHelper.test.ts GitHub Actions / linux-tests (14)
Check warning on line 26 in src/static/helpers/passwordlessHelper.test.ts GitHub Actions / linux-tests (16)
|
||
createCodeVerifier: createCodeVerifierMock, // Mock the specific function | ||
Check warning on line 27 in src/static/helpers/passwordlessHelper.test.ts GitHub Actions / linux-tests (12)
Check warning on line 27 in src/static/helpers/passwordlessHelper.test.ts GitHub Actions / linux-tests (14)
Check warning on line 27 in src/static/helpers/passwordlessHelper.test.ts GitHub Actions / linux-tests (16)
|
||
}; | ||
Check warning on line 28 in src/static/helpers/passwordlessHelper.test.ts GitHub Actions / linux-tests (12)
Check warning on line 28 in src/static/helpers/passwordlessHelper.test.ts GitHub Actions / linux-tests (14)
Check warning on line 28 in src/static/helpers/passwordlessHelper.test.ts GitHub Actions / linux-tests (16)
|
||
}); | ||
Check warning on line 29 in src/static/helpers/passwordlessHelper.test.ts GitHub Actions / linux-tests (12)
Check warning on line 29 in src/static/helpers/passwordlessHelper.test.ts GitHub Actions / linux-tests (14)
Check warning on line 29 in src/static/helpers/passwordlessHelper.test.ts GitHub Actions / linux-tests (16)
|
||
|
||
const authorizePasswordlessCustomerMock = jest.fn(); | ||
const getPasswordLessAccessTokenMock = jest.fn(); | ||
|
||
const createMockSlasClient = () => | ||
({ | ||
clientConfig: { | ||
parameters: { | ||
shortCode: 'short_code', | ||
organizationId: 'organization_id', | ||
clientId: 'client_id', | ||
siteId: 'site_id', | ||
}, | ||
}, | ||
authorizePasswordlessCustomer: authorizePasswordlessCustomerMock, | ||
getPasswordLessAccessToken: getPasswordLessAccessTokenMock, | ||
} as unknown as ShopperLogin<{ | ||
shortCode: string; | ||
organizationId: string; | ||
clientId: string; | ||
siteId: string; | ||
}>); | ||
|
||
beforeEach(() => { | ||
jest.clearAllMocks(); | ||
nock.cleanAll(); | ||
}); | ||
|
||
describe('authorizePasswordless is working', () => { | ||
test('Correct parameters are used to call SLAS Client authorize', async () => { | ||
Check warning on line 59 in src/static/helpers/passwordlessHelper.test.ts GitHub Actions / linux-tests (12)
Check warning on line 59 in src/static/helpers/passwordlessHelper.test.ts GitHub Actions / linux-tests (14)
Check warning on line 59 in src/static/helpers/passwordlessHelper.test.ts GitHub Actions / linux-tests (16)
|
||
const mockSlasClient = createMockSlasClient(); | ||
Check warning on line 60 in src/static/helpers/passwordlessHelper.test.ts GitHub Actions / linux-tests (12)
Check warning on line 60 in src/static/helpers/passwordlessHelper.test.ts GitHub Actions / linux-tests (14)
Check warning on line 60 in src/static/helpers/passwordlessHelper.test.ts GitHub Actions / linux-tests (16)
|
||
const {clientId, organizationId, siteId} = mockSlasClient.clientConfig.parameters; | ||
|
||
const credentials = { | ||
clientSecret: 'slas_private_secret', | ||
}; | ||
const parameters = { | ||
callbackURI: 'www.something.com/callback', | ||
usid: 'a_usid', | ||
userid: 'a_userid', | ||
locale: 'a_locale', | ||
mode: 'callback', | ||
}; | ||
const authHeaderExpected = `Basic ${slasHelper.stringToBase64( | ||
`${clientId}:${credentials.clientSecret}` | ||
)}`; | ||
await authorizePasswordless(mockSlasClient, credentials, parameters) | ||
const expectedReqOptions = { | ||
headers: { | ||
Authorization: authHeaderExpected | ||
}, | ||
parameters: { | ||
organizationId | ||
}, | ||
body: { | ||
user_id: parameters.userid, | ||
mode: parameters.mode, | ||
locale: parameters.locale, | ||
channel_id: siteId, | ||
callback_uri: parameters.callbackURI, | ||
usid: parameters.usid | ||
} | ||
} | ||
expect(authorizePasswordlessCustomerMock).toBeCalledWith(expectedReqOptions); | ||
}); | ||
}); | ||
|
||
describe('getPasswordLessAccessToken is working', () => { | ||
test('Correct parameters are used to call SLAS Client authorize', async () => { | ||
const mockSlasClient = createMockSlasClient(); | ||
const {clientId, organizationId} = mockSlasClient.clientConfig.parameters; | ||
|
||
const credentials = { | ||
clientSecret: 'slas_private_secret', | ||
}; | ||
const parameters = { | ||
pwdlessLoginToken: '123456', | ||
dnt: '1' | ||
}; | ||
const authHeaderExpected = `Basic ${slasHelper.stringToBase64( | ||
`${clientId}:${credentials.clientSecret}` | ||
)}`; | ||
await getPasswordLessAccessToken(mockSlasClient, credentials, parameters) | ||
const expectedReqOptions = { | ||
headers: { | ||
Authorization: authHeaderExpected | ||
}, | ||
parameters: { | ||
organizationId | ||
}, | ||
body: { | ||
dnt: parameters.dnt, | ||
code_verifier: "code_verifier", | ||
grant_type: 'client_credentials', | ||
hint: 'pwdless_login', | ||
pwdless_login_token: parameters.pwdlessLoginToken | ||
} | ||
} | ||
expect(getPasswordLessAccessTokenMock).toBeCalledWith(expectedReqOptions); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
/* | ||
* Copyright (c) 2024, Salesforce, Inc. | ||
* All rights reserved. | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause | ||
*/ | ||
import {ShopperLogin, TokenResponse} from '../../lib/shopperLogin'; | ||
import {createCodeVerifier, stringToBase64} from './slasHelper'; | ||
|
||
/** | ||
* Function to send passwordless login token | ||
* **Note** At the moment, passwordless is only supported on private client | ||
* @param slasClient a configured instance of the ShopperLogin SDK client. | ||
* @param credentials - the id and password and clientSecret (if applicable) to login with. | ||
* @param credentials.clientSecret? - secret associated with client ID | ||
* @param parameters - parameters to pass in the API calls. | ||
* @param parameters.callbackURI? - URI to send the passwordless login token to. Must be listed in your SLAS configuration. Required when mode is callback | ||
* @param parameters.usid? - Unique Shopper Identifier to enable personalization. | ||
* @param parameters.userid - User Id for login | ||
* @param parameters.locale - The locale of the template. Not needed for the callback mode | ||
* @param parameters.mode - Medium of sending login token | ||
* @returns Promise of Response or Object | ||
*/ | ||
export async function authorizePasswordless( | ||
slasClient: ShopperLogin<{ | ||
shortCode: string; | ||
organizationId: string; | ||
clientId: string; | ||
siteId: string; | ||
}>, | ||
credentials: { | ||
clientSecret: string; | ||
}, | ||
parameters: { | ||
callbackURI?: string; | ||
usid?: string; | ||
userid: string; | ||
locale?: string; | ||
mode: string; | ||
} | ||
): Promise<Response | Object> { | ||
const authHeaderIdSecret = `Basic ${stringToBase64( | ||
`${slasClient.clientConfig.parameters.clientId}:${credentials.clientSecret}` | ||
)}`; | ||
const tokenBody = { | ||
user_id: parameters.userid, | ||
mode: parameters.mode, | ||
...(parameters.locale && {locale: parameters.locale}), | ||
...(parameters.usid && {usid: parameters.usid}), | ||
channel_id: slasClient.clientConfig.parameters.siteId, | ||
...(parameters.callbackURI && {callback_uri: parameters.callbackURI}), | ||
}; | ||
|
||
return slasClient.authorizePasswordlessCustomer({ | ||
headers: { | ||
Authorization: authHeaderIdSecret, | ||
}, | ||
parameters: { | ||
organizationId: slasClient.clientConfig.parameters.organizationId, | ||
}, | ||
body: tokenBody, | ||
}); | ||
} | ||
|
||
/** | ||
* Function to login user with passwordless login token | ||
* **Note** At the moment, passwordless is only supported on private client | ||
* @param slasClient a configured instance of the ShopperLogin SDK client. | ||
* @param credentials - the id and password and clientSecret (if applicable) to login with. | ||
* @param credentials.clientSecret? - secret associated with client ID | ||
* @param parameters - parameters to pass in the API calls. | ||
* @param parameters.callbackURI? - URI to send the passwordless login token to. Must be listed in your SLAS configuration. Required when mode is callback | ||
* @param parameters.pwdlessLoginToken - Passwordless login token | ||
* @param parameters.dnt? - Optional parameter to enable Do Not Track (DNT) for the user. | ||
* @returns Promise of Response or Object | ||
*/ | ||
export async function getPasswordLessAccessToken( | ||
slasClient: ShopperLogin<{ | ||
shortCode: string; | ||
organizationId: string; | ||
clientId: string; | ||
siteId: string; | ||
}>, | ||
credentials: { | ||
clientSecret: string; | ||
}, | ||
parameters: { | ||
pwdlessLoginToken: string; | ||
dnt?: string; | ||
} | ||
): Promise<TokenResponse> { | ||
const codeVerifier = createCodeVerifier(); | ||
const authHeaderIdSecret = `Basic ${stringToBase64( | ||
`${slasClient.clientConfig.parameters.clientId}:${credentials.clientSecret}` | ||
)}`; | ||
|
||
const tokenBody = { | ||
grant_type: 'client_credentials', | ||
hint: 'pwdless_login', | ||
pwdless_login_token: parameters.pwdlessLoginToken, | ||
code_verifier: codeVerifier, | ||
...(parameters.dnt && {dnt: parameters.dnt}), | ||
}; | ||
return slasClient.getPasswordLessAccessToken({ | ||
headers: { | ||
Authorization: authHeaderIdSecret, | ||
}, | ||
parameters: { | ||
organizationId: slasClient.clientConfig.parameters.organizationId, | ||
}, | ||
body: tokenBody, | ||
}); | ||
} |