@dereekb/dbx-firebase 13.11.3 → 13.11.5
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/fesm2022/dereekb-dbx-firebase-oidc.mjs +685 -222
- package/fesm2022/dereekb-dbx-firebase-oidc.mjs.map +1 -1
- package/fesm2022/dereekb-dbx-firebase.mjs +36 -1
- package/fesm2022/dereekb-dbx-firebase.mjs.map +1 -1
- package/package.json +11 -11
- package/types/dereekb-dbx-firebase-oidc.d.ts +425 -171
- package/types/dereekb-dbx-firebase.d.ts +36 -1
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input, computed, output, ChangeDetectionStrategy, Component, inject, Injectable, signal, effect, Directive, provideAppInitializer, makeEnvironmentProviders } from '@angular/core';
|
|
3
|
-
import * as i1
|
|
4
|
-
import { DbxBasicLoadingComponent, DbxErrorComponent, DbxButtonComponent, DbxAvatarComponent,
|
|
2
|
+
import { input, computed, output, ChangeDetectionStrategy, Component, inject, Injectable, signal, effect, Directive, viewChild, provideAppInitializer, makeEnvironmentProviders } from '@angular/core';
|
|
3
|
+
import * as i1 from '@dereekb/dbx-web';
|
|
4
|
+
import { DbxBasicLoadingComponent, DbxErrorComponent, DbxButtonComponent, DbxAvatarComponent, DbxButtonSpacerDirective, DbxActionSnackbarErrorDirective, AbstractDbxSelectionListWrapperDirective, DbxListWrapperComponentImportsModule, DEFAULT_LIST_WRAPPER_COMPONENT_CONFIGURATION_TEMPLATE, AbstractDbxSelectionListViewDirective, DbxSelectionValueListViewComponentImportsModule, provideDbxListView, DEFAULT_DBX_SELECTION_VALUE_LIST_COMPONENT_CONFIGURATION_TEMPLATE, AbstractDbxValueListViewItemComponent, provideDbxListViewWrapper, DbxSpacerDirective, DbxActionConfirmDirective, DbxContentPitDirective, DbxDetailBlockComponent, DbxClickToCopyTextComponent } from '@dereekb/dbx-web';
|
|
5
5
|
import { readableError, SPACE_STRING_SPLIT_JOIN, separateValues, generatePkceCodeVerifier, generatePkceCodeChallenge } from '@dereekb/util';
|
|
6
|
-
import { DbxInjectionComponent,
|
|
6
|
+
import { DbxInjectionComponent, DbxActionDirective, DbxActionHandlerDirective, DbxActionValueDirective, DbxActionButtonDirective, DBX_INJECTION_COMPONENT_DATA, DbxRouterService, dbxRouteParamReaderInstance, completeOnDestroy, DbxActionEnforceModifiedDirective, DbxAppAuthRouterService } from '@dereekb/dbx-core';
|
|
7
|
+
import { of, map, first, switchMap, tap, BehaviorSubject } from 'rxjs';
|
|
8
|
+
import * as i1$1 from '@dereekb/dbx-form';
|
|
9
|
+
import { dbxForgeListSelectionField, AbstractConfigAsyncForgeFormDirective, DbxForgeFormComponentImportsModule, dbxForgeFormComponentProviders, DBX_FORGE_FORM_COMPONENT_TEMPLATE, DbxActionFormDirective, dbxForgeValueSelectionField, dbxForgeTextField, dbxForgeSearchableStringChipField, isWebsiteUrlValidator, dbxForgeContainer, dbxForgePickableChipField, pickableValueFieldValuesConfigForStaticLabeledValues, DbxFormSourceDirective, DbxFormValueChangeDirective } from '@dereekb/dbx-form';
|
|
10
|
+
import { successResult } from '@dereekb/rxjs';
|
|
7
11
|
import { toSignal } from '@angular/core/rxjs-interop';
|
|
8
|
-
import { DbxFirebaseAuthService, AbstractDbxFirebaseDocumentStore, firebaseDocumentStoreCreateFunction, firebaseDocumentStoreUpdateFunction, firebaseDocumentStoreDeleteFunction, AbstractDbxFirebaseCollectionStore, DbxFirebaseCollectionStoreDirective, provideDbxFirebaseCollectionStoreDirective, DbxFirebaseDocumentStoreDirective, provideDbxFirebaseDocumentStoreDirective } from '@dereekb/dbx-firebase';
|
|
12
|
+
import { DbxFirebaseAuthService, AbstractDbxFirebaseDocumentStore, firebaseDocumentStoreCreateFunction, firebaseDocumentStoreUpdateFunction, firebaseDocumentStoreDeleteFunction, AbstractDbxFirebaseCollectionStore, DbxFirebaseCollectionStoreDirective, provideDbxFirebaseCollectionStoreDirective, DbxFirebaseCollectionListDirective, DbxFirebaseCollectionChangeDirective, DbxFirebaseDocumentStoreDirective, provideDbxFirebaseDocumentStoreDirective } from '@dereekb/dbx-firebase';
|
|
9
13
|
import { HttpClient } from '@angular/common/http';
|
|
10
|
-
import {
|
|
11
|
-
import
|
|
12
|
-
import { dbxForgeValueSelectionField, dbxForgeTextField, dbxForgeSearchableStringChipField, isWebsiteUrlValidator, dbxForgeContainer, dbxForgePickableChipField, pickableValueFieldValuesConfigForStaticLabeledValues, AbstractConfigAsyncForgeFormDirective, DbxForgeFormComponentImportsModule, dbxForgeFormComponentProviders, DBX_FORGE_FORM_COMPONENT_TEMPLATE, DbxActionFormDirective, DbxFormSourceDirective, DbxFormValueChangeDirective } from '@dereekb/dbx-form';
|
|
13
|
-
import { ALL_OIDC_TOKEN_ENDPOINT_AUTH_METHOD_OPTIONS, PRIVATE_KEY_JWT_TOKEN_ENDPOINT_AUTH_METHOD, OIDC_ENTRY_CLIENT_TYPE, OidcModelFunctions, OidcModelFirestoreCollections } from '@dereekb/firebase';
|
|
14
|
-
import { CommonModule } from '@angular/common';
|
|
14
|
+
import { ALL_OIDC_TOKEN_ENDPOINT_AUTH_METHOD_OPTIONS, PRIVATE_KEY_JWT_TOKEN_ENDPOINT_AUTH_METHOD, OidcModelFunctions, OidcModelFirestoreCollections, OIDC_ENTRY_CLIENT_TYPE, oidcGrantEntriesByUidQuery } from '@dereekb/firebase';
|
|
15
|
+
import { DatePipe, CommonModule } from '@angular/common';
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* Presentational component for the OIDC OAuth login interaction.
|
|
@@ -39,6 +40,9 @@ class DbxFirebaseOAuthLoginViewComponent {
|
|
|
39
40
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: DbxFirebaseOAuthLoginViewComponent, isStandalone: true, selector: "dbx-firebase-oauth-login-view", inputs: { loginStateCase: { classPropertyName: "loginStateCase", publicName: "loginStateCase", isSignal: true, isRequired: true, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { retryClick: "retryClick" }, host: { classAttribute: "d-block dbx-firebase-oauth-login-view" }, ngImport: i0, template: `
|
|
40
41
|
<div class="dbx-firebase-oauth-login-view">
|
|
41
42
|
@switch (loginStateCase()) {
|
|
43
|
+
@case ('unknown') {
|
|
44
|
+
<dbx-basic-loading [loading]="true"></dbx-basic-loading>
|
|
45
|
+
}
|
|
42
46
|
@case ('no_user') {
|
|
43
47
|
<ng-content></ng-content>
|
|
44
48
|
}
|
|
@@ -65,6 +69,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
65
69
|
template: `
|
|
66
70
|
<div class="dbx-firebase-oauth-login-view">
|
|
67
71
|
@switch (loginStateCase()) {
|
|
72
|
+
@case ('unknown') {
|
|
73
|
+
<dbx-basic-loading [loading]="true"></dbx-basic-loading>
|
|
74
|
+
}
|
|
68
75
|
@case ('no_user') {
|
|
69
76
|
<ng-content></ng-content>
|
|
70
77
|
}
|
|
@@ -88,120 +95,174 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
88
95
|
}]
|
|
89
96
|
}], propDecorators: { loginStateCase: [{ type: i0.Input, args: [{ isSignal: true, alias: "loginStateCase", required: true }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], retryClick: [{ type: i0.Output, args: ["retryClick"] }] } });
|
|
90
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Default required scopes — `openid` is mandatory for any OIDC flow, so the
|
|
100
|
+
* UI always treats it as not-deselectable.
|
|
101
|
+
*/
|
|
102
|
+
const DEFAULT_OAUTH_CONSENT_REQUIRED_SCOPES = ['openid'];
|
|
91
103
|
/**
|
|
92
104
|
* Presentational component for the OIDC OAuth consent screen.
|
|
93
105
|
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
106
|
+
* Wires up two `dbxAction` contexts — an outer one for Approve (which hosts
|
|
107
|
+
* the scope-selection forge form via `dbxActionForm`) and a nested one for
|
|
108
|
+
* Deny (which carries no value). Buttons are bound by Angular DI's
|
|
109
|
+
* nearest-ancestor lookup: the Approve button picks up the outer action, the
|
|
110
|
+
* Deny button (wrapped in its own `<ng-container dbxAction>`) picks up the
|
|
111
|
+
* inner.
|
|
112
|
+
*
|
|
113
|
+
* Supports ng-content projection — anything provided is rendered for the
|
|
114
|
+
* `'no_user'` state (so apps can project a login view, mirroring
|
|
115
|
+
* `DbxFirebaseOAuthLoginViewComponent`).
|
|
97
116
|
*
|
|
98
117
|
* @example
|
|
99
118
|
* ```html
|
|
100
119
|
* <dbx-firebase-oauth-consent-view
|
|
101
120
|
* [details]="loginDetails"
|
|
102
|
-
* [
|
|
121
|
+
* [consentStateCase]="'user'"
|
|
103
122
|
* [scopeInjectionConfig]="scopeConfig"
|
|
104
|
-
*
|
|
105
|
-
*
|
|
123
|
+
* [approveHandler]="handleApprove"
|
|
124
|
+
* [denyHandler]="handleDeny">
|
|
106
125
|
* </dbx-firebase-oauth-consent-view>
|
|
107
126
|
* ```
|
|
108
127
|
*/
|
|
109
128
|
class DbxFirebaseOAuthConsentViewComponent {
|
|
110
129
|
details = input(...(ngDevMode ? [undefined, { debugName: "details" }] : /* istanbul ignore next */ []));
|
|
111
|
-
|
|
112
|
-
error = input(...(ngDevMode ? [undefined, { debugName: "error" }] : /* istanbul ignore next */ []));
|
|
130
|
+
consentStateCase = input.required(...(ngDevMode ? [{ debugName: "consentStateCase" }] : /* istanbul ignore next */ []));
|
|
113
131
|
scopeInjectionConfig = input.required(...(ngDevMode ? [{ debugName: "scopeInjectionConfig" }] : /* istanbul ignore next */ []));
|
|
132
|
+
/**
|
|
133
|
+
* Scopes that cannot be deselected by the user. Forwarded to the scope
|
|
134
|
+
* view so it can render an "Always granted" hint. Defaults to `['openid']`.
|
|
135
|
+
*/
|
|
136
|
+
requiredScopes = input(DEFAULT_OAUTH_CONSENT_REQUIRED_SCOPES, ...(ngDevMode ? [{ debugName: "requiredScopes" }] : /* istanbul ignore next */ []));
|
|
137
|
+
/**
|
|
138
|
+
* Approve handler — called with the form value when the Approve button
|
|
139
|
+
* triggers the outer action. Receives a `WorkUsingContext` to drive the
|
|
140
|
+
* action's loading/success/error pipeline.
|
|
141
|
+
*/
|
|
142
|
+
approveHandler = input.required(...(ngDevMode ? [{ debugName: "approveHandler" }] : /* istanbul ignore next */ []));
|
|
143
|
+
/**
|
|
144
|
+
* Deny handler — called when the Deny button triggers the inner action.
|
|
145
|
+
* No value is passed (`dbxActionValue` provides an empty payload).
|
|
146
|
+
*/
|
|
147
|
+
denyHandler = input.required(...(ngDevMode ? [{ debugName: "denyHandler" }] : /* istanbul ignore next */ []));
|
|
114
148
|
clientName = computed(() => this.details()?.client_name ?? '', ...(ngDevMode ? [{ debugName: "clientName" }] : /* istanbul ignore next */ []));
|
|
115
149
|
clientUri = computed(() => this.details()?.client_uri, ...(ngDevMode ? [{ debugName: "clientUri" }] : /* istanbul ignore next */ []));
|
|
116
150
|
logoUri = computed(() => this.details()?.logo_uri, ...(ngDevMode ? [{ debugName: "logoUri" }] : /* istanbul ignore next */ []));
|
|
117
151
|
scopes = computed(() => SPACE_STRING_SPLIT_JOIN.splitStrings(this.details()?.scopes ?? ''), ...(ngDevMode ? [{ debugName: "scopes" }] : /* istanbul ignore next */ []));
|
|
118
|
-
resolvedError = computed(() => {
|
|
119
|
-
const error = this.error();
|
|
120
|
-
return typeof error === 'string' ? readableError('ERROR', error) : error;
|
|
121
|
-
}, ...(ngDevMode ? [{ debugName: "resolvedError" }] : /* istanbul ignore next */ []));
|
|
122
|
-
approveClick = output();
|
|
123
|
-
denyClick = output();
|
|
124
152
|
resolvedScopeInjectionConfig = computed(() => {
|
|
125
153
|
const data = {
|
|
126
154
|
details: this.details(),
|
|
127
155
|
scopes: this.scopes(),
|
|
128
|
-
clientName: this.clientName()
|
|
156
|
+
clientName: this.clientName(),
|
|
157
|
+
requiredScopes: this.requiredScopes()
|
|
129
158
|
};
|
|
130
159
|
return { ...this.scopeInjectionConfig(), data };
|
|
131
160
|
}, ...(ngDevMode ? [{ debugName: "resolvedScopeInjectionConfig" }] : /* istanbul ignore next */ []));
|
|
132
161
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOAuthConsentViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
133
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: DbxFirebaseOAuthConsentViewComponent, isStandalone: true, selector: "dbx-firebase-oauth-consent-view", inputs: { details: { classPropertyName: "details", publicName: "details", isSignal: true, isRequired: false, transformFunction: null },
|
|
162
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: DbxFirebaseOAuthConsentViewComponent, isStandalone: true, selector: "dbx-firebase-oauth-consent-view", inputs: { details: { classPropertyName: "details", publicName: "details", isSignal: true, isRequired: false, transformFunction: null }, consentStateCase: { classPropertyName: "consentStateCase", publicName: "consentStateCase", isSignal: true, isRequired: true, transformFunction: null }, scopeInjectionConfig: { classPropertyName: "scopeInjectionConfig", publicName: "scopeInjectionConfig", isSignal: true, isRequired: true, transformFunction: null }, requiredScopes: { classPropertyName: "requiredScopes", publicName: "requiredScopes", isSignal: true, isRequired: false, transformFunction: null }, approveHandler: { classPropertyName: "approveHandler", publicName: "approveHandler", isSignal: true, isRequired: true, transformFunction: null }, denyHandler: { classPropertyName: "denyHandler", publicName: "denyHandler", isSignal: true, isRequired: true, transformFunction: null } }, host: { classAttribute: "d-block dbx-firebase-oauth-consent-view" }, ngImport: i0, template: `
|
|
134
163
|
<div class="dbx-firebase-oauth-consent-view">
|
|
135
|
-
@
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
164
|
+
@switch (consentStateCase()) {
|
|
165
|
+
@case ('unknown') {
|
|
166
|
+
<dbx-basic-loading [loading]="true"></dbx-basic-loading>
|
|
167
|
+
}
|
|
168
|
+
@case ('no_user') {
|
|
169
|
+
<ng-content></ng-content>
|
|
170
|
+
}
|
|
171
|
+
@case ('user') {
|
|
172
|
+
<div class="dbx-firebase-oauth-consent-header">
|
|
173
|
+
@if (clientName()) {
|
|
174
|
+
<h2>You're signing in to {{ clientName() }}</h2>
|
|
175
|
+
}
|
|
176
|
+
<div class="dbx-firebase-oauth-consent-header-info dbx-flex">
|
|
177
|
+
<dbx-avatar [avatarUrl]="logoUri()" [avatarStyle]="'square'" avatarIcon="apps"></dbx-avatar>
|
|
178
|
+
<span>
|
|
179
|
+
@if (clientUri()) {
|
|
180
|
+
<a class="dbx-firebase-oauth-consent-client-uri" [href]="clientUri()" target="_blank" rel="noopener noreferrer">{{ clientUri() }}</a>
|
|
181
|
+
}
|
|
182
|
+
</span>
|
|
183
|
+
</div>
|
|
184
|
+
</div>
|
|
139
185
|
@if (clientName()) {
|
|
140
|
-
<
|
|
186
|
+
<p class="dbx-firebase-oauth-consent-prompt">
|
|
187
|
+
<strong>{{ clientName() }}</strong>
|
|
188
|
+
is requesting these permissions:
|
|
189
|
+
</p>
|
|
141
190
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
<
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
191
|
+
|
|
192
|
+
<div dbxAction dbxActionSnackbarError [dbxActionHandler]="approveHandler()">
|
|
193
|
+
<dbx-injection [config]="resolvedScopeInjectionConfig()"></dbx-injection>
|
|
194
|
+
|
|
195
|
+
<div class="dbx-pt3 dbx-pb3 dbx-firebase-oauth-consent-actions">
|
|
196
|
+
<dbx-button dbxActionButton text="Approve" [raised]="true" color="primary"></dbx-button>
|
|
197
|
+
<dbx-button-spacer></dbx-button-spacer>
|
|
198
|
+
<ng-container dbxAction dbxActionSnackbarError dbxActionValue [dbxActionHandler]="denyHandler()">
|
|
199
|
+
<dbx-button dbxActionButton text="Deny" [flat]="true" color="warn"></dbx-button>
|
|
200
|
+
</ng-container>
|
|
201
|
+
</div>
|
|
149
202
|
</div>
|
|
150
|
-
</div>
|
|
151
|
-
<dbx-injection [config]="resolvedScopeInjectionConfig()"></dbx-injection>
|
|
152
|
-
<div class="dbx-pt3 dbx-pb3 dbx-firebase-oauth-consent-actions">
|
|
153
|
-
<dbx-button text="Approve" [raised]="true" color="primary" (buttonClick)="approveClick.emit()"></dbx-button>
|
|
154
|
-
<dbx-button-spacer></dbx-button-spacer>
|
|
155
|
-
<dbx-button text="Deny" [flat]="true" color="warn" (buttonClick)="denyClick.emit()"></dbx-button>
|
|
156
|
-
</div>
|
|
157
|
-
@if (resolvedError()) {
|
|
158
|
-
<dbx-error [error]="resolvedError()"></dbx-error>
|
|
159
203
|
}
|
|
160
204
|
}
|
|
161
205
|
</div>
|
|
162
|
-
`, isInline: true, styles: [".dbx-firebase-oauth-consent-view .dbx-firebase-oauth-consent-header-info{align-items:center;gap:12px}\n"], dependencies: [{ kind: "component", type: DbxInjectionComponent, selector: "dbx-injection, [dbxInjection], [dbx-injection]", inputs: ["config", "template"] }, { kind: "component", type: DbxAvatarComponent, selector: "dbx-avatar", inputs: ["context", "avatarSelector", "avatarUid", "avatarUrl", "avatarKey", "avatarIcon", "avatarStyle", "avatarSize", "avatarHideOnError"] }, { kind: "component", type:
|
|
206
|
+
`, isInline: true, styles: [".dbx-firebase-oauth-consent-view .dbx-firebase-oauth-consent-header-info{align-items:center;gap:12px}\n"], dependencies: [{ kind: "component", type: DbxInjectionComponent, selector: "dbx-injection, [dbxInjection], [dbx-injection]", inputs: ["config", "template"] }, { kind: "component", type: DbxAvatarComponent, selector: "dbx-avatar", inputs: ["context", "avatarSelector", "avatarUid", "avatarUrl", "avatarKey", "avatarIcon", "avatarStyle", "avatarSize", "avatarHideOnError"] }, { kind: "component", type: DbxBasicLoadingComponent, selector: "dbx-basic-loading", inputs: ["diameter", "mode", "color", "text", "linear", "show", "loading", "error"] }, { kind: "component", type: DbxButtonComponent, selector: "dbx-button", inputs: ["bar", "type", "buttonStyle", "color", "spinnerColor", "customButtonColor", "customTextColor", "customSpinnerColor", "basic", "tonal", "raised", "stroked", "flat", "iconOnly", "fab", "customContent", "allowClickPropagation", "mode"] }, { kind: "directive", type: DbxButtonSpacerDirective, selector: "dbx-button-spacer,[dbxButtonSpacer]" }, { kind: "directive", type: DbxActionDirective, selector: "dbx-action,[dbxAction]", exportAs: ["action", "dbxAction"] }, { kind: "directive", type: DbxActionHandlerDirective, selector: "[dbxActionHandler]", inputs: ["dbxActionHandler"] }, { kind: "directive", type: DbxActionValueDirective, selector: "dbxActionValue,[dbxActionValue]", inputs: ["dbxActionValue"] }, { kind: "directive", type: DbxActionButtonDirective, selector: "[dbxActionButton]", inputs: ["dbxActionButtonEcho"] }, { kind: "directive", type: DbxActionSnackbarErrorDirective, selector: "[dbxActionSnackbarError]", inputs: ["dbxActionSnackbarError"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
163
207
|
}
|
|
164
208
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOAuthConsentViewComponent, decorators: [{
|
|
165
209
|
type: Component,
|
|
166
|
-
args: [{ selector: 'dbx-firebase-oauth-consent-view', standalone: true, imports: [DbxInjectionComponent, DbxAvatarComponent,
|
|
210
|
+
args: [{ selector: 'dbx-firebase-oauth-consent-view', standalone: true, imports: [DbxInjectionComponent, DbxAvatarComponent, DbxBasicLoadingComponent, DbxButtonComponent, DbxButtonSpacerDirective, DbxActionDirective, DbxActionHandlerDirective, DbxActionValueDirective, DbxActionButtonDirective, DbxActionSnackbarErrorDirective], template: `
|
|
167
211
|
<div class="dbx-firebase-oauth-consent-view">
|
|
168
|
-
@
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
212
|
+
@switch (consentStateCase()) {
|
|
213
|
+
@case ('unknown') {
|
|
214
|
+
<dbx-basic-loading [loading]="true"></dbx-basic-loading>
|
|
215
|
+
}
|
|
216
|
+
@case ('no_user') {
|
|
217
|
+
<ng-content></ng-content>
|
|
218
|
+
}
|
|
219
|
+
@case ('user') {
|
|
220
|
+
<div class="dbx-firebase-oauth-consent-header">
|
|
221
|
+
@if (clientName()) {
|
|
222
|
+
<h2>You're signing in to {{ clientName() }}</h2>
|
|
223
|
+
}
|
|
224
|
+
<div class="dbx-firebase-oauth-consent-header-info dbx-flex">
|
|
225
|
+
<dbx-avatar [avatarUrl]="logoUri()" [avatarStyle]="'square'" avatarIcon="apps"></dbx-avatar>
|
|
226
|
+
<span>
|
|
227
|
+
@if (clientUri()) {
|
|
228
|
+
<a class="dbx-firebase-oauth-consent-client-uri" [href]="clientUri()" target="_blank" rel="noopener noreferrer">{{ clientUri() }}</a>
|
|
229
|
+
}
|
|
230
|
+
</span>
|
|
231
|
+
</div>
|
|
232
|
+
</div>
|
|
172
233
|
@if (clientName()) {
|
|
173
|
-
<
|
|
234
|
+
<p class="dbx-firebase-oauth-consent-prompt">
|
|
235
|
+
<strong>{{ clientName() }}</strong>
|
|
236
|
+
is requesting these permissions:
|
|
237
|
+
</p>
|
|
174
238
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
<
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
239
|
+
|
|
240
|
+
<div dbxAction dbxActionSnackbarError [dbxActionHandler]="approveHandler()">
|
|
241
|
+
<dbx-injection [config]="resolvedScopeInjectionConfig()"></dbx-injection>
|
|
242
|
+
|
|
243
|
+
<div class="dbx-pt3 dbx-pb3 dbx-firebase-oauth-consent-actions">
|
|
244
|
+
<dbx-button dbxActionButton text="Approve" [raised]="true" color="primary"></dbx-button>
|
|
245
|
+
<dbx-button-spacer></dbx-button-spacer>
|
|
246
|
+
<ng-container dbxAction dbxActionSnackbarError dbxActionValue [dbxActionHandler]="denyHandler()">
|
|
247
|
+
<dbx-button dbxActionButton text="Deny" [flat]="true" color="warn"></dbx-button>
|
|
248
|
+
</ng-container>
|
|
249
|
+
</div>
|
|
182
250
|
</div>
|
|
183
|
-
</div>
|
|
184
|
-
<dbx-injection [config]="resolvedScopeInjectionConfig()"></dbx-injection>
|
|
185
|
-
<div class="dbx-pt3 dbx-pb3 dbx-firebase-oauth-consent-actions">
|
|
186
|
-
<dbx-button text="Approve" [raised]="true" color="primary" (buttonClick)="approveClick.emit()"></dbx-button>
|
|
187
|
-
<dbx-button-spacer></dbx-button-spacer>
|
|
188
|
-
<dbx-button text="Deny" [flat]="true" color="warn" (buttonClick)="denyClick.emit()"></dbx-button>
|
|
189
|
-
</div>
|
|
190
|
-
@if (resolvedError()) {
|
|
191
|
-
<dbx-error [error]="resolvedError()"></dbx-error>
|
|
192
251
|
}
|
|
193
252
|
}
|
|
194
253
|
</div>
|
|
195
254
|
`, host: {
|
|
196
255
|
class: 'd-block dbx-firebase-oauth-consent-view'
|
|
197
256
|
}, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".dbx-firebase-oauth-consent-view .dbx-firebase-oauth-consent-header-info{align-items:center;gap:12px}\n"] }]
|
|
198
|
-
}], propDecorators: { details: [{ type: i0.Input, args: [{ isSignal: true, alias: "details", required: false }] }],
|
|
257
|
+
}], propDecorators: { details: [{ type: i0.Input, args: [{ isSignal: true, alias: "details", required: false }] }], consentStateCase: [{ type: i0.Input, args: [{ isSignal: true, alias: "consentStateCase", required: true }] }], scopeInjectionConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "scopeInjectionConfig", required: true }] }], requiredScopes: [{ type: i0.Input, args: [{ isSignal: true, alias: "requiredScopes", required: false }] }], approveHandler: [{ type: i0.Input, args: [{ isSignal: true, alias: "approveHandler", required: true }] }], denyHandler: [{ type: i0.Input, args: [{ isSignal: true, alias: "denyHandler", required: true }] }] } });
|
|
199
258
|
|
|
200
259
|
/**
|
|
201
260
|
* Abstract base class for consent scope view components.
|
|
202
261
|
*
|
|
203
|
-
* Provides typed access to the `DbxFirebaseOAuthConsentScopesViewData`
|
|
204
|
-
* via `DBX_INJECTION_COMPONENT_DATA`. Subclasses
|
|
262
|
+
* Provides typed access to the `DbxFirebaseOAuthConsentScopesViewData`
|
|
263
|
+
* injected via `DBX_INJECTION_COMPONENT_DATA`. Subclasses define the
|
|
264
|
+
* template that renders the requested scopes and (optionally) hosts a
|
|
265
|
+
* forge form decorated with `dbxActionForm`.
|
|
205
266
|
*
|
|
206
267
|
* @example
|
|
207
268
|
* ```typescript
|
|
@@ -216,43 +277,200 @@ class AbstractDbxFirebaseOAuthConsentScopeViewComponent {
|
|
|
216
277
|
clientName = computed(() => this.data?.clientName ?? '', ...(ngDevMode ? [{ debugName: "clientName" }] : /* istanbul ignore next */ []));
|
|
217
278
|
clientUri = computed(() => this.data?.details?.client_uri, ...(ngDevMode ? [{ debugName: "clientUri" }] : /* istanbul ignore next */ []));
|
|
218
279
|
logoUri = computed(() => this.data?.details?.logo_uri, ...(ngDevMode ? [{ debugName: "logoUri" }] : /* istanbul ignore next */ []));
|
|
280
|
+
requiredScopes = computed(() => this.data?.requiredScopes ?? [], ...(ngDevMode ? [{ debugName: "requiredScopes" }] : /* istanbul ignore next */ []));
|
|
281
|
+
isScopeRequired(scope) {
|
|
282
|
+
return this.requiredScopes().includes(scope);
|
|
283
|
+
}
|
|
219
284
|
}
|
|
220
285
|
|
|
221
286
|
/**
|
|
222
|
-
*
|
|
287
|
+
* Selection-list wrapper used as the `listComponentClass` for the OIDC
|
|
288
|
+
* consent scope `dbxForgeListSelectionField`.
|
|
289
|
+
*
|
|
290
|
+
* Reuses the workspace's `dbx-list` selection infrastructure so the existing
|
|
291
|
+
* scope-row visual treatment (name + description) remains intact while the
|
|
292
|
+
* selection state participates in the surrounding `dbxAction`/`dbxActionForm`
|
|
293
|
+
* pipeline.
|
|
223
294
|
*
|
|
224
295
|
* @example
|
|
225
|
-
* ```
|
|
226
|
-
* <
|
|
296
|
+
* ```ts
|
|
297
|
+
* dbxForgeListSelectionField<OAuthConsentScope, DbxFirebaseOAuthConsentScopeListComponent, OidcScope>({
|
|
298
|
+
* key: 'grantedOIDCScopes',
|
|
299
|
+
* props: {
|
|
300
|
+
* listComponentClass: of(DbxFirebaseOAuthConsentScopeListComponent),
|
|
301
|
+
* readKey: (scope) => scope.name,
|
|
302
|
+
* state$: of(successResult(optionalScopes)),
|
|
303
|
+
* wrapped: false,
|
|
304
|
+
* maxHeight: 'none'
|
|
305
|
+
* }
|
|
306
|
+
* });
|
|
227
307
|
* ```
|
|
228
308
|
*/
|
|
229
|
-
class DbxFirebaseOAuthConsentScopeListComponent {
|
|
230
|
-
|
|
309
|
+
class DbxFirebaseOAuthConsentScopeListComponent extends AbstractDbxSelectionListWrapperDirective {
|
|
310
|
+
constructor() {
|
|
311
|
+
super({ componentClass: DbxFirebaseOAuthConsentScopeListViewComponent, defaultSelectionMode: 'select' });
|
|
312
|
+
}
|
|
231
313
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOAuthConsentScopeListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
232
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
314
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: DbxFirebaseOAuthConsentScopeListComponent, isStandalone: true, selector: "dbx-firebase-oauth-consent-scope-list", host: { classAttribute: "dbx-list-no-hover-effects dbx-list-card-items-list" }, usesInheritance: true, ngImport: i0, template: "\n <dbx-list [state]=\"currentState$\" [config]=\"configSignal()\" [hasMore]=\"hasMore()\" [disabled]=\"disabledSignal()\" [selectionMode]=\"selectionModeSignal()\">\n <ng-content top select=\"[top]\"></ng-content>\n <ng-content bottom select=\"[bottom]\"></ng-content>\n <ng-content empty select=\"[empty]\"></ng-content>\n <ng-content emptyLoading select=\"[emptyLoading]\"></ng-content>\n <ng-content end select=\"[end]\"></ng-content>\n </dbx-list>", isInline: true, dependencies: [{ kind: "ngmodule", type: DbxListWrapperComponentImportsModule }, { kind: "component", type: i1.DbxListComponent, selector: "dbx-list", inputs: ["padded", "state", "config", "disabled", "selectionMode", "hasMore"], outputs: ["contentScrolled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
315
|
+
}
|
|
316
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOAuthConsentScopeListComponent, decorators: [{
|
|
317
|
+
type: Component,
|
|
318
|
+
args: [{
|
|
319
|
+
selector: 'dbx-firebase-oauth-consent-scope-list',
|
|
320
|
+
template: DEFAULT_LIST_WRAPPER_COMPONENT_CONFIGURATION_TEMPLATE,
|
|
321
|
+
host: {
|
|
322
|
+
class: 'dbx-list-no-hover-effects dbx-list-card-items-list'
|
|
323
|
+
},
|
|
324
|
+
imports: [DbxListWrapperComponentImportsModule],
|
|
325
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
326
|
+
standalone: true
|
|
327
|
+
}]
|
|
328
|
+
}], ctorParameters: () => [] });
|
|
329
|
+
/**
|
|
330
|
+
* Selection list view that pairs with `DbxFirebaseOAuthConsentScopeListComponent`.
|
|
331
|
+
* Maps each `OAuthConsentScope` to a `DbxValueListItem` keyed by the scope name
|
|
332
|
+
* and renders it through `DbxFirebaseOAuthConsentScopeListItemComponent`.
|
|
333
|
+
*/
|
|
334
|
+
class DbxFirebaseOAuthConsentScopeListViewComponent extends AbstractDbxSelectionListViewDirective {
|
|
335
|
+
config = {
|
|
336
|
+
componentClass: DbxFirebaseOAuthConsentScopeListItemComponent,
|
|
337
|
+
mapValuesToItemValues: (values) => of(values.map((scope) => ({ ...scope, key: scope.name, itemValue: scope })))
|
|
338
|
+
};
|
|
339
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOAuthConsentScopeListViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
340
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: DbxFirebaseOAuthConsentScopeListViewComponent, isStandalone: true, selector: "dbx-firebase-oauth-consent-scope-list-view", providers: provideDbxListView(DbxFirebaseOAuthConsentScopeListViewComponent), usesInheritance: true, ngImport: i0, template: "<dbx-selection-list-view [config]=\"config\"></dbx-selection-list-view>", isInline: true, dependencies: [{ kind: "ngmodule", type: DbxSelectionValueListViewComponentImportsModule }, { kind: "component", type: i1.DbxSelectionValueListViewComponent, selector: "dbx-selection-list-view" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
341
|
+
}
|
|
342
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOAuthConsentScopeListViewComponent, decorators: [{
|
|
343
|
+
type: Component,
|
|
344
|
+
args: [{
|
|
345
|
+
selector: 'dbx-firebase-oauth-consent-scope-list-view',
|
|
346
|
+
template: DEFAULT_DBX_SELECTION_VALUE_LIST_COMPONENT_CONFIGURATION_TEMPLATE,
|
|
347
|
+
imports: [DbxSelectionValueListViewComponentImportsModule],
|
|
348
|
+
providers: provideDbxListView(DbxFirebaseOAuthConsentScopeListViewComponent),
|
|
349
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
350
|
+
standalone: true
|
|
351
|
+
}]
|
|
352
|
+
}] });
|
|
353
|
+
/**
|
|
354
|
+
* Item row inside the OIDC consent scope selection list. Shown as the visual
|
|
355
|
+
* row for both selected and unselected scopes — the selection chrome (the
|
|
356
|
+
* leading checkbox/highlight) is provided by the wrapping
|
|
357
|
+
* `dbx-selection-list-view`.
|
|
358
|
+
*/
|
|
359
|
+
class DbxFirebaseOAuthConsentScopeListItemComponent extends AbstractDbxValueListViewItemComponent {
|
|
360
|
+
get name() {
|
|
361
|
+
return this.itemValue.name;
|
|
362
|
+
}
|
|
363
|
+
get description() {
|
|
364
|
+
return this.itemValue.description;
|
|
365
|
+
}
|
|
366
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOAuthConsentScopeListItemComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
367
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: DbxFirebaseOAuthConsentScopeListItemComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: `
|
|
368
|
+
<div class="dbx-list-item-padded dbx-list-item-padded-thick dbx-list-two-line-item">
|
|
369
|
+
<div class="item-left">
|
|
370
|
+
<div class="mat-subtitle-2">{{ name }}</div>
|
|
371
|
+
@if (description) {
|
|
372
|
+
<div class="item-details">{{ description }}</div>
|
|
238
373
|
}
|
|
239
374
|
</div>
|
|
240
|
-
|
|
241
|
-
`, isInline: true,
|
|
375
|
+
</div>
|
|
376
|
+
`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
242
377
|
}
|
|
243
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type:
|
|
378
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOAuthConsentScopeListItemComponent, decorators: [{
|
|
244
379
|
type: Component,
|
|
245
|
-
args: [{
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
380
|
+
args: [{
|
|
381
|
+
template: `
|
|
382
|
+
<div class="dbx-list-item-padded dbx-list-item-padded-thick dbx-list-two-line-item">
|
|
383
|
+
<div class="item-left">
|
|
384
|
+
<div class="mat-subtitle-2">{{ name }}</div>
|
|
385
|
+
@if (description) {
|
|
386
|
+
<div class="item-details">{{ description }}</div>
|
|
251
387
|
}
|
|
252
388
|
</div>
|
|
253
|
-
|
|
254
|
-
`,
|
|
255
|
-
|
|
389
|
+
</div>
|
|
390
|
+
`,
|
|
391
|
+
standalone: true,
|
|
392
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
393
|
+
}]
|
|
394
|
+
}] });
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Validator key emitted when the user has not selected any optional scope.
|
|
398
|
+
* Surfaces alongside the form's invalid state so the action button stays disabled.
|
|
399
|
+
*/
|
|
400
|
+
const OAUTH_CONSENT_SCOPES_REQUIRED_VALIDATOR_KIND = 'mustSelectAtLeastOneScope';
|
|
401
|
+
/**
|
|
402
|
+
* Default message shown when the user has cleared every optional scope.
|
|
403
|
+
*/
|
|
404
|
+
const OAUTH_CONSENT_SCOPES_REQUIRED_VALIDATOR_DEFAULT_MESSAGE = 'Select at least one scope to grant.';
|
|
405
|
+
/**
|
|
406
|
+
* Builds a complete `FormConfig` ready to feed into a forge form component.
|
|
407
|
+
*
|
|
408
|
+
* The resulting form has a single `grantedOIDCScopes` field — a
|
|
409
|
+
* `dbxForgeListSelectionField` rendered through
|
|
410
|
+
* `DbxFirebaseOAuthConsentScopeListComponent` (a `dbx-list` selection wrapper).
|
|
411
|
+
* The list renders bare (no Material form-field wrapper) and without the
|
|
412
|
+
* default 300px height cap so it grows to fit the scope list.
|
|
413
|
+
*
|
|
414
|
+
* @param config - The consent scopes form fields configuration.
|
|
415
|
+
* @returns A `FormConfig` whose single field selects an `OidcScope[]` of granted scopes.
|
|
416
|
+
*/
|
|
417
|
+
function oauthConsentScopesFormConfig(config) {
|
|
418
|
+
const { optionalScopes, initiallySelected } = config;
|
|
419
|
+
const value = (initiallySelected ?? optionalScopes.map((scope) => scope.name)).slice();
|
|
420
|
+
const optionalScopesArray = optionalScopes.slice();
|
|
421
|
+
const validators = [
|
|
422
|
+
{
|
|
423
|
+
type: 'custom',
|
|
424
|
+
expression: 'fieldValue && fieldValue.length > 0',
|
|
425
|
+
kind: OAUTH_CONSENT_SCOPES_REQUIRED_VALIDATOR_KIND
|
|
426
|
+
}
|
|
427
|
+
];
|
|
428
|
+
return {
|
|
429
|
+
fields: [
|
|
430
|
+
dbxForgeListSelectionField({
|
|
431
|
+
key: 'grantedOIDCScopes',
|
|
432
|
+
value,
|
|
433
|
+
validators,
|
|
434
|
+
validationMessages: {
|
|
435
|
+
[OAUTH_CONSENT_SCOPES_REQUIRED_VALIDATOR_KIND]: OAUTH_CONSENT_SCOPES_REQUIRED_VALIDATOR_DEFAULT_MESSAGE
|
|
436
|
+
},
|
|
437
|
+
props: {
|
|
438
|
+
listComponentClass: of(DbxFirebaseOAuthConsentScopeListComponent),
|
|
439
|
+
readKey: (scope) => scope.name,
|
|
440
|
+
state$: of(successResult(optionalScopesArray)),
|
|
441
|
+
wrapped: false,
|
|
442
|
+
maxHeight: 'none'
|
|
443
|
+
}
|
|
444
|
+
})
|
|
445
|
+
]
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Reusable forge form component that renders one checkbox per OIDC scope
|
|
451
|
+
* defined in {@link OAuthConsentScopesFormFieldsConfig}. Required scopes are
|
|
452
|
+
* rendered as checked-and-disabled.
|
|
453
|
+
*
|
|
454
|
+
* Pair with `<dbx-firebase-oauth-consent-scope-default-view>` for the default
|
|
455
|
+
* consent flow, or embed directly in custom consent UIs that supply their
|
|
456
|
+
* own scope/required configuration.
|
|
457
|
+
*/
|
|
458
|
+
class DbxFirebaseOAuthConsentScopeFormComponent extends AbstractConfigAsyncForgeFormDirective {
|
|
459
|
+
formConfig$ = this.currentConfig$.pipe(map((config) => (config ? oauthConsentScopesFormConfig(config) : undefined)));
|
|
460
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOAuthConsentScopeFormComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
461
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: DbxFirebaseOAuthConsentScopeFormComponent, isStandalone: true, selector: "dbx-firebase-oauth-consent-scope-form", providers: dbxForgeFormComponentProviders(), usesInheritance: true, ngImport: i0, template: "<dbx-forge></dbx-forge>", isInline: true, dependencies: [{ kind: "ngmodule", type: DbxForgeFormComponentImportsModule }, { kind: "component", type: i1$1.DbxForgeFormComponent, selector: "dbx-forge" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
462
|
+
}
|
|
463
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOAuthConsentScopeFormComponent, decorators: [{
|
|
464
|
+
type: Component,
|
|
465
|
+
args: [{
|
|
466
|
+
selector: 'dbx-firebase-oauth-consent-scope-form',
|
|
467
|
+
template: DBX_FORGE_FORM_COMPONENT_TEMPLATE,
|
|
468
|
+
providers: dbxForgeFormComponentProviders(),
|
|
469
|
+
imports: [DbxForgeFormComponentImportsModule],
|
|
470
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
471
|
+
standalone: true
|
|
472
|
+
}]
|
|
473
|
+
}] });
|
|
256
474
|
|
|
257
475
|
const DEFAULT_OIDC_AUTHORIZATION_ENDPOINT_PATH = '/oidc/auth';
|
|
258
476
|
const DEFAULT_OIDC_INTERACTION_ENDPOINT_PATH = '/interaction';
|
|
@@ -336,18 +554,33 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
336
554
|
}] });
|
|
337
555
|
|
|
338
556
|
/**
|
|
339
|
-
* Default consent scope view component
|
|
340
|
-
* using the `OidcScopeDetails` from the app-level OIDC configuration.
|
|
557
|
+
* Default consent scope view component.
|
|
341
558
|
*
|
|
342
|
-
*
|
|
343
|
-
*
|
|
559
|
+
* Reads the requested scopes (and required scopes) from the
|
|
560
|
+
* `DBX_INJECTION_COMPONENT_DATA` provided by the parent consent view,
|
|
561
|
+
* resolves human-readable descriptions from the app-level
|
|
562
|
+
* `DbxFirebaseOidcConfigService`, then renders a
|
|
563
|
+
* `DbxFirebaseOAuthConsentScopeFormComponent` with `dbxActionForm` so the
|
|
564
|
+
* form's value participates in the surrounding `dbxAction` (the consent
|
|
565
|
+
* view's outer Approve action).
|
|
566
|
+
*
|
|
567
|
+
* Required scopes are not user-selectable. They are surfaced as an "Always
|
|
568
|
+
* granted" hint above the form because the server enforces them regardless
|
|
569
|
+
* of payload — including them in the selection list would just add noise.
|
|
570
|
+
*
|
|
571
|
+
* Apps can override this default via
|
|
572
|
+
* `DbxFirebaseOidcConfig.consentScopeListViewClass` or
|
|
573
|
+
* `DbxOAuthConsentComponentConfig.consentScopeListViewClass`. Custom views
|
|
574
|
+
* should similarly apply `dbxActionForm` to a forge form whose value matches
|
|
575
|
+
* `OAuthConsentScopesFormValue`.
|
|
344
576
|
*/
|
|
345
|
-
class DbxFirebaseOAuthConsentScopeDefaultViewComponent
|
|
346
|
-
|
|
577
|
+
class DbxFirebaseOAuthConsentScopeDefaultViewComponent {
|
|
578
|
+
_oidcConfigService = inject(DbxFirebaseOidcConfigService);
|
|
579
|
+
_data = inject(DBX_INJECTION_COMPONENT_DATA);
|
|
347
580
|
mappedScopes = computed(() => {
|
|
348
|
-
const availableScopes = this.
|
|
581
|
+
const availableScopes = this._oidcConfigService.availableScopes;
|
|
349
582
|
const availableScopeValues = new Set(availableScopes.map((s) => s.value));
|
|
350
|
-
const { included: knownScopes, excluded: unknownScopes } = separateValues(this.scopes
|
|
583
|
+
const { included: knownScopes, excluded: unknownScopes } = separateValues(this._data.scopes, (name) => availableScopeValues.has(name));
|
|
351
584
|
return [
|
|
352
585
|
...knownScopes.map((name) => {
|
|
353
586
|
const details = availableScopes.find((s) => s.value === name);
|
|
@@ -356,29 +589,38 @@ class DbxFirebaseOAuthConsentScopeDefaultViewComponent extends AbstractDbxFireba
|
|
|
356
589
|
...unknownScopes.map((name) => ({ name, description: 'unknown' }))
|
|
357
590
|
];
|
|
358
591
|
}, ...(ngDevMode ? [{ debugName: "mappedScopes" }] : /* istanbul ignore next */ []));
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
592
|
+
optionalScopes = computed(() => {
|
|
593
|
+
const requiredSet = new Set(this._data.requiredScopes ?? []);
|
|
594
|
+
return this.mappedScopes().filter((scope) => !requiredSet.has(scope.name));
|
|
595
|
+
}, ...(ngDevMode ? [{ debugName: "optionalScopes" }] : /* istanbul ignore next */ []));
|
|
596
|
+
alwaysGrantedLabel = computed(() => {
|
|
597
|
+
const required = this._data.requiredScopes ?? [];
|
|
598
|
+
return required.length > 0 ? required.join(', ') : null;
|
|
599
|
+
}, ...(ngDevMode ? [{ debugName: "alwaysGrantedLabel" }] : /* istanbul ignore next */ []));
|
|
600
|
+
formFieldsConfig = computed(() => ({
|
|
601
|
+
optionalScopes: this.optionalScopes()
|
|
602
|
+
}), ...(ngDevMode ? [{ debugName: "formFieldsConfig" }] : /* istanbul ignore next */ []));
|
|
603
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOAuthConsentScopeDefaultViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
604
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: DbxFirebaseOAuthConsentScopeDefaultViewComponent, isStandalone: true, selector: "dbx-firebase-oauth-consent-scope-default-view", ngImport: i0, template: `
|
|
605
|
+
@if (alwaysGrantedLabel(); as label) {
|
|
606
|
+
<p class="dbx-firebase-oauth-consent-always-granted dbx-hint">Always granted: {{ label }}</p>
|
|
607
|
+
}
|
|
608
|
+
<dbx-firebase-oauth-consent-scope-form dbxActionForm [config]="formFieldsConfig()"></dbx-firebase-oauth-consent-scope-form>
|
|
609
|
+
`, isInline: true, dependencies: [{ kind: "component", type: DbxFirebaseOAuthConsentScopeFormComponent, selector: "dbx-firebase-oauth-consent-scope-form" }, { kind: "directive", type: DbxActionFormDirective, selector: "[dbxActionForm]", inputs: ["dbxActionFormDisabledOnWorking", "dbxActionFormIsValid", "dbxActionFormIsEqual", "dbxActionFormIsModified", "dbxActionFormMapValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
367
610
|
}
|
|
368
611
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOAuthConsentScopeDefaultViewComponent, decorators: [{
|
|
369
612
|
type: Component,
|
|
370
613
|
args: [{
|
|
371
614
|
selector: 'dbx-firebase-oauth-consent-scope-default-view',
|
|
372
|
-
standalone: true,
|
|
373
|
-
imports: [DbxFirebaseOAuthConsentScopeListComponent],
|
|
374
615
|
template: `
|
|
375
|
-
|
|
376
|
-
<
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
<dbx-firebase-oauth-consent-scope-list [scopes]="mappedScopes()"></dbx-firebase-oauth-consent-scope-list>
|
|
616
|
+
@if (alwaysGrantedLabel(); as label) {
|
|
617
|
+
<p class="dbx-firebase-oauth-consent-always-granted dbx-hint">Always granted: {{ label }}</p>
|
|
618
|
+
}
|
|
619
|
+
<dbx-firebase-oauth-consent-scope-form dbxActionForm [config]="formFieldsConfig()"></dbx-firebase-oauth-consent-scope-form>
|
|
380
620
|
`,
|
|
381
|
-
|
|
621
|
+
imports: [DbxFirebaseOAuthConsentScopeFormComponent, DbxActionFormDirective],
|
|
622
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
623
|
+
standalone: true
|
|
382
624
|
}]
|
|
383
625
|
}] });
|
|
384
626
|
|
|
@@ -418,14 +660,23 @@ class DbxFirebaseOidcInteractionService {
|
|
|
418
660
|
/**
|
|
419
661
|
* Submit consent decision to complete the consent interaction.
|
|
420
662
|
*
|
|
421
|
-
* Automatically attaches the current user's Firebase ID token.
|
|
663
|
+
* Automatically attaches the current user's Firebase ID token. When `approved`
|
|
664
|
+
* is true, optional `grants` may be passed to grant only a subset of the
|
|
665
|
+
* requested scopes/claims/resource scopes; the server validates that any
|
|
666
|
+
* subset is contained in the corresponding `missing*` set on the prompt.
|
|
667
|
+
*
|
|
668
|
+
* When `approved` is false, `grants` is ignored (not sent).
|
|
422
669
|
*
|
|
423
670
|
* @param uid - The OIDC interaction UID identifying the current consent interaction.
|
|
424
671
|
* @param approved - Whether the user approved or denied the consent request.
|
|
672
|
+
* @param grants - Optional subset of OIDC scopes / OIDC claims / resource scopes to grant.
|
|
425
673
|
* @returns Observable that emits the redirect URL from the server response.
|
|
426
674
|
*/
|
|
427
|
-
submitConsent(uid, approved) {
|
|
428
|
-
return this._authService.idTokenString$.pipe(first(), switchMap((idToken) =>
|
|
675
|
+
submitConsent(uid, approved, grants) {
|
|
676
|
+
return this._authService.idTokenString$.pipe(first(), switchMap((idToken) => {
|
|
677
|
+
const body = approved && grants ? { idToken, approved, ...grants } : { idToken, approved };
|
|
678
|
+
return this.http.post(`${this.baseUrl}/${uid}/consent`, body);
|
|
679
|
+
}));
|
|
429
680
|
}
|
|
430
681
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOidcInteractionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
431
682
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOidcInteractionService, providedIn: 'root' });
|
|
@@ -454,7 +705,7 @@ class DbxFirebaseOAuthLoginComponent {
|
|
|
454
705
|
interactionService = inject(DbxFirebaseOidcInteractionService);
|
|
455
706
|
uidParamReader = dbxRouteParamReaderInstance(this.dbxRouterService, DEFAULT_OIDC_INTERACTION_UID_PARAM_KEY);
|
|
456
707
|
interactionUid = toSignal(this.uidParamReader.value$);
|
|
457
|
-
isLoggedIn = toSignal(this.dbxFirebaseAuthService.isLoggedIn
|
|
708
|
+
isLoggedIn = toSignal(this.dbxFirebaseAuthService.isLoggedIn$);
|
|
458
709
|
submitting = signal(false, ...(ngDevMode ? [{ debugName: "submitting" }] : /* istanbul ignore next */ []));
|
|
459
710
|
errorMessage = signal(null, ...(ngDevMode ? [{ debugName: "errorMessage" }] : /* istanbul ignore next */ []));
|
|
460
711
|
loginStateCase = computed(() => {
|
|
@@ -464,7 +715,11 @@ class DbxFirebaseOAuthLoginComponent {
|
|
|
464
715
|
if (this.errorMessage()) {
|
|
465
716
|
return 'error';
|
|
466
717
|
}
|
|
467
|
-
|
|
718
|
+
const isLoggedIn = this.isLoggedIn();
|
|
719
|
+
if (isLoggedIn === undefined) {
|
|
720
|
+
return 'unknown';
|
|
721
|
+
}
|
|
722
|
+
if (!isLoggedIn) {
|
|
468
723
|
return 'no_user';
|
|
469
724
|
}
|
|
470
725
|
return 'user';
|
|
@@ -530,17 +785,29 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
530
785
|
}]
|
|
531
786
|
}], ctorParameters: () => [] });
|
|
532
787
|
|
|
788
|
+
/**
|
|
789
|
+
* OIDC scopes that cannot be deselected on the consent screen. `openid` is
|
|
790
|
+
* mandatory for any OIDC flow, so the UI shows it as always-granted and the
|
|
791
|
+
* server enforces it regardless of payload.
|
|
792
|
+
*/
|
|
793
|
+
const OAUTH_CONSENT_REQUIRED_SCOPES = ['openid'];
|
|
533
794
|
/**
|
|
534
795
|
* Container component for the OIDC OAuth consent screen.
|
|
535
796
|
*
|
|
536
|
-
* Manages all state: route param reading, consent submission, and error handling.
|
|
537
|
-
* Delegates visual rendering to `DbxFirebaseOAuthConsentViewComponent`.
|
|
538
|
-
*
|
|
539
797
|
* Reads interaction UID and client details from route params (populated by
|
|
540
|
-
* the server redirect),
|
|
798
|
+
* the server redirect), assembles them into `OAuthInteractionLoginDetails`,
|
|
799
|
+
* and exposes Approve / Deny handlers that drive the view's nested
|
|
800
|
+
* `dbxAction` contexts.
|
|
801
|
+
*
|
|
802
|
+
* Submission progress and error states are owned by the action stores; this
|
|
803
|
+
* container is just routing-glue + handler factories.
|
|
804
|
+
*
|
|
805
|
+
* Supports ng-content projection — any content provided is passed through to
|
|
806
|
+
* the view component for the `'no_user'` state (e.g. an app's login view).
|
|
541
807
|
*/
|
|
542
808
|
class DbxOAuthConsentComponent {
|
|
543
809
|
dbxRouterService = inject(DbxRouterService);
|
|
810
|
+
dbxFirebaseAuthService = inject(DbxFirebaseAuthService);
|
|
544
811
|
interactionService = inject(DbxFirebaseOidcInteractionService);
|
|
545
812
|
oidcConfigService = inject(DbxFirebaseOidcConfigService);
|
|
546
813
|
// Config input
|
|
@@ -559,6 +826,8 @@ class DbxOAuthConsentComponent {
|
|
|
559
826
|
routeClientUri = toSignal(this.clientUriParamReader.value$);
|
|
560
827
|
routeLogoUri = toSignal(this.logoUriParamReader.value$);
|
|
561
828
|
routeScopes = toSignal(this.scopesParamReader.value$);
|
|
829
|
+
// Auth state — undefined until Firebase resolves to avoid a flash between 'unknown' → 'no_user'/'user'
|
|
830
|
+
isLoggedIn = toSignal(this.dbxFirebaseAuthService.isLoggedIn$);
|
|
562
831
|
// Resolved values
|
|
563
832
|
resolvedInteractionUid = computed(() => this.routeUid(), ...(ngDevMode ? [{ debugName: "resolvedInteractionUid" }] : /* istanbul ignore next */ []));
|
|
564
833
|
resolvedDetails = computed(() => {
|
|
@@ -579,8 +848,21 @@ class DbxOAuthConsentComponent {
|
|
|
579
848
|
scopeInjectionConfig = computed(() => ({
|
|
580
849
|
componentClass: this.config()?.consentScopeListViewClass ?? this.oidcConfigService.consentScopeListViewClass ?? DbxFirebaseOAuthConsentScopeDefaultViewComponent
|
|
581
850
|
}), ...(ngDevMode ? [{ debugName: "scopeInjectionConfig" }] : /* istanbul ignore next */ []));
|
|
582
|
-
|
|
583
|
-
|
|
851
|
+
/**
|
|
852
|
+
* Scopes the user cannot deselect. Forwarded to the view, which shows
|
|
853
|
+
* them as a static "Always granted" hint above the selection list.
|
|
854
|
+
*/
|
|
855
|
+
requiredScopes = OAUTH_CONSENT_REQUIRED_SCOPES;
|
|
856
|
+
consentStateCase = computed(() => {
|
|
857
|
+
const isLoggedIn = this.isLoggedIn();
|
|
858
|
+
if (isLoggedIn === undefined) {
|
|
859
|
+
return 'unknown';
|
|
860
|
+
}
|
|
861
|
+
if (!isLoggedIn) {
|
|
862
|
+
return 'no_user';
|
|
863
|
+
}
|
|
864
|
+
return 'user';
|
|
865
|
+
}, ...(ngDevMode ? [{ debugName: "consentStateCase" }] : /* istanbul ignore next */ []));
|
|
584
866
|
ngOnDestroy() {
|
|
585
867
|
this.interactionUidParamReader.destroy();
|
|
586
868
|
this.clientIdParamReader.destroy();
|
|
@@ -589,37 +871,47 @@ class DbxOAuthConsentComponent {
|
|
|
589
871
|
this.logoUriParamReader.destroy();
|
|
590
872
|
this.scopesParamReader.destroy();
|
|
591
873
|
}
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
874
|
+
/**
|
|
875
|
+
* Handles the Approve action. Pulls the form's selected scope array
|
|
876
|
+
* straight off the form value (it already matches the API field name
|
|
877
|
+
* `grantedOIDCScopes`) and forwards it through `submitConsent`. On a
|
|
878
|
+
* successful response, hard-navigates to the OIDC server's redirect URL.
|
|
879
|
+
*/
|
|
880
|
+
handleApprove = (formValue, context) => {
|
|
599
881
|
const uid = this.resolvedInteractionUid();
|
|
600
882
|
if (!uid) {
|
|
601
|
-
|
|
883
|
+
context.reject(new Error('Missing interaction UID'));
|
|
602
884
|
return;
|
|
603
885
|
}
|
|
604
|
-
|
|
605
|
-
this.
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
this.loading.set(false);
|
|
609
|
-
if (response.redirectTo) {
|
|
610
|
-
window.location.href = response.redirectTo;
|
|
611
|
-
}
|
|
612
|
-
},
|
|
613
|
-
error: () => {
|
|
614
|
-
this.loading.set(false);
|
|
615
|
-
this.error.set('Failed to process consent. Please try again.');
|
|
886
|
+
const grantedOIDCScopes = formValue.grantedOIDCScopes;
|
|
887
|
+
context.startWorkingWithObservable(this.interactionService.submitConsent(uid, true, { grantedOIDCScopes }).pipe(tap((response) => {
|
|
888
|
+
if (response.redirectTo) {
|
|
889
|
+
window.location.href = response.redirectTo;
|
|
616
890
|
}
|
|
617
|
-
});
|
|
618
|
-
}
|
|
891
|
+
})));
|
|
892
|
+
};
|
|
893
|
+
/**
|
|
894
|
+
* Handles the Deny action. No payload is sent — the server returns
|
|
895
|
+
* `access_denied` to the OAuth client.
|
|
896
|
+
*/
|
|
897
|
+
handleDeny = (_value, context) => {
|
|
898
|
+
const uid = this.resolvedInteractionUid();
|
|
899
|
+
if (!uid) {
|
|
900
|
+
context.reject(new Error('Missing interaction UID'));
|
|
901
|
+
return;
|
|
902
|
+
}
|
|
903
|
+
context.startWorkingWithObservable(this.interactionService.submitConsent(uid, false).pipe(tap((response) => {
|
|
904
|
+
if (response.redirectTo) {
|
|
905
|
+
window.location.href = response.redirectTo;
|
|
906
|
+
}
|
|
907
|
+
})));
|
|
908
|
+
};
|
|
619
909
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxOAuthConsentComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
620
910
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.11", type: DbxOAuthConsentComponent, isStandalone: true, selector: "dbx-firebase-oauth-consent", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "d-block dbx-firebase-oauth-consent" }, ngImport: i0, template: `
|
|
621
|
-
<dbx-firebase-oauth-consent-view [details]="resolvedDetails()" [
|
|
622
|
-
|
|
911
|
+
<dbx-firebase-oauth-consent-view [details]="resolvedDetails()" [consentStateCase]="consentStateCase()" [scopeInjectionConfig]="scopeInjectionConfig()" [requiredScopes]="requiredScopes" [approveHandler]="handleApprove" [denyHandler]="handleDeny">
|
|
912
|
+
<ng-content />
|
|
913
|
+
</dbx-firebase-oauth-consent-view>
|
|
914
|
+
`, isInline: true, dependencies: [{ kind: "component", type: DbxFirebaseOAuthConsentViewComponent, selector: "dbx-firebase-oauth-consent-view", inputs: ["details", "consentStateCase", "scopeInjectionConfig", "requiredScopes", "approveHandler", "denyHandler"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
623
915
|
}
|
|
624
916
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxOAuthConsentComponent, decorators: [{
|
|
625
917
|
type: Component,
|
|
@@ -628,7 +920,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
628
920
|
standalone: true,
|
|
629
921
|
imports: [DbxFirebaseOAuthConsentViewComponent],
|
|
630
922
|
template: `
|
|
631
|
-
<dbx-firebase-oauth-consent-view [details]="resolvedDetails()" [
|
|
923
|
+
<dbx-firebase-oauth-consent-view [details]="resolvedDetails()" [consentStateCase]="consentStateCase()" [scopeInjectionConfig]="scopeInjectionConfig()" [requiredScopes]="requiredScopes" [approveHandler]="handleApprove" [denyHandler]="handleDeny">
|
|
924
|
+
<ng-content />
|
|
925
|
+
</dbx-firebase-oauth-consent-view>
|
|
632
926
|
`,
|
|
633
927
|
host: {
|
|
634
928
|
class: 'd-block dbx-firebase-oauth-consent'
|
|
@@ -856,7 +1150,7 @@ class DbxFirebaseOidcEntryClientForgeFormComponent extends AbstractConfigAsyncFo
|
|
|
856
1150
|
});
|
|
857
1151
|
}));
|
|
858
1152
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOidcEntryClientForgeFormComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
859
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: DbxFirebaseOidcEntryClientForgeFormComponent, isStandalone: true, selector: "dbx-firebase-oidc-client-forge-form", providers: dbxForgeFormComponentProviders(), usesInheritance: true, ngImport: i0, template: "<dbx-forge></dbx-forge>", isInline: true, dependencies: [{ kind: "ngmodule", type: DbxForgeFormComponentImportsModule }, { kind: "component", type: i1.DbxForgeFormComponent, selector: "dbx-forge" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1153
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: DbxFirebaseOidcEntryClientForgeFormComponent, isStandalone: true, selector: "dbx-firebase-oidc-client-forge-form", providers: dbxForgeFormComponentProviders(), usesInheritance: true, ngImport: i0, template: "<dbx-forge></dbx-forge>", isInline: true, dependencies: [{ kind: "ngmodule", type: DbxForgeFormComponentImportsModule }, { kind: "component", type: i1$1.DbxForgeFormComponent, selector: "dbx-forge" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
860
1154
|
}
|
|
861
1155
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOidcEntryClientForgeFormComponent, decorators: [{
|
|
862
1156
|
type: Component,
|
|
@@ -878,7 +1172,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
878
1172
|
class DbxFirebaseOidcEntryClientTestForgeFormComponent extends AbstractConfigAsyncForgeFormDirective {
|
|
879
1173
|
formConfig$ = this.currentConfig$.pipe(map((config) => (config ? oidcEntryClientTestForgeFormFields(config) : undefined)));
|
|
880
1174
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOidcEntryClientTestForgeFormComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
881
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: DbxFirebaseOidcEntryClientTestForgeFormComponent, isStandalone: true, selector: "dbx-firebase-oidc-client-test-forge-form", providers: dbxForgeFormComponentProviders(), usesInheritance: true, ngImport: i0, template: "<dbx-forge></dbx-forge>", isInline: true, dependencies: [{ kind: "ngmodule", type: DbxForgeFormComponentImportsModule }, { kind: "component", type: i1.DbxForgeFormComponent, selector: "dbx-forge" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1175
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: DbxFirebaseOidcEntryClientTestForgeFormComponent, isStandalone: true, selector: "dbx-firebase-oidc-client-test-forge-form", providers: dbxForgeFormComponentProviders(), usesInheritance: true, ngImport: i0, template: "<dbx-forge></dbx-forge>", isInline: true, dependencies: [{ kind: "ngmodule", type: DbxForgeFormComponentImportsModule }, { kind: "component", type: i1$1.DbxForgeFormComponent, selector: "dbx-forge" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
882
1176
|
}
|
|
883
1177
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOidcEntryClientTestForgeFormComponent, decorators: [{
|
|
884
1178
|
type: Component,
|
|
@@ -892,6 +1186,173 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
892
1186
|
}]
|
|
893
1187
|
}] });
|
|
894
1188
|
|
|
1189
|
+
/**
|
|
1190
|
+
* Document store for a single {@link OidcEntry}.
|
|
1191
|
+
*/
|
|
1192
|
+
class OidcEntryDocumentStore extends AbstractDbxFirebaseDocumentStore {
|
|
1193
|
+
oidcModelFunctions = inject(OidcModelFunctions);
|
|
1194
|
+
_latestClientSecret$ = completeOnDestroy(new BehaviorSubject(undefined));
|
|
1195
|
+
/**
|
|
1196
|
+
* The client secret from the most recent create operation.
|
|
1197
|
+
*
|
|
1198
|
+
* Only available immediately after creation — the server does not return it again.
|
|
1199
|
+
*/
|
|
1200
|
+
latestClientSecret$ = this._latestClientSecret$.asObservable();
|
|
1201
|
+
get latestClientSecret() {
|
|
1202
|
+
return this._latestClientSecret$.value;
|
|
1203
|
+
}
|
|
1204
|
+
constructor() {
|
|
1205
|
+
super({ firestoreCollection: inject(OidcModelFirestoreCollections).oidcEntryCollection });
|
|
1206
|
+
}
|
|
1207
|
+
createClient = firebaseDocumentStoreCreateFunction(this, this.oidcModelFunctions.oidcEntry.createOidcEntry.client, {
|
|
1208
|
+
onResult: (_params, result) => {
|
|
1209
|
+
this._latestClientSecret$.next(result.client_secret);
|
|
1210
|
+
}
|
|
1211
|
+
});
|
|
1212
|
+
updateClient = firebaseDocumentStoreUpdateFunction(this, this.oidcModelFunctions.oidcEntry.updateOidcEntry.client);
|
|
1213
|
+
rotateClientSecret = firebaseDocumentStoreUpdateFunction(this, this.oidcModelFunctions.oidcEntry.updateOidcEntry.rotateClientSecret, {
|
|
1214
|
+
onResult: (_params, result) => {
|
|
1215
|
+
this._latestClientSecret$.next(result.client_secret);
|
|
1216
|
+
}
|
|
1217
|
+
});
|
|
1218
|
+
deleteClient = firebaseDocumentStoreDeleteFunction(this, this.oidcModelFunctions.oidcEntry.deleteOidcEntry.client);
|
|
1219
|
+
deleteToken = firebaseDocumentStoreDeleteFunction(this, this.oidcModelFunctions.oidcEntry.deleteOidcEntry.token);
|
|
1220
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: OidcEntryDocumentStore, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1221
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: OidcEntryDocumentStore });
|
|
1222
|
+
}
|
|
1223
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: OidcEntryDocumentStore, decorators: [{
|
|
1224
|
+
type: Injectable
|
|
1225
|
+
}], ctorParameters: () => [] });
|
|
1226
|
+
|
|
1227
|
+
/**
|
|
1228
|
+
* Wrapper list of {@link OidcEntry} Grant rows belonging to the current user.
|
|
1229
|
+
*
|
|
1230
|
+
* Renders one row per Grant — i.e. one row per "app with access to my account" —
|
|
1231
|
+
* with an inline Revoke button that cascades through every grantable token.
|
|
1232
|
+
*/
|
|
1233
|
+
class DbxFirebaseOidcEntryGrantListComponent extends AbstractDbxSelectionListWrapperDirective {
|
|
1234
|
+
constructor() {
|
|
1235
|
+
super({
|
|
1236
|
+
componentClass: DbxFirebaseOidcEntryGrantListViewComponent,
|
|
1237
|
+
defaultSelectionMode: 'view'
|
|
1238
|
+
});
|
|
1239
|
+
}
|
|
1240
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOidcEntryGrantListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1241
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: DbxFirebaseOidcEntryGrantListComponent, isStandalone: true, selector: "dbx-firebase-oidc-grant-list", host: { classAttribute: "dbx-list-no-hover-effects dbx-list-card-items-list" }, providers: provideDbxListViewWrapper(DbxFirebaseOidcEntryGrantListComponent), usesInheritance: true, ngImport: i0, template: "\n <dbx-list [state]=\"currentState$\" [config]=\"configSignal()\" [hasMore]=\"hasMore()\" [disabled]=\"disabledSignal()\" [selectionMode]=\"selectionModeSignal()\">\n <ng-content top select=\"[top]\"></ng-content>\n <ng-content bottom select=\"[bottom]\"></ng-content>\n <ng-content empty select=\"[empty]\"></ng-content>\n <ng-content emptyLoading select=\"[emptyLoading]\"></ng-content>\n <ng-content end select=\"[end]\"></ng-content>\n </dbx-list>", isInline: true, dependencies: [{ kind: "ngmodule", type: DbxListWrapperComponentImportsModule }, { kind: "component", type: i1.DbxListComponent, selector: "dbx-list", inputs: ["padded", "state", "config", "disabled", "selectionMode", "hasMore"], outputs: ["contentScrolled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1242
|
+
}
|
|
1243
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOidcEntryGrantListComponent, decorators: [{
|
|
1244
|
+
type: Component,
|
|
1245
|
+
args: [{
|
|
1246
|
+
selector: 'dbx-firebase-oidc-grant-list',
|
|
1247
|
+
template: DEFAULT_LIST_WRAPPER_COMPONENT_CONFIGURATION_TEMPLATE,
|
|
1248
|
+
providers: provideDbxListViewWrapper(DbxFirebaseOidcEntryGrantListComponent),
|
|
1249
|
+
standalone: true,
|
|
1250
|
+
host: {
|
|
1251
|
+
class: 'dbx-list-no-hover-effects dbx-list-card-items-list'
|
|
1252
|
+
},
|
|
1253
|
+
imports: [DbxListWrapperComponentImportsModule],
|
|
1254
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
1255
|
+
}]
|
|
1256
|
+
}], ctorParameters: () => [] });
|
|
1257
|
+
class DbxFirebaseOidcEntryGrantListViewComponent extends AbstractDbxSelectionListViewDirective {
|
|
1258
|
+
config = {
|
|
1259
|
+
componentClass: DbxFirebaseOidcEntryGrantListViewItemComponent,
|
|
1260
|
+
mapValuesToItemValues: (x) => of(x.map((y, i) => {
|
|
1261
|
+
const id = y.id;
|
|
1262
|
+
return { ...y, key: id ?? `grant_${i}`, itemValue: y };
|
|
1263
|
+
}))
|
|
1264
|
+
};
|
|
1265
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOidcEntryGrantListViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
1266
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: DbxFirebaseOidcEntryGrantListViewComponent, isStandalone: true, selector: "dbx-firebase-oidc-grant-list-view", providers: provideDbxListView(DbxFirebaseOidcEntryGrantListViewComponent), usesInheritance: true, ngImport: i0, template: "<dbx-selection-list-view [config]=\"config\"></dbx-selection-list-view>", isInline: true, dependencies: [{ kind: "ngmodule", type: DbxSelectionValueListViewComponentImportsModule }, { kind: "component", type: i1.DbxSelectionValueListViewComponent, selector: "dbx-selection-list-view" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1267
|
+
}
|
|
1268
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOidcEntryGrantListViewComponent, decorators: [{
|
|
1269
|
+
type: Component,
|
|
1270
|
+
args: [{
|
|
1271
|
+
selector: 'dbx-firebase-oidc-grant-list-view',
|
|
1272
|
+
template: DEFAULT_DBX_SELECTION_VALUE_LIST_COMPONENT_CONFIGURATION_TEMPLATE,
|
|
1273
|
+
providers: provideDbxListView(DbxFirebaseOidcEntryGrantListViewComponent),
|
|
1274
|
+
standalone: true,
|
|
1275
|
+
imports: [DbxSelectionValueListViewComponentImportsModule],
|
|
1276
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
1277
|
+
}]
|
|
1278
|
+
}] });
|
|
1279
|
+
// MARK: Item
|
|
1280
|
+
/**
|
|
1281
|
+
* Per-row view for a Grant entry. Inline "Revoke" button uses a per-component
|
|
1282
|
+
* {@link OidcEntryDocumentStore} keyed to this entry's id so calling
|
|
1283
|
+
* `deleteToken` invokes the {@link DeleteOidcTokenParams} callModel against
|
|
1284
|
+
* the right document.
|
|
1285
|
+
*/
|
|
1286
|
+
class DbxFirebaseOidcEntryGrantListViewItemComponent extends AbstractDbxValueListViewItemComponent {
|
|
1287
|
+
oidcEntryDocumentStore = inject(OidcEntryDocumentStore);
|
|
1288
|
+
clientIdSignal = computed(() => this._payload().clientId ?? '', ...(ngDevMode ? [{ debugName: "clientIdSignal" }] : /* istanbul ignore next */ []));
|
|
1289
|
+
scopeSignal = computed(() => this._payload().openid?.scope ?? null, ...(ngDevMode ? [{ debugName: "scopeSignal" }] : /* istanbul ignore next */ []));
|
|
1290
|
+
expiresAtSignal = computed(() => this.itemValue.expiresAt ?? null, ...(ngDevMode ? [{ debugName: "expiresAtSignal" }] : /* istanbul ignore next */ []));
|
|
1291
|
+
revokeConfirmConfig = {
|
|
1292
|
+
title: 'Revoke access',
|
|
1293
|
+
prompt: 'This app will lose access to your account immediately. Existing access and refresh tokens stop working.',
|
|
1294
|
+
confirmText: 'Revoke'
|
|
1295
|
+
};
|
|
1296
|
+
handleRevoke = (_, context) => {
|
|
1297
|
+
context.startWorkingWithLoadingStateObservable(this.oidcEntryDocumentStore.deleteToken({}));
|
|
1298
|
+
};
|
|
1299
|
+
constructor() {
|
|
1300
|
+
super();
|
|
1301
|
+
const id = this.itemValue.id;
|
|
1302
|
+
if (id) {
|
|
1303
|
+
this.oidcEntryDocumentStore.setId(id);
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
_payload() {
|
|
1307
|
+
return this.itemValue.payload ?? {};
|
|
1308
|
+
}
|
|
1309
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOidcEntryGrantListViewItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1310
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: DbxFirebaseOidcEntryGrantListViewItemComponent, isStandalone: true, selector: "dbx-firebase-oidc-grant-list-view-item", providers: [OidcEntryDocumentStore], usesInheritance: true, ngImport: i0, template: `
|
|
1311
|
+
<div class="dbx-list-item-padded dbx-list-item-padded-thick dbx-list-two-line-item">
|
|
1312
|
+
<div class="item-left">
|
|
1313
|
+
<span class="item-title">{{ clientIdSignal() }}</span>
|
|
1314
|
+
@if (scopeSignal()) {
|
|
1315
|
+
<span class="item-details">{{ scopeSignal() }}</span>
|
|
1316
|
+
}
|
|
1317
|
+
@if (expiresAtSignal()) {
|
|
1318
|
+
<span class="item-details-footnote">Expires {{ expiresAtSignal() | date: 'medium' }}</span>
|
|
1319
|
+
}
|
|
1320
|
+
</div>
|
|
1321
|
+
<dbx-spacer></dbx-spacer>
|
|
1322
|
+
<div class="item-right">
|
|
1323
|
+
<dbx-button dbxAction [dbxActionHandler]="handleRevoke" [dbxActionConfirm]="revokeConfirmConfig" dbxActionButton text="Revoke" icon="block" color="warn" [raised]="true"></dbx-button>
|
|
1324
|
+
</div>
|
|
1325
|
+
</div>
|
|
1326
|
+
`, isInline: true, dependencies: [{ kind: "directive", type: DbxSpacerDirective, selector: "dbx-spacer, [dbxSpacer]" }, { kind: "component", type: DbxButtonComponent, selector: "dbx-button", inputs: ["bar", "type", "buttonStyle", "color", "spinnerColor", "customButtonColor", "customTextColor", "customSpinnerColor", "basic", "tonal", "raised", "stroked", "flat", "iconOnly", "fab", "customContent", "allowClickPropagation", "mode"] }, { kind: "directive", type: DbxActionDirective, selector: "dbx-action,[dbxAction]", exportAs: ["action", "dbxAction"] }, { kind: "directive", type: DbxActionHandlerDirective, selector: "[dbxActionHandler]", inputs: ["dbxActionHandler"] }, { kind: "directive", type: DbxActionButtonDirective, selector: "[dbxActionButton]", inputs: ["dbxActionButtonEcho"] }, { kind: "directive", type: DbxActionConfirmDirective, selector: "[dbxActionConfirm]", inputs: ["dbxActionConfirm", "dbxActionConfirmSkip"] }, { kind: "pipe", type: DatePipe, name: "date" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1327
|
+
}
|
|
1328
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOidcEntryGrantListViewItemComponent, decorators: [{
|
|
1329
|
+
type: Component,
|
|
1330
|
+
args: [{
|
|
1331
|
+
selector: 'dbx-firebase-oidc-grant-list-view-item',
|
|
1332
|
+
template: `
|
|
1333
|
+
<div class="dbx-list-item-padded dbx-list-item-padded-thick dbx-list-two-line-item">
|
|
1334
|
+
<div class="item-left">
|
|
1335
|
+
<span class="item-title">{{ clientIdSignal() }}</span>
|
|
1336
|
+
@if (scopeSignal()) {
|
|
1337
|
+
<span class="item-details">{{ scopeSignal() }}</span>
|
|
1338
|
+
}
|
|
1339
|
+
@if (expiresAtSignal()) {
|
|
1340
|
+
<span class="item-details-footnote">Expires {{ expiresAtSignal() | date: 'medium' }}</span>
|
|
1341
|
+
}
|
|
1342
|
+
</div>
|
|
1343
|
+
<dbx-spacer></dbx-spacer>
|
|
1344
|
+
<div class="item-right">
|
|
1345
|
+
<dbx-button dbxAction [dbxActionHandler]="handleRevoke" [dbxActionConfirm]="revokeConfirmConfig" dbxActionButton text="Revoke" icon="block" color="warn" [raised]="true"></dbx-button>
|
|
1346
|
+
</div>
|
|
1347
|
+
</div>
|
|
1348
|
+
`,
|
|
1349
|
+
standalone: true,
|
|
1350
|
+
imports: [DatePipe, DbxSpacerDirective, DbxButtonComponent, DbxActionDirective, DbxActionHandlerDirective, DbxActionButtonDirective, DbxActionConfirmDirective],
|
|
1351
|
+
providers: [OidcEntryDocumentStore],
|
|
1352
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
1353
|
+
}]
|
|
1354
|
+
}], ctorParameters: () => [] });
|
|
1355
|
+
|
|
895
1356
|
class DbxFirebaseOidcEntryClientListComponent extends AbstractDbxSelectionListWrapperDirective {
|
|
896
1357
|
constructor() {
|
|
897
1358
|
super({
|
|
@@ -900,7 +1361,7 @@ class DbxFirebaseOidcEntryClientListComponent extends AbstractDbxSelectionListWr
|
|
|
900
1361
|
});
|
|
901
1362
|
}
|
|
902
1363
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOidcEntryClientListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
903
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: DbxFirebaseOidcEntryClientListComponent, isStandalone: true, selector: "dbx-firebase-oidc-client-list", providers: provideDbxListViewWrapper(DbxFirebaseOidcEntryClientListComponent), usesInheritance: true, ngImport: i0, template: "\n <dbx-list [state]=\"currentState$\" [config]=\"configSignal()\" [hasMore]=\"hasMore()\" [disabled]=\"disabledSignal()\" [selectionMode]=\"selectionModeSignal()\">\n <ng-content top select=\"[top]\"></ng-content>\n <ng-content bottom select=\"[bottom]\"></ng-content>\n <ng-content empty select=\"[empty]\"></ng-content>\n <ng-content emptyLoading select=\"[emptyLoading]\"></ng-content>\n <ng-content end select=\"[end]\"></ng-content>\n </dbx-list>", isInline: true, dependencies: [{ kind: "ngmodule", type: DbxListWrapperComponentImportsModule }, { kind: "component", type: i1
|
|
1364
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: DbxFirebaseOidcEntryClientListComponent, isStandalone: true, selector: "dbx-firebase-oidc-client-list", providers: provideDbxListViewWrapper(DbxFirebaseOidcEntryClientListComponent), usesInheritance: true, ngImport: i0, template: "\n <dbx-list [state]=\"currentState$\" [config]=\"configSignal()\" [hasMore]=\"hasMore()\" [disabled]=\"disabledSignal()\" [selectionMode]=\"selectionModeSignal()\">\n <ng-content top select=\"[top]\"></ng-content>\n <ng-content bottom select=\"[bottom]\"></ng-content>\n <ng-content empty select=\"[empty]\"></ng-content>\n <ng-content emptyLoading select=\"[emptyLoading]\"></ng-content>\n <ng-content end select=\"[end]\"></ng-content>\n </dbx-list>", isInline: true, dependencies: [{ kind: "ngmodule", type: DbxListWrapperComponentImportsModule }, { kind: "component", type: i1.DbxListComponent, selector: "dbx-list", inputs: ["padded", "state", "config", "disabled", "selectionMode", "hasMore"], outputs: ["contentScrolled"] }] });
|
|
904
1365
|
}
|
|
905
1366
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOidcEntryClientListComponent, decorators: [{
|
|
906
1367
|
type: Component,
|
|
@@ -918,7 +1379,7 @@ class DbxFirebaseOidcEntryClientListViewComponent extends AbstractDbxSelectionLi
|
|
|
918
1379
|
mapValuesToItemValues: (x) => of(x.map((y, i) => ({ ...y, key: `oidc_${i}`, itemValue: y })))
|
|
919
1380
|
};
|
|
920
1381
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOidcEntryClientListViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
921
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: DbxFirebaseOidcEntryClientListViewComponent, isStandalone: true, selector: "dbx-firebase-oidc-client-list-view", providers: provideDbxListView(DbxFirebaseOidcEntryClientListViewComponent), usesInheritance: true, ngImport: i0, template: "<dbx-selection-list-view [config]=\"config\"></dbx-selection-list-view>", isInline: true, dependencies: [{ kind: "ngmodule", type: DbxSelectionValueListViewComponentImportsModule }, { kind: "component", type: i1
|
|
1382
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: DbxFirebaseOidcEntryClientListViewComponent, isStandalone: true, selector: "dbx-firebase-oidc-client-list-view", providers: provideDbxListView(DbxFirebaseOidcEntryClientListViewComponent), usesInheritance: true, ngImport: i0, template: "<dbx-selection-list-view [config]=\"config\"></dbx-selection-list-view>", isInline: true, dependencies: [{ kind: "ngmodule", type: DbxSelectionValueListViewComponentImportsModule }, { kind: "component", type: i1.DbxSelectionValueListViewComponent, selector: "dbx-selection-list-view" }] });
|
|
922
1383
|
}
|
|
923
1384
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOidcEntryClientListViewComponent, decorators: [{
|
|
924
1385
|
type: Component,
|
|
@@ -1016,42 +1477,77 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
1016
1477
|
}] });
|
|
1017
1478
|
|
|
1018
1479
|
/**
|
|
1019
|
-
*
|
|
1480
|
+
* Collection store for querying {@link OidcEntry} documents.
|
|
1020
1481
|
*/
|
|
1021
|
-
class
|
|
1022
|
-
oidcModelFunctions = inject(OidcModelFunctions);
|
|
1023
|
-
_latestClientSecret$ = completeOnDestroy(new BehaviorSubject(undefined));
|
|
1024
|
-
/**
|
|
1025
|
-
* The client secret from the most recent create operation.
|
|
1026
|
-
*
|
|
1027
|
-
* Only available immediately after creation — the server does not return it again.
|
|
1028
|
-
*/
|
|
1029
|
-
latestClientSecret$ = this._latestClientSecret$.asObservable();
|
|
1030
|
-
get latestClientSecret() {
|
|
1031
|
-
return this._latestClientSecret$.value;
|
|
1032
|
-
}
|
|
1482
|
+
class OidcEntryCollectionStore extends AbstractDbxFirebaseCollectionStore {
|
|
1033
1483
|
constructor() {
|
|
1034
1484
|
super({ firestoreCollection: inject(OidcModelFirestoreCollections).oidcEntryCollection });
|
|
1035
1485
|
}
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
this._latestClientSecret$.next(result.client_secret);
|
|
1039
|
-
}
|
|
1040
|
-
});
|
|
1041
|
-
updateClient = firebaseDocumentStoreUpdateFunction(this, this.oidcModelFunctions.oidcEntry.updateOidcEntry.client);
|
|
1042
|
-
rotateClientSecret = firebaseDocumentStoreUpdateFunction(this, this.oidcModelFunctions.oidcEntry.updateOidcEntry.rotateClientSecret, {
|
|
1043
|
-
onResult: (_params, result) => {
|
|
1044
|
-
this._latestClientSecret$.next(result.client_secret);
|
|
1045
|
-
}
|
|
1046
|
-
});
|
|
1047
|
-
deleteClient = firebaseDocumentStoreDeleteFunction(this, this.oidcModelFunctions.oidcEntry.deleteOidcEntry.client);
|
|
1048
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: OidcEntryDocumentStore, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1049
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: OidcEntryDocumentStore });
|
|
1486
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: OidcEntryCollectionStore, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1487
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: OidcEntryCollectionStore });
|
|
1050
1488
|
}
|
|
1051
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type:
|
|
1489
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: OidcEntryCollectionStore, decorators: [{
|
|
1052
1490
|
type: Injectable
|
|
1053
1491
|
}], ctorParameters: () => [] });
|
|
1054
1492
|
|
|
1493
|
+
/**
|
|
1494
|
+
* Directive providing a {@link OidcEntryCollectionStore} for querying {@link OidcEntry} documents.
|
|
1495
|
+
*/
|
|
1496
|
+
class OidcEntryCollectionStoreDirective extends DbxFirebaseCollectionStoreDirective {
|
|
1497
|
+
constructor() {
|
|
1498
|
+
super(inject(OidcEntryCollectionStore));
|
|
1499
|
+
}
|
|
1500
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: OidcEntryCollectionStoreDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
1501
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.11", type: OidcEntryCollectionStoreDirective, isStandalone: true, selector: "[dbxOidcEntryCollection]", providers: provideDbxFirebaseCollectionStoreDirective(OidcEntryCollectionStoreDirective, OidcEntryCollectionStore), usesInheritance: true, ngImport: i0 });
|
|
1502
|
+
}
|
|
1503
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: OidcEntryCollectionStoreDirective, decorators: [{
|
|
1504
|
+
type: Directive,
|
|
1505
|
+
args: [{
|
|
1506
|
+
selector: '[dbxOidcEntryCollection]',
|
|
1507
|
+
providers: provideDbxFirebaseCollectionStoreDirective(OidcEntryCollectionStoreDirective, OidcEntryCollectionStore),
|
|
1508
|
+
standalone: true
|
|
1509
|
+
}]
|
|
1510
|
+
}], ctorParameters: () => [] });
|
|
1511
|
+
|
|
1512
|
+
/**
|
|
1513
|
+
* Drop-in container for the "apps with access to my account" management UI.
|
|
1514
|
+
*
|
|
1515
|
+
* Wires a {@link OidcEntryCollectionStoreDirective} to query Grant entries
|
|
1516
|
+
* for the signed-in user, then renders {@link DbxFirebaseOidcEntryGrantListComponent}
|
|
1517
|
+
* with inline Revoke buttons. No inputs — the container resolves the current
|
|
1518
|
+
* user via {@link DbxFirebaseAuthService}.
|
|
1519
|
+
*/
|
|
1520
|
+
class DbxFirebaseOidcEntryGrantListContainerComponent {
|
|
1521
|
+
dbxFirebaseAuthService = inject(DbxFirebaseAuthService);
|
|
1522
|
+
oidcEntryCollectionStoreDirective = viewChild(OidcEntryCollectionStoreDirective, ...(ngDevMode ? [{ debugName: "oidcEntryCollectionStoreDirective" }] : /* istanbul ignore next */ []));
|
|
1523
|
+
grantConstraintsSignal = toSignal(this.dbxFirebaseAuthService.currentAuthUser$.pipe(map((user) => (user?.uid ? oidcGrantEntriesByUidQuery(user.uid) : []))));
|
|
1524
|
+
ngOnInit() {
|
|
1525
|
+
const directive = this.oidcEntryCollectionStoreDirective();
|
|
1526
|
+
directive?.setMaxPages(5);
|
|
1527
|
+
directive?.setItemsPerPage(20);
|
|
1528
|
+
}
|
|
1529
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOidcEntryGrantListContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1530
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.11", type: DbxFirebaseOidcEntryGrantListContainerComponent, isStandalone: true, selector: "dbx-firebase-oidc-grant-list-container", viewQueries: [{ propertyName: "oidcEntryCollectionStoreDirective", first: true, predicate: OidcEntryCollectionStoreDirective, descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
1531
|
+
<div dbxOidcEntryCollection dbxFirebaseCollectionChange="auto" [constraints]="grantConstraintsSignal()">
|
|
1532
|
+
<dbx-firebase-oidc-grant-list dbxFirebaseCollectionList></dbx-firebase-oidc-grant-list>
|
|
1533
|
+
</div>
|
|
1534
|
+
`, isInline: true, dependencies: [{ kind: "directive", type: OidcEntryCollectionStoreDirective, selector: "[dbxOidcEntryCollection]" }, { kind: "directive", type: DbxFirebaseCollectionListDirective, selector: "[dbxFirebaseCollectionList]" }, { kind: "directive", type: DbxFirebaseCollectionChangeDirective, selector: "[dbxFirebaseCollectionChange]", inputs: ["dbxFirebaseCollectionChange"] }, { kind: "component", type: DbxFirebaseOidcEntryGrantListComponent, selector: "dbx-firebase-oidc-grant-list" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1535
|
+
}
|
|
1536
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOidcEntryGrantListContainerComponent, decorators: [{
|
|
1537
|
+
type: Component,
|
|
1538
|
+
args: [{
|
|
1539
|
+
selector: 'dbx-firebase-oidc-grant-list-container',
|
|
1540
|
+
template: `
|
|
1541
|
+
<div dbxOidcEntryCollection dbxFirebaseCollectionChange="auto" [constraints]="grantConstraintsSignal()">
|
|
1542
|
+
<dbx-firebase-oidc-grant-list dbxFirebaseCollectionList></dbx-firebase-oidc-grant-list>
|
|
1543
|
+
</div>
|
|
1544
|
+
`,
|
|
1545
|
+
standalone: true,
|
|
1546
|
+
imports: [OidcEntryCollectionStoreDirective, DbxFirebaseCollectionListDirective, DbxFirebaseCollectionChangeDirective, DbxFirebaseOidcEntryGrantListComponent],
|
|
1547
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
1548
|
+
}]
|
|
1549
|
+
}], propDecorators: { oidcEntryCollectionStoreDirective: [{ type: i0.ViewChild, args: [i0.forwardRef(() => OidcEntryCollectionStoreDirective), { isSignal: true }] }] } });
|
|
1550
|
+
|
|
1055
1551
|
/**
|
|
1056
1552
|
* Container component for creating a new OAuth client.
|
|
1057
1553
|
*
|
|
@@ -1365,39 +1861,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
1365
1861
|
}]
|
|
1366
1862
|
}] });
|
|
1367
1863
|
|
|
1368
|
-
/**
|
|
1369
|
-
* Collection store for querying {@link OidcEntry} documents.
|
|
1370
|
-
*/
|
|
1371
|
-
class OidcEntryCollectionStore extends AbstractDbxFirebaseCollectionStore {
|
|
1372
|
-
constructor() {
|
|
1373
|
-
super({ firestoreCollection: inject(OidcModelFirestoreCollections).oidcEntryCollection });
|
|
1374
|
-
}
|
|
1375
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: OidcEntryCollectionStore, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1376
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: OidcEntryCollectionStore });
|
|
1377
|
-
}
|
|
1378
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: OidcEntryCollectionStore, decorators: [{
|
|
1379
|
-
type: Injectable
|
|
1380
|
-
}], ctorParameters: () => [] });
|
|
1381
|
-
|
|
1382
|
-
/**
|
|
1383
|
-
* Directive providing a {@link OidcEntryCollectionStore} for querying {@link OidcEntry} documents.
|
|
1384
|
-
*/
|
|
1385
|
-
class OidcEntryCollectionStoreDirective extends DbxFirebaseCollectionStoreDirective {
|
|
1386
|
-
constructor() {
|
|
1387
|
-
super(inject(OidcEntryCollectionStore));
|
|
1388
|
-
}
|
|
1389
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: OidcEntryCollectionStoreDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
1390
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.11", type: OidcEntryCollectionStoreDirective, isStandalone: true, selector: "[dbxOidcEntryCollection]", providers: provideDbxFirebaseCollectionStoreDirective(OidcEntryCollectionStoreDirective, OidcEntryCollectionStore), usesInheritance: true, ngImport: i0 });
|
|
1391
|
-
}
|
|
1392
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: OidcEntryCollectionStoreDirective, decorators: [{
|
|
1393
|
-
type: Directive,
|
|
1394
|
-
args: [{
|
|
1395
|
-
selector: '[dbxOidcEntryCollection]',
|
|
1396
|
-
providers: provideDbxFirebaseCollectionStoreDirective(OidcEntryCollectionStoreDirective, OidcEntryCollectionStore),
|
|
1397
|
-
standalone: true
|
|
1398
|
-
}]
|
|
1399
|
-
}], ctorParameters: () => [] });
|
|
1400
|
-
|
|
1401
1864
|
/**
|
|
1402
1865
|
* Directive providing a {@link OidcEntryDocumentStore} for accessing a single {@link OidcEntry} document.
|
|
1403
1866
|
*/
|
|
@@ -1465,5 +1928,5 @@ function provideDbxFirebaseOidc(config) {
|
|
|
1465
1928
|
* Generated bundle index. Do not edit.
|
|
1466
1929
|
*/
|
|
1467
1930
|
|
|
1468
|
-
export { AbstractDbxFirebaseOAuthConsentScopeViewComponent, DEFAULT_OIDC_AUTHORIZATION_ENDPOINT_PATH, DEFAULT_OIDC_CLIENT_ID_PARAM_KEY, DEFAULT_OIDC_CLIENT_NAME_PARAM_KEY, DEFAULT_OIDC_CLIENT_URI_PARAM_KEY, DEFAULT_OIDC_INTERACTION_ENDPOINT_PATH, DEFAULT_OIDC_INTERACTION_UID_PARAM_KEY, DEFAULT_OIDC_LOGO_URI_PARAM_KEY, DEFAULT_OIDC_SCOPES_PARAM_KEY, DEFAULT_OIDC_TOKEN_ENDPOINT_AUTH_METHODS, DbxFirebaseOAuthConsentScopeDefaultViewComponent, DbxFirebaseOAuthConsentScopeListComponent, DbxFirebaseOAuthConsentViewComponent, DbxFirebaseOAuthLoginComponent, DbxFirebaseOAuthLoginViewComponent, DbxFirebaseOidcConfig, DbxFirebaseOidcConfigService, DbxFirebaseOidcEntryClientCreateComponent, DbxFirebaseOidcEntryClientForgeFormComponent, DbxFirebaseOidcEntryClientListComponent, DbxFirebaseOidcEntryClientListViewComponent, DbxFirebaseOidcEntryClientListViewItemClientComponent, DbxFirebaseOidcEntryClientListViewItemComponent, DbxFirebaseOidcEntryClientListViewItemDefaultComponent, DbxFirebaseOidcEntryClientTestComponent, DbxFirebaseOidcEntryClientTestForgeFormComponent, DbxFirebaseOidcEntryClientUpdateComponent, DbxFirebaseOidcEntryClientViewComponent, DbxFirebaseOidcInteractionService, DbxOAuthConsentComponent, OidcEntryCollectionStore, OidcEntryCollectionStoreDirective, OidcEntryDocumentStore, OidcEntryDocumentStoreDirective, oidcClientHomepageUriForgeField, oidcClientJwksUriForgeField, oidcClientLogoUriForgeField, oidcClientNameForgeField, oidcClientRedirectUrisForgeField, oidcClientTestClientIdForgeField, oidcClientTestRedirectUriForgeField, oidcClientTestScopesForgeField, oidcClientTokenEndpointAuthMethodForgeField, oidcEntryClientForgeFormFields, oidcEntryClientTestForgeFormFields, oidcEntryClientUpdateForgeFormFields, provideDbxFirebaseOidc, provideOidcModelFirestoreCollections };
|
|
1931
|
+
export { AbstractDbxFirebaseOAuthConsentScopeViewComponent, DEFAULT_OIDC_AUTHORIZATION_ENDPOINT_PATH, DEFAULT_OIDC_CLIENT_ID_PARAM_KEY, DEFAULT_OIDC_CLIENT_NAME_PARAM_KEY, DEFAULT_OIDC_CLIENT_URI_PARAM_KEY, DEFAULT_OIDC_INTERACTION_ENDPOINT_PATH, DEFAULT_OIDC_INTERACTION_UID_PARAM_KEY, DEFAULT_OIDC_LOGO_URI_PARAM_KEY, DEFAULT_OIDC_SCOPES_PARAM_KEY, DEFAULT_OIDC_TOKEN_ENDPOINT_AUTH_METHODS, DbxFirebaseOAuthConsentScopeDefaultViewComponent, DbxFirebaseOAuthConsentScopeFormComponent, DbxFirebaseOAuthConsentScopeListComponent, DbxFirebaseOAuthConsentScopeListItemComponent, DbxFirebaseOAuthConsentScopeListViewComponent, DbxFirebaseOAuthConsentViewComponent, DbxFirebaseOAuthLoginComponent, DbxFirebaseOAuthLoginViewComponent, DbxFirebaseOidcConfig, DbxFirebaseOidcConfigService, DbxFirebaseOidcEntryClientCreateComponent, DbxFirebaseOidcEntryClientForgeFormComponent, DbxFirebaseOidcEntryClientListComponent, DbxFirebaseOidcEntryClientListViewComponent, DbxFirebaseOidcEntryClientListViewItemClientComponent, DbxFirebaseOidcEntryClientListViewItemComponent, DbxFirebaseOidcEntryClientListViewItemDefaultComponent, DbxFirebaseOidcEntryClientTestComponent, DbxFirebaseOidcEntryClientTestForgeFormComponent, DbxFirebaseOidcEntryClientUpdateComponent, DbxFirebaseOidcEntryClientViewComponent, DbxFirebaseOidcEntryGrantListComponent, DbxFirebaseOidcEntryGrantListContainerComponent, DbxFirebaseOidcEntryGrantListViewComponent, DbxFirebaseOidcEntryGrantListViewItemComponent, DbxFirebaseOidcInteractionService, DbxOAuthConsentComponent, OAUTH_CONSENT_SCOPES_REQUIRED_VALIDATOR_DEFAULT_MESSAGE, OAUTH_CONSENT_SCOPES_REQUIRED_VALIDATOR_KIND, OidcEntryCollectionStore, OidcEntryCollectionStoreDirective, OidcEntryDocumentStore, OidcEntryDocumentStoreDirective, oauthConsentScopesFormConfig, oidcClientHomepageUriForgeField, oidcClientJwksUriForgeField, oidcClientLogoUriForgeField, oidcClientNameForgeField, oidcClientRedirectUrisForgeField, oidcClientTestClientIdForgeField, oidcClientTestRedirectUriForgeField, oidcClientTestScopesForgeField, oidcClientTokenEndpointAuthMethodForgeField, oidcEntryClientForgeFormFields, oidcEntryClientTestForgeFormFields, oidcEntryClientUpdateForgeFormFields, provideDbxFirebaseOidc, provideOidcModelFirestoreCollections };
|
|
1469
1932
|
//# sourceMappingURL=dereekb-dbx-firebase-oidc.mjs.map
|