@mintplayer/ng-spark 22.29.0 → 22.31.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/README.md +3 -3
- package/auth/README.md +216 -0
- package/fesm2022/mintplayer-ng-spark-auth-account.mjs +2023 -0
- package/fesm2022/mintplayer-ng-spark-auth-account.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-auth-auth-bar.mjs +96 -0
- package/fesm2022/mintplayer-ng-spark-auth-auth-bar.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-auth-confirm-email.mjs +200 -0
- package/fesm2022/mintplayer-ng-spark-auth-confirm-email.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-auth-core.mjs +452 -0
- package/fesm2022/mintplayer-ng-spark-auth-core.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-auth-external-login.mjs +201 -0
- package/fesm2022/mintplayer-ng-spark-auth-external-login.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-auth-forgot-password.mjs +196 -0
- package/fesm2022/mintplayer-ng-spark-auth-forgot-password.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-auth-guards.mjs +16 -0
- package/fesm2022/mintplayer-ng-spark-auth-guards.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-auth-interceptors.mjs +18 -0
- package/fesm2022/mintplayer-ng-spark-auth-interceptors.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-auth-login.mjs +282 -0
- package/fesm2022/mintplayer-ng-spark-auth-login.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-auth-models.mjs +114 -0
- package/fesm2022/mintplayer-ng-spark-auth-models.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-auth-pipes.mjs +43 -0
- package/fesm2022/mintplayer-ng-spark-auth-pipes.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-auth-register.mjs +216 -0
- package/fesm2022/mintplayer-ng-spark-auth-register.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-auth-reset-password.mjs +223 -0
- package/fesm2022/mintplayer-ng-spark-auth-reset-password.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-auth-routes.mjs +194 -0
- package/fesm2022/mintplayer-ng-spark-auth-routes.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-auth-sign-in.mjs +210 -0
- package/fesm2022/mintplayer-ng-spark-auth-sign-in.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-auth-two-factor.mjs +218 -0
- package/fesm2022/mintplayer-ng-spark-auth-two-factor.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-auth.mjs +48 -0
- package/fesm2022/mintplayer-ng-spark-auth.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-client-operations.mjs +368 -2
- package/fesm2022/mintplayer-ng-spark-client-operations.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-grid.mjs +22 -9
- package/fesm2022/mintplayer-ng-spark-grid.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-identity-provider-connected-applications.mjs +389 -0
- package/fesm2022/mintplayer-ng-spark-identity-provider-connected-applications.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-identity-provider-core.mjs +204 -0
- package/fesm2022/mintplayer-ng-spark-identity-provider-core.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-identity-provider-developers.mjs +486 -0
- package/fesm2022/mintplayer-ng-spark-identity-provider-developers.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-identity-provider-management.mjs +350 -0
- package/fesm2022/mintplayer-ng-spark-identity-provider-management.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-identity-provider.mjs +66 -0
- package/fesm2022/mintplayer-ng-spark-identity-provider.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-models.mjs +2 -1
- package/fesm2022/mintplayer-ng-spark-models.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-po-detail.mjs +13 -3
- package/fesm2022/mintplayer-ng-spark-po-detail.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-po-form.mjs +6 -3
- package/fesm2022/mintplayer-ng-spark-po-form.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-pwa.mjs +162 -0
- package/fesm2022/mintplayer-ng-spark-pwa.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-query-list.mjs +5 -2
- package/fesm2022/mintplayer-ng-spark-query-list.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-renderers.mjs +109 -4
- package/fesm2022/mintplayer-ng-spark-renderers.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-retry-action-modal.mjs +36 -6
- package/fesm2022/mintplayer-ng-spark-retry-action-modal.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-services.mjs +48 -6
- package/fesm2022/mintplayer-ng-spark-services.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-shell.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark.mjs.map +1 -1
- package/package.json +101 -3
- package/types/mintplayer-ng-spark-auth-account.d.ts +255 -0
- package/types/mintplayer-ng-spark-auth-auth-bar.d.ts +22 -0
- package/types/mintplayer-ng-spark-auth-confirm-email.d.ts +21 -0
- package/types/mintplayer-ng-spark-auth-core.d.ts +197 -0
- package/types/mintplayer-ng-spark-auth-external-login.d.ts +132 -0
- package/types/mintplayer-ng-spark-auth-forgot-password.d.ts +18 -0
- package/types/mintplayer-ng-spark-auth-guards.d.ts +15 -0
- package/types/mintplayer-ng-spark-auth-interceptors.d.ts +2 -0
- package/types/mintplayer-ng-spark-auth-login.d.ts +46 -0
- package/types/mintplayer-ng-spark-auth-models.d.ts +489 -0
- package/types/mintplayer-ng-spark-auth-pipes.d.ts +8 -0
- package/types/mintplayer-ng-spark-auth-register.d.ts +21 -0
- package/types/mintplayer-ng-spark-auth-reset-password.d.ts +25 -0
- package/types/mintplayer-ng-spark-auth-routes.d.ts +154 -0
- package/types/mintplayer-ng-spark-auth-sign-in.d.ts +84 -0
- package/types/mintplayer-ng-spark-auth-two-factor.d.ts +23 -0
- package/types/mintplayer-ng-spark-auth.d.ts +24 -0
- package/types/mintplayer-ng-spark-client-operations.d.ts +148 -3
- package/types/mintplayer-ng-spark-grid.d.ts +19 -1
- package/types/mintplayer-ng-spark-identity-provider-connected-applications.d.ts +35 -0
- package/types/mintplayer-ng-spark-identity-provider-core.d.ts +144 -0
- package/types/mintplayer-ng-spark-identity-provider-developers.d.ts +55 -0
- package/types/mintplayer-ng-spark-identity-provider-management.d.ts +33 -0
- package/types/mintplayer-ng-spark-identity-provider.d.ts +64 -0
- package/types/mintplayer-ng-spark-models.d.ts +28 -0
- package/types/mintplayer-ng-spark-po-detail.d.ts +8 -0
- package/types/mintplayer-ng-spark-po-form.d.ts +2 -0
- package/types/mintplayer-ng-spark-pwa.d.ts +89 -0
- package/types/mintplayer-ng-spark-query-list.d.ts +2 -0
- package/types/mintplayer-ng-spark-renderers.d.ts +47 -0
- package/types/mintplayer-ng-spark-retry-action-modal.d.ts +1 -0
- package/types/mintplayer-ng-spark-services.d.ts +37 -1
- package/types/mintplayer-ng-spark-shell.d.ts +2 -2
- package/types/mintplayer-ng-spark.d.ts +4 -4
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import * as i0 from "@angular/core";
|
|
2
|
+
import { ChangeDetectionStrategy, Component, inject, signal } from "@angular/core";
|
|
3
|
+
import * as i1 from "@angular/forms";
|
|
4
|
+
import { FormBuilder, ReactiveFormsModule } from "@angular/forms";
|
|
5
|
+
import { ActivatedRoute, Router, RouterLink } from "@angular/router";
|
|
6
|
+
import { Color } from "@mintplayer/ng-bootstrap";
|
|
7
|
+
import { BsAlertComponent } from "@mintplayer/ng-bootstrap/alert";
|
|
8
|
+
import { BsCardComponent, BsCardHeaderComponent } from "@mintplayer/ng-bootstrap/card";
|
|
9
|
+
import { BsFormComponent, BsFormControlDirective } from "@mintplayer/ng-bootstrap/form";
|
|
10
|
+
import { BsSpinnerComponent } from "@mintplayer/ng-bootstrap/spinner";
|
|
11
|
+
import { SPARK_AUTH_CONFIG, SPARK_AUTH_ROUTE_PATHS, sanitizeReturnUrl } from "@mintplayer/ng-spark/auth/models";
|
|
12
|
+
import { SparkAuthService, SparkAuthTranslationService } from "@mintplayer/ng-spark/auth/core";
|
|
13
|
+
import { TranslateKeyPipe } from "@mintplayer/ng-spark/auth/pipes";
|
|
14
|
+
var SparkTwoFactorComponent = class SparkTwoFactorComponent {
|
|
15
|
+
fb = inject(FormBuilder);
|
|
16
|
+
authService = inject(SparkAuthService);
|
|
17
|
+
router = inject(Router);
|
|
18
|
+
route = inject(ActivatedRoute);
|
|
19
|
+
config = inject(SPARK_AUTH_CONFIG);
|
|
20
|
+
translation = inject(SparkAuthTranslationService);
|
|
21
|
+
routePaths = inject(SPARK_AUTH_ROUTE_PATHS);
|
|
22
|
+
colors = Color;
|
|
23
|
+
loading = signal(false, ...ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []);
|
|
24
|
+
errorMessage = signal("", ...ngDevMode ? [{ debugName: "errorMessage" }] : /* istanbul ignore next */ []);
|
|
25
|
+
useRecoveryCode = signal(false, ...ngDevMode ? [{ debugName: "useRecoveryCode" }] : /* istanbul ignore next */ []);
|
|
26
|
+
form = this.fb.group({
|
|
27
|
+
code: [""],
|
|
28
|
+
recoveryCode: [""]
|
|
29
|
+
});
|
|
30
|
+
toggleRecoveryCode() {
|
|
31
|
+
this.useRecoveryCode.update((v) => !v);
|
|
32
|
+
this.errorMessage.set("");
|
|
33
|
+
}
|
|
34
|
+
async onSubmit() {
|
|
35
|
+
const isRecovery = this.useRecoveryCode();
|
|
36
|
+
const code = isRecovery ? this.form.value.recoveryCode : this.form.value.code;
|
|
37
|
+
if (!code?.trim()) {
|
|
38
|
+
this.errorMessage.set(isRecovery ? this.translation.t("auth.enterRecoveryCodeError") : this.translation.t("auth.enterCodeError"));
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
this.loading.set(true);
|
|
42
|
+
this.errorMessage.set("");
|
|
43
|
+
const twoFactorCode = isRecovery ? void 0 : code;
|
|
44
|
+
const twoFactorRecoveryCode = isRecovery ? code : void 0;
|
|
45
|
+
try {
|
|
46
|
+
await this.authService.loginTwoFactor(twoFactorCode ?? "", twoFactorRecoveryCode);
|
|
47
|
+
const returnUrl = sanitizeReturnUrl(this.route.snapshot.queryParamMap.get("returnUrl"), this.config.defaultRedirectUrl);
|
|
48
|
+
this.router.navigateByUrl(returnUrl);
|
|
49
|
+
} catch {
|
|
50
|
+
this.errorMessage.set(this.translation.t("auth.invalidCode"));
|
|
51
|
+
} finally {
|
|
52
|
+
this.loading.set(false);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
56
|
+
minVersion: "12.0.0",
|
|
57
|
+
version: "22.2.0",
|
|
58
|
+
ngImport: i0,
|
|
59
|
+
type: SparkTwoFactorComponent,
|
|
60
|
+
deps: [],
|
|
61
|
+
target: i0.ɵɵFactoryTarget.Component
|
|
62
|
+
});
|
|
63
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
64
|
+
minVersion: "17.0.0",
|
|
65
|
+
version: "22.2.0",
|
|
66
|
+
type: SparkTwoFactorComponent,
|
|
67
|
+
isStandalone: true,
|
|
68
|
+
selector: "spark-two-factor",
|
|
69
|
+
ngImport: i0,
|
|
70
|
+
template: "<div class=\"d-flex justify-content-center\">\n <bs-card style=\"width: 100%; max-width: 400px;\">\n <bs-card-header>\n <h3 class=\"mb-0 text-center\">{{ 'auth.twoFactorTitle' | t }}</h3>\n </bs-card-header>\n <div class=\"p-4\">\n @if (errorMessage()) {\n <bs-alert [type]=\"colors.danger\" class=\"mb-3\">{{ errorMessage() }}</bs-alert>\n }\n\n <bs-form>\n <form [formGroup]=\"form\" (ngSubmit)=\"onSubmit()\">\n @if (!useRecoveryCode()) {\n <div class=\"mb-3\">\n <label for=\"code\" class=\"form-label\">{{ 'auth.code' | t }}</label>\n <input\n type=\"text\"\n id=\"code\"\n formControlName=\"code\"\n autocomplete=\"one-time-code\"\n maxlength=\"6\"\n [placeholder]=\"'auth.enterCode' | t\"\n />\n </div>\n } @else {\n <div class=\"mb-3\">\n <label for=\"recoveryCode\" class=\"form-label\">{{ 'auth.recoveryCode' | t }}</label>\n <input\n type=\"text\"\n id=\"recoveryCode\"\n formControlName=\"recoveryCode\"\n autocomplete=\"off\"\n [placeholder]=\"'auth.enterRecoveryCode' | t\"\n />\n </div>\n }\n\n <button\n type=\"submit\"\n class=\"btn btn-primary w-100\"\n [disabled]=\"loading()\"\n >\n @if (loading()) {\n <bs-spinner class=\"me-1\" />\n }\n {{ 'auth.verify' | t }}\n </button>\n </form>\n </bs-form>\n\n <div class=\"mt-3 text-center\">\n <button class=\"btn btn-link\" (click)=\"toggleRecoveryCode()\">\n @if (useRecoveryCode()) {\n {{ 'auth.useAuthCode' | t }}\n } @else {\n {{ 'auth.useRecoveryCode' | t }}\n }\n </button>\n </div>\n <div class=\"mt-2 text-center\">\n <a [routerLink]=\"routePaths.login\">{{ 'auth.backToLogin' | t }}</a>\n </div>\n </div>\n </bs-card>\n</div>\n",
|
|
71
|
+
dependencies: [
|
|
72
|
+
{
|
|
73
|
+
kind: "ngmodule",
|
|
74
|
+
type: ReactiveFormsModule
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
kind: "directive",
|
|
78
|
+
type: i1.ɵNgNoValidate,
|
|
79
|
+
selector: "form:not([ngNoForm]):not([ngNativeValidate])"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
kind: "directive",
|
|
83
|
+
type: i1.DefaultValueAccessor,
|
|
84
|
+
selector: "input:not([type=checkbox]):not([ngNoCva])[formControlName],textarea:not([ngNoCva])[formControlName],input:not([type=checkbox]):not([ngNoCva])[formControl],textarea:not([ngNoCva])[formControl],input:not([type=checkbox]):not([ngNoCva])[ngModel],textarea:not([ngNoCva])[ngModel],[ngDefaultControl]"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
kind: "directive",
|
|
88
|
+
type: i1.NgControlStatus,
|
|
89
|
+
selector: "[formControlName],[ngModel],[formControl]"
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
kind: "directive",
|
|
93
|
+
type: i1.NgControlStatusGroup,
|
|
94
|
+
selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]"
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
kind: "directive",
|
|
98
|
+
type: i1.MaxLengthValidator,
|
|
99
|
+
selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]",
|
|
100
|
+
inputs: ["maxlength"]
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
kind: "directive",
|
|
104
|
+
type: i1.FormGroupDirective,
|
|
105
|
+
selector: "[formGroup]",
|
|
106
|
+
inputs: ["formGroup"],
|
|
107
|
+
outputs: ["ngSubmit"],
|
|
108
|
+
exportAs: ["ngForm"]
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
kind: "directive",
|
|
112
|
+
type: i1.FormControlName,
|
|
113
|
+
selector: "[formControlName]",
|
|
114
|
+
inputs: [
|
|
115
|
+
"formControlName",
|
|
116
|
+
"disabled",
|
|
117
|
+
"ngModel"
|
|
118
|
+
],
|
|
119
|
+
outputs: ["ngModelChange"]
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
kind: "directive",
|
|
123
|
+
type: RouterLink,
|
|
124
|
+
selector: "[routerLink]",
|
|
125
|
+
inputs: [
|
|
126
|
+
"target",
|
|
127
|
+
"queryParams",
|
|
128
|
+
"fragment",
|
|
129
|
+
"queryParamsHandling",
|
|
130
|
+
"state",
|
|
131
|
+
"info",
|
|
132
|
+
"relativeTo",
|
|
133
|
+
"preserveFragment",
|
|
134
|
+
"skipLocationChange",
|
|
135
|
+
"replaceUrl",
|
|
136
|
+
"browserUrl",
|
|
137
|
+
"routerLink"
|
|
138
|
+
]
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
kind: "component",
|
|
142
|
+
type: BsAlertComponent,
|
|
143
|
+
selector: "bs-alert",
|
|
144
|
+
inputs: [
|
|
145
|
+
"type",
|
|
146
|
+
"announce",
|
|
147
|
+
"isVisible"
|
|
148
|
+
],
|
|
149
|
+
outputs: ["isVisibleChange", "afterOpenedOrClosed"]
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
kind: "component",
|
|
153
|
+
type: BsCardComponent,
|
|
154
|
+
selector: "bs-card",
|
|
155
|
+
inputs: ["color", "outline"]
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
kind: "component",
|
|
159
|
+
type: BsCardHeaderComponent,
|
|
160
|
+
selector: "bs-card-header",
|
|
161
|
+
inputs: ["color", "navStyle"]
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
kind: "component",
|
|
165
|
+
type: BsFormComponent,
|
|
166
|
+
selector: "bs-form",
|
|
167
|
+
inputs: ["action", "method"],
|
|
168
|
+
outputs: ["submitted"]
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
kind: "directive",
|
|
172
|
+
type: BsFormControlDirective,
|
|
173
|
+
selector: "bs-form input:not(.no-form-control), bs-form textarea:not(.no-form-control)"
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
kind: "component",
|
|
177
|
+
type: BsSpinnerComponent,
|
|
178
|
+
selector: "bs-spinner",
|
|
179
|
+
inputs: ["type", "color"]
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
kind: "pipe",
|
|
183
|
+
type: TranslateKeyPipe,
|
|
184
|
+
name: "t"
|
|
185
|
+
}
|
|
186
|
+
],
|
|
187
|
+
changeDetection: i0.ChangeDetectionStrategy.OnPush
|
|
188
|
+
});
|
|
189
|
+
};
|
|
190
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
191
|
+
minVersion: "12.0.0",
|
|
192
|
+
version: "22.2.0",
|
|
193
|
+
ngImport: i0,
|
|
194
|
+
type: SparkTwoFactorComponent,
|
|
195
|
+
decorators: [{
|
|
196
|
+
type: Component,
|
|
197
|
+
args: [{
|
|
198
|
+
selector: "spark-two-factor",
|
|
199
|
+
standalone: true,
|
|
200
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
201
|
+
imports: [
|
|
202
|
+
ReactiveFormsModule,
|
|
203
|
+
RouterLink,
|
|
204
|
+
BsAlertComponent,
|
|
205
|
+
BsCardComponent,
|
|
206
|
+
BsCardHeaderComponent,
|
|
207
|
+
BsFormComponent,
|
|
208
|
+
BsFormControlDirective,
|
|
209
|
+
BsSpinnerComponent,
|
|
210
|
+
TranslateKeyPipe
|
|
211
|
+
],
|
|
212
|
+
template: "<div class=\"d-flex justify-content-center\">\n <bs-card style=\"width: 100%; max-width: 400px;\">\n <bs-card-header>\n <h3 class=\"mb-0 text-center\">{{ 'auth.twoFactorTitle' | t }}</h3>\n </bs-card-header>\n <div class=\"p-4\">\n @if (errorMessage()) {\n <bs-alert [type]=\"colors.danger\" class=\"mb-3\">{{ errorMessage() }}</bs-alert>\n }\n\n <bs-form>\n <form [formGroup]=\"form\" (ngSubmit)=\"onSubmit()\">\n @if (!useRecoveryCode()) {\n <div class=\"mb-3\">\n <label for=\"code\" class=\"form-label\">{{ 'auth.code' | t }}</label>\n <input\n type=\"text\"\n id=\"code\"\n formControlName=\"code\"\n autocomplete=\"one-time-code\"\n maxlength=\"6\"\n [placeholder]=\"'auth.enterCode' | t\"\n />\n </div>\n } @else {\n <div class=\"mb-3\">\n <label for=\"recoveryCode\" class=\"form-label\">{{ 'auth.recoveryCode' | t }}</label>\n <input\n type=\"text\"\n id=\"recoveryCode\"\n formControlName=\"recoveryCode\"\n autocomplete=\"off\"\n [placeholder]=\"'auth.enterRecoveryCode' | t\"\n />\n </div>\n }\n\n <button\n type=\"submit\"\n class=\"btn btn-primary w-100\"\n [disabled]=\"loading()\"\n >\n @if (loading()) {\n <bs-spinner class=\"me-1\" />\n }\n {{ 'auth.verify' | t }}\n </button>\n </form>\n </bs-form>\n\n <div class=\"mt-3 text-center\">\n <button class=\"btn btn-link\" (click)=\"toggleRecoveryCode()\">\n @if (useRecoveryCode()) {\n {{ 'auth.useAuthCode' | t }}\n } @else {\n {{ 'auth.useRecoveryCode' | t }}\n }\n </button>\n </div>\n <div class=\"mt-2 text-center\">\n <a [routerLink]=\"routePaths.login\">{{ 'auth.backToLogin' | t }}</a>\n </div>\n </div>\n </bs-card>\n</div>\n"
|
|
213
|
+
}]
|
|
214
|
+
}]
|
|
215
|
+
});
|
|
216
|
+
export { SparkTwoFactorComponent };
|
|
217
|
+
|
|
218
|
+
//# sourceMappingURL=mintplayer-ng-spark-auth-two-factor.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mintplayer-ng-spark-auth-two-factor.mjs","names":[],"sources":["../../auth/two-factor/src/spark-two-factor.component.ts","../../auth/two-factor/src/spark-two-factor.component.html"],"sourcesContent":["import { ChangeDetectionStrategy, Component, inject, signal } from '@angular/core';\nimport { ReactiveFormsModule, FormBuilder, Validators } from '@angular/forms';\nimport { RouterLink, ActivatedRoute, Router } from '@angular/router';\nimport { Color } from '@mintplayer/ng-bootstrap';\nimport { BsAlertComponent } from '@mintplayer/ng-bootstrap/alert';\nimport { BsCardComponent, BsCardHeaderComponent } from '@mintplayer/ng-bootstrap/card';\nimport { BsFormComponent, BsFormControlDirective } from '@mintplayer/ng-bootstrap/form';\nimport { BsSpinnerComponent } from '@mintplayer/ng-bootstrap/spinner';\nimport { SPARK_AUTH_CONFIG, SPARK_AUTH_ROUTE_PATHS, sanitizeReturnUrl } from '@mintplayer/ng-spark/auth/models';\nimport { SparkAuthService, SparkAuthTranslationService } from '@mintplayer/ng-spark/auth/core';\nimport { TranslateKeyPipe } from '@mintplayer/ng-spark/auth/pipes';\n\n@Component({\n selector: 'spark-two-factor',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [ReactiveFormsModule, RouterLink, BsAlertComponent, BsCardComponent, BsCardHeaderComponent, BsFormComponent, BsFormControlDirective, BsSpinnerComponent, TranslateKeyPipe],\n templateUrl: './spark-two-factor.component.html',\n})\nexport class SparkTwoFactorComponent {\n private readonly fb = inject(FormBuilder);\n private readonly authService = inject(SparkAuthService);\n private readonly router = inject(Router);\n private readonly route = inject(ActivatedRoute);\n private readonly config = inject(SPARK_AUTH_CONFIG);\n private readonly translation = inject(SparkAuthTranslationService);\n readonly routePaths = inject(SPARK_AUTH_ROUTE_PATHS);\n\n colors = Color;\n readonly loading = signal(false);\n readonly errorMessage = signal('');\n readonly useRecoveryCode = signal(false);\n\n readonly form = this.fb.group({\n code: [''],\n recoveryCode: [''],\n });\n\n toggleRecoveryCode(): void {\n this.useRecoveryCode.update(v => !v);\n this.errorMessage.set('');\n }\n\n async onSubmit(): Promise<void> {\n const isRecovery = this.useRecoveryCode();\n const code = isRecovery ? this.form.value.recoveryCode : this.form.value.code;\n\n if (!code?.trim()) {\n this.errorMessage.set(isRecovery\n ? this.translation.t('auth.enterRecoveryCodeError')\n : this.translation.t('auth.enterCodeError'));\n return;\n }\n\n this.loading.set(true);\n this.errorMessage.set('');\n\n const twoFactorCode = isRecovery ? undefined : code;\n const twoFactorRecoveryCode = isRecovery ? code : undefined;\n\n try {\n await this.authService.loginTwoFactor(twoFactorCode ?? '', twoFactorRecoveryCode);\n // R2-H9: same sanitization as login. The 2FA component receives returnUrl\n // forwarded from the login step but must still validate — query params\n // travel through router state and a deep-link to /two-factor?returnUrl=…\n // is a viable attacker vector.\n const returnUrl = sanitizeReturnUrl(\n this.route.snapshot.queryParamMap.get('returnUrl'),\n this.config.defaultRedirectUrl);\n this.router.navigateByUrl(returnUrl);\n } catch {\n this.errorMessage.set(this.translation.t('auth.invalidCode'));\n } finally {\n this.loading.set(false);\n }\n }\n}\n\nexport default SparkTwoFactorComponent;\n","<div class=\"d-flex justify-content-center\">\n <bs-card style=\"width: 100%; max-width: 400px;\">\n <bs-card-header>\n <h3 class=\"mb-0 text-center\">{{ 'auth.twoFactorTitle' | t }}</h3>\n </bs-card-header>\n <div class=\"p-4\">\n @if (errorMessage()) {\n <bs-alert [type]=\"colors.danger\" class=\"mb-3\">{{ errorMessage() }}</bs-alert>\n }\n\n <bs-form>\n <form [formGroup]=\"form\" (ngSubmit)=\"onSubmit()\">\n @if (!useRecoveryCode()) {\n <div class=\"mb-3\">\n <label for=\"code\" class=\"form-label\">{{ 'auth.code' | t }}</label>\n <input\n type=\"text\"\n id=\"code\"\n formControlName=\"code\"\n autocomplete=\"one-time-code\"\n maxlength=\"6\"\n [placeholder]=\"'auth.enterCode' | t\"\n />\n </div>\n } @else {\n <div class=\"mb-3\">\n <label for=\"recoveryCode\" class=\"form-label\">{{ 'auth.recoveryCode' | t }}</label>\n <input\n type=\"text\"\n id=\"recoveryCode\"\n formControlName=\"recoveryCode\"\n autocomplete=\"off\"\n [placeholder]=\"'auth.enterRecoveryCode' | t\"\n />\n </div>\n }\n\n <button\n type=\"submit\"\n class=\"btn btn-primary w-100\"\n [disabled]=\"loading()\"\n >\n @if (loading()) {\n <bs-spinner class=\"me-1\" />\n }\n {{ 'auth.verify' | t }}\n </button>\n </form>\n </bs-form>\n\n <div class=\"mt-3 text-center\">\n <button class=\"btn btn-link\" (click)=\"toggleRecoveryCode()\">\n @if (useRecoveryCode()) {\n {{ 'auth.useAuthCode' | t }}\n } @else {\n {{ 'auth.useRecoveryCode' | t }}\n }\n </button>\n </div>\n <div class=\"mt-2 text-center\">\n <a [routerLink]=\"routePaths.login\">{{ 'auth.backToLogin' | t }}</a>\n </div>\n </div>\n </bs-card>\n</div>\n"],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { SPARK_AUTH_CONFIG, SPARK_AUTH_CONFIG as SPARK_AUTH_CONFIG$1, defaultSparkAuthConfig, defaultSparkAuthConfig as defaultSparkAuthConfig$1, passkeysSupported, sparkPasskeyError } from "@mintplayer/ng-spark/auth/models";
|
|
2
|
+
import { inject, makeEnvironmentProviders } from "@angular/core";
|
|
3
|
+
import { withInterceptors, withXsrfConfiguration } from "@angular/common/http";
|
|
4
|
+
import { SPARK_AUTH_STATE } from "@mintplayer/ng-spark";
|
|
5
|
+
import { provideSparkClientMethods } from "@mintplayer/ng-spark/client-operations";
|
|
6
|
+
import { sparkAuthInterceptor } from "@mintplayer/ng-spark/auth/interceptors";
|
|
7
|
+
import { SparkAuthService } from "@mintplayer/ng-spark/auth/core";
|
|
8
|
+
const sparkAuthClientMethods = { "webauthn.create": {
|
|
9
|
+
supported: passkeysSupported,
|
|
10
|
+
unsupportedReason: "auth.passkeyUnsupported",
|
|
11
|
+
async invoke(args) {
|
|
12
|
+
try {
|
|
13
|
+
const options = PublicKeyCredential.parseCreationOptionsFromJSON(args);
|
|
14
|
+
const credential = await navigator.credentials.create({ publicKey: options });
|
|
15
|
+
if (!credential) throw new DOMException("No credential was produced.", "NotAllowedError");
|
|
16
|
+
return JSON.parse(JSON.stringify(credential));
|
|
17
|
+
} catch (error) {
|
|
18
|
+
const code = sparkPasskeyError(error);
|
|
19
|
+
if (code === "cancelled" || code === "no_credential") throw error;
|
|
20
|
+
return { error: code };
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
} };
|
|
24
|
+
function provideSparkAuth(config) {
|
|
25
|
+
return makeEnvironmentProviders([
|
|
26
|
+
{
|
|
27
|
+
provide: SPARK_AUTH_CONFIG$1,
|
|
28
|
+
useValue: {
|
|
29
|
+
...defaultSparkAuthConfig$1,
|
|
30
|
+
...config
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
provide: SPARK_AUTH_STATE,
|
|
35
|
+
useFactory: () => inject(SparkAuthService).user
|
|
36
|
+
},
|
|
37
|
+
provideSparkClientMethods(sparkAuthClientMethods)
|
|
38
|
+
]);
|
|
39
|
+
}
|
|
40
|
+
function withSparkAuth() {
|
|
41
|
+
return [withInterceptors([sparkAuthInterceptor]), withXsrfConfiguration({
|
|
42
|
+
cookieName: "XSRF-TOKEN",
|
|
43
|
+
headerName: "X-XSRF-TOKEN"
|
|
44
|
+
})];
|
|
45
|
+
}
|
|
46
|
+
export { SPARK_AUTH_CONFIG, defaultSparkAuthConfig, provideSparkAuth, sparkAuthClientMethods, withSparkAuth };
|
|
47
|
+
|
|
48
|
+
//# sourceMappingURL=mintplayer-ng-spark-auth.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mintplayer-ng-spark-auth.mjs","names":[],"sources":["../../auth/src/lib/webauthn-client-methods.ts","../../auth/src/lib/provide-spark-auth.ts"],"sourcesContent":["import type { SparkClientMethodMap } from '@mintplayer/ng-spark/client-operations';\nimport { passkeysSupported, sparkPasskeyError } from '@mintplayer/ng-spark/auth/models';\n\n/**\n * The browser steps the Authorization library's server actions invoke (`IRetryAccessor.Invoke`),\n * registered by {@link provideSparkAuth}.\n *\n * `webauthn.create` is the enrollment ceremony of the passkeys page's `AddPasskey` action: the\n * server hands it the creation options and receives the credential back in the same action, which\n * attests it against the ceremony cookie its first pass set. The server keeps the challenge; nothing\n * here chooses or carries one.\n *\n * - The user dismissing the prompt (`cancelled`, `no_credential`) rejects, which answers the server\n * with `Cancel`: not an error, so no banner.\n * - Any other failure (an authenticator already holding a credential for this account, a security\n * error) resolves as `{ error }`, so the server can say it did not work.\n * - An unsupported browser never runs it (`supported`), and the action shows disabled with\n * `auth.passkeyUnsupported` as the reason.\n */\nexport const sparkAuthClientMethods: SparkClientMethodMap = {\n 'webauthn.create': {\n supported: passkeysSupported,\n unsupportedReason: 'auth.passkeyUnsupported',\n async invoke(args: unknown): Promise<unknown> {\n try {\n const options = PublicKeyCredential.parseCreationOptionsFromJSON(args as PublicKeyCredentialCreationOptionsJSON);\n const credential = await navigator.credentials.create({ publicKey: options });\n if (!credential) throw new DOMException('No credential was produced.', 'NotAllowedError');\n // The credential's own toJSON is WebAuthn's JSON encoding, which the server's attestation reads.\n return JSON.parse(JSON.stringify(credential));\n } catch (error) {\n const code = sparkPasskeyError(error);\n if (code === 'cancelled' || code === 'no_credential') throw error;\n return { error: code };\n }\n },\n },\n};\n","import { EnvironmentProviders, inject, makeEnvironmentProviders } from '@angular/core';\nimport { HttpFeature, HttpFeatureKind, withInterceptors, withXsrfConfiguration } from '@angular/common/http';\nimport { SPARK_AUTH_STATE } from '@mintplayer/ng-spark';\nimport { provideSparkClientMethods } from '@mintplayer/ng-spark/client-operations';\nimport {\n defaultSparkAuthConfig,\n SPARK_AUTH_CONFIG,\n SparkAuthConfig,\n} from '@mintplayer/ng-spark/auth/models';\nimport { sparkAuthInterceptor } from '@mintplayer/ng-spark/auth/interceptors';\nimport { SparkAuthService } from '@mintplayer/ng-spark/auth/core';\nimport { sparkAuthClientMethods } from './webauthn-client-methods';\n\nexport function provideSparkAuth(\n config?: Partial<SparkAuthConfig>,\n): EnvironmentProviders {\n return makeEnvironmentProviders([\n {\n provide: SPARK_AUTH_CONFIG,\n useValue: { ...defaultSparkAuthConfig, ...config },\n },\n // Bridges sign-in/out into ng-spark (which must not depend on this package): auth-sensitive\n // consumers there — the program-units menu — track this signal and re-fetch on change.\n {\n provide: SPARK_AUTH_STATE,\n useFactory: () => inject(SparkAuthService).user,\n },\n // The browser steps the library's server actions invoke: `webauthn.create` for AddPasskey.\n provideSparkClientMethods(sparkAuthClientMethods),\n ]);\n}\n\nexport function withSparkAuth(): HttpFeature<HttpFeatureKind>[] {\n return [\n withInterceptors([sparkAuthInterceptor]),\n withXsrfConfiguration({ cookieName: 'XSRF-TOKEN', headerName: 'X-XSRF-TOKEN' }),\n ];\n}\n"],"mappings":";;;;;;;AAmBA,MAAa,yBAA+C,EAC1D,mBAAmB;CACjB,WAAW;CACX,mBAAmB;CACnB,MAAM,OAAO,MAAa;EACxB,IAAI;GACF,MAAM,UAAU,oBAAoB,6BAA6B,IAA8C;GAC/G,MAAM,aAAa,MAAM,UAAU,YAAY,OAAO,EAAE,WAAW,QAAO,CAAE;GAC5E,IAAI,CAAC,YAAY,MAAM,IAAI,aAAa,+BAA+B,iBAAiB;GAExF,OAAO,KAAK,MAAM,KAAK,UAAU,UAAU,CAAC;EAC9C,SAAS,OAAO;GACd,MAAM,OAAO,kBAAkB,KAAK;GACpC,IAAI,SAAS,eAAe,SAAS,iBAAiB,MAAM;GAC5D,OAAO,EAAE,OAAO,KAAI;EACtB;CACF;AACD,EACF;ACxBD,SAAgB,iBACd,QAAiC;CAEjC,OAAO,yBAAyB;EAC9B;GACE,SAAS;GACT,UAAU;IAAE,GAAG;IAAwB,GAAG;GAAM;EACjD;EAGD;GACE,SAAS;GACT,kBAAkB,OAAO,gBAAgB,CAAC,CAAC;EAC5C;EAED,0BAA0B,sBAAsB;CACjD,CAAA;AACH;AAEA,SAAgB,gBAAa;CAC3B,OAAO,CACL,iBAAiB,CAAC,oBAAoB,CAAC,GACvC,sBAAsB;EAAE,YAAY;EAAc,YAAY;CAAc,CAAE,CAC/E;AACH"}
|