@atlasauth/angular 0.15.1 → 0.16.1
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/CHANGELOG.md +8 -0
- package/dist/esm2022/lib/components/attempt-flow.component.mjs +88 -13
- package/dist/esm2022/lib/components/email-link.component.mjs +103 -0
- package/dist/esm2022/lib/components/flow-controller.mjs +6 -3
- package/dist/esm2022/lib/components/sign-in.component.mjs +22 -5
- package/dist/esm2022/lib/components/sign-up.component.mjs +24 -5
- package/dist/esm2022/lib/i18n.mjs +19 -1
- package/dist/esm2022/lib/version.mjs +2 -2
- package/dist/esm2022/public-api.mjs +2 -1
- package/dist/fesm2022/atlasauth-angular.mjs +248 -23
- package/dist/fesm2022/atlasauth-angular.mjs.map +1 -1
- package/dist/lib/components/attempt-flow.component.d.ts +8 -1
- package/dist/lib/components/email-link.component.d.ts +26 -0
- package/dist/lib/components/sign-in.component.d.ts +4 -0
- package/dist/lib/components/sign-up.component.d.ts +4 -0
- package/dist/lib/version.d.ts +1 -1
- package/dist/public-api.d.ts +1 -0
- package/package.json +4 -4
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, signal, inject, PLATFORM_ID, computed, Injectable, TemplateRef, ViewContainerRef, Directive, Input, ElementRef, Renderer2, EventEmitter, Output, ChangeDetectionStrategy, Component, ChangeDetectorRef, effect, untracked, DestroyRef, makeEnvironmentProviders, ENVIRONMENT_INITIALIZER, NgModule } from '@angular/core';
|
|
2
|
+
import { InjectionToken, signal, inject, PLATFORM_ID, computed, Injectable, TemplateRef, ViewContainerRef, Directive, Input, ElementRef, Renderer2, EventEmitter, Output, ChangeDetectionStrategy, Component, ChangeDetectorRef, afterNextRender, effect, untracked, DestroyRef, makeEnvironmentProviders, ENVIRONMENT_INITIALIZER, NgModule } from '@angular/core';
|
|
3
3
|
import { isPlatformBrowser, DOCUMENT } from '@angular/common';
|
|
4
4
|
import { toSignal } from '@angular/core/rxjs-interop';
|
|
5
5
|
import { BehaviorSubject, Subject, combineLatest, firstValueFrom } from 'rxjs';
|
|
6
6
|
import { map, distinctUntilChanged, filter, take } from 'rxjs/operators';
|
|
7
|
-
import { createOrganizationAuditLog, POLICY_STRINGS, TokenCache, SignOutNotifier, resolveFrontendApi, withDevBrowser, catalogLocale, configureReferralCapture, FapiClient, SignOutGuard, localizedErrorMessage, reauthenticate, getTemplateToken, getProviderToken, signOutReasonFromClient, readRedirectResult, completeOAuthPopupLanding, mapOAuthPopupPayload, stripRedirectParams, closeOAuthPopupAfterSignIn, SDK_HEADER, sdkHeaderValue, reportSdkAdvisory, readExpiry, msUntilRefresh, policyTranslator, injectPolicyStyles, mountPolicyClickwrap, mountPolicyConsent, controllerForPending, mountPolicyAcceptStep, joinTitles, formatPolicyDate, PolicyGateController, groupSetupKey, enrollmentSubmitKey, nextStep, awaitingSignUpLink, canDownloadRecoveryCodes, copyRecoveryCodes, downloadRecoveryCodes, createCaptchaController, atlasCaptchaLabels, PolicyAcceptanceController, flowFromPending, initialFlow, createMfaEnrollment, createPasskeySignInController, startSignInWithAtlas, mfaChoicesFrom, fetchInstanceSettings, fetchLastSignInMethod, offeredFirstFactors, preparePasswordHoldProof, prepareFactor, signInCaptchaOptions, flowNeedsCaptcha, planFirstFactor, attemptPasswordHoldProof, advanceWithCaptcha, loadPolicies, createSignUp, prepareSecondFactorCode, resendSignUpVerification, createPasskeySignUp, finishPasskeySignUp, pendingRecoveryCodes, acknowledgeRecoveryCodes, pendingExistingAccountNotice, acknowledgeExistingAccount, shouldKeepPolling, pollAttempt, lastUsedMethodLabel, signUp, passkeysSupported, confirmPolicies, existingAccountResetUrl, signUpProvedByLink, signInAfterProofUrl, awaitingPasskey, listCibaRequests, getCibaPin, decideCibaRequest, setCibaPin, clearCibaPin, OrganizationProfileController, describeAuditAction, actorFromClaims } from '@atlasauth/js';
|
|
7
|
+
import { createOrganizationAuditLog, POLICY_STRINGS, TokenCache, SignOutNotifier, resolveFrontendApi, withDevBrowser, catalogLocale, configureReferralCapture, FapiClient, SignOutGuard, localizedErrorMessage, reauthenticate, getTemplateToken, getProviderToken, signOutReasonFromClient, readRedirectResult, completeOAuthPopupLanding, mapOAuthPopupPayload, stripRedirectParams, closeOAuthPopupAfterSignIn, SDK_HEADER, sdkHeaderValue, reportSdkAdvisory, readExpiry, msUntilRefresh, policyTranslator, injectPolicyStyles, mountPolicyClickwrap, mountPolicyConsent, controllerForPending, mountPolicyAcceptStep, joinTitles, formatPolicyDate, PolicyGateController, enrollmentOptionKey, groupSetupKey, enrollmentSubmitKey, nextStep, awaitingSignUpLink, createEmailLinkConfirmation, canDownloadRecoveryCodes, copyRecoveryCodes, downloadRecoveryCodes, createCaptchaController, atlasCaptchaLabels, PolicyAcceptanceController, flowFromPending, initialFlow, createMfaEnrollment, createPasskeySignInController, startSignInWithAtlas, mfaChoicesFrom, fetchInstanceSettings, fetchLastSignInMethod, offeredFirstFactors, preparePasswordHoldProof, prepareFactor, signInCaptchaOptions, flowNeedsCaptcha, planFirstFactor, attemptPasswordHoldProof, advanceWithCaptcha, loadPolicies, createSignUp, prepareSecondFactorCode, resendSignUpVerification, createPasskeySignUp, finishPasskeySignUp, pendingRecoveryCodes, acknowledgeRecoveryCodes, pendingExistingAccountNotice, acknowledgeExistingAccount, shouldKeepPolling, pollAttempt, emailLinkFromUrl, lastUsedMethodLabel, signUp, passkeysSupported, confirmPolicies, existingAccountResetUrl, signUpProvedByLink, signInAfterProofUrl, awaitingPasskey, listCibaRequests, getCibaPin, decideCibaRequest, setCibaPin, clearCibaPin, OrganizationProfileController, describeAuditAction, actorFromClaims } from '@atlasauth/js';
|
|
8
8
|
export { FapiClient, SIGN_OUT_EVENT, SignOutError, advance, flowFromPending, getProviderToken, initialFlow, onAtlasSignOut, pollAttempt, prepareFactor, requestForStep, shouldKeepPolling } from '@atlasauth/js';
|
|
9
9
|
import { evaluate } from '@atlasauth/authz';
|
|
10
10
|
export { evaluate, hasFromClaims } from '@atlasauth/authz';
|
|
@@ -266,6 +266,23 @@ const EN_US = {
|
|
|
266
266
|
'mfa.enrollChoose': 'Set up a second step for signing in.',
|
|
267
267
|
'mfa.enrollTotpOption': 'Use an authenticator app',
|
|
268
268
|
'mfa.enrollSmsOption': 'Use text messages',
|
|
269
|
+
'link.title': "Confirm it's you",
|
|
270
|
+
'link.matchCodeHint': 'Opening the link on another device? Enter this code there.',
|
|
271
|
+
'link.checking': 'Checking your link…',
|
|
272
|
+
'link.enterCodeHelp': 'Enter the code shown on the device where you started.',
|
|
273
|
+
'link.codeLabel': 'Code',
|
|
274
|
+
'link.confirm': 'Confirm',
|
|
275
|
+
'link.confirmed': 'Confirmed. You can close this tab and go back to where you started.',
|
|
276
|
+
'link.invalid': 'This link is no longer valid. Go back to where you started and ask for a new one.',
|
|
277
|
+
'mfa.enrollHotpOption': 'Use a counter-based code generator',
|
|
278
|
+
'mfa.enrollYubikeyOption': 'Use a YubiKey',
|
|
279
|
+
'mfa.enrollDuoOption': 'Use Duo',
|
|
280
|
+
'mfa.enrollPasskeyOption': 'Use a passkey',
|
|
281
|
+
'mfa.yubikeyLabel': 'Touch your YubiKey',
|
|
282
|
+
'mfa.enrollDuoHelp': 'Open Duo and approve the request, then come back and continue.',
|
|
283
|
+
'mfa.enrollDuoOpen': 'Open Duo',
|
|
284
|
+
'mfa.enrollPasskeyHelp': 'Create a passkey on this device to use as your second step. It must ask for your PIN or biometrics.',
|
|
285
|
+
'mfa.enrollPasskeyCreate': 'Create passkey',
|
|
269
286
|
'mfa.enrollScan': 'Scan this QR code with your authenticator app, or enter the setup key.',
|
|
270
287
|
'mfa.enrollQrAlt': 'QR code for your authenticator app',
|
|
271
288
|
'mfa.enrollSetupKey': 'Setup key',
|
|
@@ -364,6 +381,7 @@ const EN_US = {
|
|
|
364
381
|
'error.form_password_reused': 'Your new password must not match any of your last {history_count} passwords.',
|
|
365
382
|
'error.password_expired': 'Your password has expired. Reset it to continue.',
|
|
366
383
|
'error.email_not_verified': 'Your email address is not verified yet. Verify it before signing in with your password.',
|
|
384
|
+
'error.mfa_setup_unavailable': "This account needs 2-Step Verification, but it can't be set up here. Contact the app's support to continue.",
|
|
367
385
|
'error.sign_in_token_invalid': 'That sign-in token is invalid or has expired.',
|
|
368
386
|
'error.too_many_attempts': 'Too many failed attempts. Try again later.',
|
|
369
387
|
'error.too_many_requests': 'Too many requests. Please try again later.',
|
|
@@ -403,7 +421,7 @@ function withFallback(locale) {
|
|
|
403
421
|
}
|
|
404
422
|
|
|
405
423
|
/** This package's version, sent as `X-Atlas-SDK` (kept in step with package.json by a test). */
|
|
406
|
-
const ATLAS_ANGULAR_VERSION = '0.
|
|
424
|
+
const ATLAS_ANGULAR_VERSION = '0.16.1';
|
|
407
425
|
const ATLAS_ANGULAR_SDK = { name: '@atlasauth/angular', version: ATLAS_ANGULAR_VERSION };
|
|
408
426
|
|
|
409
427
|
/**
|
|
@@ -1481,6 +1499,8 @@ class AttemptFlowComponent {
|
|
|
1481
1499
|
/** `FlowState.sessionKept`: whether this browser kept the session the sign-in created. */
|
|
1482
1500
|
sessionKept = undefined;
|
|
1483
1501
|
titleKey = 'signIn.title';
|
|
1502
|
+
/** Sign-up only: the sign-in link beside the code step's "an account already uses this email". */
|
|
1503
|
+
signInHref = null;
|
|
1484
1504
|
/**
|
|
1485
1505
|
* The sign-in captcha, drawn above the submit button on the identifier step
|
|
1486
1506
|
* (an always-on sign-in captcha) and on the challenge step the server demands
|
|
@@ -1536,6 +1556,8 @@ class AttemptFlowComponent {
|
|
|
1536
1556
|
* while the flow polls, and offers a resend (`resend`).
|
|
1537
1557
|
*/
|
|
1538
1558
|
emailVerification = 'code';
|
|
1559
|
+
/** `FlowState.matchCode`: shown while a mailed link waits, to type if it's opened on another device. */
|
|
1560
|
+
matchCode = null;
|
|
1539
1561
|
resend = new EventEmitter();
|
|
1540
1562
|
/** The user declined a policy the sign-in was waiting on (`needs_policy_acceptance`): cancel the attempt. */
|
|
1541
1563
|
policyDeclined = new EventEmitter();
|
|
@@ -1583,6 +1605,12 @@ class AttemptFlowComponent {
|
|
|
1583
1605
|
resendEnrollment() {
|
|
1584
1606
|
void this.enrollment?.resend();
|
|
1585
1607
|
}
|
|
1608
|
+
optionKey(method) {
|
|
1609
|
+
return enrollmentOptionKey(method);
|
|
1610
|
+
}
|
|
1611
|
+
showMatchCode() {
|
|
1612
|
+
return !!this.matchCode && (this.step().kind === 'collect_email_code' || this.linkSentText() !== null);
|
|
1613
|
+
}
|
|
1586
1614
|
otherMethods(state) {
|
|
1587
1615
|
return state.options.filter((m) => m !== state.method);
|
|
1588
1616
|
}
|
|
@@ -1604,6 +1632,9 @@ class AttemptFlowComponent {
|
|
|
1604
1632
|
formErrors() {
|
|
1605
1633
|
return this.errors.filter((error) => !error.param);
|
|
1606
1634
|
}
|
|
1635
|
+
signInLink(error) {
|
|
1636
|
+
return this.step().kind === 'collect_email_code' && error.code === 'IDENTIFIER_EXISTS' ? this.signInHref : null;
|
|
1637
|
+
}
|
|
1607
1638
|
fieldErrorsFor(name) {
|
|
1608
1639
|
return this.errors.filter((error) => error.param === name);
|
|
1609
1640
|
}
|
|
@@ -1730,12 +1761,17 @@ class AttemptFlowComponent {
|
|
|
1730
1761
|
}
|
|
1731
1762
|
}
|
|
1732
1763
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AttemptFlowComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1733
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: AttemptFlowComponent, isStandalone: true, selector: "atlas-attempt-flow", inputs: { attempt: "attempt", busy: "busy", errors: "errors", sessionKept: "sessionKept", titleKey: "titleKey", captcha: "captcha", firstFactors: "firstFactors", preparedFactor: "preparedFactor", passwordHold: "passwordHold", holdProof: "holdProof", offerEmailSecondFactor: "offerEmailSecondFactor", emailedSecondFactor: "emailedSecondFactor", offerSmsSecondFactor: "offerSmsSecondFactor", textedSecondFactor: "textedSecondFactor", enrollment: "enrollment", enrollmentState: "enrollmentState", emailVerification: "emailVerification" }, outputs: { submitFlow: "submitFlow", chooseFactor: "chooseFactor", usePassword: "usePassword", emailSecondFactor: "emailSecondFactor", smsSecondFactor: "smsSecondFactor", resend: "resend", policyDeclined: "policyDeclined" }, ngImport: i0, template: `
|
|
1764
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: AttemptFlowComponent, isStandalone: true, selector: "atlas-attempt-flow", inputs: { attempt: "attempt", busy: "busy", errors: "errors", sessionKept: "sessionKept", titleKey: "titleKey", signInHref: "signInHref", captcha: "captcha", firstFactors: "firstFactors", preparedFactor: "preparedFactor", passwordHold: "passwordHold", holdProof: "holdProof", offerEmailSecondFactor: "offerEmailSecondFactor", emailedSecondFactor: "emailedSecondFactor", offerSmsSecondFactor: "offerSmsSecondFactor", textedSecondFactor: "textedSecondFactor", enrollment: "enrollment", enrollmentState: "enrollmentState", emailVerification: "emailVerification", matchCode: "matchCode" }, outputs: { submitFlow: "submitFlow", chooseFactor: "chooseFactor", usePassword: "usePassword", emailSecondFactor: "emailSecondFactor", smsSecondFactor: "smsSecondFactor", resend: "resend", policyDeclined: "policyDeclined" }, ngImport: i0, template: `
|
|
1734
1765
|
<div [class]="cls('card', 'atlas-card')">
|
|
1735
1766
|
<h1 [class]="cls('headerTitle', 'atlas-title')">{{ t(titleKey) }}</h1>
|
|
1736
1767
|
|
|
1737
1768
|
@for (error of formErrors(); track error.code) {
|
|
1738
|
-
<p [class]="cls('formFieldError', 'atlas-error')" role="alert">
|
|
1769
|
+
<p [class]="cls('formFieldError', 'atlas-error')" role="alert">
|
|
1770
|
+
{{ errorText(error) }}
|
|
1771
|
+
@if (signInLink(error); as href) {
|
|
1772
|
+
<a class="atlas-link" [href]="href">{{ t('signIn.title') }}</a>
|
|
1773
|
+
}
|
|
1774
|
+
</p>
|
|
1739
1775
|
}
|
|
1740
1776
|
|
|
1741
1777
|
<form (submit)="onSubmit($event)">
|
|
@@ -1760,6 +1796,9 @@ class AttemptFlowComponent {
|
|
|
1760
1796
|
{{ t('signIn.resendLink') }}
|
|
1761
1797
|
</button>
|
|
1762
1798
|
}
|
|
1799
|
+
@if (showMatchCode()) {
|
|
1800
|
+
<p class="atlas-text" data-atlas="link-match-code">{{ t('link.matchCodeHint') }} <strong><code>{{ matchCode }}</code></strong></p>
|
|
1801
|
+
}
|
|
1763
1802
|
@if (enrolling() && enrollmentState; as enrol) {
|
|
1764
1803
|
@if (enrol.method === null) {
|
|
1765
1804
|
<p class="atlas-text">{{ t('mfa.enrollChoose') }}</p>
|
|
@@ -1771,10 +1810,31 @@ class AttemptFlowComponent {
|
|
|
1771
1810
|
[disabled]="busy || enrol.busy"
|
|
1772
1811
|
(click)="chooseMethod(m)"
|
|
1773
1812
|
>
|
|
1774
|
-
{{ t(m
|
|
1813
|
+
{{ t(optionKey(m)) }}
|
|
1775
1814
|
</button>
|
|
1776
1815
|
}
|
|
1777
|
-
} @else if (enrol.method === '
|
|
1816
|
+
} @else if (enrol.method === 'yubikey') {
|
|
1817
|
+
<label class="atlas-field">
|
|
1818
|
+
<span>{{ t('mfa.yubikeyLabel') }}</span>
|
|
1819
|
+
<input [class]="cls('formFieldInput', 'atlas-input')" type="text" name="otp" autocomplete="off" [value]="values['otp'] ?? ''" (input)="setValue('otp', $any($event.target).value)" />
|
|
1820
|
+
@for (error of fieldErrorsFor('otp'); track error.code) {
|
|
1821
|
+
<span [class]="cls('formFieldError', 'atlas-error')">{{ errorText(error) }}</span>
|
|
1822
|
+
}
|
|
1823
|
+
</label>
|
|
1824
|
+
} @else if (enrol.method === 'duo' || enrol.method === 'passkey') {
|
|
1825
|
+
@if (enrol.enrollment; as setup) {
|
|
1826
|
+
@if (enrol.method === 'passkey') {
|
|
1827
|
+
<p class="atlas-text">{{ t('mfa.enrollPasskeyHelp') }}</p>
|
|
1828
|
+
} @else {
|
|
1829
|
+
<p class="atlas-text">{{ t('mfa.enrollDuoHelp') }}</p>
|
|
1830
|
+
@if (setup.authorizationUrl) {
|
|
1831
|
+
<a class="atlas-link" data-atlas="mfa-duo-open" [href]="setup.authorizationUrl" target="_blank" rel="noopener noreferrer">{{ t('mfa.enrollDuoOpen') }}</a>
|
|
1832
|
+
}
|
|
1833
|
+
}
|
|
1834
|
+
} @else {
|
|
1835
|
+
<p class="atlas-text" aria-live="polite">{{ enrol.busy ? t('mfa.enrollPreparing') : '' }}</p>
|
|
1836
|
+
}
|
|
1837
|
+
} @else if (enrol.method === 'totp' || enrol.method === 'hotp') {
|
|
1778
1838
|
@if (enrol.enrollment; as setup) {
|
|
1779
1839
|
<p class="atlas-text">{{ t('mfa.enrollScan') }}</p>
|
|
1780
1840
|
@if (setup.qrCode) {
|
|
@@ -1787,7 +1847,7 @@ class AttemptFlowComponent {
|
|
|
1787
1847
|
<span>{{ t('mfa.enrollFirstCodeLabel') }}</span>
|
|
1788
1848
|
<input [class]="cls('formFieldInput', 'atlas-input')" type="text" name="code" autocomplete="one-time-code" inputmode="numeric" [value]="values['code'] ?? ''" (input)="setValue('code', $any($event.target).value)" />
|
|
1789
1849
|
</label>
|
|
1790
|
-
@if (enrol.totpCodes >= 2) {
|
|
1850
|
+
@if (enrol.method === 'totp' && enrol.totpCodes >= 2) {
|
|
1791
1851
|
<label class="atlas-field">
|
|
1792
1852
|
<span>{{ t('mfa.enrollSecondCodeLabel') }}</span>
|
|
1793
1853
|
<input [class]="cls('formFieldInput', 'atlas-input')" type="text" name="secondCode" autocomplete="one-time-code" inputmode="numeric" [value]="values['secondCode'] ?? ''" (input)="setValue('secondCode', $any($event.target).value)" />
|
|
@@ -1832,7 +1892,7 @@ class AttemptFlowComponent {
|
|
|
1832
1892
|
[disabled]="busy || enrol.busy"
|
|
1833
1893
|
(click)="chooseMethod(other)"
|
|
1834
1894
|
>
|
|
1835
|
-
{{ t(other
|
|
1895
|
+
{{ t(optionKey(other)) }}
|
|
1836
1896
|
</button>
|
|
1837
1897
|
}
|
|
1838
1898
|
}
|
|
@@ -1977,7 +2037,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
1977
2037
|
<h1 [class]="cls('headerTitle', 'atlas-title')">{{ t(titleKey) }}</h1>
|
|
1978
2038
|
|
|
1979
2039
|
@for (error of formErrors(); track error.code) {
|
|
1980
|
-
<p [class]="cls('formFieldError', 'atlas-error')" role="alert">
|
|
2040
|
+
<p [class]="cls('formFieldError', 'atlas-error')" role="alert">
|
|
2041
|
+
{{ errorText(error) }}
|
|
2042
|
+
@if (signInLink(error); as href) {
|
|
2043
|
+
<a class="atlas-link" [href]="href">{{ t('signIn.title') }}</a>
|
|
2044
|
+
}
|
|
2045
|
+
</p>
|
|
1981
2046
|
}
|
|
1982
2047
|
|
|
1983
2048
|
<form (submit)="onSubmit($event)">
|
|
@@ -2002,6 +2067,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
2002
2067
|
{{ t('signIn.resendLink') }}
|
|
2003
2068
|
</button>
|
|
2004
2069
|
}
|
|
2070
|
+
@if (showMatchCode()) {
|
|
2071
|
+
<p class="atlas-text" data-atlas="link-match-code">{{ t('link.matchCodeHint') }} <strong><code>{{ matchCode }}</code></strong></p>
|
|
2072
|
+
}
|
|
2005
2073
|
@if (enrolling() && enrollmentState; as enrol) {
|
|
2006
2074
|
@if (enrol.method === null) {
|
|
2007
2075
|
<p class="atlas-text">{{ t('mfa.enrollChoose') }}</p>
|
|
@@ -2013,10 +2081,31 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
2013
2081
|
[disabled]="busy || enrol.busy"
|
|
2014
2082
|
(click)="chooseMethod(m)"
|
|
2015
2083
|
>
|
|
2016
|
-
{{ t(m
|
|
2084
|
+
{{ t(optionKey(m)) }}
|
|
2017
2085
|
</button>
|
|
2018
2086
|
}
|
|
2019
|
-
} @else if (enrol.method === '
|
|
2087
|
+
} @else if (enrol.method === 'yubikey') {
|
|
2088
|
+
<label class="atlas-field">
|
|
2089
|
+
<span>{{ t('mfa.yubikeyLabel') }}</span>
|
|
2090
|
+
<input [class]="cls('formFieldInput', 'atlas-input')" type="text" name="otp" autocomplete="off" [value]="values['otp'] ?? ''" (input)="setValue('otp', $any($event.target).value)" />
|
|
2091
|
+
@for (error of fieldErrorsFor('otp'); track error.code) {
|
|
2092
|
+
<span [class]="cls('formFieldError', 'atlas-error')">{{ errorText(error) }}</span>
|
|
2093
|
+
}
|
|
2094
|
+
</label>
|
|
2095
|
+
} @else if (enrol.method === 'duo' || enrol.method === 'passkey') {
|
|
2096
|
+
@if (enrol.enrollment; as setup) {
|
|
2097
|
+
@if (enrol.method === 'passkey') {
|
|
2098
|
+
<p class="atlas-text">{{ t('mfa.enrollPasskeyHelp') }}</p>
|
|
2099
|
+
} @else {
|
|
2100
|
+
<p class="atlas-text">{{ t('mfa.enrollDuoHelp') }}</p>
|
|
2101
|
+
@if (setup.authorizationUrl) {
|
|
2102
|
+
<a class="atlas-link" data-atlas="mfa-duo-open" [href]="setup.authorizationUrl" target="_blank" rel="noopener noreferrer">{{ t('mfa.enrollDuoOpen') }}</a>
|
|
2103
|
+
}
|
|
2104
|
+
}
|
|
2105
|
+
} @else {
|
|
2106
|
+
<p class="atlas-text" aria-live="polite">{{ enrol.busy ? t('mfa.enrollPreparing') : '' }}</p>
|
|
2107
|
+
}
|
|
2108
|
+
} @else if (enrol.method === 'totp' || enrol.method === 'hotp') {
|
|
2020
2109
|
@if (enrol.enrollment; as setup) {
|
|
2021
2110
|
<p class="atlas-text">{{ t('mfa.enrollScan') }}</p>
|
|
2022
2111
|
@if (setup.qrCode) {
|
|
@@ -2029,7 +2118,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
2029
2118
|
<span>{{ t('mfa.enrollFirstCodeLabel') }}</span>
|
|
2030
2119
|
<input [class]="cls('formFieldInput', 'atlas-input')" type="text" name="code" autocomplete="one-time-code" inputmode="numeric" [value]="values['code'] ?? ''" (input)="setValue('code', $any($event.target).value)" />
|
|
2031
2120
|
</label>
|
|
2032
|
-
@if (enrol.totpCodes >= 2) {
|
|
2121
|
+
@if (enrol.method === 'totp' && enrol.totpCodes >= 2) {
|
|
2033
2122
|
<label class="atlas-field">
|
|
2034
2123
|
<span>{{ t('mfa.enrollSecondCodeLabel') }}</span>
|
|
2035
2124
|
<input [class]="cls('formFieldInput', 'atlas-input')" type="text" name="secondCode" autocomplete="one-time-code" inputmode="numeric" [value]="values['secondCode'] ?? ''" (input)="setValue('secondCode', $any($event.target).value)" />
|
|
@@ -2074,7 +2163,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
2074
2163
|
[disabled]="busy || enrol.busy"
|
|
2075
2164
|
(click)="chooseMethod(other)"
|
|
2076
2165
|
>
|
|
2077
|
-
{{ t(other
|
|
2166
|
+
{{ t(optionKey(other)) }}
|
|
2078
2167
|
</button>
|
|
2079
2168
|
}
|
|
2080
2169
|
}
|
|
@@ -2217,6 +2306,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
2217
2306
|
type: Input
|
|
2218
2307
|
}], titleKey: [{
|
|
2219
2308
|
type: Input
|
|
2309
|
+
}], signInHref: [{
|
|
2310
|
+
type: Input
|
|
2220
2311
|
}], captcha: [{
|
|
2221
2312
|
type: Input
|
|
2222
2313
|
}], firstFactors: [{
|
|
@@ -2251,6 +2342,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
2251
2342
|
type: Input
|
|
2252
2343
|
}], emailVerification: [{
|
|
2253
2344
|
type: Input
|
|
2345
|
+
}], matchCode: [{
|
|
2346
|
+
type: Input
|
|
2254
2347
|
}], resend: [{
|
|
2255
2348
|
type: Output
|
|
2256
2349
|
}], policyDeclined: [{
|
|
@@ -2264,6 +2357,103 @@ function released() {
|
|
|
2264
2357
|
return { kind: 'released', name: '', labelKey: 'signIn.passwordHoldReleased', type: 'text' };
|
|
2265
2358
|
}
|
|
2266
2359
|
|
|
2360
|
+
/**
|
|
2361
|
+
* What `<atlas-sign-in>` / `<atlas-sign-up>` draw when opened from a mailed link:
|
|
2362
|
+
* tries this browser's stored secret, then asks for the code the starting tab
|
|
2363
|
+
* shows. A success signs nobody in here: the starting tab continues on its own.
|
|
2364
|
+
*/
|
|
2365
|
+
class EmailLinkComponent {
|
|
2366
|
+
atlas = inject(AtlasService);
|
|
2367
|
+
link;
|
|
2368
|
+
state = signal({ status: 'checking', busy: false, errors: [] });
|
|
2369
|
+
code = '';
|
|
2370
|
+
controller = null;
|
|
2371
|
+
stop = null;
|
|
2372
|
+
ngOnInit() {
|
|
2373
|
+
this.controller = createEmailLinkConfirmation(this.atlas.createFapiClient(), this.link);
|
|
2374
|
+
this.stop = this.controller.subscribe((next) => this.state.set(next));
|
|
2375
|
+
void this.controller.start();
|
|
2376
|
+
}
|
|
2377
|
+
ngOnDestroy() {
|
|
2378
|
+
this.stop?.();
|
|
2379
|
+
}
|
|
2380
|
+
onSubmit(event) {
|
|
2381
|
+
event.preventDefault();
|
|
2382
|
+
void this.controller?.submitCode(this.code);
|
|
2383
|
+
}
|
|
2384
|
+
message() {
|
|
2385
|
+
const status = this.state().status;
|
|
2386
|
+
return status === 'confirmed' ? 'link.confirmed' : status === 'invalid' ? 'link.invalid' : 'link.checking';
|
|
2387
|
+
}
|
|
2388
|
+
t(key) {
|
|
2389
|
+
return translate(this.atlas.localization, key);
|
|
2390
|
+
}
|
|
2391
|
+
cls(key, base) {
|
|
2392
|
+
return classFor(key, this.atlas.appearance, base);
|
|
2393
|
+
}
|
|
2394
|
+
errorText(error) {
|
|
2395
|
+
return localizedErrorMessage(error, this.atlas.localization);
|
|
2396
|
+
}
|
|
2397
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EmailLinkComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2398
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: EmailLinkComponent, isStandalone: true, selector: "atlas-email-link", inputs: { link: "link" }, ngImport: i0, template: `
|
|
2399
|
+
<div [class]="cls('card', 'atlas-card')" data-atlas="email-link" [attr.data-atlas-status]="state().status">
|
|
2400
|
+
<h1 [class]="cls('headerTitle', 'atlas-title')">{{ t('link.title') }}</h1>
|
|
2401
|
+
@if (state().status === 'needs_code') {
|
|
2402
|
+
<form (submit)="onSubmit($event)">
|
|
2403
|
+
<p class="atlas-text">{{ t('link.enterCodeHelp') }}</p>
|
|
2404
|
+
<label class="atlas-field">
|
|
2405
|
+
<span>{{ t('link.codeLabel') }}</span>
|
|
2406
|
+
<input [class]="cls('formFieldInput', 'atlas-input')" type="text" name="match_code" autocomplete="off" inputmode="numeric" required [value]="code" (input)="code = $any($event.target).value" />
|
|
2407
|
+
</label>
|
|
2408
|
+
@for (error of state().errors; track error.code) {
|
|
2409
|
+
<p [class]="cls('formFieldError', 'atlas-error')" role="alert">{{ errorText(error) }}</p>
|
|
2410
|
+
}
|
|
2411
|
+
<button [class]="cls('formButtonPrimary', 'atlas-button')" type="submit" [disabled]="state().busy">{{ t('link.confirm') }}</button>
|
|
2412
|
+
</form>
|
|
2413
|
+
} @else {
|
|
2414
|
+
<p class="atlas-text" role="status" aria-live="polite">{{ t(message()) }}</p>
|
|
2415
|
+
}
|
|
2416
|
+
@if (state().resetUrl; as resetUrl) {
|
|
2417
|
+
<p class="atlas-text"><a class="atlas-link" data-atlas-reset-link="" [href]="resetUrl">{{ t('signIn.forgotPassword') }}</a></p>
|
|
2418
|
+
}
|
|
2419
|
+
</div>
|
|
2420
|
+
`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2421
|
+
}
|
|
2422
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EmailLinkComponent, decorators: [{
|
|
2423
|
+
type: Component,
|
|
2424
|
+
args: [{
|
|
2425
|
+
selector: 'atlas-email-link',
|
|
2426
|
+
standalone: true,
|
|
2427
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
2428
|
+
template: `
|
|
2429
|
+
<div [class]="cls('card', 'atlas-card')" data-atlas="email-link" [attr.data-atlas-status]="state().status">
|
|
2430
|
+
<h1 [class]="cls('headerTitle', 'atlas-title')">{{ t('link.title') }}</h1>
|
|
2431
|
+
@if (state().status === 'needs_code') {
|
|
2432
|
+
<form (submit)="onSubmit($event)">
|
|
2433
|
+
<p class="atlas-text">{{ t('link.enterCodeHelp') }}</p>
|
|
2434
|
+
<label class="atlas-field">
|
|
2435
|
+
<span>{{ t('link.codeLabel') }}</span>
|
|
2436
|
+
<input [class]="cls('formFieldInput', 'atlas-input')" type="text" name="match_code" autocomplete="off" inputmode="numeric" required [value]="code" (input)="code = $any($event.target).value" />
|
|
2437
|
+
</label>
|
|
2438
|
+
@for (error of state().errors; track error.code) {
|
|
2439
|
+
<p [class]="cls('formFieldError', 'atlas-error')" role="alert">{{ errorText(error) }}</p>
|
|
2440
|
+
}
|
|
2441
|
+
<button [class]="cls('formButtonPrimary', 'atlas-button')" type="submit" [disabled]="state().busy">{{ t('link.confirm') }}</button>
|
|
2442
|
+
</form>
|
|
2443
|
+
} @else {
|
|
2444
|
+
<p class="atlas-text" role="status" aria-live="polite">{{ t(message()) }}</p>
|
|
2445
|
+
}
|
|
2446
|
+
@if (state().resetUrl; as resetUrl) {
|
|
2447
|
+
<p class="atlas-text"><a class="atlas-link" data-atlas-reset-link="" [href]="resetUrl">{{ t('signIn.forgotPassword') }}</a></p>
|
|
2448
|
+
}
|
|
2449
|
+
</div>
|
|
2450
|
+
`,
|
|
2451
|
+
}]
|
|
2452
|
+
}], propDecorators: { link: [{
|
|
2453
|
+
type: Input,
|
|
2454
|
+
args: [{ required: true }]
|
|
2455
|
+
}] } });
|
|
2456
|
+
|
|
2267
2457
|
/**
|
|
2268
2458
|
* The recovery codes a mid-sign-in MFA enrolment came with, shown once before
|
|
2269
2459
|
* the sign-in finishes: copy them, download them as a .txt file, then
|
|
@@ -2801,8 +2991,11 @@ class AtlasFlowController {
|
|
|
2801
2991
|
return;
|
|
2802
2992
|
this.pollTimer = setInterval(() => {
|
|
2803
2993
|
void (async () => {
|
|
2804
|
-
const
|
|
2805
|
-
this.
|
|
2994
|
+
const polled = this.state();
|
|
2995
|
+
const { state: next, ticket } = await pollAttempt(this.client, polled);
|
|
2996
|
+
// A resend rotated the secret meanwhile: this answer is stale.
|
|
2997
|
+
if (this.state().pollSecret === polled.pollSecret)
|
|
2998
|
+
this.setState(next);
|
|
2806
2999
|
// e.g. a passkey sign-up whose email was just proven: only this tab can go on.
|
|
2807
3000
|
if (!ticket && !shouldKeepPolling(next))
|
|
2808
3001
|
this.stopPolling();
|
|
@@ -2847,6 +3040,11 @@ class AtlasFlowController {
|
|
|
2847
3040
|
*/
|
|
2848
3041
|
class SignInComponent {
|
|
2849
3042
|
atlas = inject(AtlasService);
|
|
3043
|
+
/** Opened from a mailed link: that page, not the flow. Read after the first render, so hydration matches. */
|
|
3044
|
+
emailLink = signal(null);
|
|
3045
|
+
constructor() {
|
|
3046
|
+
afterNextRender(() => this.emailLink.set(emailLinkFromUrl(undefined, 'sign_in')));
|
|
3047
|
+
}
|
|
2850
3048
|
/** Where to send the user once the flow completes. Reserved for host routing. */
|
|
2851
3049
|
afterUrl;
|
|
2852
3050
|
/**
|
|
@@ -2912,6 +3110,9 @@ class SignInComponent {
|
|
|
2912
3110
|
}
|
|
2913
3111
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SignInComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2914
3112
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: SignInComponent, isStandalone: true, selector: "atlas-sign-in", inputs: { afterUrl: "afterUrl", signUpUrl: "signUpUrl" }, ngImport: i0, template: `
|
|
3113
|
+
@if (emailLink(); as link) {
|
|
3114
|
+
<atlas-email-link [link]="link"></atlas-email-link>
|
|
3115
|
+
} @else {
|
|
2915
3116
|
@if (lastUsedLabel(); as label) {
|
|
2916
3117
|
<p class="atlas-text atlas-last-used-hint" data-atlas="last-used" [attr.data-atlas-method]="flow.lastMethod()">
|
|
2917
3118
|
{{ t('signIn.lastUsed') }}: {{ label }}
|
|
@@ -2937,6 +3138,7 @@ class SignInComponent {
|
|
|
2937
3138
|
[captcha]="flow.captchaDrawn() ? flow.captcha : null"
|
|
2938
3139
|
[firstFactors]="flow.firstFactors()"
|
|
2939
3140
|
[preparedFactor]="flow.preparedFactor()"
|
|
3141
|
+
[matchCode]="flow.state().matchCode ?? null"
|
|
2940
3142
|
[passwordHold]="flow.state().passwordHold ?? null"
|
|
2941
3143
|
[holdProof]="flow.holdProof()"
|
|
2942
3144
|
(usePassword)="flow.usePassword()"
|
|
@@ -2969,7 +3171,8 @@ class SignInComponent {
|
|
|
2969
3171
|
{{ t('signIn.noAccount') }} <a class="atlas-link" [href]="href">{{ t('signIn.signUpLink') }}</a>
|
|
2970
3172
|
</p>
|
|
2971
3173
|
}
|
|
2972
|
-
|
|
3174
|
+
}
|
|
3175
|
+
`, isInline: true, dependencies: [{ kind: "component", type: EmailLinkComponent, selector: "atlas-email-link", inputs: ["link"] }, { kind: "component", type: AttemptFlowComponent, selector: "atlas-attempt-flow", inputs: ["attempt", "busy", "errors", "sessionKept", "titleKey", "signInHref", "captcha", "firstFactors", "preparedFactor", "passwordHold", "holdProof", "offerEmailSecondFactor", "emailedSecondFactor", "offerSmsSecondFactor", "textedSecondFactor", "enrollment", "enrollmentState", "emailVerification", "matchCode"], outputs: ["submitFlow", "chooseFactor", "usePassword", "emailSecondFactor", "smsSecondFactor", "resend", "policyDeclined"] }, { kind: "component", type: RecoveryCodesComponent, selector: "atlas-recovery-codes", inputs: ["codes", "busy"], outputs: ["saved"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2973
3176
|
}
|
|
2974
3177
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SignInComponent, decorators: [{
|
|
2975
3178
|
type: Component,
|
|
@@ -2977,8 +3180,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
2977
3180
|
selector: 'atlas-sign-in',
|
|
2978
3181
|
standalone: true,
|
|
2979
3182
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
2980
|
-
imports: [AttemptFlowComponent, RecoveryCodesComponent],
|
|
3183
|
+
imports: [EmailLinkComponent, AttemptFlowComponent, RecoveryCodesComponent],
|
|
2981
3184
|
template: `
|
|
3185
|
+
@if (emailLink(); as link) {
|
|
3186
|
+
<atlas-email-link [link]="link"></atlas-email-link>
|
|
3187
|
+
} @else {
|
|
2982
3188
|
@if (lastUsedLabel(); as label) {
|
|
2983
3189
|
<p class="atlas-text atlas-last-used-hint" data-atlas="last-used" [attr.data-atlas-method]="flow.lastMethod()">
|
|
2984
3190
|
{{ t('signIn.lastUsed') }}: {{ label }}
|
|
@@ -3004,6 +3210,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
3004
3210
|
[captcha]="flow.captchaDrawn() ? flow.captcha : null"
|
|
3005
3211
|
[firstFactors]="flow.firstFactors()"
|
|
3006
3212
|
[preparedFactor]="flow.preparedFactor()"
|
|
3213
|
+
[matchCode]="flow.state().matchCode ?? null"
|
|
3007
3214
|
[passwordHold]="flow.state().passwordHold ?? null"
|
|
3008
3215
|
[holdProof]="flow.holdProof()"
|
|
3009
3216
|
(usePassword)="flow.usePassword()"
|
|
@@ -3036,9 +3243,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
3036
3243
|
{{ t('signIn.noAccount') }} <a class="atlas-link" [href]="href">{{ t('signIn.signUpLink') }}</a>
|
|
3037
3244
|
</p>
|
|
3038
3245
|
}
|
|
3246
|
+
}
|
|
3039
3247
|
`,
|
|
3040
3248
|
}]
|
|
3041
|
-
}], propDecorators: { afterUrl: [{
|
|
3249
|
+
}], ctorParameters: () => [], propDecorators: { afterUrl: [{
|
|
3042
3250
|
type: Input
|
|
3043
3251
|
}], signUpUrl: [{
|
|
3044
3252
|
type: Input
|
|
@@ -3615,6 +3823,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
3615
3823
|
*/
|
|
3616
3824
|
class SignUpComponent {
|
|
3617
3825
|
atlas = inject(AtlasService);
|
|
3826
|
+
/** Opened from a mailed link: that page, not the flow. Read after the first render, so hydration matches. */
|
|
3827
|
+
emailLink = signal(null);
|
|
3828
|
+
constructor() {
|
|
3829
|
+
afterNextRender(() => this.emailLink.set(emailLinkFromUrl(undefined, 'sign_up')));
|
|
3830
|
+
}
|
|
3618
3831
|
/** Where to send the user once the flow completes. Reserved for host routing. */
|
|
3619
3832
|
afterUrl;
|
|
3620
3833
|
/** Where the existing-account notice's "Forgot password?" goes. Default: the hosted sign-in page; `null` hides it. */
|
|
@@ -3670,6 +3883,9 @@ class SignUpComponent {
|
|
|
3670
3883
|
}
|
|
3671
3884
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SignUpComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3672
3885
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: SignUpComponent, isStandalone: true, selector: "atlas-sign-up", inputs: { afterUrl: "afterUrl", resetPasswordUrl: "resetPasswordUrl", signInUrl: "signInUrl" }, ngImport: i0, template: `
|
|
3886
|
+
@if (emailLink(); as link) {
|
|
3887
|
+
<atlas-email-link [link]="link"></atlas-email-link>
|
|
3888
|
+
} @else {
|
|
3673
3889
|
@if (flow.recoveryCodes(); as codes) {
|
|
3674
3890
|
<atlas-recovery-codes [codes]="codes" [busy]="flow.state().busy" (saved)="flow.saveRecoveryCodes()"></atlas-recovery-codes>
|
|
3675
3891
|
} @else if (flow.existingAccountNotice()) {
|
|
@@ -3722,6 +3938,7 @@ class SignUpComponent {
|
|
|
3722
3938
|
[emailVerification]="flow.settings()?.account?.emailVerification ?? 'code'"
|
|
3723
3939
|
(submitFlow)="flow.submit($event)"
|
|
3724
3940
|
(resend)="flow.resendSignUp()"
|
|
3941
|
+
[matchCode]="flow.state().matchCode ?? null"
|
|
3725
3942
|
[offerEmailSecondFactor]="flow.settings()?.account?.emailSecondFactor === true"
|
|
3726
3943
|
[emailedSecondFactor]="flow.emailSecondFactor()"
|
|
3727
3944
|
[offerSmsSecondFactor]="flow.settings() !== null && flow.mfaChoices().sms"
|
|
@@ -3731,6 +3948,7 @@ class SignUpComponent {
|
|
|
3731
3948
|
(emailSecondFactor)="flow.sendEmailSecondFactor()"
|
|
3732
3949
|
(smsSecondFactor)="flow.sendSmsSecondFactor()"
|
|
3733
3950
|
(policyDeclined)="flow.declinePolicy($event)"
|
|
3951
|
+
[signInHref]="signInHref()"
|
|
3734
3952
|
></atlas-attempt-flow>
|
|
3735
3953
|
} @else {
|
|
3736
3954
|
<atlas-sign-up-form
|
|
@@ -3747,7 +3965,8 @@ class SignUpComponent {
|
|
|
3747
3965
|
"
|
|
3748
3966
|
></atlas-sign-up-form>
|
|
3749
3967
|
}
|
|
3750
|
-
|
|
3968
|
+
}
|
|
3969
|
+
`, isInline: true, dependencies: [{ kind: "component", type: EmailLinkComponent, selector: "atlas-email-link", inputs: ["link"] }, { kind: "component", type: AttemptFlowComponent, selector: "atlas-attempt-flow", inputs: ["attempt", "busy", "errors", "sessionKept", "titleKey", "signInHref", "captcha", "firstFactors", "preparedFactor", "passwordHold", "holdProof", "offerEmailSecondFactor", "emailedSecondFactor", "offerSmsSecondFactor", "textedSecondFactor", "enrollment", "enrollmentState", "emailVerification", "matchCode"], outputs: ["submitFlow", "chooseFactor", "usePassword", "emailSecondFactor", "smsSecondFactor", "resend", "policyDeclined"] }, { kind: "component", type: RecoveryCodesComponent, selector: "atlas-recovery-codes", inputs: ["codes", "busy"], outputs: ["saved"] }, { kind: "component", type: SignUpFormComponent, selector: "atlas-sign-up-form", inputs: ["settings", "busy", "errors", "captcha", "passkey", "switchable", "policies"], outputs: ["switchMode", "submitSignUp"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3751
3970
|
}
|
|
3752
3971
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SignUpComponent, decorators: [{
|
|
3753
3972
|
type: Component,
|
|
@@ -3755,8 +3974,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
3755
3974
|
selector: 'atlas-sign-up',
|
|
3756
3975
|
standalone: true,
|
|
3757
3976
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
3758
|
-
imports: [AttemptFlowComponent, RecoveryCodesComponent, SignUpFormComponent],
|
|
3977
|
+
imports: [EmailLinkComponent, AttemptFlowComponent, RecoveryCodesComponent, SignUpFormComponent],
|
|
3759
3978
|
template: `
|
|
3979
|
+
@if (emailLink(); as link) {
|
|
3980
|
+
<atlas-email-link [link]="link"></atlas-email-link>
|
|
3981
|
+
} @else {
|
|
3760
3982
|
@if (flow.recoveryCodes(); as codes) {
|
|
3761
3983
|
<atlas-recovery-codes [codes]="codes" [busy]="flow.state().busy" (saved)="flow.saveRecoveryCodes()"></atlas-recovery-codes>
|
|
3762
3984
|
} @else if (flow.existingAccountNotice()) {
|
|
@@ -3809,6 +4031,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
3809
4031
|
[emailVerification]="flow.settings()?.account?.emailVerification ?? 'code'"
|
|
3810
4032
|
(submitFlow)="flow.submit($event)"
|
|
3811
4033
|
(resend)="flow.resendSignUp()"
|
|
4034
|
+
[matchCode]="flow.state().matchCode ?? null"
|
|
3812
4035
|
[offerEmailSecondFactor]="flow.settings()?.account?.emailSecondFactor === true"
|
|
3813
4036
|
[emailedSecondFactor]="flow.emailSecondFactor()"
|
|
3814
4037
|
[offerSmsSecondFactor]="flow.settings() !== null && flow.mfaChoices().sms"
|
|
@@ -3818,6 +4041,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
3818
4041
|
(emailSecondFactor)="flow.sendEmailSecondFactor()"
|
|
3819
4042
|
(smsSecondFactor)="flow.sendSmsSecondFactor()"
|
|
3820
4043
|
(policyDeclined)="flow.declinePolicy($event)"
|
|
4044
|
+
[signInHref]="signInHref()"
|
|
3821
4045
|
></atlas-attempt-flow>
|
|
3822
4046
|
} @else {
|
|
3823
4047
|
<atlas-sign-up-form
|
|
@@ -3834,9 +4058,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
3834
4058
|
"
|
|
3835
4059
|
></atlas-sign-up-form>
|
|
3836
4060
|
}
|
|
4061
|
+
}
|
|
3837
4062
|
`,
|
|
3838
4063
|
}]
|
|
3839
|
-
}], propDecorators: { afterUrl: [{
|
|
4064
|
+
}], ctorParameters: () => [], propDecorators: { afterUrl: [{
|
|
3840
4065
|
type: Input
|
|
3841
4066
|
}], resetPasswordUrl: [{
|
|
3842
4067
|
type: Input
|
|
@@ -5298,5 +5523,5 @@ function atlasChildGuard(options = {}) {
|
|
|
5298
5523
|
* Generated bundle index. Do not edit.
|
|
5299
5524
|
*/
|
|
5300
5525
|
|
|
5301
|
-
export { ATLAS_ANGULAR_SDK, ATLAS_ANGULAR_VERSION, ATLAS_OPTIONS, ATLAS_UI, AtlasCaptchaSlotDirective, AtlasFlowController, AtlasLoadedDirective, AtlasLoadingDirective, AtlasModule, AtlasOrganizationAuditLog, AtlasPoliciesDirective, AtlasProtectDirective, AtlasRootDirective, AtlasService, AtlasSignedInDirective, AtlasSignedOutDirective, AttemptFlowComponent, DEFAULT_TOKENS, EN_US, ImpersonationBannerComponent, ManageCibaComponent, OrganizationAuditLogComponent, OrganizationProfileComponent, OrganizationSwitcherComponent, PolicyAcceptStepComponent, PolicyGateComponent, SignInComponent, SignUpComponent, SignUpFormComponent, THEMES, UserButtonComponent, UserProfileComponent, atlasChildGuard, atlasGuard, classFor, cssVariables, explicitTokens, provideAtlas, renderAppearance, resolveTokens, translate, withFallback };
|
|
5526
|
+
export { ATLAS_ANGULAR_SDK, ATLAS_ANGULAR_VERSION, ATLAS_OPTIONS, ATLAS_UI, AtlasCaptchaSlotDirective, AtlasFlowController, AtlasLoadedDirective, AtlasLoadingDirective, AtlasModule, AtlasOrganizationAuditLog, AtlasPoliciesDirective, AtlasProtectDirective, AtlasRootDirective, AtlasService, AtlasSignedInDirective, AtlasSignedOutDirective, AttemptFlowComponent, DEFAULT_TOKENS, EN_US, EmailLinkComponent, ImpersonationBannerComponent, ManageCibaComponent, OrganizationAuditLogComponent, OrganizationProfileComponent, OrganizationSwitcherComponent, PolicyAcceptStepComponent, PolicyGateComponent, SignInComponent, SignUpComponent, SignUpFormComponent, THEMES, UserButtonComponent, UserProfileComponent, atlasChildGuard, atlasGuard, classFor, cssVariables, explicitTokens, provideAtlas, renderAppearance, resolveTokens, translate, withFallback };
|
|
5302
5527
|
//# sourceMappingURL=atlasauth-angular.mjs.map
|