@dereekb/firebase-server 13.29.0 → 13.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.cjs.js +129 -1
- package/index.esm.js +129 -3
- package/mailgun/package.json +9 -9
- package/mcp/index.cjs.js +42 -17
- package/mcp/index.esm.js +43 -18
- package/mcp/package.json +11 -11
- package/mcp/src/lib/mcp.config.d.ts +19 -1
- package/mcp/src/lib/service/mcp.server.factory.d.ts +1 -1
- package/mcp/src/lib/service/mcp.tool-generator.d.ts +12 -1
- package/mcp/src/lib/service/mcp.visibility.d.ts +9 -6
- package/model/package.json +9 -9
- package/oidc/index.cjs.js +30 -65
- package/oidc/index.esm.js +34 -68
- package/oidc/package.json +10 -10
- package/oidc/src/lib/index.d.ts +0 -1
- package/oidc/src/lib/oidc.config.d.ts +11 -0
- package/oidc/src/lib/profile.d.ts +7 -0
- package/oidc/src/lib/service/oidc.auth.d.ts +1 -1
- package/package.json +10 -10
- package/src/lib/nest/controller/model/index.d.ts +1 -0
- package/src/lib/nest/controller/model/model.api.dispatch.d.ts +14 -2
- package/src/lib/nest/controller/model/model.api.get.service.d.ts +14 -0
- package/src/lib/nest/controller/model/model.api.scope.d.ts +102 -0
- package/src/lib/nest/model/api.details.d.ts +13 -8
- package/src/lib/nest/model/crud.assert.function.d.ts +7 -6
- package/test/index.cjs.js +94 -58
- package/test/index.esm.js +95 -59
- package/test/package.json +11 -11
- package/test/src/lib/oidc/oidc.test.fixture.d.ts +9 -1
- package/test/src/lib/oidc/oidc.test.flow.d.ts +13 -3
- package/twilio/package.json +8 -8
- package/zoho/package.json +9 -9
- package/oidc/src/lib/scope.d.ts +0 -24
package/mcp/index.esm.js
CHANGED
|
@@ -2,12 +2,12 @@ import { Injectable, Inject, Optional, Logger, Post, Req, Res, Controller, Get }
|
|
|
2
2
|
import { existsSync, readFileSync } from 'node:fs';
|
|
3
3
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
4
4
|
import { ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
5
|
+
import { callModelOidcScopeForCallType, resolveEffectiveOidcScopeTerms, inferKeyFromTwoWayFlatFirestoreModelKey, oidcScopeTermsSatisfied } from '@dereekb/firebase';
|
|
5
6
|
import { getOidcScopesFromRequest, OidcProviderConfigService } from '@dereekb/firebase-server/oidc';
|
|
6
|
-
import {
|
|
7
|
+
import { makeValuesGroupMap, IMPERSONATION_URL_QUERY_PARAM, performAsyncTasks, authRolesSetHasRoles } from '@dereekb/util';
|
|
7
8
|
import { ModelApiCallModelDispatchService, ModelApiGetService, FirebaseServerStorageService, FirebaseServerEnvService, FirebaseServerAnalyticsService } from '@dereekb/firebase-server';
|
|
8
9
|
import { inspect } from 'node:util';
|
|
9
10
|
import { arktypeToJsonSchemaForExport } from '@dereekb/model';
|
|
10
|
-
import { callModelOidcScopeForCallType, inferKeyFromTwoWayFlatFirestoreModelKey } from '@dereekb/firebase';
|
|
11
11
|
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
12
12
|
|
|
13
13
|
function _class_call_check$5(instance, Constructor) {
|
|
@@ -165,6 +165,22 @@ function _define_property$9(obj, key, value) {
|
|
|
165
165
|
* fills with a short justification for the call. The value is forwarded to analytics and stripped
|
|
166
166
|
* from the dispatched handler body. See {@link McpReasonParameterConfig}.
|
|
167
167
|
*/ _define_property$9(this, "reasonParameter", void 0);
|
|
168
|
+
/**
|
|
169
|
+
* Default OIDC scope group term required on EVERY `callModel` op, mirrored into MCP tool-list
|
|
170
|
+
* visibility, unless a finer term overrides it (a per-function `requiredScope`, then a
|
|
171
|
+
* {@link McpModuleConfig.modelRequiredScopes} entry). Threaded into the same
|
|
172
|
+
* `resolveEffectiveOidcScopeTerms` composition the server-side model-api scope gate
|
|
173
|
+
* (`assertModelApiOidcScope`) uses, so a tool is advertised only when the caller could actually invoke it.
|
|
174
|
+
*
|
|
175
|
+
* Set this to the SAME value passed to `ModelApiDispatchConfig.defaultRequiredScope` to
|
|
176
|
+
* keep tool visibility and enforcement in lockstep.
|
|
177
|
+
*/ _define_property$9(this, "defaultRequiredScope", void 0);
|
|
178
|
+
/**
|
|
179
|
+
* Per-model OIDC scope group-term overrides, keyed by {@link FirestoreModelType}, mirrored into MCP
|
|
180
|
+
* tool-list visibility. Set this to the SAME value passed to
|
|
181
|
+
* `ModelApiDispatchConfig.modelRequiredScopes` so per-model / verb-keyed restrictions that
|
|
182
|
+
* confine a subset client apply identically to the advertised tool list.
|
|
183
|
+
*/ _define_property$9(this, "modelRequiredScopes", void 0);
|
|
168
184
|
};
|
|
169
185
|
/**
|
|
170
186
|
* NestJS injection token for the optional {@link McpAuthRoleReader} provider.
|
|
@@ -1398,6 +1414,8 @@ function _unsupported_iterable_to_array$9(o, minLen) {
|
|
|
1398
1414
|
var seenNames = new Set();
|
|
1399
1415
|
var manifest = context === null || context === void 0 ? void 0 : context.manifest;
|
|
1400
1416
|
var naming = context === null || context === void 0 ? void 0 : context.naming;
|
|
1417
|
+
var defaultRequiredScope = context === null || context === void 0 ? void 0 : context.defaultRequiredScope;
|
|
1418
|
+
var modelRequiredScopes = context === null || context === void 0 ? void 0 : context.modelRequiredScopes;
|
|
1401
1419
|
var candidates = planMcpToolCandidates(apiDetails, naming);
|
|
1402
1420
|
var clashCounts = countVisibleAutoNameClashes(candidates);
|
|
1403
1421
|
var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
|
|
@@ -1409,6 +1427,8 @@ function _unsupported_iterable_to_array$9(o, minLen) {
|
|
|
1409
1427
|
clashCounts: clashCounts,
|
|
1410
1428
|
options: options,
|
|
1411
1429
|
manifest: manifest,
|
|
1430
|
+
defaultRequiredScope: defaultRequiredScope,
|
|
1431
|
+
modelRequiredScopes: modelRequiredScopes,
|
|
1412
1432
|
seenNames: seenNames,
|
|
1413
1433
|
outTools: tools,
|
|
1414
1434
|
outNeverVisibleTools: neverVisibleTools,
|
|
@@ -1580,7 +1600,7 @@ function _unsupported_iterable_to_array$9(o, minLen) {
|
|
|
1580
1600
|
*/ function buildToolFromCandidate(context) {
|
|
1581
1601
|
var _clashCounts_get, _ref;
|
|
1582
1602
|
var _handlerDetails_mcp, _handlerDetails_mcp1;
|
|
1583
|
-
var candidate = context.candidate, clashCounts = context.clashCounts, options = context.options, manifest = context.manifest, seenNames = context.seenNames, outTools = context.outTools, outNeverVisibleTools = context.outNeverVisibleTools, outSkipped = context.outSkipped, outWarnings = context.outWarnings;
|
|
1603
|
+
var candidate = context.candidate, clashCounts = context.clashCounts, options = context.options, manifest = context.manifest, defaultRequiredScope = context.defaultRequiredScope, modelRequiredScopes = context.modelRequiredScopes, seenNames = context.seenNames, outTools = context.outTools, outNeverVisibleTools = context.outNeverVisibleTools, outSkipped = context.outSkipped, outWarnings = context.outWarnings;
|
|
1584
1604
|
var modelType = candidate.modelType, callType = candidate.callType, handlerDetails = candidate.handlerDetails, specifier = candidate.specifier, dispatch = candidate.dispatch, modelSegment = candidate.modelSegment, overrideName = candidate.overrideName, baseName = candidate.baseName, classified = candidate.classified, isVisible = candidate.isVisible;
|
|
1585
1605
|
// A visible auto-named tool whose preferred name is produced by more than one visible tool is
|
|
1586
1606
|
// re-derived with the abbreviated call type so both survive on the wire. Overrides and hidden tools
|
|
@@ -1630,13 +1650,18 @@ function _unsupported_iterable_to_array$9(o, minLen) {
|
|
|
1630
1650
|
});
|
|
1631
1651
|
}
|
|
1632
1652
|
}
|
|
1633
|
-
//
|
|
1634
|
-
//
|
|
1635
|
-
//
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1653
|
+
// AND-of-ORs scope terms: the per-verb call-type scope (model.<call>) plus the effective group term,
|
|
1654
|
+
// resolved by the same precedence the server model-api scope gate uses (per-function requiredScope > per-model
|
|
1655
|
+
// requirement > module default) via the shared resolveEffectiveOidcScopeTerms — so tool visibility
|
|
1656
|
+
// tracks callability. Empty when no term applies (a non-CRUD call type with no per-function/model/
|
|
1657
|
+
// default term → no scope gate).
|
|
1658
|
+
var requiredScopeTerms = resolveEffectiveOidcScopeTerms({
|
|
1659
|
+
perVerbScope: resolveRequiredScope(callType),
|
|
1660
|
+
requiredScope: handlerDetails.requiredScope,
|
|
1661
|
+
modelRequirement: modelRequiredScopes === null || modelRequiredScopes === void 0 ? void 0 : modelRequiredScopes[modelType],
|
|
1662
|
+
call: callType,
|
|
1663
|
+
defaultRequiredScope: defaultRequiredScope
|
|
1664
|
+
});
|
|
1640
1665
|
var effectiveReadOnly = resolveEffectiveReadOnly((_handlerDetails_mcp = handlerDetails.mcp) === null || _handlerDetails_mcp === void 0 ? void 0 : _handlerDetails_mcp.readOnly, callType);
|
|
1641
1666
|
var annotations = resolveMcpToolAnnotations(effectiveReadOnly);
|
|
1642
1667
|
var description = applyWriteMarker(baseDescription, annotations);
|
|
@@ -1645,20 +1670,20 @@ function _unsupported_iterable_to_array$9(o, minLen) {
|
|
|
1645
1670
|
filterMetadata = {
|
|
1646
1671
|
visibilityKind: 'declarative',
|
|
1647
1672
|
rule: classified.rule,
|
|
1648
|
-
|
|
1673
|
+
requiredScopeTerms: requiredScopeTerms,
|
|
1649
1674
|
effectiveReadOnly: effectiveReadOnly
|
|
1650
1675
|
};
|
|
1651
1676
|
} else if (classified.visibilityKind === 'dynamic') {
|
|
1652
1677
|
filterMetadata = {
|
|
1653
1678
|
visibilityKind: 'dynamic',
|
|
1654
1679
|
visibilityFn: classified.visibilityFn,
|
|
1655
|
-
|
|
1680
|
+
requiredScopeTerms: requiredScopeTerms,
|
|
1656
1681
|
effectiveReadOnly: effectiveReadOnly
|
|
1657
1682
|
};
|
|
1658
1683
|
} else {
|
|
1659
1684
|
filterMetadata = {
|
|
1660
1685
|
visibilityKind: classified.visibilityKind,
|
|
1661
|
-
|
|
1686
|
+
requiredScopeTerms: requiredScopeTerms,
|
|
1662
1687
|
effectiveReadOnly: effectiveReadOnly
|
|
1663
1688
|
};
|
|
1664
1689
|
}
|
|
@@ -6161,7 +6186,9 @@ var McpServerFactoryService_1;
|
|
|
6161
6186
|
} else {
|
|
6162
6187
|
result = generateMcpToolDefinitions(apiDetails, undefined, {
|
|
6163
6188
|
manifest: manifest,
|
|
6164
|
-
naming: this._resolveToolNamingOptions()
|
|
6189
|
+
naming: this._resolveToolNamingOptions(),
|
|
6190
|
+
defaultRequiredScope: this.mcpConfig.defaultRequiredScope,
|
|
6191
|
+
modelRequiredScopes: this.mcpConfig.modelRequiredScopes
|
|
6165
6192
|
});
|
|
6166
6193
|
}
|
|
6167
6194
|
this._cachedTools = result;
|
|
@@ -6630,7 +6657,7 @@ var McpServerFactoryService_1;
|
|
|
6630
6657
|
* Synthesizes the same `{ auth: { token } }` shape that `getOidcScopesFromRequest`
|
|
6631
6658
|
* expects post-dispatch, so the upstream helper stays the single source of scope parsing.
|
|
6632
6659
|
* Returns `undefined` for non-OIDC callers (no `oidcValidatedToken.scope`) — the filter
|
|
6633
|
-
* loop treats that as "skip scope enforcement", matching `
|
|
6660
|
+
* loop treats that as "skip scope enforcement", matching the model-api scope gate (`assertModelApiOidcScope`).
|
|
6634
6661
|
*
|
|
6635
6662
|
* @param ctx - The per-request context carrying the validated auth payload.
|
|
6636
6663
|
* @returns The set of granted OIDC scopes, or `undefined` when scope enforcement should be skipped.
|
|
@@ -6674,9 +6701,7 @@ var McpServerFactoryService_1;
|
|
|
6674
6701
|
for(var _iterator = tools[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
|
|
6675
6702
|
var tool = _step.value;
|
|
6676
6703
|
var filterMetadata = tool.filterMetadata;
|
|
6677
|
-
if (scopes != null && filterMetadata.
|
|
6678
|
-
return scopes.has(scope);
|
|
6679
|
-
})) {
|
|
6704
|
+
if (scopes != null && filterMetadata.requiredScopeTerms != null && !oidcScopeTermsSatisfied(filterMetadata.requiredScopeTerms, scopes)) {
|
|
6680
6705
|
continue;
|
|
6681
6706
|
}
|
|
6682
6707
|
if (readOnlyMode && filterMetadata.effectiveReadOnly !== true) {
|
package/mcp/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dereekb/firebase-server/mcp",
|
|
3
|
-
"version": "13.
|
|
3
|
+
"version": "13.31.0",
|
|
4
4
|
"peerDependencies": {
|
|
5
|
-
"@dereekb/analytics": "13.
|
|
6
|
-
"@dereekb/date": "13.
|
|
7
|
-
"@dereekb/firebase": "13.
|
|
8
|
-
"@dereekb/firebase-server": "13.
|
|
9
|
-
"@dereekb/firebase-server/oidc": "13.
|
|
10
|
-
"@dereekb/model": "13.
|
|
11
|
-
"@dereekb/nestjs": "13.
|
|
12
|
-
"@dereekb/rxjs": "13.
|
|
13
|
-
"@dereekb/util": "13.
|
|
14
|
-
"@dereekb/zoho": "13.
|
|
5
|
+
"@dereekb/analytics": "13.31.0",
|
|
6
|
+
"@dereekb/date": "13.31.0",
|
|
7
|
+
"@dereekb/firebase": "13.31.0",
|
|
8
|
+
"@dereekb/firebase-server": "13.31.0",
|
|
9
|
+
"@dereekb/firebase-server/oidc": "13.31.0",
|
|
10
|
+
"@dereekb/model": "13.31.0",
|
|
11
|
+
"@dereekb/nestjs": "13.31.0",
|
|
12
|
+
"@dereekb/rxjs": "13.31.0",
|
|
13
|
+
"@dereekb/util": "13.31.0",
|
|
14
|
+
"@dereekb/zoho": "13.31.0",
|
|
15
15
|
"@modelcontextprotocol/sdk": "1.29.0",
|
|
16
16
|
"@nestjs/common": "^11.1.19",
|
|
17
17
|
"@nestjs/core": "^11.1.19",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type AuthClaims, type AuthRoleSet } from '@dereekb/util';
|
|
2
|
-
import { type OidcScope } from '@dereekb/firebase';
|
|
2
|
+
import { type FirestoreModelType, type OidcModelScopeRequirement, type OidcScope, type OidcScopeTerm } from '@dereekb/firebase';
|
|
3
3
|
/**
|
|
4
4
|
* Default path the MCP Streamable HTTP transport is mounted at.
|
|
5
5
|
*
|
|
@@ -200,6 +200,24 @@ export declare abstract class McpModuleConfig {
|
|
|
200
200
|
* from the dispatched handler body. See {@link McpReasonParameterConfig}.
|
|
201
201
|
*/
|
|
202
202
|
readonly reasonParameter?: McpReasonParameterConfig | boolean;
|
|
203
|
+
/**
|
|
204
|
+
* Default OIDC scope group term required on EVERY `callModel` op, mirrored into MCP tool-list
|
|
205
|
+
* visibility, unless a finer term overrides it (a per-function `requiredScope`, then a
|
|
206
|
+
* {@link McpModuleConfig.modelRequiredScopes} entry). Threaded into the same
|
|
207
|
+
* `resolveEffectiveOidcScopeTerms` composition the server-side model-api scope gate
|
|
208
|
+
* (`assertModelApiOidcScope`) uses, so a tool is advertised only when the caller could actually invoke it.
|
|
209
|
+
*
|
|
210
|
+
* Set this to the SAME value passed to `ModelApiDispatchConfig.defaultRequiredScope` to
|
|
211
|
+
* keep tool visibility and enforcement in lockstep.
|
|
212
|
+
*/
|
|
213
|
+
readonly defaultRequiredScope?: OidcScopeTerm;
|
|
214
|
+
/**
|
|
215
|
+
* Per-model OIDC scope group-term overrides, keyed by {@link FirestoreModelType}, mirrored into MCP
|
|
216
|
+
* tool-list visibility. Set this to the SAME value passed to
|
|
217
|
+
* `ModelApiDispatchConfig.modelRequiredScopes` so per-model / verb-keyed restrictions that
|
|
218
|
+
* confine a subset client apply identically to the advertised tool list.
|
|
219
|
+
*/
|
|
220
|
+
readonly modelRequiredScopes?: Record<FirestoreModelType, OidcModelScopeRequirement>;
|
|
203
221
|
}
|
|
204
222
|
/**
|
|
205
223
|
* Signature for the optional role reader the MCP module uses when evaluating
|
|
@@ -152,7 +152,7 @@ export declare class McpServerFactoryService {
|
|
|
152
152
|
* Synthesizes the same `{ auth: { token } }` shape that `getOidcScopesFromRequest`
|
|
153
153
|
* expects post-dispatch, so the upstream helper stays the single source of scope parsing.
|
|
154
154
|
* Returns `undefined` for non-OIDC callers (no `oidcValidatedToken.scope`) — the filter
|
|
155
|
-
* loop treats that as "skip scope enforcement", matching `
|
|
155
|
+
* loop treats that as "skip scope enforcement", matching the model-api scope gate (`assertModelApiOidcScope`).
|
|
156
156
|
*
|
|
157
157
|
* @param ctx - The per-request context carrying the validated auth payload.
|
|
158
158
|
* @returns The set of granted OIDC scopes, or `undefined` when scope enforcement should be skipped.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Maybe } from '@dereekb/util';
|
|
2
|
-
import { type KnownOnCallFunctionType } from '@dereekb/firebase';
|
|
2
|
+
import { type FirestoreModelType, type KnownOnCallFunctionType, type OidcModelScopeRequirement, type OidcScopeTerm } from '@dereekb/firebase';
|
|
3
3
|
import { type ModelApiDetailsResult, type OnCallModelFunctionApiDetails, type FirebaseServerAuthData, type McpToolDetailsBuilder, type McpVisibilityRule } from '@dereekb/firebase-server';
|
|
4
4
|
import { type Request } from 'express';
|
|
5
5
|
import { type CallToolResult, type ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';
|
|
@@ -452,6 +452,17 @@ export interface GenerateMcpToolDefinitionsContext {
|
|
|
452
452
|
* Per-model name segment overrides (e.g. collection prefixes).
|
|
453
453
|
*/
|
|
454
454
|
readonly naming?: McpToolGenerationNamingOptions;
|
|
455
|
+
/**
|
|
456
|
+
* Default OIDC scope group term required on every op unless a finer term overrides it. Mirrors the
|
|
457
|
+
* model-api layer's `ModelApiDispatchConfig.defaultRequiredScope` so a tool is advertised only when
|
|
458
|
+
* the caller could invoke it.
|
|
459
|
+
*/
|
|
460
|
+
readonly defaultRequiredScope?: OidcScopeTerm;
|
|
461
|
+
/**
|
|
462
|
+
* Per-model OIDC scope group-term overrides, keyed by {@link FirestoreModelType}. Mirrors the model-api
|
|
463
|
+
* layer's `ModelApiDispatchConfig.modelRequiredScopes` so per-model / verb-keyed restrictions apply to tool visibility.
|
|
464
|
+
*/
|
|
465
|
+
readonly modelRequiredScopes?: Record<FirestoreModelType, OidcModelScopeRequirement>;
|
|
455
466
|
}
|
|
456
467
|
/**
|
|
457
468
|
* Generates MCP tool definitions from a model-first API details tree.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Maybe } from '@dereekb/util';
|
|
2
|
-
import { type CallModelOidcScope, type
|
|
2
|
+
import { type CallModelOidcScope, type OidcScopeTerm } from '@dereekb/firebase';
|
|
3
3
|
import { type McpToolVisibility, type McpVisibilityContext, type McpVisibilityRule } from '@dereekb/firebase-server';
|
|
4
4
|
import { type ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';
|
|
5
5
|
/**
|
|
@@ -41,12 +41,15 @@ export interface ClassifiedMcpToolVisibilityDynamic {
|
|
|
41
41
|
export type McpToolFilterMetadata = McpToolFilterMetadataAlways | McpToolFilterMetadataNever | McpToolFilterMetadataDeclarative | McpToolFilterMetadataDynamic;
|
|
42
42
|
interface McpToolFilterMetadataBase {
|
|
43
43
|
/**
|
|
44
|
-
* OIDC
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
44
|
+
* OIDC scope TERMS required to invoke this tool, evaluated AND-of-ORs — the caller must satisfy
|
|
45
|
+
* EVERY term, and an array term (OR-group) is satisfied by holding ANY member. Checked with the
|
|
46
|
+
* shared `oidcScopeTermsSatisfied` so tool-list visibility matches the server-side `callModel` gate
|
|
47
|
+
* exactly. Precomputed from the dispatch call type's per-verb scope (`model.<call>`) plus the
|
|
48
|
+
* effective group term (per-function `requiredScope` > per-model requirement > module default).
|
|
49
|
+
* Empty when no scope is enforced (a non-CRUD call type with no per-function/model/default term);
|
|
50
|
+
* apps gate custom verbs via their own preAssert.
|
|
48
51
|
*/
|
|
49
|
-
readonly
|
|
52
|
+
readonly requiredScopeTerms?: readonly OidcScopeTerm[];
|
|
50
53
|
/**
|
|
51
54
|
* Effective read-only classification used by the module-level `readOnly` filter.
|
|
52
55
|
*
|
package/model/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dereekb/firebase-server/model",
|
|
3
|
-
"version": "13.
|
|
3
|
+
"version": "13.31.0",
|
|
4
4
|
"peerDependencies": {
|
|
5
|
-
"@dereekb/analytics": "13.
|
|
6
|
-
"@dereekb/date": "13.
|
|
7
|
-
"@dereekb/firebase": "13.
|
|
8
|
-
"@dereekb/firebase-server": "13.
|
|
9
|
-
"@dereekb/model": "13.
|
|
10
|
-
"@dereekb/nestjs": "13.
|
|
11
|
-
"@dereekb/rxjs": "13.
|
|
12
|
-
"@dereekb/util": "13.
|
|
5
|
+
"@dereekb/analytics": "13.31.0",
|
|
6
|
+
"@dereekb/date": "13.31.0",
|
|
7
|
+
"@dereekb/firebase": "13.31.0",
|
|
8
|
+
"@dereekb/firebase-server": "13.31.0",
|
|
9
|
+
"@dereekb/model": "13.31.0",
|
|
10
|
+
"@dereekb/nestjs": "13.31.0",
|
|
11
|
+
"@dereekb/rxjs": "13.31.0",
|
|
12
|
+
"@dereekb/util": "13.31.0",
|
|
13
13
|
"@nestjs/common": "^11.1.19",
|
|
14
14
|
"@nestjs/config": "^4.0.4",
|
|
15
15
|
"archiver": "^7.0.1",
|
package/oidc/index.cjs.js
CHANGED
|
@@ -3555,11 +3555,18 @@ exports.OidcProviderConfigService = __decorate([
|
|
|
3555
3555
|
* Resolves the unlocked + required scope sets for a client from the provider-profile registry and
|
|
3556
3556
|
* the profile keys assigned to that client.
|
|
3557
3557
|
*
|
|
3558
|
+
* A client with NO assigned profiles resolves to the registry's default profiles (those marked
|
|
3559
|
+
* `isDefault`), so a registry declaring no default resolves exactly as it would from the assigned
|
|
3560
|
+
* keys alone.
|
|
3561
|
+
*
|
|
3562
|
+
* This is the single choke point for a client's profile resolution — the consent unlock gate, the
|
|
3563
|
+
* consent required gate, and the `requiredScopes` interaction param all read through it.
|
|
3564
|
+
*
|
|
3558
3565
|
* @param providerProfiles - The provider-profile registry (from {@link OidcProviderConfig.providerProfiles}).
|
|
3559
3566
|
* @param clientProfileKeys - The profile keys assigned to the client (its `dbx_provider_profiles`).
|
|
3560
3567
|
* @returns The unlocked and required scope sets for the client.
|
|
3561
3568
|
*/ function oidcClientProviderProfileScopes(providerProfiles, clientProfileKeys) {
|
|
3562
|
-
var clientProfiles = firebase.
|
|
3569
|
+
var clientProfiles = firebase.oidcProviderProfilesForClient(providerProfiles !== null && providerProfiles !== void 0 ? providerProfiles : [], clientProfileKeys);
|
|
3563
3570
|
return {
|
|
3564
3571
|
unlocked: firebase.scopesForOidcProviderProfiles(clientProfiles),
|
|
3565
3572
|
required: firebase.requiredScopesForOidcProviderProfiles(clientProfiles)
|
|
@@ -5395,7 +5402,7 @@ function _unsupported_iterable_to_array$2(o, minLen) {
|
|
|
5395
5402
|
* `request.auth.token.scope` for OIDC callers and is `undefined` for non-OIDC
|
|
5396
5403
|
* (regular Firebase ID-token) callers.
|
|
5397
5404
|
*
|
|
5398
|
-
* Returning `undefined` for non-OIDC callers lets
|
|
5405
|
+
* Returning `undefined` for non-OIDC callers lets consumers (e.g. the MCP tool-visibility filter)
|
|
5399
5406
|
* skip scope enforcement instead of falsely treating the missing claim as "no scopes granted".
|
|
5400
5407
|
*
|
|
5401
5408
|
* The parameter is intentionally typed as `unknown` because `DecodedIdToken` (Firebase
|
|
@@ -5407,10 +5414,7 @@ function _unsupported_iterable_to_array$2(o, minLen) {
|
|
|
5407
5414
|
*/ function getOidcScopesFromRequest(request) {
|
|
5408
5415
|
var _request_auth_token, _request_auth;
|
|
5409
5416
|
var scope = request === null || request === void 0 ? void 0 : (_request_auth = request.auth) === null || _request_auth === void 0 ? void 0 : (_request_auth_token = _request_auth.token) === null || _request_auth_token === void 0 ? void 0 : _request_auth_token.scope;
|
|
5410
|
-
|
|
5411
|
-
return value.length > 0;
|
|
5412
|
-
})) : undefined;
|
|
5413
|
-
return result;
|
|
5417
|
+
return firebase.oidcScopesFromScopeClaim(scope);
|
|
5414
5418
|
}
|
|
5415
5419
|
|
|
5416
5420
|
function asyncGeneratorStep$3(gen, resolve, reject, _next, _throw, key, arg) {
|
|
@@ -6215,7 +6219,7 @@ var OidcInteractionController_1;
|
|
|
6215
6219
|
* @throws {HttpException} HTTP 400 when the consent interaction cannot be completed.
|
|
6216
6220
|
*/ function postConsent(uid, body, res) {
|
|
6217
6221
|
return _async_to_generator$2(function() {
|
|
6218
|
-
var startedAt, clientId, accountId, _ref, _prompt_details_missingOIDCScope, _this_accountService_providerConfig_adminOnlyScopes, _ref1, _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, adminOnlyScopes, requestsServiceToken, isAdmin, _tmp1, _ref5, redirectTo1,
|
|
6222
|
+
var startedAt, clientId, accountId, _ref, _prompt_details_missingOIDCScope, _this_accountService_providerConfig_adminOnlyScopes, _ref1, _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, configAdminOnlyScopes, adminOnlyScopes, requestedAdminOnlyScopes, requestsServiceToken, isAdmin, _tmp1, _ref5, redirectTo1, _oidcClientProviderProfileScopes, clientUnlockedScopes, clientRequiredScopes, profileGatedScopes, disallowedGatedScopes, _ref6, redirectTo2, missingRequiredScopes, _ref7, redirectTo3, requestedRawTtl, clientMaxSessionTtl, expiresInSeconds, grant, _tmp2, _resolveEffectiveSubset, granted, rejected, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, value, encounteredOIDCClaims, missingOIDCClaims, _resolveEffectiveSubset1, granted1, rejected1, missingResourceScopes, _iteratorNormalCompletion1, _didIteratorError1, _iteratorError1, _iterator1, _step1, _step_value, indicator, scopes, _body_grantedResourceScopes, requestedSubset, encounteredResourceScopes, _resolveEffectiveSubset2, granted2, rejected2, _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, value1, grantId, _ref8, redirectTo4, err;
|
|
6219
6223
|
return _ts_generator$2(this, function(_state) {
|
|
6220
6224
|
switch(_state.label){
|
|
6221
6225
|
case 0:
|
|
@@ -6299,11 +6303,20 @@ var OidcInteractionController_1;
|
|
|
6299
6303
|
clientPayload = _state.sent();
|
|
6300
6304
|
// Admin-only scope gate. The requested OIDC scope set is `missingOIDCScope ∪ encounteredOIDCScopes`
|
|
6301
6305
|
// (a fresh consent has everything in `missing`; a re-consent may carry already-granted scopes in
|
|
6302
|
-
// `encountered`). If that set intersects the provider's `adminOnlyScopes`
|
|
6303
|
-
//
|
|
6306
|
+
// `encountered`). If that set intersects the admin-only scopes — the provider's `adminOnlyScopes`
|
|
6307
|
+
// unioned with the scopes of every profile marked `adminOnly` — and the resolving user is not an
|
|
6308
|
+
// admin, hard-reject with `access_denied` rather than silently dropping the scope.
|
|
6304
6309
|
requestedOIDCScopeSet = new Set(_to_consumable_array$1(missingOIDCScope).concat(_to_consumable_array$1(encounteredOIDCScopes)));
|
|
6305
|
-
|
|
6306
|
-
|
|
6310
|
+
providerProfiles = this.accountService.providerConfig.providerProfiles;
|
|
6311
|
+
configAdminOnlyScopes = (_this_accountService_providerConfig_adminOnlyScopes = this.accountService.providerConfig.adminOnlyScopes) !== null && _this_accountService_providerConfig_adminOnlyScopes !== void 0 ? _this_accountService_providerConfig_adminOnlyScopes : [];
|
|
6312
|
+
adminOnlyScopes = new Set(_to_consumable_array$1(configAdminOnlyScopes).concat(_to_consumable_array$1(firebase.adminOnlyScopesForOidcProviderProfiles(providerProfiles !== null && providerProfiles !== void 0 ? providerProfiles : []))));
|
|
6313
|
+
requestedAdminOnlyScopes = Array.from(adminOnlyScopes).filter(function(scope) {
|
|
6314
|
+
return requestedOIDCScopeSet.has(scope);
|
|
6315
|
+
});
|
|
6316
|
+
// Deliberately sourced from the provider config's `adminOnlyScopes` ALONE, unlike the gate above:
|
|
6317
|
+
// this flag also selects the (highest) service-token TTL tier further down, and a profile marked
|
|
6318
|
+
// `adminOnly` must gate by admin status WITHOUT widening its grant's lifetime to that tier.
|
|
6319
|
+
requestsServiceToken = configAdminOnlyScopes.some(function(scope) {
|
|
6307
6320
|
return requestedOIDCScopeSet.has(scope);
|
|
6308
6321
|
});
|
|
6309
6322
|
if (!accountId) return [
|
|
@@ -6325,7 +6338,7 @@ var OidcInteractionController_1;
|
|
|
6325
6338
|
_state.label = 12;
|
|
6326
6339
|
case 12:
|
|
6327
6340
|
isAdmin = _tmp1;
|
|
6328
|
-
if (!(
|
|
6341
|
+
if (!(requestedAdminOnlyScopes.length > 0 && !isAdmin)) return [
|
|
6329
6342
|
3,
|
|
6330
6343
|
14
|
|
6331
6344
|
];
|
|
@@ -6333,7 +6346,7 @@ var OidcInteractionController_1;
|
|
|
6333
6346
|
4,
|
|
6334
6347
|
this.oidcInteractionService.finishInteractionByUid(uid, {
|
|
6335
6348
|
error: 'access_denied',
|
|
6336
|
-
error_description:
|
|
6349
|
+
error_description: "The following scope(s) are restricted to admins: ".concat(requestedAdminOnlyScopes.join(', '), ".")
|
|
6337
6350
|
}, {
|
|
6338
6351
|
mergeWithLastSubmission: true
|
|
6339
6352
|
})
|
|
@@ -6345,7 +6358,7 @@ var OidcInteractionController_1;
|
|
|
6345
6358
|
isSuccessful: false,
|
|
6346
6359
|
uid: accountId,
|
|
6347
6360
|
clientId: clientId,
|
|
6348
|
-
serviceToken:
|
|
6361
|
+
serviceToken: requestsServiceToken,
|
|
6349
6362
|
isAdmin: false,
|
|
6350
6363
|
reason: 'service_token_non_admin',
|
|
6351
6364
|
durationMs: Date.now() - startedAt
|
|
@@ -6358,9 +6371,9 @@ var OidcInteractionController_1;
|
|
|
6358
6371
|
];
|
|
6359
6372
|
case 14:
|
|
6360
6373
|
// Provider-profile scope gate. Any scope referenced by a provider profile is "gated" — available
|
|
6361
|
-
// only to clients whose assigned profiles unlock it
|
|
6362
|
-
// scope may be
|
|
6363
|
-
|
|
6374
|
+
// only to clients whose assigned profiles unlock it (a client with NO assigned profiles resolves
|
|
6375
|
+
// to the registry's default profiles). Independent of the admin-only gate above; a scope may be
|
|
6376
|
+
// subject to both.
|
|
6364
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;
|
|
6365
6378
|
profileGatedScopes = firebase.scopesForOidcProviderProfiles(providerProfiles !== null && providerProfiles !== void 0 ? providerProfiles : []);
|
|
6366
6379
|
// Unlock gate: reject any requested gated scope this client's profiles do not unlock.
|
|
@@ -7781,53 +7794,6 @@ function _unsupported_iterable_to_array(o, minLen) {
|
|
|
7781
7794
|
};
|
|
7782
7795
|
}
|
|
7783
7796
|
|
|
7784
|
-
/**
|
|
7785
|
-
* Builds a {@link AssertModelCrudRequestFunction} that rejects callModel requests
|
|
7786
|
-
* lacking the required OIDC scope(s) for the call.
|
|
7787
|
-
*
|
|
7788
|
-
* Enforcement is additive: an OIDC caller must hold BOTH the per-verb scope mapped
|
|
7789
|
-
* from the call type (`model.<call>`) AND any per-function scope a handler declared
|
|
7790
|
-
* via `withApiDetails({ requiredScope })` — surfaced on `context.requiredScope`.
|
|
7791
|
-
*
|
|
7792
|
-
* Bypasses the check (no-op) when the request is not OIDC-authenticated — i.e.
|
|
7793
|
-
* when {@link getOidcScopesFromRequest} returns `undefined` because there is no
|
|
7794
|
-
* `auth.token.scope` claim on the request. Regular Firebase ID-token callers are
|
|
7795
|
-
* unaffected and continue to be gated by auth roles.
|
|
7796
|
-
*
|
|
7797
|
-
* Bypasses the check for custom (non-CRUD) call types that declare no per-function
|
|
7798
|
-
* scope, so app-specific verbs remain unrestricted unless an app wires its own
|
|
7799
|
-
* assertion or declares a `requiredScope`.
|
|
7800
|
-
*
|
|
7801
|
-
* Wire as the `preAssert` of {@link onCallModel}.
|
|
7802
|
-
*
|
|
7803
|
-
* @returns The pre-assertion function ready to plug into `OnCallModelConfig.preAssert`.
|
|
7804
|
-
*/ function oidcCallModelScopePreAssert() {
|
|
7805
|
-
var fn = function fn(context) {
|
|
7806
|
-
var requiredScopes = util.filterMaybeArrayValues([
|
|
7807
|
-
firebase.callModelOidcScopeForCallType(context.call),
|
|
7808
|
-
context.requiredScope
|
|
7809
|
-
]);
|
|
7810
|
-
// No requirement (custom verb + no per-function scope) short-circuits without reading scopes.
|
|
7811
|
-
// A non-OIDC caller yields `undefined` scopes below and bypasses just like the per-verb check.
|
|
7812
|
-
var scopes = requiredScopes.length === 0 ? undefined : getOidcScopesFromRequest(context.request);
|
|
7813
|
-
var missingScopes = scopes == null ? [] : requiredScopes.filter(function(scope) {
|
|
7814
|
-
return !scopes.has(scope);
|
|
7815
|
-
});
|
|
7816
|
-
if (missingScopes.length > 0) {
|
|
7817
|
-
throw firebaseServer.forbiddenError({
|
|
7818
|
-
status: 403,
|
|
7819
|
-
code: firebase.CALL_MODEL_MISSING_OIDC_SCOPE_ERROR_CODE,
|
|
7820
|
-
message: "Missing required OIDC scope for callModel: ".concat(missingScopes.join(', ')),
|
|
7821
|
-
data: {
|
|
7822
|
-
requiredScopes: missingScopes,
|
|
7823
|
-
call: context.call
|
|
7824
|
-
}
|
|
7825
|
-
});
|
|
7826
|
-
}
|
|
7827
|
-
};
|
|
7828
|
-
return fn;
|
|
7829
|
-
}
|
|
7830
|
-
|
|
7831
7797
|
exports.DBX_FIREBASE_SERVER_OIDC_PROVIDER_PROFILES_CLIENT_METADATA = DBX_FIREBASE_SERVER_OIDC_PROVIDER_PROFILES_CLIENT_METADATA;
|
|
7832
7798
|
exports.DEFAULT_APP_OAUTH_CONSENT_PATH_PART = DEFAULT_APP_OAUTH_CONSENT_PATH_PART;
|
|
7833
7799
|
exports.DEFAULT_APP_OAUTH_INTERACTION_PATH = DEFAULT_APP_OAUTH_INTERACTION_PATH;
|
|
@@ -7890,7 +7856,6 @@ exports.jwksKeyIdentity = jwksKeyIdentity;
|
|
|
7890
7856
|
exports.jwksKeysWithStatusQuery = jwksKeysWithStatusQuery;
|
|
7891
7857
|
exports.nonRetiredJwksKeysQuery = nonRetiredJwksKeysQuery;
|
|
7892
7858
|
exports.noopOidcAnalyticsService = noopOidcAnalyticsService;
|
|
7893
|
-
exports.oidcCallModelScopePreAssert = oidcCallModelScopePreAssert;
|
|
7894
7859
|
exports.oidcClientProviderProfileScopes = oidcClientProviderProfileScopes;
|
|
7895
7860
|
exports.oidcCorsOriginDelegate = oidcCorsOriginDelegate;
|
|
7896
7861
|
exports.oidcFirestoreCollectionsFactory = oidcFirestoreCollectionsFactory;
|