@dereekb/firebase-server 13.31.0 → 13.33.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/calcom/index.cjs.default.js +1 -0
- package/calcom/index.cjs.js +1451 -0
- package/calcom/index.cjs.mjs +2 -0
- package/calcom/index.d.ts +1 -0
- package/calcom/index.esm.js +1437 -0
- package/calcom/package.json +29 -0
- package/calcom/src/index.d.ts +1 -0
- package/calcom/src/lib/calcom.oauth.connection.cache.d.ts +49 -0
- package/calcom/src/lib/calcom.oauth.connection.config.d.ts +75 -0
- package/calcom/src/lib/calcom.oauth.connection.context.d.ts +84 -0
- package/calcom/src/lib/calcom.oauth.connection.controller.d.ts +18 -0
- package/calcom/src/lib/calcom.oauth.connection.module.d.ts +55 -0
- package/calcom/src/lib/calcom.oauth.connection.service.d.ts +33 -0
- package/calcom/src/lib/index.d.ts +6 -0
- package/discord/index.cjs.default.js +1 -0
- package/discord/index.cjs.js +761 -0
- package/discord/index.cjs.mjs +2 -0
- package/discord/index.d.ts +1 -0
- package/discord/index.esm.js +753 -0
- package/discord/package.json +29 -0
- package/discord/src/index.d.ts +1 -0
- package/discord/src/lib/discord.oauth.connection.config.d.ts +69 -0
- package/discord/src/lib/discord.oauth.connection.controller.d.ts +18 -0
- package/discord/src/lib/discord.oauth.connection.module.d.ts +39 -0
- package/discord/src/lib/discord.oauth.connection.service.d.ts +43 -0
- package/discord/src/lib/index.d.ts +4 -0
- package/index.cjs.js +14 -3
- package/index.esm.js +14 -3
- package/mailgun/package.json +9 -9
- package/mcp/package.json +11 -11
- package/model/index.cjs.js +11077 -6072
- package/model/index.esm.js +11020 -6081
- package/model/package.json +10 -9
- package/model/src/lib/index.d.ts +1 -0
- package/model/src/lib/mailgun/index.d.ts +1 -0
- package/model/src/lib/mailgun/notification.healthcheck.mailgun.d.ts +115 -0
- package/model/src/lib/notification/index.d.ts +2 -0
- package/model/src/lib/notification/notification.action.server.d.ts +42 -3
- package/model/src/lib/notification/notification.error.d.ts +31 -0
- package/model/src/lib/notification/notification.healthcheck.d.ts +39 -0
- package/model/src/lib/notification/notification.healthcheck.service.d.ts +118 -0
- package/model/src/lib/notification/notification.send.service.d.ts +22 -0
- package/model/src/lib/userexternalconnection/index.d.ts +8 -0
- package/model/src/lib/userexternalconnection/oauth/index.d.ts +7 -0
- package/model/src/lib/userexternalconnection/oauth/userexternalconnection.oauth.config.d.ts +110 -0
- package/model/src/lib/userexternalconnection/oauth/userexternalconnection.oauth.controller.d.ts +68 -0
- package/model/src/lib/userexternalconnection/oauth/userexternalconnection.oauth.error.d.ts +29 -0
- package/model/src/lib/userexternalconnection/oauth/userexternalconnection.oauth.refresh.d.ts +24 -0
- package/model/src/lib/userexternalconnection/oauth/userexternalconnection.oauth.registry.d.ts +54 -0
- package/model/src/lib/userexternalconnection/oauth/userexternalconnection.oauth.service.d.ts +216 -0
- package/model/src/lib/userexternalconnection/oauth/userexternalconnection.oauth.state.d.ts +114 -0
- package/model/src/lib/userexternalconnection/userexternalconnection.accessor.service.d.ts +111 -0
- package/model/src/lib/userexternalconnection/userexternalconnection.action.server.d.ts +172 -0
- package/model/src/lib/userexternalconnection/userexternalconnection.error.d.ts +44 -0
- package/model/src/lib/userexternalconnection/userexternalconnection.module.d.ts +129 -0
- package/model/src/lib/userexternalconnection/userexternalconnection.private.d.ts +192 -0
- package/model/src/lib/userexternalconnection/userexternalconnection.reader.service.d.ts +157 -0
- package/model/src/lib/userexternalconnection/userexternalconnection.refresh.service.d.ts +46 -0
- package/oidc/index.cjs.js +104 -78
- package/oidc/index.esm.js +104 -78
- package/oidc/package.json +10 -10
- package/package.json +24 -10
- package/src/lib/env/env.config.d.ts +15 -0
- package/src/lib/env/env.service.d.ts +7 -0
- package/src/lib/nest/env/env.service.d.ts +1 -0
- package/test/index.cjs.js +14 -2
- package/test/index.esm.js +15 -3
- package/test/package.json +11 -11
- package/test/src/lib/firebase/firebase.admin.auth.d.ts +1 -1
- package/twilio/package.json +8 -8
- package/zoho/README.md +8 -0
- package/zoho/index.cjs.js +1223 -33
- package/zoho/index.esm.js +1212 -36
- package/zoho/package.json +12 -9
- package/zoho/src/lib/index.d.ts +5 -0
- package/zoho/src/lib/zoho.oauth.connection.cache.d.ts +45 -0
- package/zoho/src/lib/zoho.oauth.connection.config.d.ts +80 -0
- package/zoho/src/lib/zoho.oauth.connection.controller.d.ts +18 -0
- package/zoho/src/lib/zoho.oauth.connection.module.d.ts +43 -0
- package/zoho/src/lib/zoho.oauth.connection.service.d.ts +107 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { type FactoryWithRequiredInput, type Maybe, type Milliseconds } from '@dereekb/util';
|
|
2
|
+
import { type FirebaseAuthUserId, type FirebaseAuthUserIdRef, type UserExternalConnectionErrorCode, type UserExternalConnectionProviderType } from '@dereekb/firebase';
|
|
3
|
+
import { type UserExternalConnectionAccessor, type UserExternalConnectionForProvider, type UserExternalConnectionReadParams } from './userexternalconnection.accessor.service';
|
|
4
|
+
import { type UserExternalConnectionCredentials } from './userexternalconnection.private';
|
|
5
|
+
import { type UserExternalConnectionCredentialsRefresher } from './userexternalconnection.refresh.service';
|
|
6
|
+
import { type UserExternalConnectionCredentialsAndFailureWriter } from './userexternalconnection.action.server';
|
|
7
|
+
/**
|
|
8
|
+
* How long before its stated expiration a set of credentials is treated as already expired.
|
|
9
|
+
*
|
|
10
|
+
* A token that expires mid-flight is indistinguishable from one that was never valid, so the check
|
|
11
|
+
* needs headroom. One minute matches the `tokenExpirationBuffer` default that the Cal.com and Zoho
|
|
12
|
+
* token factories already use, so a credential this reader hands out is one those factories would also
|
|
13
|
+
* consider live.
|
|
14
|
+
*/
|
|
15
|
+
export declare const DEFAULT_USER_EXTERNAL_CONNECTION_CREDENTIALS_EXPIRATION_BUFFER: Milliseconds;
|
|
16
|
+
/**
|
|
17
|
+
* The error code recorded when a refresh attempt fails.
|
|
18
|
+
*
|
|
19
|
+
* `expired` rather than `revoked`: a failed refresh is nearly always `invalid_grant`, which does not
|
|
20
|
+
* distinguish a revoked grant from a refresh token that was already spent, and claiming the user
|
|
21
|
+
* revoked access when they did not would send the UI down the wrong path.
|
|
22
|
+
*/
|
|
23
|
+
export declare const DEFAULT_USER_EXTERNAL_CONNECTION_REFRESH_FAILURE_ERROR_CODE: UserExternalConnectionErrorCode;
|
|
24
|
+
/**
|
|
25
|
+
* Configuration for {@link userExternalConnectionReader}.
|
|
26
|
+
*/
|
|
27
|
+
export interface UserExternalConnectionReaderConfig {
|
|
28
|
+
/**
|
|
29
|
+
* The paired read surface this reader adds policy on top of.
|
|
30
|
+
*/
|
|
31
|
+
readonly accessor: UserExternalConnectionAccessor;
|
|
32
|
+
/**
|
|
33
|
+
* Used to persist a refresh and to record a failure. Both go through the paired write.
|
|
34
|
+
*
|
|
35
|
+
* Narrowed to those two writes: a full `UserExternalConnectionServerActions` satisfies it, and
|
|
36
|
+
* a caller wiring a reader over something else does not have to implement writes it never reaches.
|
|
37
|
+
*/
|
|
38
|
+
readonly actions: UserExternalConnectionCredentialsAndFailureWriter;
|
|
39
|
+
/**
|
|
40
|
+
* Optional. Without one, expired credentials cannot be renewed and
|
|
41
|
+
* {@link UserExternalConnectionReaderProviderInstance.readUsableUserExternalConnectionCredentials}
|
|
42
|
+
* throws instead.
|
|
43
|
+
*/
|
|
44
|
+
readonly refresher?: Maybe<UserExternalConnectionCredentialsRefresher>;
|
|
45
|
+
/**
|
|
46
|
+
* How long before its stated expiration a credential is treated as expired. Defaults to
|
|
47
|
+
* {@link DEFAULT_USER_EXTERNAL_CONNECTION_CREDENTIALS_EXPIRATION_BUFFER}.
|
|
48
|
+
*/
|
|
49
|
+
readonly expirationBuffer?: Maybe<Milliseconds>;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Why a provider rejected a user's credentials.
|
|
53
|
+
*/
|
|
54
|
+
export interface UserExternalConnectionReportFailureInput {
|
|
55
|
+
/**
|
|
56
|
+
* Why the credentials were rejected. Defaults to `unauthorized`, the code for the 401 this is
|
|
57
|
+
* almost always called in response to.
|
|
58
|
+
*/
|
|
59
|
+
readonly error?: Maybe<UserExternalConnectionErrorCode>;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Parameters for reporting that a provider rejected a user's credentials.
|
|
63
|
+
*/
|
|
64
|
+
export interface UserExternalConnectionReportFailureParams extends UserExternalConnectionReadParams, UserExternalConnectionReportFailureInput {
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Input identifying the user a {@link UserExternalConnectionReaderUserInstance} reads for.
|
|
68
|
+
*/
|
|
69
|
+
export interface UserExternalConnectionReaderUserInput extends FirebaseAuthUserIdRef {
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* A {@link UserExternalConnectionReader} narrowed to ONE user and ONE provider.
|
|
73
|
+
*
|
|
74
|
+
* The reader's entire read surface, with `{ uid, providerType }` already applied — so a consumer acting
|
|
75
|
+
* as one user against one provider, the normal case for code making provider API calls, states that
|
|
76
|
+
* pair once instead of at every call and cannot accidentally mix two providers up.
|
|
77
|
+
*/
|
|
78
|
+
export interface UserExternalConnectionReaderProviderInstance {
|
|
79
|
+
readonly uid: FirebaseAuthUserId;
|
|
80
|
+
readonly providerType: UserExternalConnectionProviderType;
|
|
81
|
+
/**
|
|
82
|
+
* Loads both halves of the pair, applying no policy. Never throws for an absent or unusable
|
|
83
|
+
* connection.
|
|
84
|
+
*/
|
|
85
|
+
readUserExternalConnectionForProvider(): Promise<UserExternalConnectionForProvider>;
|
|
86
|
+
/**
|
|
87
|
+
* Loads the stored credentials as-is, applying no policy. They may be expired.
|
|
88
|
+
*/
|
|
89
|
+
readUserExternalConnectionCredentials(): Promise<Maybe<UserExternalConnectionCredentials>>;
|
|
90
|
+
/**
|
|
91
|
+
* Returns credentials that are safe to attempt a provider call with, renewing them first if needed.
|
|
92
|
+
*
|
|
93
|
+
* @throws When the user is not connected to the provider, or the credentials have expired and could
|
|
94
|
+
* not be renewed.
|
|
95
|
+
*/
|
|
96
|
+
readUsableUserExternalConnectionCredentials(): Promise<UserExternalConnectionCredentials>;
|
|
97
|
+
/**
|
|
98
|
+
* Records that the provider rejected these credentials, moving the entry to the `error` status.
|
|
99
|
+
*
|
|
100
|
+
* Exists so a caller that gets a 401 mid-call can report it without reaching for the write surface.
|
|
101
|
+
* Never throws — a failure to record a failure is logged and swallowed, because the caller is already
|
|
102
|
+
* handling an error and losing that error to this one would be worse.
|
|
103
|
+
*
|
|
104
|
+
* @param input - Why the credentials were rejected. Defaults to `unauthorized`.
|
|
105
|
+
*/
|
|
106
|
+
reportUserExternalConnectionFailure(input?: Maybe<UserExternalConnectionReportFailureInput>): Promise<void>;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* A {@link UserExternalConnectionReader} narrowed to one user, awaiting the provider to target.
|
|
110
|
+
*
|
|
111
|
+
* The second of the reader's two factory levels. Splitting them this way is what lets ONE reader — the
|
|
112
|
+
* app has a single provider-agnostic instance — be narrowed to a user once and then used against any
|
|
113
|
+
* number of that user's providers.
|
|
114
|
+
*/
|
|
115
|
+
export type UserExternalConnectionReaderUserInstance = FactoryWithRequiredInput<UserExternalConnectionReaderProviderInstance, UserExternalConnectionProviderType>;
|
|
116
|
+
/**
|
|
117
|
+
* Reads a user's third-party credentials for a specific provider, and keeps them usable.
|
|
118
|
+
*
|
|
119
|
+
* The read surface a consumer should reach for. It wraps a {@link UserExternalConnectionAccessor} and
|
|
120
|
+
* adds the policy that would otherwise be re-implemented at every call site: whether the connection is
|
|
121
|
+
* usable, whether the credentials are near enough to expiring to renew, renewing them, persisting the
|
|
122
|
+
* result, and recording a failure.
|
|
123
|
+
*
|
|
124
|
+
* A consumer that has this does not need `UserExternalConnectionServerActions` at all, which is
|
|
125
|
+
* the point — that class is the write surface.
|
|
126
|
+
*/
|
|
127
|
+
export declare abstract class UserExternalConnectionReader {
|
|
128
|
+
/**
|
|
129
|
+
* Narrows this reader to one user, returning a factory that narrows it further to one provider.
|
|
130
|
+
*
|
|
131
|
+
* The reader's only entry point. Every read and the failure report live on the narrowed instance, so
|
|
132
|
+
* a caller states the user and provider it is acting for once instead of threading that pair through
|
|
133
|
+
* each call:
|
|
134
|
+
*
|
|
135
|
+
* ```ts
|
|
136
|
+
* const connections = reader.readerForUser({ uid });
|
|
137
|
+
* const credentials = await connections(CALCOM).readUsableUserExternalConnectionCredentials();
|
|
138
|
+
* ```
|
|
139
|
+
*
|
|
140
|
+
* @param input - The user to read for.
|
|
141
|
+
* @returns A factory producing a reader for whichever of that user's providers is needed.
|
|
142
|
+
*/
|
|
143
|
+
abstract readerForUser(input: UserExternalConnectionReaderUserInput): UserExternalConnectionReaderUserInstance;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Reference to a {@link UserExternalConnectionReader} instance.
|
|
147
|
+
*/
|
|
148
|
+
export interface UserExternalConnectionReaderRef {
|
|
149
|
+
readonly userExternalConnectionReader: UserExternalConnectionReader;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Creates a {@link UserExternalConnectionReader}.
|
|
153
|
+
*
|
|
154
|
+
* @param config - The accessor and actions to build over, plus the optional refresher.
|
|
155
|
+
* @returns A concrete UserExternalConnectionReader implementation.
|
|
156
|
+
*/
|
|
157
|
+
export declare function userExternalConnectionReader(config: UserExternalConnectionReaderConfig): UserExternalConnectionReader;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { type Maybe } from '@dereekb/util';
|
|
2
|
+
import { type FirebaseAuthUserId, type UserExternalConnectionProviderType } from '@dereekb/firebase';
|
|
3
|
+
import { type UserExternalConnectionCredentials } from './userexternalconnection.private';
|
|
4
|
+
/**
|
|
5
|
+
* Input for {@link UserExternalConnectionCredentialsRefresher.refreshUserExternalConnectionCredentials}.
|
|
6
|
+
*/
|
|
7
|
+
export interface UserExternalConnectionRefreshCredentialsInput {
|
|
8
|
+
readonly uid: FirebaseAuthUserId;
|
|
9
|
+
readonly providerType: UserExternalConnectionProviderType;
|
|
10
|
+
/**
|
|
11
|
+
* The credentials currently stored for this provider.
|
|
12
|
+
*
|
|
13
|
+
* Passed whole rather than as a bare refresh token because a refresh can need more than that:
|
|
14
|
+
* Zoho's refresh must be sent to the datacenter that issued the grant, which is only recorded on
|
|
15
|
+
* `extra`.
|
|
16
|
+
*/
|
|
17
|
+
readonly credentials: UserExternalConnectionCredentials;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Exchanges a user's stored credentials for fresh ones.
|
|
21
|
+
*
|
|
22
|
+
* Declared here rather than beside the OAuth registry on purpose: {@link UserExternalConnectionReader}
|
|
23
|
+
* takes a refresher as OPTIONAL configuration, and if the reader could only be configured with a
|
|
24
|
+
* registry-backed one it would have to import the OAuth layer — whose provider services depend on the
|
|
25
|
+
* accessor the reader is built over. Keeping this an interface in the middle is what keeps that graph
|
|
26
|
+
* acyclic, and it also lets a caller supply a refresher that has nothing to do with OAuth.
|
|
27
|
+
*
|
|
28
|
+
* Implementations return the credentials the provider issued, and are NOT responsible for carrying
|
|
29
|
+
* forward values the provider's response omits — see `mergeRefreshedUserExternalConnectionCredentials`,
|
|
30
|
+
* which the reader applies to every result.
|
|
31
|
+
*/
|
|
32
|
+
export declare abstract class UserExternalConnectionCredentialsRefresher {
|
|
33
|
+
/**
|
|
34
|
+
* Refreshes one provider's credentials.
|
|
35
|
+
*
|
|
36
|
+
* @param input - The acting user, the provider, and the credentials currently stored.
|
|
37
|
+
* @returns The refreshed credentials, or null when this provider has no refresh path at all.
|
|
38
|
+
*/
|
|
39
|
+
abstract refreshUserExternalConnectionCredentials(input: UserExternalConnectionRefreshCredentialsInput): Promise<Maybe<UserExternalConnectionCredentials>>;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Reference to a {@link UserExternalConnectionCredentialsRefresher} instance.
|
|
43
|
+
*/
|
|
44
|
+
export interface UserExternalConnectionCredentialsRefresherRef {
|
|
45
|
+
readonly userExternalConnectionCredentialsRefresher: UserExternalConnectionCredentialsRefresher;
|
|
46
|
+
}
|
package/oidc/index.cjs.js
CHANGED
|
@@ -6219,7 +6219,7 @@ var OidcInteractionController_1;
|
|
|
6219
6219
|
* @throws {HttpException} HTTP 400 when the consent interaction cannot be completed.
|
|
6220
6220
|
*/ function postConsent(uid, body, res) {
|
|
6221
6221
|
return _async_to_generator$2(function() {
|
|
6222
|
-
var startedAt, clientId, accountId, _ref, _prompt_details_missingOIDCScope,
|
|
6222
|
+
var startedAt, clientId, accountId, _ref, _prompt_details_missingOIDCScope, _ref1, _this_accountService_providerConfig_adminOnlyScopes, _ref2, _ref3, _prompt_details_missingOIDCClaims, _prompt_details_missingResourceScopes, _this_accountService_delegate_isAdminUser, _this_accountService_delegate, _ref4, redirectTo, interaction, prompt, params, session, missingOIDCScope, existingGrant, _tmp, encounteredOIDCScopes, clientPayload, requestedOIDCScopeSet, providerProfiles, _oidcClientProviderProfileScopes, clientUnlockedScopes, clientRequiredScopes, profileGatedScopes, disallowedGatedScopes, _ref5, redirectTo1, missingRequiredScopes, _ref6, redirectTo2, effectiveOIDCScopes, heldOIDCScopes, consentedOIDCScopeSet, configAdminOnlyScopes, adminOnlyScopes, consentedAdminOnlyScopes, requestsServiceToken, isAdmin, _tmp1, _ref7, redirectTo3, requestedRawTtl, clientMaxSessionTtl, expiresInSeconds, grant, _tmp2, granted, rejected, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, value, encounteredOIDCClaims, missingOIDCClaims, _resolveEffectiveSubset, granted1, rejected1, missingResourceScopes, _iteratorNormalCompletion1, _didIteratorError1, _iteratorError1, _iterator1, _step1, _step_value, indicator, scopes, _ref8, _body_grantedResourceScopes, requestedSubset, encounteredResourceScopes, _resolveEffectiveSubset1, granted2, rejected2, _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, value1, grantId, _ref9, redirectTo4, err;
|
|
6223
6223
|
return _ts_generator$2(this, function(_state) {
|
|
6224
6224
|
switch(_state.label){
|
|
6225
6225
|
case 0:
|
|
@@ -6301,66 +6301,44 @@ var OidcInteractionController_1;
|
|
|
6301
6301
|
];
|
|
6302
6302
|
case 9:
|
|
6303
6303
|
clientPayload = _state.sent();
|
|
6304
|
-
//
|
|
6305
|
-
//
|
|
6306
|
-
//
|
|
6307
|
-
//
|
|
6308
|
-
//
|
|
6304
|
+
// The requested OIDC scope set is `missingOIDCScope ∪ encounteredOIDCScopes` (a fresh consent has
|
|
6305
|
+
// everything in `missing`; a re-consent may carry already-granted scopes in `encountered`). The two
|
|
6306
|
+
// provider-profile gates below judge the REQUEST — what this client may ask for at all — so they
|
|
6307
|
+
// read this set. The admin-only gate further down judges what the user actually consented to
|
|
6308
|
+
// instead, and reads `consentedOIDCScopeSet`.
|
|
6309
6309
|
requestedOIDCScopeSet = new Set(_to_consumable_array$1(missingOIDCScope).concat(_to_consumable_array$1(encounteredOIDCScopes)));
|
|
6310
6310
|
providerProfiles = this.accountService.providerConfig.providerProfiles;
|
|
6311
|
-
|
|
6312
|
-
|
|
6313
|
-
|
|
6314
|
-
|
|
6315
|
-
|
|
6316
|
-
|
|
6317
|
-
//
|
|
6318
|
-
|
|
6319
|
-
|
|
6320
|
-
return requestedOIDCScopeSet.has(scope);
|
|
6311
|
+
// Provider-profile scope gate. Any scope referenced by a provider profile is "gated" — available
|
|
6312
|
+
// only to clients whose assigned profiles unlock it (a client with NO assigned profiles resolves
|
|
6313
|
+
// to the registry's default profiles). Independent of the admin-only gate below; a scope may be
|
|
6314
|
+
// subject to both.
|
|
6315
|
+
_oidcClientProviderProfileScopes = oidcClientProviderProfileScopes(providerProfiles, (_ref1 = clientPayload === null || clientPayload === void 0 ? void 0 : clientPayload.dbx_provider_profiles) !== null && _ref1 !== void 0 ? _ref1 : undefined), clientUnlockedScopes = _oidcClientProviderProfileScopes.unlocked, clientRequiredScopes = _oidcClientProviderProfileScopes.required;
|
|
6316
|
+
profileGatedScopes = firebase.scopesForOidcProviderProfiles(providerProfiles !== null && providerProfiles !== void 0 ? providerProfiles : []);
|
|
6317
|
+
// Unlock gate: reject any requested gated scope this client's profiles do not unlock.
|
|
6318
|
+
disallowedGatedScopes = Array.from(requestedOIDCScopeSet).filter(function(scope) {
|
|
6319
|
+
return profileGatedScopes.has(scope) && !clientUnlockedScopes.has(scope);
|
|
6321
6320
|
});
|
|
6322
|
-
if (!
|
|
6321
|
+
if (!(disallowedGatedScopes.length > 0)) return [
|
|
6323
6322
|
3,
|
|
6324
6323
|
11
|
|
6325
6324
|
];
|
|
6326
|
-
return [
|
|
6327
|
-
4,
|
|
6328
|
-
(_ref1 = (_this_accountService_delegate_isAdminUser = (_this_accountService_delegate = this.accountService.delegate).isAdminUser) === null || _this_accountService_delegate_isAdminUser === void 0 ? void 0 : _this_accountService_delegate_isAdminUser.call(_this_accountService_delegate, this.accountService.userContext(accountId).authUserContext)) !== null && _ref1 !== void 0 ? _ref1 : false
|
|
6329
|
-
];
|
|
6330
|
-
case 10:
|
|
6331
|
-
_tmp1 = _state.sent();
|
|
6332
|
-
return [
|
|
6333
|
-
3,
|
|
6334
|
-
12
|
|
6335
|
-
];
|
|
6336
|
-
case 11:
|
|
6337
|
-
_tmp1 = false;
|
|
6338
|
-
_state.label = 12;
|
|
6339
|
-
case 12:
|
|
6340
|
-
isAdmin = _tmp1;
|
|
6341
|
-
if (!(requestedAdminOnlyScopes.length > 0 && !isAdmin)) return [
|
|
6342
|
-
3,
|
|
6343
|
-
14
|
|
6344
|
-
];
|
|
6345
6325
|
return [
|
|
6346
6326
|
4,
|
|
6347
6327
|
this.oidcInteractionService.finishInteractionByUid(uid, {
|
|
6348
6328
|
error: 'access_denied',
|
|
6349
|
-
error_description: "The following scope(s) are
|
|
6329
|
+
error_description: "The following scope(s) are not available to this client: ".concat(disallowedGatedScopes.join(', '), ".")
|
|
6350
6330
|
}, {
|
|
6351
6331
|
mergeWithLastSubmission: true
|
|
6352
6332
|
})
|
|
6353
6333
|
];
|
|
6354
|
-
case
|
|
6334
|
+
case 10:
|
|
6355
6335
|
_ref5 = _state.sent(), redirectTo1 = _ref5.returnTo;
|
|
6356
6336
|
emitOidcAnalyticsEvent(this._analytics, {
|
|
6357
6337
|
type: 'consent',
|
|
6358
6338
|
isSuccessful: false,
|
|
6359
6339
|
uid: accountId,
|
|
6360
6340
|
clientId: clientId,
|
|
6361
|
-
|
|
6362
|
-
isAdmin: false,
|
|
6363
|
-
reason: 'service_token_non_admin',
|
|
6341
|
+
reason: 'scope_not_unlocked_for_client',
|
|
6364
6342
|
durationMs: Date.now() - startedAt
|
|
6365
6343
|
}, this._logger);
|
|
6366
6344
|
res.json({
|
|
@@ -6369,38 +6347,33 @@ var OidcInteractionController_1;
|
|
|
6369
6347
|
return [
|
|
6370
6348
|
2
|
|
6371
6349
|
];
|
|
6372
|
-
case
|
|
6373
|
-
//
|
|
6374
|
-
//
|
|
6375
|
-
|
|
6376
|
-
|
|
6377
|
-
_oidcClientProviderProfileScopes = oidcClientProviderProfileScopes(providerProfiles, (_ref2 = clientPayload === null || clientPayload === void 0 ? void 0 : clientPayload.dbx_provider_profiles) !== null && _ref2 !== void 0 ? _ref2 : undefined), clientUnlockedScopes = _oidcClientProviderProfileScopes.unlocked, clientRequiredScopes = _oidcClientProviderProfileScopes.required;
|
|
6378
|
-
profileGatedScopes = firebase.scopesForOidcProviderProfiles(providerProfiles !== null && providerProfiles !== void 0 ? providerProfiles : []);
|
|
6379
|
-
// Unlock gate: reject any requested gated scope this client's profiles do not unlock.
|
|
6380
|
-
disallowedGatedScopes = Array.from(requestedOIDCScopeSet).filter(function(scope) {
|
|
6381
|
-
return profileGatedScopes.has(scope) && !clientUnlockedScopes.has(scope);
|
|
6350
|
+
case 11:
|
|
6351
|
+
// Required gate: a scope a client's profiles force-require (`require: 'required'`) must be present
|
|
6352
|
+
// in the request. Reject when the client did not request a required scope.
|
|
6353
|
+
missingRequiredScopes = Array.from(clientRequiredScopes).filter(function(scope) {
|
|
6354
|
+
return !requestedOIDCScopeSet.has(scope);
|
|
6382
6355
|
});
|
|
6383
|
-
if (!(
|
|
6356
|
+
if (!(missingRequiredScopes.length > 0)) return [
|
|
6384
6357
|
3,
|
|
6385
|
-
|
|
6358
|
+
13
|
|
6386
6359
|
];
|
|
6387
6360
|
return [
|
|
6388
6361
|
4,
|
|
6389
6362
|
this.oidcInteractionService.finishInteractionByUid(uid, {
|
|
6390
6363
|
error: 'access_denied',
|
|
6391
|
-
error_description: "
|
|
6364
|
+
error_description: "This client must request the required scope(s): ".concat(missingRequiredScopes.join(', '), ".")
|
|
6392
6365
|
}, {
|
|
6393
6366
|
mergeWithLastSubmission: true
|
|
6394
6367
|
})
|
|
6395
6368
|
];
|
|
6396
|
-
case
|
|
6369
|
+
case 12:
|
|
6397
6370
|
_ref6 = _state.sent(), redirectTo2 = _ref6.returnTo;
|
|
6398
6371
|
emitOidcAnalyticsEvent(this._analytics, {
|
|
6399
6372
|
type: 'consent',
|
|
6400
6373
|
isSuccessful: false,
|
|
6401
6374
|
uid: accountId,
|
|
6402
6375
|
clientId: clientId,
|
|
6403
|
-
reason: '
|
|
6376
|
+
reason: 'required_scope_missing',
|
|
6404
6377
|
durationMs: Date.now() - startedAt
|
|
6405
6378
|
}, this._logger);
|
|
6406
6379
|
res.json({
|
|
@@ -6409,13 +6382,62 @@ var OidcInteractionController_1;
|
|
|
6409
6382
|
return [
|
|
6410
6383
|
2
|
|
6411
6384
|
];
|
|
6412
|
-
case
|
|
6413
|
-
//
|
|
6414
|
-
//
|
|
6415
|
-
|
|
6416
|
-
|
|
6385
|
+
case 13:
|
|
6386
|
+
// The scopes this consent actually puts in force. Resolved once here and re-applied to the grant
|
|
6387
|
+
// further down, so the admin-only gate below judges exactly the set that will be granted.
|
|
6388
|
+
//
|
|
6389
|
+
// Force-grants the client's required profile scopes (in addition to `openid`) so they cannot be
|
|
6390
|
+
// dropped at consent — the required gate above already guarantees they were requested.
|
|
6391
|
+
effectiveOIDCScopes = resolveEffectiveSubset({
|
|
6392
|
+
missing: missingOIDCScope,
|
|
6393
|
+
requestedSubset: body.grantedOIDCScopes,
|
|
6394
|
+
alwaysGranted: _to_consumable_array$1(ALWAYS_GRANTED_OIDC_SCOPES).concat(_to_consumable_array$1(clientRequiredScopes)),
|
|
6395
|
+
alreadyEncountered: encounteredOIDCScopes
|
|
6417
6396
|
});
|
|
6418
|
-
|
|
6397
|
+
// Scopes the existing Grant already holds (granted, minus any it rejected). Nothing here revokes
|
|
6398
|
+
// them, so they stay in force through this consent and the gate below has to count them too.
|
|
6399
|
+
heldOIDCScopes = existingGrant ? existingGrant.getOIDCScope().split(' ').filter(Boolean) : [];
|
|
6400
|
+
consentedOIDCScopeSet = new Set(_to_consumable_array$1(heldOIDCScopes).concat(_to_consumable_array$1(effectiveOIDCScopes.granted)));
|
|
6401
|
+
// Admin-only scope gate. If the consented set intersects the admin-only scopes — the provider's
|
|
6402
|
+
// `adminOnlyScopes` unioned with the scopes of every profile marked `adminOnly` — and the resolving
|
|
6403
|
+
// user is not an admin, hard-reject with `access_denied` rather than silently dropping the scope.
|
|
6404
|
+
//
|
|
6405
|
+
// Deliberately gated on what the user CONSENTED to rather than on what the client requested: the
|
|
6406
|
+
// consent UI renders a deselectable checkbox for every scope in the auth request, and a client
|
|
6407
|
+
// cannot know the caller's admin status when it builds that request. Gating on the request would
|
|
6408
|
+
// make an admin-only scope in `scopes_supported` fatal for every non-admin — deselecting it at
|
|
6409
|
+
// consent has to be a way through.
|
|
6410
|
+
configAdminOnlyScopes = (_this_accountService_providerConfig_adminOnlyScopes = this.accountService.providerConfig.adminOnlyScopes) !== null && _this_accountService_providerConfig_adminOnlyScopes !== void 0 ? _this_accountService_providerConfig_adminOnlyScopes : [];
|
|
6411
|
+
adminOnlyScopes = new Set(_to_consumable_array$1(configAdminOnlyScopes).concat(_to_consumable_array$1(firebase.adminOnlyScopesForOidcProviderProfiles(providerProfiles !== null && providerProfiles !== void 0 ? providerProfiles : []))));
|
|
6412
|
+
consentedAdminOnlyScopes = Array.from(adminOnlyScopes).filter(function(scope) {
|
|
6413
|
+
return consentedOIDCScopeSet.has(scope);
|
|
6414
|
+
});
|
|
6415
|
+
// Deliberately sourced from the provider config's `adminOnlyScopes` ALONE, unlike the gate above:
|
|
6416
|
+
// this flag also selects the (highest) service-token TTL tier further down, and a profile marked
|
|
6417
|
+
// `adminOnly` must gate by admin status WITHOUT widening its grant's lifetime to that tier.
|
|
6418
|
+
requestsServiceToken = configAdminOnlyScopes.some(function(scope) {
|
|
6419
|
+
return consentedOIDCScopeSet.has(scope);
|
|
6420
|
+
});
|
|
6421
|
+
if (!accountId) return [
|
|
6422
|
+
3,
|
|
6423
|
+
15
|
|
6424
|
+
];
|
|
6425
|
+
return [
|
|
6426
|
+
4,
|
|
6427
|
+
(_ref2 = (_this_accountService_delegate_isAdminUser = (_this_accountService_delegate = this.accountService.delegate).isAdminUser) === null || _this_accountService_delegate_isAdminUser === void 0 ? void 0 : _this_accountService_delegate_isAdminUser.call(_this_accountService_delegate, this.accountService.userContext(accountId).authUserContext)) !== null && _ref2 !== void 0 ? _ref2 : false
|
|
6428
|
+
];
|
|
6429
|
+
case 14:
|
|
6430
|
+
_tmp1 = _state.sent();
|
|
6431
|
+
return [
|
|
6432
|
+
3,
|
|
6433
|
+
16
|
|
6434
|
+
];
|
|
6435
|
+
case 15:
|
|
6436
|
+
_tmp1 = false;
|
|
6437
|
+
_state.label = 16;
|
|
6438
|
+
case 16:
|
|
6439
|
+
isAdmin = _tmp1;
|
|
6440
|
+
if (!(consentedAdminOnlyScopes.length > 0 && !isAdmin)) return [
|
|
6419
6441
|
3,
|
|
6420
6442
|
18
|
|
6421
6443
|
];
|
|
@@ -6423,7 +6445,7 @@ var OidcInteractionController_1;
|
|
|
6423
6445
|
4,
|
|
6424
6446
|
this.oidcInteractionService.finishInteractionByUid(uid, {
|
|
6425
6447
|
error: 'access_denied',
|
|
6426
|
-
error_description: "
|
|
6448
|
+
error_description: "The following scope(s) are restricted to admins: ".concat(consentedAdminOnlyScopes.join(', '), ".")
|
|
6427
6449
|
}, {
|
|
6428
6450
|
mergeWithLastSubmission: true
|
|
6429
6451
|
})
|
|
@@ -6435,7 +6457,9 @@ var OidcInteractionController_1;
|
|
|
6435
6457
|
isSuccessful: false,
|
|
6436
6458
|
uid: accountId,
|
|
6437
6459
|
clientId: clientId,
|
|
6438
|
-
|
|
6460
|
+
serviceToken: requestsServiceToken,
|
|
6461
|
+
isAdmin: false,
|
|
6462
|
+
reason: 'service_token_non_admin',
|
|
6439
6463
|
durationMs: Date.now() - startedAt
|
|
6440
6464
|
}, this._logger);
|
|
6441
6465
|
res.json({
|
|
@@ -6478,14 +6502,7 @@ var OidcInteractionController_1;
|
|
|
6478
6502
|
case 21:
|
|
6479
6503
|
grant = _tmp2;
|
|
6480
6504
|
if (missingOIDCScope.length > 0) {
|
|
6481
|
-
|
|
6482
|
-
// dropped at consent — the required gate above already guarantees they were requested.
|
|
6483
|
-
_resolveEffectiveSubset = resolveEffectiveSubset({
|
|
6484
|
-
missing: missingOIDCScope,
|
|
6485
|
-
requestedSubset: body.grantedOIDCScopes,
|
|
6486
|
-
alwaysGranted: _to_consumable_array$1(ALWAYS_GRANTED_OIDC_SCOPES).concat(_to_consumable_array$1(clientRequiredScopes)),
|
|
6487
|
-
alreadyEncountered: encounteredOIDCScopes
|
|
6488
|
-
}), granted = _resolveEffectiveSubset.granted, rejected = _resolveEffectiveSubset.rejected;
|
|
6505
|
+
granted = effectiveOIDCScopes.granted, rejected = effectiveOIDCScopes.rejected;
|
|
6489
6506
|
if (granted.length > 0) {
|
|
6490
6507
|
grant.addOIDCScope(granted.join(' '));
|
|
6491
6508
|
}
|
|
@@ -6513,11 +6530,11 @@ var OidcInteractionController_1;
|
|
|
6513
6530
|
encounteredOIDCClaims = grant.getOIDCClaimsEncountered();
|
|
6514
6531
|
missingOIDCClaims = (_prompt_details_missingOIDCClaims = prompt.details.missingOIDCClaims) !== null && _prompt_details_missingOIDCClaims !== void 0 ? _prompt_details_missingOIDCClaims : [];
|
|
6515
6532
|
if (missingOIDCClaims.length > 0) {
|
|
6516
|
-
|
|
6533
|
+
_resolveEffectiveSubset = resolveEffectiveSubset({
|
|
6517
6534
|
missing: missingOIDCClaims,
|
|
6518
6535
|
requestedSubset: body.grantedOIDCClaims,
|
|
6519
6536
|
alreadyEncountered: encounteredOIDCClaims
|
|
6520
|
-
}), granted1 =
|
|
6537
|
+
}), granted1 = _resolveEffectiveSubset.granted, rejected1 = _resolveEffectiveSubset.rejected;
|
|
6521
6538
|
if (granted1.length > 0) {
|
|
6522
6539
|
grant.addOIDCClaims(granted1);
|
|
6523
6540
|
}
|
|
@@ -6531,13 +6548,22 @@ var OidcInteractionController_1;
|
|
|
6531
6548
|
for(_iterator1 = Object.entries(missingResourceScopes)[Symbol.iterator](); !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
|
|
6532
6549
|
_step_value = _sliced_to_array(_step1.value, 2), indicator = _step_value[0], scopes = _step_value[1];
|
|
6533
6550
|
;
|
|
6534
|
-
|
|
6551
|
+
;
|
|
6552
|
+
// A submission with no explicit per-resource selection falls back to the OIDC scope selection
|
|
6553
|
+
// rather than granting everything the resource server declares. A resource server's scope list
|
|
6554
|
+
// is drawn from the same provider scopes the consent UI renders as one checkbox list, so a scope
|
|
6555
|
+
// deselected there must not reappear on the resource-bound access token — otherwise deselecting
|
|
6556
|
+
// an admin-only scope would clear the gate above while the token still carried it.
|
|
6557
|
+
// `grantedOIDCScopes` being absent still means "grant everything requested".
|
|
6558
|
+
requestedSubset = (_ref8 = (_body_grantedResourceScopes = body.grantedResourceScopes) === null || _body_grantedResourceScopes === void 0 ? void 0 : _body_grantedResourceScopes[indicator]) !== null && _ref8 !== void 0 ? _ref8 : body.grantedOIDCScopes ? scopes.filter(function(scope) {
|
|
6559
|
+
return consentedOIDCScopeSet.has(scope);
|
|
6560
|
+
}) : undefined;
|
|
6535
6561
|
encounteredResourceScopes = grant.getResourceScopeEncountered(indicator).split(' ').filter(Boolean);
|
|
6536
|
-
|
|
6562
|
+
_resolveEffectiveSubset1 = resolveEffectiveSubset({
|
|
6537
6563
|
missing: scopes,
|
|
6538
6564
|
requestedSubset: requestedSubset,
|
|
6539
6565
|
alreadyEncountered: encounteredResourceScopes
|
|
6540
|
-
}), granted2 =
|
|
6566
|
+
}), granted2 = _resolveEffectiveSubset1.granted, rejected2 = _resolveEffectiveSubset1.rejected;
|
|
6541
6567
|
if (granted2.length > 0) {
|
|
6542
6568
|
grant.addResourceScope(indicator, granted2.join(' '));
|
|
6543
6569
|
}
|
|
@@ -6593,7 +6619,7 @@ var OidcInteractionController_1;
|
|
|
6593
6619
|
})
|
|
6594
6620
|
];
|
|
6595
6621
|
case 23:
|
|
6596
|
-
|
|
6622
|
+
_ref9 = _state.sent(), redirectTo4 = _ref9.returnTo;
|
|
6597
6623
|
emitOidcAnalyticsEvent(this._analytics, {
|
|
6598
6624
|
type: 'consent',
|
|
6599
6625
|
isSuccessful: true,
|