@oneblink/apps-react 11.0.0-beta.8 → 11.0.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/apps/auth-service.d.ts +12 -5
- package/dist/apps/auth-service.js +16 -6
- package/dist/apps/auth-service.js.map +1 -1
- package/dist/apps/job-service.d.ts +34 -0
- package/dist/apps/job-service.js +45 -0
- package/dist/apps/job-service.js.map +1 -1
- package/dist/apps/mfa-service.d.ts +2 -2
- package/dist/apps/mfa-service.js +1 -1
- package/dist/apps/mfa-service.js.map +1 -1
- package/dist/apps/services/AWSCognitoClient.d.ts +3 -0
- package/dist/apps/services/AWSCognitoClient.js +58 -27
- package/dist/apps/services/AWSCognitoClient.js.map +1 -1
- package/dist/apps/services/cognito.d.ts +2 -2
- package/dist/apps/services/cognito.js.map +1 -1
- package/dist/apps/services/submit.js +10 -0
- package/dist/apps/services/submit.js.map +1 -1
- package/dist/components/mfa/MfaMethodRow.d.ts +4 -2
- package/dist/components/mfa/MfaMethodRow.js +7 -4
- package/dist/components/mfa/MfaMethodRow.js.map +1 -1
- package/dist/components/mfa/MultiFactorAuthentication.d.ts +2 -1
- package/dist/components/mfa/MultiFactorAuthentication.js +12 -11
- package/dist/components/mfa/MultiFactorAuthentication.js.map +1 -1
- package/dist/styles/barcode-scanner.scss +4 -0
- package/dist/styles.css +5 -0
- package/dist/styles.scss +1 -0
- package/dist/utils/mfa-requirement.d.ts +4 -4
- package/dist/utils/mfa-requirement.js +65 -16
- package/dist/utils/mfa-requirement.js.map +1 -1
- package/package.json +1 -1
|
@@ -34,23 +34,30 @@ export declare function init({ oAuthClientId }: {
|
|
|
34
34
|
}): void;
|
|
35
35
|
/**
|
|
36
36
|
* Determine if the current user is a OneBlink App User for a OneBlink Forms
|
|
37
|
-
* App. Returns `false` if the current user is not logged in
|
|
37
|
+
* App. Returns `false` if the current user is not logged in or not authorised
|
|
38
|
+
* for the given SAML groups.
|
|
38
39
|
*
|
|
39
40
|
* #### Example
|
|
40
41
|
*
|
|
41
42
|
* ```js
|
|
42
|
-
* const
|
|
43
|
-
*
|
|
43
|
+
* const isAuthorised = await authService.isAuthorised({
|
|
44
|
+
* formsAppId: 1,
|
|
45
|
+
* samlGroups: ['group1', 'group2'],
|
|
46
|
+
* })
|
|
44
47
|
* if (!isAuthorised) {
|
|
45
48
|
* // handle unauthorised user
|
|
46
49
|
* }
|
|
47
50
|
* ```
|
|
48
51
|
*
|
|
49
|
-
* @param formsAppId
|
|
52
|
+
* @param options.formsAppId
|
|
53
|
+
* @param options.samlGroups
|
|
50
54
|
* @param abortSignal
|
|
51
55
|
* @returns
|
|
52
56
|
*/
|
|
53
|
-
export declare function isAuthorised(formsAppId
|
|
57
|
+
export declare function isAuthorised({ formsAppId, samlGroups }: {
|
|
58
|
+
formsAppId: number;
|
|
59
|
+
samlGroups?: string[];
|
|
60
|
+
}, abortSignal?: AbortSignal): Promise<boolean>;
|
|
54
61
|
/**
|
|
55
62
|
* Get the current user's App User details for a OneBlink Forms App. Returns
|
|
56
63
|
* `undefined` if the current user is not logged in.
|
|
@@ -58,25 +58,35 @@ export function init({ oAuthClientId }) {
|
|
|
58
58
|
}
|
|
59
59
|
/**
|
|
60
60
|
* Determine if the current user is a OneBlink App User for a OneBlink Forms
|
|
61
|
-
* App. Returns `false` if the current user is not logged in
|
|
61
|
+
* App. Returns `false` if the current user is not logged in or not authorised
|
|
62
|
+
* for the given SAML groups.
|
|
62
63
|
*
|
|
63
64
|
* #### Example
|
|
64
65
|
*
|
|
65
66
|
* ```js
|
|
66
|
-
* const
|
|
67
|
-
*
|
|
67
|
+
* const isAuthorised = await authService.isAuthorised({
|
|
68
|
+
* formsAppId: 1,
|
|
69
|
+
* samlGroups: ['group1', 'group2'],
|
|
70
|
+
* })
|
|
68
71
|
* if (!isAuthorised) {
|
|
69
72
|
* // handle unauthorised user
|
|
70
73
|
* }
|
|
71
74
|
* ```
|
|
72
75
|
*
|
|
73
|
-
* @param formsAppId
|
|
76
|
+
* @param options.formsAppId
|
|
77
|
+
* @param options.samlGroups
|
|
74
78
|
* @param abortSignal
|
|
75
79
|
* @returns
|
|
76
80
|
*/
|
|
77
|
-
export async function isAuthorised(formsAppId, abortSignal) {
|
|
81
|
+
export async function isAuthorised({ formsAppId, samlGroups }, abortSignal) {
|
|
78
82
|
return getCurrentFormsAppUser(formsAppId, abortSignal)
|
|
79
|
-
.then(() =>
|
|
83
|
+
.then((userProfile) => {
|
|
84
|
+
// if no SAML groups are provided, then provided the user is authenticated then they're authorised
|
|
85
|
+
if (!samlGroups) {
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
return samlGroups.some((group) => userProfile === null || userProfile === void 0 ? void 0 : userProfile.groups.includes(group));
|
|
89
|
+
})
|
|
80
90
|
.catch((error) => {
|
|
81
91
|
if (error.status >= 400 && error.status < 500) {
|
|
82
92
|
return false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-service.js","sourceRoot":"","sources":["../../src/apps/auth-service.ts"],"names":[],"mappings":"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","sourcesContent":["import { MiscTypes } from '@oneblink/types'\nimport OneBlinkAppsError from './services/errors/oneBlinkAppsError'\nimport {\n getIdToken,\n getFormsKeyId,\n setFormsKeyToken,\n} from './services/forms-key'\nimport {\n init as initCognito,\n registerAuthListener,\n isLoggedIn,\n loginHostedUI,\n loginUsernamePassword,\n changePassword,\n forgotPassword,\n handleAuthentication,\n logoutHostedUI,\n logout as logoutCognito,\n getUserProfile,\n getUsername,\n getUserFriendlyName,\n} from './services/cognito'\nimport { getRequest, postRequest, HTTPError } from './services/fetch'\nimport tenants from './tenants'\nimport { getUserToken, setUserToken } from './services/user-token'\nimport utilsService from './services/utils'\n\nexport {\n registerAuthListener,\n loginHostedUI,\n loginUsernamePassword,\n handleAuthentication,\n logoutHostedUI,\n changePassword,\n forgotPassword,\n isLoggedIn,\n getIdToken,\n getUserProfile,\n getFormsKeyId,\n setFormsKeyToken,\n getUserToken,\n setUserToken,\n getUserFriendlyName,\n}\nexport type { LoginAttemptResponse } from './services/cognito'\nimport Sentry from './Sentry'\n\n/**\n * Log the current user out and remove an data stored locally by the user e.g.\n * drafts.\n *\n * #### Example\n *\n * ```js\n * await authService.logout()\n * ```\n */\nexport async function logout() {\n console.log('Logging out...')\n\n try {\n await utilsService.localForage.clear()\n } catch (error) {\n Sentry.captureException(error)\n console.warn('Could not clear localForage before logging out', error)\n }\n\n await logoutCognito()\n}\n\n/**\n * Initialize the service with required configuration. **This must be done\n * before using before some of the function in this service.**\n *\n * #### Example\n *\n * ```js\n * authService.init({\n * oAuthClientId: 'YOUR_OAUTH_CLIENT_ID',\n * })\n * ```\n *\n * @param options\n */\nexport function init({ oAuthClientId }: { oAuthClientId: string }) {\n initCognito({\n region: tenants.current.awsRegion,\n loginDomain: tenants.current.loginDomain,\n oAuthClientId,\n redirectUri: window.location.origin + '/callback',\n logoutUri: window.location.origin + '/logout',\n })\n\n const listener = () => {\n Sentry.setTag('username', getUsername() || undefined)\n }\n listener()\n registerAuthListener(listener)\n}\n\n/**\n * Determine if the current user is a OneBlink App User for a OneBlink Forms\n * App. Returns `false` if the current user is not logged in.\n *\n * #### Example\n *\n * ```js\n * const formsAppId = 1\n * const isAuthorised = await authService.isAuthorised(formsAppId)\n * if (!isAuthorised) {\n * // handle unauthorised user\n * }\n * ```\n *\n * @param formsAppId\n * @param abortSignal\n * @returns\n */\nexport async function isAuthorised(\n formsAppId: number,\n abortSignal?: AbortSignal,\n): Promise<boolean> {\n return getCurrentFormsAppUser(formsAppId, abortSignal)\n .then(() => true)\n .catch((error) => {\n if (error.status >= 400 && error.status < 500) {\n return false\n } else {\n Sentry.captureException(error)\n console.log(\n 'Could not determine if the current user has access to this forms app',\n error,\n )\n return false\n }\n })\n}\n\n/**\n * Get the current user's App User details for a OneBlink Forms App. Returns\n * `undefined` if the current user is not logged in.\n *\n * #### Example\n *\n * ```js\n * const formsAppId = 1\n * const formsAppUserDetails =\n * await authService.getCurrentFormsAppUser(formsAppId)\n * if (!formsAppUserDetails) {\n * // handle unauthorised user\n * }\n * ```\n *\n * @param formsAppId\n * @returns\n */\nexport async function getCurrentFormsAppUser(\n formsAppId: number,\n abortSignal?: AbortSignal,\n): Promise<\n | {\n userProfile?: MiscTypes.UserProfile\n formsAppId: number\n groups: string[]\n }\n | undefined\n> {\n if (getFormsKeyId()) {\n return {\n formsAppId,\n groups: [],\n }\n }\n\n const userProfile = getUserProfile()\n\n if (!userProfile) {\n return undefined\n }\n\n const url = `${tenants.current.apiOrigin}/forms-apps/${formsAppId}/my-forms-app-user`\n return await getRequest<{\n userProfile?: MiscTypes.UserProfile\n formsAppId: number\n groups: string[]\n }>(url, abortSignal)\n}\n\n/**\n * If the current user is not a Forms App User, this function will send a\n * request on behalf of the current user to the OneBlink Forms App\n * administrators to request access.\n *\n * #### Example\n *\n * ```js\n * const formsAppId = 1\n * await authService.requestAccess(formsAppId)\n * // Display a message to user indicating a request has been sent to the application administrators\n * ```\n *\n * @param formsAppId\n */\nexport async function requestAccess(formsAppId: number): Promise<void> {\n if (!isLoggedIn()) {\n throw new OneBlinkAppsError(\n 'You must login before requesting access to this application',\n {\n requiresLogin: true,\n },\n )\n }\n\n try {\n const url = `${tenants.current.apiOrigin}/forms-apps/${formsAppId}/request-access`\n await postRequest(url)\n } catch (error) {\n Sentry.captureException(error)\n console.warn('Error while requesting access to forms app', error)\n\n throw new OneBlinkAppsError(\n 'Sorry, we could not request access automatically right now, please try again. If the problem persists, please contact your administrator yourself.',\n {\n originalError: error as Error,\n title: 'Error Requesting Access',\n httpStatusCode: (error as HTTPError).status,\n },\n )\n }\n}\n\n/**\n * Allow a user to sign up to a forms app.\n *\n * #### Example\n *\n * ```js\n * await authService.signUp({\n * formsAppId: 1,\n * email: 'test@oneblink.io',\n * firstName: 'first',\n * lastName: 'last',\n * })\n * ```\n *\n * @param {formsAppId, email, generatePassword, firstName, lastName}\n * @returns\n */\n\nexport async function signUp({\n formsAppId,\n email,\n firstName,\n lastName,\n}: {\n formsAppId: number\n email: string\n firstName?: string\n lastName?: string\n}): Promise<void> {\n try {\n const url = `${tenants.current.apiOrigin}/forms-apps/${formsAppId}/sign-up`\n return await postRequest(url, {\n email,\n firstName,\n lastName,\n })\n } catch (error) {\n Sentry.captureException(error)\n console.warn('Error while calling sign-up to forms app', error)\n\n throw new OneBlinkAppsError(\n 'Sorry, we could not create you a account right now, please try again. If the problem persists, please contact your administrator yourself.',\n {\n originalError: error as Error,\n title: 'Error Signing up',\n httpStatusCode: (error as HTTPError).status,\n },\n )\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"auth-service.js","sourceRoot":"","sources":["../../src/apps/auth-service.ts"],"names":[],"mappings":"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","sourcesContent":["import { MiscTypes } from '@oneblink/types'\nimport OneBlinkAppsError from './services/errors/oneBlinkAppsError'\nimport {\n getIdToken,\n getFormsKeyId,\n setFormsKeyToken,\n} from './services/forms-key'\nimport {\n init as initCognito,\n registerAuthListener,\n isLoggedIn,\n loginHostedUI,\n loginUsernamePassword,\n changePassword,\n forgotPassword,\n handleAuthentication,\n logoutHostedUI,\n logout as logoutCognito,\n getUserProfile,\n getUsername,\n getUserFriendlyName,\n} from './services/cognito'\nimport { getRequest, postRequest, HTTPError } from './services/fetch'\nimport tenants from './tenants'\nimport { getUserToken, setUserToken } from './services/user-token'\nimport utilsService from './services/utils'\n\nexport {\n registerAuthListener,\n loginHostedUI,\n loginUsernamePassword,\n handleAuthentication,\n logoutHostedUI,\n changePassword,\n forgotPassword,\n isLoggedIn,\n getIdToken,\n getUserProfile,\n getFormsKeyId,\n setFormsKeyToken,\n getUserToken,\n setUserToken,\n getUserFriendlyName,\n}\nexport type { LoginAttemptResponse } from './services/cognito'\nimport Sentry from './Sentry'\n\n/**\n * Log the current user out and remove an data stored locally by the user e.g.\n * drafts.\n *\n * #### Example\n *\n * ```js\n * await authService.logout()\n * ```\n */\nexport async function logout() {\n console.log('Logging out...')\n\n try {\n await utilsService.localForage.clear()\n } catch (error) {\n Sentry.captureException(error)\n console.warn('Could not clear localForage before logging out', error)\n }\n\n await logoutCognito()\n}\n\n/**\n * Initialize the service with required configuration. **This must be done\n * before using before some of the function in this service.**\n *\n * #### Example\n *\n * ```js\n * authService.init({\n * oAuthClientId: 'YOUR_OAUTH_CLIENT_ID',\n * })\n * ```\n *\n * @param options\n */\nexport function init({ oAuthClientId }: { oAuthClientId: string }) {\n initCognito({\n region: tenants.current.awsRegion,\n loginDomain: tenants.current.loginDomain,\n oAuthClientId,\n redirectUri: window.location.origin + '/callback',\n logoutUri: window.location.origin + '/logout',\n })\n\n const listener = () => {\n Sentry.setTag('username', getUsername() || undefined)\n }\n listener()\n registerAuthListener(listener)\n}\n\n/**\n * Determine if the current user is a OneBlink App User for a OneBlink Forms\n * App. Returns `false` if the current user is not logged in or not authorised\n * for the given SAML groups.\n *\n * #### Example\n *\n * ```js\n * const isAuthorised = await authService.isAuthorised({\n * formsAppId: 1,\n * samlGroups: ['group1', 'group2'],\n * })\n * if (!isAuthorised) {\n * // handle unauthorised user\n * }\n * ```\n *\n * @param options.formsAppId\n * @param options.samlGroups\n * @param abortSignal\n * @returns\n */\nexport async function isAuthorised(\n { formsAppId, samlGroups }: { formsAppId: number; samlGroups?: string[] },\n abortSignal?: AbortSignal,\n): Promise<boolean> {\n return getCurrentFormsAppUser(formsAppId, abortSignal)\n .then((userProfile) => {\n // if no SAML groups are provided, then provided the user is authenticated then they're authorised\n if (!samlGroups) {\n return true\n }\n return samlGroups.some((group) => userProfile?.groups.includes(group))\n })\n .catch((error) => {\n if (error.status >= 400 && error.status < 500) {\n return false\n } else {\n Sentry.captureException(error)\n console.log(\n 'Could not determine if the current user has access to this forms app',\n error,\n )\n return false\n }\n })\n}\n\n/**\n * Get the current user's App User details for a OneBlink Forms App. Returns\n * `undefined` if the current user is not logged in.\n *\n * #### Example\n *\n * ```js\n * const formsAppId = 1\n * const formsAppUserDetails =\n * await authService.getCurrentFormsAppUser(formsAppId)\n * if (!formsAppUserDetails) {\n * // handle unauthorised user\n * }\n * ```\n *\n * @param formsAppId\n * @returns\n */\nexport async function getCurrentFormsAppUser(\n formsAppId: number,\n abortSignal?: AbortSignal,\n): Promise<\n | {\n userProfile?: MiscTypes.UserProfile\n formsAppId: number\n groups: string[]\n }\n | undefined\n> {\n if (getFormsKeyId()) {\n return {\n formsAppId,\n groups: [],\n }\n }\n\n const userProfile = getUserProfile()\n\n if (!userProfile) {\n return undefined\n }\n\n const url = `${tenants.current.apiOrigin}/forms-apps/${formsAppId}/my-forms-app-user`\n return await getRequest<{\n userProfile?: MiscTypes.UserProfile\n formsAppId: number\n groups: string[]\n }>(url, abortSignal)\n}\n\n/**\n * If the current user is not a Forms App User, this function will send a\n * request on behalf of the current user to the OneBlink Forms App\n * administrators to request access.\n *\n * #### Example\n *\n * ```js\n * const formsAppId = 1\n * await authService.requestAccess(formsAppId)\n * // Display a message to user indicating a request has been sent to the application administrators\n * ```\n *\n * @param formsAppId\n */\nexport async function requestAccess(formsAppId: number): Promise<void> {\n if (!isLoggedIn()) {\n throw new OneBlinkAppsError(\n 'You must login before requesting access to this application',\n {\n requiresLogin: true,\n },\n )\n }\n\n try {\n const url = `${tenants.current.apiOrigin}/forms-apps/${formsAppId}/request-access`\n await postRequest(url)\n } catch (error) {\n Sentry.captureException(error)\n console.warn('Error while requesting access to forms app', error)\n\n throw new OneBlinkAppsError(\n 'Sorry, we could not request access automatically right now, please try again. If the problem persists, please contact your administrator yourself.',\n {\n originalError: error as Error,\n title: 'Error Requesting Access',\n httpStatusCode: (error as HTTPError).status,\n },\n )\n }\n}\n\n/**\n * Allow a user to sign up to a forms app.\n *\n * #### Example\n *\n * ```js\n * await authService.signUp({\n * formsAppId: 1,\n * email: 'test@oneblink.io',\n * firstName: 'first',\n * lastName: 'last',\n * })\n * ```\n *\n * @param {formsAppId, email, generatePassword, firstName, lastName}\n * @returns\n */\n\nexport async function signUp({\n formsAppId,\n email,\n firstName,\n lastName,\n}: {\n formsAppId: number\n email: string\n firstName?: string\n lastName?: string\n}): Promise<void> {\n try {\n const url = `${tenants.current.apiOrigin}/forms-apps/${formsAppId}/sign-up`\n return await postRequest(url, {\n email,\n firstName,\n lastName,\n })\n } catch (error) {\n Sentry.captureException(error)\n console.warn('Error while calling sign-up to forms app', error)\n\n throw new OneBlinkAppsError(\n 'Sorry, we could not create you a account right now, please try again. If the problem persists, please contact your administrator yourself.',\n {\n originalError: error as Error,\n title: 'Error Signing up',\n httpStatusCode: (error as HTTPError).status,\n },\n )\n }\n}\n"]}
|
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
import { ensurePrefillFormDataExists } from './services/job-prefill';
|
|
2
2
|
import { SubmissionTypes } from '@oneblink/types';
|
|
3
|
+
export type JobListenerEvent = {
|
|
4
|
+
action: 'SUBMITTED';
|
|
5
|
+
jobId: string;
|
|
6
|
+
};
|
|
7
|
+
export type JobsListener = (event: JobListenerEvent) => unknown;
|
|
8
|
+
/**
|
|
9
|
+
* Register a listener function that will be called when jobs state should be
|
|
10
|
+
* updated after a submission.
|
|
11
|
+
*
|
|
12
|
+
* #### Example
|
|
13
|
+
*
|
|
14
|
+
* ```js
|
|
15
|
+
* const listener = ({ action, jobId }) => {
|
|
16
|
+
* if (action === 'SUBMITTED') {
|
|
17
|
+
* // remove job from local state...
|
|
18
|
+
* }
|
|
19
|
+
* }
|
|
20
|
+
* const deregister = jobService.registerJobsListener(listener)
|
|
21
|
+
*
|
|
22
|
+
* // When no longer needed, remember to deregister the listener
|
|
23
|
+
* deregister()
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @param listener
|
|
27
|
+
* @returns
|
|
28
|
+
*/
|
|
29
|
+
export declare function registerJobsListener(listener: JobsListener): () => void;
|
|
30
|
+
/**
|
|
31
|
+
* Notify listeners that a job has been submitted and should no longer appear in
|
|
32
|
+
* the jobs list.
|
|
33
|
+
*
|
|
34
|
+
* @param jobId
|
|
35
|
+
*/
|
|
36
|
+
export declare function notifyJobSubmitted(jobId: string): void;
|
|
3
37
|
/**
|
|
4
38
|
* Get Jobs for the current user. Jobs that are in the pending queue will be
|
|
5
39
|
* filtered out and Jobs with drafts will include the `draft` property.
|
package/dist/apps/job-service.js
CHANGED
|
@@ -8,6 +8,51 @@ import { isLoggedIn } from './auth-service';
|
|
|
8
8
|
import { getDrafts } from './draft-service';
|
|
9
9
|
import tenants from './tenants';
|
|
10
10
|
import Sentry from './Sentry';
|
|
11
|
+
const jobsListeners = [];
|
|
12
|
+
/**
|
|
13
|
+
* Register a listener function that will be called when jobs state should be
|
|
14
|
+
* updated after a submission.
|
|
15
|
+
*
|
|
16
|
+
* #### Example
|
|
17
|
+
*
|
|
18
|
+
* ```js
|
|
19
|
+
* const listener = ({ action, jobId }) => {
|
|
20
|
+
* if (action === 'SUBMITTED') {
|
|
21
|
+
* // remove job from local state...
|
|
22
|
+
* }
|
|
23
|
+
* }
|
|
24
|
+
* const deregister = jobService.registerJobsListener(listener)
|
|
25
|
+
*
|
|
26
|
+
* // When no longer needed, remember to deregister the listener
|
|
27
|
+
* deregister()
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* @param listener
|
|
31
|
+
* @returns
|
|
32
|
+
*/
|
|
33
|
+
export function registerJobsListener(listener) {
|
|
34
|
+
jobsListeners.push(listener);
|
|
35
|
+
return () => {
|
|
36
|
+
const index = jobsListeners.indexOf(listener);
|
|
37
|
+
if (index !== -1) {
|
|
38
|
+
jobsListeners.splice(index, 1);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function executeJobsListeners(event) {
|
|
43
|
+
for (const jobsListener of jobsListeners) {
|
|
44
|
+
jobsListener(event);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Notify listeners that a job has been submitted and should no longer appear in
|
|
49
|
+
* the jobs list.
|
|
50
|
+
*
|
|
51
|
+
* @param jobId
|
|
52
|
+
*/
|
|
53
|
+
export function notifyJobSubmitted(jobId) {
|
|
54
|
+
executeJobsListeners({ action: 'SUBMITTED', jobId });
|
|
55
|
+
}
|
|
11
56
|
async function removePendingSubmissions(jobList) {
|
|
12
57
|
// Get list of pending submissions, remove jobs that are in the pending queue
|
|
13
58
|
return getPendingQueueSubmissions().then((submissions) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"job-service.js","sourceRoot":"","sources":["../../src/apps/job-service.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAA;AAErC,OAAO,iBAAiB,MAAM,qCAAqC,CAAA;AACnE,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAChD,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAA;AACrE,OAAO,EAAE,2BAA2B,EAAE,MAAM,wBAAwB,CAAA;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,OAAO,MAAM,WAAW,CAAA;AAE/B,OAAO,MAAM,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"job-service.js","sourceRoot":"","sources":["../../src/apps/job-service.ts"],"names":[],"mappings":"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","sourcesContent":["import _orderBy from 'lodash.orderby'\n\nimport OneBlinkAppsError from './services/errors/oneBlinkAppsError'\nimport { searchRequest } from './services/fetch'\nimport { getPendingQueueSubmissions } from './services/pending-queue'\nimport { ensurePrefillFormDataExists } from './services/job-prefill'\nimport { isOffline } from './offline-service'\nimport { isLoggedIn } from './auth-service'\nimport { getDrafts } from './draft-service'\nimport tenants from './tenants'\nimport { SubmissionTypes } from '@oneblink/types'\nimport Sentry from './Sentry'\n\nexport type JobListenerEvent = {\n action: 'SUBMITTED'\n jobId: string\n}\n\nexport type JobsListener = (event: JobListenerEvent) => unknown\n\nconst jobsListeners: Array<JobsListener> = []\n\n/**\n * Register a listener function that will be called when jobs state should be\n * updated after a submission.\n *\n * #### Example\n *\n * ```js\n * const listener = ({ action, jobId }) => {\n * if (action === 'SUBMITTED') {\n * // remove job from local state...\n * }\n * }\n * const deregister = jobService.registerJobsListener(listener)\n *\n * // When no longer needed, remember to deregister the listener\n * deregister()\n * ```\n *\n * @param listener\n * @returns\n */\nexport function registerJobsListener(listener: JobsListener): () => void {\n jobsListeners.push(listener)\n\n return () => {\n const index = jobsListeners.indexOf(listener)\n if (index !== -1) {\n jobsListeners.splice(index, 1)\n }\n }\n}\n\nfunction executeJobsListeners(event: JobListenerEvent) {\n for (const jobsListener of jobsListeners) {\n jobsListener(event)\n }\n}\n\n/**\n * Notify listeners that a job has been submitted and should no longer appear in\n * the jobs list.\n *\n * @param jobId\n */\nexport function notifyJobSubmitted(jobId: string) {\n executeJobsListeners({ action: 'SUBMITTED', jobId })\n}\n\nasync function removePendingSubmissions(\n jobList: SubmissionTypes.FormsAppJob[],\n) {\n // Get list of pending submissions, remove jobs that are in the pending queue\n return getPendingQueueSubmissions().then((submissions) => {\n const unprocessedJobs = jobList.filter(\n (job) => !submissions.some((sub) => sub.jobId === job.id),\n )\n return unprocessedJobs\n })\n}\n\nasync function tagDrafts(\n jobList: SubmissionTypes.FormsAppJob[],\n abortSignal?: AbortSignal,\n) {\n return getDrafts(abortSignal).then((drafts) =>\n jobList.map((job) => {\n const draft = drafts.find((draft) => draft.jobId === job.id)\n return {\n ...job,\n draft,\n }\n }),\n )\n}\n\n/**\n * Get Jobs for the current user. Jobs that are in the pending queue will be\n * filtered out and Jobs with drafts will include the `draft` property.\n *\n * #### Example\n *\n * ```js\n * const formsAppId = 1\n * const label = 'Applications'\n * const jobs = await jobService.getJobs(formsAppId, label)\n * ```\n *\n * @param formsAppId\n * @param jobsLabel\n * @param abortSignal - Signal to abort the requests\n * @returns\n */\nexport async function getJobs(\n formsAppId: number,\n jobsLabel: string,\n abortSignal?: AbortSignal,\n): Promise<SubmissionTypes.FormsAppJob[]> {\n if (!isLoggedIn()) {\n return []\n }\n\n return searchRequest<{ jobs: Array<SubmissionTypes.FormsAppJob> }>(\n `${tenants.current.apiOrigin}/forms-apps/${formsAppId}/jobs`,\n {\n isSubmitted: false,\n },\n )\n .then((data) => removePendingSubmissions(data.jobs))\n .then((jobs) => tagDrafts(jobs, abortSignal))\n .then((jobList) =>\n _orderBy(\n jobList,\n ['details.priority', (job) => Date.parse(job.createdAt)],\n ['asc', 'asc'],\n ),\n )\n .catch((error) => {\n Sentry.captureException(error)\n console.warn('Error retrieving Jobs for forms app', error)\n\n if (isOffline()) {\n throw new OneBlinkAppsError(\n 'You are currently offline and do not have a local copy of this app available, please connect to the internet and try again',\n {\n originalError: error,\n isOffline: true,\n },\n )\n }\n\n switch (error.status) {\n case 401: {\n throw new OneBlinkAppsError(\n `You need to log in to see your ${jobsLabel}. Please login and try again.`,\n {\n originalError: error,\n requiresLogin: true,\n httpStatusCode: error.status,\n },\n )\n }\n case 403: {\n throw new OneBlinkAppsError(\n `You have not been granted access to ${jobsLabel}. Please contact your administrator to gain the correct level of access.`,\n {\n originalError: error,\n requiresAccessRequest: true,\n httpStatusCode: error.status,\n },\n )\n }\n case 400:\n case 404: {\n throw new OneBlinkAppsError(\n 'We could not find the application you are looking for. Please contact your administrator to ensure your application configuration has been completed successfully.',\n {\n originalError: error,\n title: 'Unknown Application',\n httpStatusCode: error.status,\n },\n )\n }\n default: {\n throw new OneBlinkAppsError(\n 'An unknown error has occurred. Please contact support if the problem persists.',\n {\n originalError: error,\n httpStatusCode: error.status,\n },\n )\n }\n }\n })\n}\n\nexport { ensurePrefillFormDataExists }\n"]}
|
|
@@ -2,8 +2,8 @@ import { MiscTypes } from '@oneblink/types';
|
|
|
2
2
|
import { getMfaSettings } from './services/cognito';
|
|
3
3
|
export { getMfaSettings };
|
|
4
4
|
export { updateUserPhoneNumber, removeUserPhoneNumber, verifyUserPhoneNumber, disableMfaMethod, setPreferredMfaMethod, setupMfaAuthenticatorApp, setupSmsMfa, generateMfaAuthenticatorAppQrCodeUrl, DEFAULT_MFA_SETTINGS, } from './services/cognito';
|
|
5
|
-
export type { MfaMethod, MfaSettings } from './services/cognito';
|
|
6
|
-
export { isMfaRequired, mfaRequirementToSelectedMethods, mfaSelectedMethodsToMfaRequirement, formatMfaRequirementLabel,
|
|
5
|
+
export type { MfaMethod, MfaSettings, LoggedInMfaMethod } from './services/cognito';
|
|
6
|
+
export { isMfaRequired, mfaRequirementToSelectedMethods, mfaSelectedMethodsToMfaRequirement, formatMfaRequirementLabel, userMeetsMfaRequirement, formatMfaSetupRequiredMessage, formatMfaMethodRequirementMessage, isMfaMethodUsedForLogin, } from '../utils/mfa-requirement';
|
|
7
7
|
export type { MfaRequirementMethod } from '../utils/mfa-requirement';
|
|
8
8
|
export type MfaRequirementCheckResult = {
|
|
9
9
|
mfaSettings: Awaited<ReturnType<typeof getMfaSettings>>;
|
package/dist/apps/mfa-service.js
CHANGED
|
@@ -2,7 +2,7 @@ import { getMfaSettings } from './services/cognito';
|
|
|
2
2
|
import { userMeetsMfaRequirement } from '../utils/mfa-requirement';
|
|
3
3
|
export { getMfaSettings };
|
|
4
4
|
export { updateUserPhoneNumber, removeUserPhoneNumber, verifyUserPhoneNumber, disableMfaMethod, setPreferredMfaMethod, setupMfaAuthenticatorApp, setupSmsMfa, generateMfaAuthenticatorAppQrCodeUrl, DEFAULT_MFA_SETTINGS, } from './services/cognito';
|
|
5
|
-
export { isMfaRequired, mfaRequirementToSelectedMethods, mfaSelectedMethodsToMfaRequirement, formatMfaRequirementLabel,
|
|
5
|
+
export { isMfaRequired, mfaRequirementToSelectedMethods, mfaSelectedMethodsToMfaRequirement, formatMfaRequirementLabel, userMeetsMfaRequirement, formatMfaSetupRequiredMessage, formatMfaMethodRequirementMessage, isMfaMethodUsedForLogin, } from '../utils/mfa-requirement';
|
|
6
6
|
/**
|
|
7
7
|
* Check if the current user meets an MFA requirement.
|
|
8
8
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mfa-service.js","sourceRoot":"","sources":["../../src/apps/mfa-service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAA;AAElE,OAAO,EAAE,cAAc,EAAE,CAAA;AACzB,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,gBAAgB,EAChB,qBAAqB,EACrB,wBAAwB,EACxB,WAAW,EACX,oCAAoC,EACpC,oBAAoB,GACrB,MAAM,oBAAoB,CAAA;AAE3B,OAAO,EACL,aAAa,EACb,+BAA+B,EAC/B,kCAAkC,EAClC,yBAAyB,EACzB
|
|
1
|
+
{"version":3,"file":"mfa-service.js","sourceRoot":"","sources":["../../src/apps/mfa-service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAA;AAElE,OAAO,EAAE,cAAc,EAAE,CAAA;AACzB,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,gBAAgB,EAChB,qBAAqB,EACrB,wBAAwB,EACxB,WAAW,EACX,oCAAoC,EACpC,oBAAoB,GACrB,MAAM,oBAAoB,CAAA;AAE3B,OAAO,EACL,aAAa,EACb,+BAA+B,EAC/B,kCAAkC,EAClC,yBAAyB,EACzB,uBAAuB,EACvB,6BAA6B,EAC7B,iCAAiC,EACjC,uBAAuB,GACxB,MAAM,0BAA0B,CAAA;AAQjC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,cAAoD;IAEpD,MAAM,WAAW,GAAG,MAAM,cAAc,EAAE,CAAA;IAE1C,OAAO;QACL,WAAW;QACX,uBAAuB,EAAE,uBAAuB,CAC9C,cAAc,EACd,WAAW,CACZ;KACF,CAAA;AACH,CAAC","sourcesContent":["import { MiscTypes } from '@oneblink/types'\r\nimport { getMfaSettings } from './services/cognito'\r\nimport { userMeetsMfaRequirement } from '../utils/mfa-requirement'\r\n\r\nexport { getMfaSettings }\r\nexport {\r\n updateUserPhoneNumber,\r\n removeUserPhoneNumber,\r\n verifyUserPhoneNumber,\r\n disableMfaMethod,\r\n setPreferredMfaMethod,\r\n setupMfaAuthenticatorApp,\r\n setupSmsMfa,\r\n generateMfaAuthenticatorAppQrCodeUrl,\r\n DEFAULT_MFA_SETTINGS,\r\n} from './services/cognito'\r\nexport type { MfaMethod, MfaSettings, LoggedInMfaMethod } from './services/cognito'\r\nexport {\r\n isMfaRequired,\r\n mfaRequirementToSelectedMethods,\r\n mfaSelectedMethodsToMfaRequirement,\r\n formatMfaRequirementLabel,\r\n userMeetsMfaRequirement,\r\n formatMfaSetupRequiredMessage,\r\n formatMfaMethodRequirementMessage,\r\n isMfaMethodUsedForLogin,\r\n} from '../utils/mfa-requirement'\r\nexport type { MfaRequirementMethod } from '../utils/mfa-requirement'\r\n\r\nexport type MfaRequirementCheckResult = {\r\n mfaSettings: Awaited<ReturnType<typeof getMfaSettings>>\r\n userMeetsMfaRequirement: boolean\r\n}\r\n\r\n/**\r\n * Check if the current user meets an MFA requirement.\r\n *\r\n * #### Example\r\n *\r\n * ```js\r\n * const { mfaSettings, userMeetsMfaRequirement } =\r\n * await mfaService.checkIsMfaEnabled('any')\r\n * if (userMeetsMfaRequirement) {\r\n * // User has met the MFA requirement\r\n * } else {\r\n * // Prompt user to set up MFA\r\n * }\r\n * ```\r\n *\r\n * @returns\r\n */\r\nexport async function checkIsMfaEnabled(\r\n mfaRequirement: MiscTypes.MfaRequirement | undefined,\r\n): Promise<MfaRequirementCheckResult> {\r\n const mfaSettings = await getMfaSettings()\r\n\r\n return {\r\n mfaSettings,\r\n userMeetsMfaRequirement: userMeetsMfaRequirement(\r\n mfaRequirement,\r\n mfaSettings,\r\n ),\r\n }\r\n}\r\n"]}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { AuthenticationResultType, CognitoIdentityProviderClient, InitiateAuthResponse } from '@aws-sdk/client-cognito-identity-provider';
|
|
2
2
|
export type MfaMethod = 'authenticator' | 'sms';
|
|
3
|
+
export type LoggedInMfaMethod = 'SOFTWARE_TOKEN_MFA' | 'SMS_MFA' | 'NO_MFA_ENABLED';
|
|
3
4
|
export type MfaSettings = {
|
|
5
|
+
loggedInWithMfaMethod: LoggedInMfaMethod;
|
|
4
6
|
authenticator: {
|
|
5
7
|
enabled: boolean;
|
|
6
8
|
preferred: boolean;
|
|
@@ -13,6 +15,7 @@ export type MfaSettings = {
|
|
|
13
15
|
};
|
|
14
16
|
};
|
|
15
17
|
export declare const DEFAULT_MFA_SETTINGS: MfaSettings;
|
|
18
|
+
export declare function resolveLoggedInMfaMethod(idToken: string | undefined): LoggedInMfaMethod;
|
|
16
19
|
export declare function resolveMfaPreferredFlags({ authenticatorEnabled, smsEnabled, preferredMfaSetting, }: {
|
|
17
20
|
authenticatorEnabled: boolean;
|
|
18
21
|
smsEnabled: boolean;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { AssociateSoftwareTokenCommand, ChangePasswordCommand, CognitoIdentityProviderClient, ConfirmForgotPasswordCommand, DeleteUserAttributesCommand, GetUserCommand, GlobalSignOutCommand, InitiateAuthCommand, RespondToAuthChallengeCommand, SetUserMFAPreferenceCommand, UpdateUserAttributesCommand, VerifySoftwareTokenCommand, VerifyUserAttributeCommand, } from '@aws-sdk/client-cognito-identity-provider';
|
|
1
|
+
import { AssociateSoftwareTokenCommand, ChangePasswordCommand, CognitoIdentityProviderClient, ConfirmForgotPasswordCommand, DeleteUserAttributesCommand, GetUserCommand, GlobalSignOutCommand, InitiateAuthCommand, RespondToAuthChallengeCommand, SetUserMFAPreferenceCommand, UpdateUserAttributesCommand, VerifySoftwareTokenCommand, VerifyUserAttributeCommand, NotAuthorizedException, } from '@aws-sdk/client-cognito-identity-provider';
|
|
2
|
+
import { jwtDecode } from 'jwt-decode';
|
|
2
3
|
import Sentry from '../Sentry';
|
|
3
4
|
import { OneBlinkAppsError } from '..';
|
|
4
5
|
export const DEFAULT_MFA_SETTINGS = {
|
|
6
|
+
loggedInWithMfaMethod: 'NO_MFA_ENABLED',
|
|
5
7
|
authenticator: { enabled: false, preferred: false },
|
|
6
8
|
sms: {
|
|
7
9
|
enabled: false,
|
|
@@ -10,6 +12,23 @@ export const DEFAULT_MFA_SETTINGS = {
|
|
|
10
12
|
isPhoneNumberVerified: false,
|
|
11
13
|
},
|
|
12
14
|
};
|
|
15
|
+
export function resolveLoggedInMfaMethod(idToken) {
|
|
16
|
+
if (idToken) {
|
|
17
|
+
try {
|
|
18
|
+
const payload = jwtDecode(idToken);
|
|
19
|
+
switch (payload.mfa_method) {
|
|
20
|
+
case 'SOFTWARE_TOKEN_MFA':
|
|
21
|
+
case 'SMS_MFA':
|
|
22
|
+
return payload.mfa_method;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
console.warn('Error while decoding id token for logged in MFA method', error);
|
|
27
|
+
Sentry.captureException(error);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return 'NO_MFA_ENABLED';
|
|
31
|
+
}
|
|
13
32
|
export function resolveMfaPreferredFlags({ authenticatorEnabled, smsEnabled, preferredMfaSetting, }) {
|
|
14
33
|
const cognitoAuthenticatorPreferred = preferredMfaSetting === 'SOFTWARE_TOKEN_MFA';
|
|
15
34
|
const cognitoSmsPreferred = preferredMfaSetting === 'SMS_MFA';
|
|
@@ -387,32 +406,44 @@ export default class AWSCognitoClient {
|
|
|
387
406
|
if (!accessToken) {
|
|
388
407
|
return DEFAULT_MFA_SETTINGS;
|
|
389
408
|
}
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
409
|
+
try {
|
|
410
|
+
const user = await this.cognitoIdentityProviderClient.send(new GetUserCommand({
|
|
411
|
+
AccessToken: accessToken,
|
|
412
|
+
}), { abortSignal });
|
|
413
|
+
const mfaList = user.UserMFASettingList || [];
|
|
414
|
+
const preferredMfaSetting = user.PreferredMfaSetting;
|
|
415
|
+
const phoneNumber = (_b = (_a = user.UserAttributes) === null || _a === void 0 ? void 0 : _a.find((attribute) => attribute.Name === 'phone_number')) === null || _b === void 0 ? void 0 : _b.Value;
|
|
416
|
+
const isPhoneNumberVerified = ((_d = (_c = user.UserAttributes) === null || _c === void 0 ? void 0 : _c.find((attribute) => attribute.Name === 'phone_number_verified')) === null || _d === void 0 ? void 0 : _d.Value) === 'true';
|
|
417
|
+
const authenticatorEnabled = mfaList.includes('SOFTWARE_TOKEN_MFA');
|
|
418
|
+
const smsEnabled = mfaList.includes('SMS_MFA');
|
|
419
|
+
const { authenticatorPreferred, smsPreferred } = resolveMfaPreferredFlags({
|
|
420
|
+
authenticatorEnabled,
|
|
421
|
+
smsEnabled,
|
|
422
|
+
preferredMfaSetting,
|
|
423
|
+
});
|
|
424
|
+
const loggedInWithMfaMethod = resolveLoggedInMfaMethod(this._getIdToken());
|
|
425
|
+
return {
|
|
426
|
+
loggedInWithMfaMethod,
|
|
427
|
+
authenticator: {
|
|
428
|
+
enabled: authenticatorEnabled,
|
|
429
|
+
preferred: authenticatorPreferred,
|
|
430
|
+
},
|
|
431
|
+
sms: {
|
|
432
|
+
enabled: smsEnabled,
|
|
433
|
+
preferred: smsPreferred,
|
|
434
|
+
phoneNumber,
|
|
435
|
+
isPhoneNumberVerified,
|
|
436
|
+
},
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
catch (error) {
|
|
440
|
+
if (error instanceof NotAuthorizedException) {
|
|
441
|
+
console.warn('User session has expired, returning default MFA settings', error);
|
|
442
|
+
this._removeAuthenticationResult();
|
|
443
|
+
return DEFAULT_MFA_SETTINGS;
|
|
444
|
+
}
|
|
445
|
+
throw error;
|
|
446
|
+
}
|
|
416
447
|
}
|
|
417
448
|
async updateUserPhoneNumber(phoneNumber) {
|
|
418
449
|
const accessToken = await this.getAccessToken();
|