@noodleseed/one 0.127.2 → 0.129.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/dist/commands/assistant-embed-ops.d.ts.map +1 -1
- package/dist/commands/assistant-embed-ops.js +82 -9
- package/dist/commands/assistant-embed-ops.js.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/skill-embedded-assistant-ref.d.ts.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/skill-embedded-assistant-ref.js +6 -4
- package/node_modules/@noodle-borg/agent-kit/dist/skill-embedded-assistant-ref.js.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/package.json +1 -1
- package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-store.d.ts +9 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-store.d.ts.map +1 -1
- package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-store.js +11 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-store.js.map +1 -1
- package/node_modules/@noodle-borg/assistant-gateway/dist/elevation.d.ts +13 -1
- package/node_modules/@noodle-borg/assistant-gateway/dist/elevation.d.ts.map +1 -1
- package/node_modules/@noodle-borg/assistant-gateway/dist/elevation.js +4 -3
- package/node_modules/@noodle-borg/assistant-gateway/dist/elevation.js.map +1 -1
- package/node_modules/@noodle-borg/assistant-gateway/dist/postgres-assistant.d.ts +3 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/postgres-assistant.d.ts.map +1 -1
- package/node_modules/@noodle-borg/assistant-gateway/dist/postgres-assistant.js +8 -1
- package/node_modules/@noodle-borg/assistant-gateway/dist/postgres-assistant.js.map +1 -1
- package/node_modules/@noodle-borg/assistant-gateway/package.json +1 -1
- package/node_modules/@noodle-borg/auth/dist/index.d.ts +1 -0
- package/node_modules/@noodle-borg/auth/dist/index.d.ts.map +1 -1
- package/node_modules/@noodle-borg/auth/dist/index.js +1 -0
- package/node_modules/@noodle-borg/auth/dist/index.js.map +1 -1
- package/node_modules/@noodle-borg/auth/dist/oauth-client-redirect-policy.d.ts +34 -0
- package/node_modules/@noodle-borg/auth/dist/oauth-client-redirect-policy.d.ts.map +1 -0
- package/node_modules/@noodle-borg/auth/dist/oauth-client-redirect-policy.js +230 -0
- package/node_modules/@noodle-borg/auth/dist/oauth-client-redirect-policy.js.map +1 -0
- package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-assistant.d.ts.map +1 -1
- package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-assistant.js +16 -0
- package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-assistant.js.map +1 -1
- package/node_modules/@noodle-borg/connector-defs/dist/delegated-token-exchange-identity.js +16 -1
- package/node_modules/@noodle-borg/connector-defs/dist/delegated-token-exchange-identity.js.map +1 -1
- package/node_modules/@noodle-borg/oauth-client-registry/dist/authorization-handler.d.ts +17 -0
- package/node_modules/@noodle-borg/oauth-client-registry/dist/authorization-handler.d.ts.map +1 -0
- package/node_modules/@noodle-borg/oauth-client-registry/dist/authorization-handler.js +118 -0
- package/node_modules/@noodle-borg/oauth-client-registry/dist/authorization-handler.js.map +1 -0
- package/node_modules/@noodle-borg/oauth-client-registry/dist/client-registration-handler.d.ts +18 -0
- package/node_modules/@noodle-borg/oauth-client-registry/dist/client-registration-handler.d.ts.map +1 -0
- package/node_modules/@noodle-borg/oauth-client-registry/dist/client-registration-handler.js +130 -0
- package/node_modules/@noodle-borg/oauth-client-registry/dist/client-registration-handler.js.map +1 -0
- package/node_modules/@noodle-borg/oauth-client-registry/dist/index.d.ts +5 -0
- package/node_modules/@noodle-borg/oauth-client-registry/dist/index.d.ts.map +1 -0
- package/node_modules/@noodle-borg/oauth-client-registry/dist/index.js +5 -0
- package/node_modules/@noodle-borg/oauth-client-registry/dist/index.js.map +1 -0
- package/node_modules/@noodle-borg/oauth-client-registry/dist/legacy-inventory.d.ts +54 -0
- package/node_modules/@noodle-borg/oauth-client-registry/dist/legacy-inventory.d.ts.map +1 -0
- package/node_modules/@noodle-borg/oauth-client-registry/dist/legacy-inventory.js +256 -0
- package/node_modules/@noodle-borg/oauth-client-registry/dist/legacy-inventory.js.map +1 -0
- package/node_modules/@noodle-borg/oauth-client-registry/dist/legacy-redirect-rollout.d.ts +7 -0
- package/node_modules/@noodle-borg/oauth-client-registry/dist/legacy-redirect-rollout.d.ts.map +1 -0
- package/node_modules/@noodle-borg/oauth-client-registry/dist/legacy-redirect-rollout.js +6 -0
- package/node_modules/@noodle-borg/oauth-client-registry/dist/legacy-redirect-rollout.js.map +1 -0
- package/node_modules/@noodle-borg/oauth-client-registry/package.json +36 -0
- package/node_modules/@noodle-borg/service/dist/assistant-delegated-projection.d.ts +12 -0
- package/node_modules/@noodle-borg/service/dist/assistant-delegated-projection.d.ts.map +1 -0
- package/node_modules/@noodle-borg/service/dist/assistant-delegated-projection.js +68 -0
- package/node_modules/@noodle-borg/service/dist/assistant-delegated-projection.js.map +1 -0
- package/node_modules/@noodle-borg/service/dist/credential-broker.d.ts +6 -0
- package/node_modules/@noodle-borg/service/dist/credential-broker.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/credential-broker.js +9 -0
- package/node_modules/@noodle-borg/service/dist/credential-broker.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/oauth/app.d.ts +2 -1
- package/node_modules/@noodle-borg/service/dist/oauth/app.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/oauth/app.js +3 -21
- package/node_modules/@noodle-borg/service/dist/oauth/app.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/oauth/service-bootstrap.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/oauth/service-bootstrap.js +1 -0
- package/node_modules/@noodle-borg/service/dist/oauth/service-bootstrap.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/registry-compile.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/registry-compile.js +8 -0
- package/node_modules/@noodle-borg/service/dist/registry-compile.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/assistant-agent.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/assistant-agent.js +26 -7
- package/node_modules/@noodle-borg/service/dist/routes/assistant-agent.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/assistant-dispatch.js +2 -1
- package/node_modules/@noodle-borg/service/dist/routes/assistant-dispatch.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/assistant-doctor.d.ts +10 -0
- package/node_modules/@noodle-borg/service/dist/routes/assistant-doctor.d.ts.map +1 -0
- package/node_modules/@noodle-borg/service/dist/routes/assistant-doctor.js +164 -0
- package/node_modules/@noodle-borg/service/dist/routes/assistant-doctor.js.map +1 -0
- package/node_modules/@noodle-borg/service/dist/routes/assistant-elevation.d.ts +21 -3
- package/node_modules/@noodle-borg/service/dist/routes/assistant-elevation.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/assistant-elevation.js +45 -7
- package/node_modules/@noodle-borg/service/dist/routes/assistant-elevation.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/assistant.d.ts +0 -2
- package/node_modules/@noodle-borg/service/dist/routes/assistant.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/assistant.js +7 -88
- package/node_modules/@noodle-borg/service/dist/routes/assistant.js.map +1 -1
- package/node_modules/@noodle-borg/service/package.json +2 -1
- package/node_modules/@noodleseed/assistant/README.md +68 -0
- package/node_modules/@noodleseed/assistant/dist/{chunk-S373FCAI.js → chunk-52XT7BLR.js} +9 -4
- package/node_modules/@noodleseed/assistant/dist/{chunk-S373FCAI.js.map → chunk-52XT7BLR.js.map} +1 -1
- package/node_modules/@noodleseed/assistant/dist/{chunk-RFETV5KQ.js → chunk-DLUINP4W.js} +9 -9
- package/node_modules/@noodleseed/assistant/dist/{chunk-RFETV5KQ.js.map → chunk-DLUINP4W.js.map} +1 -1
- package/node_modules/@noodleseed/assistant/dist/{client-BQ30Fq-c.d.cts → client-7o7n2nqw.d.cts} +6 -4
- package/node_modules/@noodleseed/assistant/dist/{client-B6pnBmF8.d.ts → client-CysBQBdd.d.ts} +6 -4
- package/node_modules/@noodleseed/assistant/dist/client.cjs +8 -3
- package/node_modules/@noodleseed/assistant/dist/client.cjs.map +1 -1
- package/node_modules/@noodleseed/assistant/dist/client.d.cts +1 -1
- package/node_modules/@noodleseed/assistant/dist/client.d.ts +1 -1
- package/node_modules/@noodleseed/assistant/dist/client.js +1 -1
- package/node_modules/@noodleseed/assistant/dist/embed.global.js +4 -4
- package/node_modules/@noodleseed/assistant/dist/index.cjs +15 -10
- package/node_modules/@noodleseed/assistant/dist/index.cjs.map +1 -1
- package/node_modules/@noodleseed/assistant/dist/index.d.cts +2 -2
- package/node_modules/@noodleseed/assistant/dist/index.d.ts +2 -2
- package/node_modules/@noodleseed/assistant/dist/index.js +2 -2
- package/node_modules/@noodleseed/assistant/dist/react/client.cjs +8 -3
- package/node_modules/@noodleseed/assistant/dist/react/client.cjs.map +1 -1
- package/node_modules/@noodleseed/assistant/dist/react/client.d.cts +1 -1
- package/node_modules/@noodleseed/assistant/dist/react/client.d.ts +1 -1
- package/node_modules/@noodleseed/assistant/dist/react/client.js +1 -1
- package/node_modules/@noodleseed/assistant/dist/react.cjs +15 -10
- package/node_modules/@noodleseed/assistant/dist/react.cjs.map +1 -1
- package/node_modules/@noodleseed/assistant/dist/react.d.cts +1 -1
- package/node_modules/@noodleseed/assistant/dist/react.d.ts +1 -1
- package/node_modules/@noodleseed/assistant/dist/react.js +2 -2
- package/node_modules/@noodleseed/assistant/dist/server.cjs +47 -1
- package/node_modules/@noodleseed/assistant/dist/server.cjs.map +1 -1
- package/node_modules/@noodleseed/assistant/dist/server.d.cts +60 -7
- package/node_modules/@noodleseed/assistant/dist/server.d.ts +60 -7
- package/node_modules/@noodleseed/assistant/dist/server.js +45 -1
- package/node_modules/@noodleseed/assistant/dist/server.js.map +1 -1
- package/node_modules/@noodleseed/assistant/package.json +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { OAuthRegisteredClientsStore } from '@modelcontextprotocol/sdk/server/auth/clients.js';
|
|
2
|
+
import { type OAuthClientInformationFull } from '@modelcontextprotocol/sdk/shared/auth.js';
|
|
3
|
+
import { type NormalizedOAuthRedirectClientMetadata } from '@noodle-borg/auth';
|
|
4
|
+
import { type RequestHandler } from 'express';
|
|
5
|
+
import { type Options as RateLimitOptions } from 'express-rate-limit';
|
|
6
|
+
export type RegisteredOAuthClient = OAuthClientInformationFull & Omit<NormalizedOAuthRedirectClientMetadata, 'redirect_uris'> & {
|
|
7
|
+
readonly redirect_uris: string[];
|
|
8
|
+
};
|
|
9
|
+
export interface SafeClientRegistrationHandlerOptions {
|
|
10
|
+
readonly clientsStore: OAuthRegisteredClientsStore;
|
|
11
|
+
readonly clientSecretExpirySeconds?: number;
|
|
12
|
+
readonly rateLimit?: Partial<RateLimitOptions> | false;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Preserve the MCP SDK's DCR transport while retaining Noodle's normalized redirect-policy metadata.
|
|
16
|
+
*/
|
|
17
|
+
export declare function safeClientRegistrationHandler({ clientsStore, clientSecretExpirySeconds, rateLimit: rateLimitConfig, }: SafeClientRegistrationHandlerOptions): RequestHandler;
|
|
18
|
+
//# sourceMappingURL=client-registration-handler.d.ts.map
|
package/node_modules/@noodle-borg/oauth-client-registry/dist/client-registration-handler.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-registration-handler.d.ts","sourceRoot":"","sources":["../src/client-registration-handler.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,kDAAkD,CAAC;AAQpG,OAAO,EACL,KAAK,0BAA0B,EAGhC,MAAM,0CAA0C,CAAC;AAClD,OAAO,EACL,KAAK,qCAAqC,EAI3C,MAAM,mBAAmB,CAAC;AAE3B,OAAgB,EAA4B,KAAK,cAAc,EAAE,MAAM,SAAS,CAAC;AACjF,OAAO,EAAE,KAAK,OAAO,IAAI,gBAAgB,EAAa,MAAM,oBAAoB,CAAC;AAIjF,MAAM,MAAM,qBAAqB,GAAG,0BAA0B,GAC5D,IAAI,CAAC,qCAAqC,EAAE,eAAe,CAAC,GAAG;IAC7D,QAAQ,CAAC,aAAa,EAAE,MAAM,EAAE,CAAC;CAClC,CAAC;AAEJ,MAAM,WAAW,oCAAoC;IACnD,QAAQ,CAAC,YAAY,EAAE,2BAA2B,CAAC;IACnD,QAAQ,CAAC,yBAAyB,CAAC,EAAE,MAAM,CAAC;IAC5C,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,KAAK,CAAC;CACxD;AAED;;GAEG;AACH,wBAAgB,6BAA6B,CAAC,EAC5C,YAAY,EACZ,yBAAgE,EAChE,SAAS,EAAE,eAAe,GAC3B,EAAE,oCAAoC,GAAG,cAAc,CAuEvD"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
import { InvalidClientMetadataError, OAuthError, ServerError, TooManyRequestsError, } from '@modelcontextprotocol/sdk/server/auth/errors.js';
|
|
3
|
+
import { allowedMethods } from '@modelcontextprotocol/sdk/server/auth/middleware/allowedMethods.js';
|
|
4
|
+
import { OAuthClientInformationFullSchema, OAuthClientMetadataSchema, } from '@modelcontextprotocol/sdk/shared/auth.js';
|
|
5
|
+
import { normalizeOAuthClientMetadata, OAuthRedirectPolicyError, } from '@noodle-borg/auth';
|
|
6
|
+
import cors from 'cors';
|
|
7
|
+
import express, {} from 'express';
|
|
8
|
+
import { rateLimit } from 'express-rate-limit';
|
|
9
|
+
const DEFAULT_CLIENT_SECRET_EXPIRY_SECONDS = 30 * 24 * 60 * 60;
|
|
10
|
+
/**
|
|
11
|
+
* Preserve the MCP SDK's DCR transport while retaining Noodle's normalized redirect-policy metadata.
|
|
12
|
+
*/
|
|
13
|
+
export function safeClientRegistrationHandler({ clientsStore, clientSecretExpirySeconds = DEFAULT_CLIENT_SECRET_EXPIRY_SECONDS, rateLimit: rateLimitConfig, }) {
|
|
14
|
+
if (!clientsStore.registerClient) {
|
|
15
|
+
throw new Error('Client registration store does not support registering clients');
|
|
16
|
+
}
|
|
17
|
+
const registerClient = clientsStore.registerClient.bind(clientsStore);
|
|
18
|
+
const router = express.Router();
|
|
19
|
+
router.use(cors());
|
|
20
|
+
router.use(allowedMethods(['POST']));
|
|
21
|
+
router.use(express.json());
|
|
22
|
+
router.use(invalidJsonHandler);
|
|
23
|
+
if (rateLimitConfig !== false) {
|
|
24
|
+
router.use(rateLimit({
|
|
25
|
+
windowMs: 60 * 60 * 1000,
|
|
26
|
+
max: 20,
|
|
27
|
+
standardHeaders: true,
|
|
28
|
+
legacyHeaders: false,
|
|
29
|
+
message: new TooManyRequestsError('You have exceeded the rate limit for client registration requests').toResponseObject(),
|
|
30
|
+
...rateLimitConfig,
|
|
31
|
+
}));
|
|
32
|
+
}
|
|
33
|
+
router.post('/', async (req, res) => {
|
|
34
|
+
res.setHeader('Cache-Control', 'no-store');
|
|
35
|
+
try {
|
|
36
|
+
const parseResult = OAuthClientMetadataSchema.safeParse(req.body);
|
|
37
|
+
if (!parseResult.success) {
|
|
38
|
+
throw new InvalidClientMetadataError(parseResult.error.message);
|
|
39
|
+
}
|
|
40
|
+
const submitted = requestObject(req.body);
|
|
41
|
+
const normalized = normalizeOAuthClientMetadata({
|
|
42
|
+
application_type: submitted.application_type,
|
|
43
|
+
redirect_uris: parseResult.data.redirect_uris,
|
|
44
|
+
token_endpoint_auth_method: submitted.token_endpoint_auth_method,
|
|
45
|
+
noodle_redirect_policy_version: submitted.noodle_redirect_policy_version,
|
|
46
|
+
});
|
|
47
|
+
const persistedPolicy = { ...normalized, redirect_uris: [...normalized.redirect_uris] };
|
|
48
|
+
const issuedAt = Math.floor(Date.now() / 1000);
|
|
49
|
+
const hasSecret = normalized.token_endpoint_auth_method === 'client_secret_post';
|
|
50
|
+
const credentials = hasSecret
|
|
51
|
+
? {
|
|
52
|
+
client_secret: crypto.randomBytes(32).toString('hex'),
|
|
53
|
+
client_secret_expires_at: clientSecretExpirySeconds > 0 ? issuedAt + clientSecretExpirySeconds : 0,
|
|
54
|
+
}
|
|
55
|
+
: {};
|
|
56
|
+
const client = {
|
|
57
|
+
...parseResult.data,
|
|
58
|
+
...persistedPolicy,
|
|
59
|
+
...credentials,
|
|
60
|
+
client_id: crypto.randomUUID(),
|
|
61
|
+
client_id_issued_at: issuedAt,
|
|
62
|
+
};
|
|
63
|
+
const stored = await registerClient(client);
|
|
64
|
+
res.status(201).json(validatedStoredClient(stored, persistedPolicy));
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
const oauthError = registrationError(error);
|
|
68
|
+
const status = oauthError instanceof ServerError ? 500 : 400;
|
|
69
|
+
res.status(status).json(oauthError.toResponseObject());
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
return router;
|
|
73
|
+
}
|
|
74
|
+
const invalidJsonHandler = (error, _req, res, next) => {
|
|
75
|
+
if (!isInvalidJson(error)) {
|
|
76
|
+
next(error);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
res.setHeader('Cache-Control', 'no-store');
|
|
80
|
+
res
|
|
81
|
+
.status(400)
|
|
82
|
+
.json(new InvalidClientMetadataError('client metadata must be valid JSON').toResponseObject());
|
|
83
|
+
};
|
|
84
|
+
function isInvalidJson(error) {
|
|
85
|
+
if (!(error instanceof SyntaxError))
|
|
86
|
+
return false;
|
|
87
|
+
const parseError = error;
|
|
88
|
+
return parseError.status === 400 && parseError.type === 'entity.parse.failed';
|
|
89
|
+
}
|
|
90
|
+
function requestObject(value) {
|
|
91
|
+
return typeof value === 'object' && value !== null ? value : {};
|
|
92
|
+
}
|
|
93
|
+
function validatedStoredClient(value, normalized) {
|
|
94
|
+
const sdkRecord = OAuthClientInformationFullSchema.safeParse(value);
|
|
95
|
+
const stored = requestObject(value);
|
|
96
|
+
if (!sdkRecord.success ||
|
|
97
|
+
stored.application_type !== normalized.application_type ||
|
|
98
|
+
stored.token_endpoint_auth_method !== normalized.token_endpoint_auth_method ||
|
|
99
|
+
stored.noodle_redirect_policy_version !== normalized.noodle_redirect_policy_version ||
|
|
100
|
+
!sameRedirectUris(stored.redirect_uris, normalized.redirect_uris)) {
|
|
101
|
+
throw new ServerError('Internal Server Error');
|
|
102
|
+
}
|
|
103
|
+
return value;
|
|
104
|
+
}
|
|
105
|
+
function sameRedirectUris(actual, expected) {
|
|
106
|
+
return (Array.isArray(actual) &&
|
|
107
|
+
actual.length === expected.length &&
|
|
108
|
+
actual.every((value, index) => value === expected[index]));
|
|
109
|
+
}
|
|
110
|
+
function registrationError(error) {
|
|
111
|
+
if (error instanceof OAuthRedirectPolicyError) {
|
|
112
|
+
return new InvalidClientMetadataError(policyErrorDescription(error.reason));
|
|
113
|
+
}
|
|
114
|
+
if (error instanceof OAuthError)
|
|
115
|
+
return error;
|
|
116
|
+
return new ServerError('Internal Server Error');
|
|
117
|
+
}
|
|
118
|
+
function policyErrorDescription(reason) {
|
|
119
|
+
switch (reason) {
|
|
120
|
+
case 'invalid_application_type':
|
|
121
|
+
return 'application_type must be web or native';
|
|
122
|
+
case 'invalid_redirect_uris':
|
|
123
|
+
return 'redirect_uris must be a non-empty list of URI strings';
|
|
124
|
+
case 'unsafe_redirect_uri':
|
|
125
|
+
return 'redirect_uris must use HTTPS or a permitted loopback HTTP redirect without credentials or fragments';
|
|
126
|
+
case 'unsupported_token_endpoint_auth_method':
|
|
127
|
+
return 'token_endpoint_auth_method must be none or client_secret_post';
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=client-registration-handler.js.map
|
package/node_modules/@noodle-borg/oauth-client-registry/dist/client-registration-handler.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-registration-handler.js","sourceRoot":"","sources":["../src/client-registration-handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { type AuthorizationRedirectLogger, type AuthorizationRedirectScalarFields, type SafeAuthorizationHandlerOptions, safeAuthorizationHandler, } from './authorization-handler.js';
|
|
2
|
+
export { type RegisteredOAuthClient, type SafeClientRegistrationHandlerOptions, safeClientRegistrationHandler, } from './client-registration-handler.js';
|
|
3
|
+
export { type LegacyOAuthRedirectInventoryCommandOptions, runLegacyOAuthRedirectInventoryCommand, } from './legacy-inventory.js';
|
|
4
|
+
export { type OAuthLegacyRedirectRollout, stageALegacyRedirectRollout, } from './legacy-redirect-rollout.js';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,2BAA2B,EAChC,KAAK,iCAAiC,EACtC,KAAK,+BAA+B,EACpC,wBAAwB,GACzB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,KAAK,qBAAqB,EAC1B,KAAK,oCAAoC,EACzC,6BAA6B,GAC9B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACL,KAAK,0CAA0C,EAC/C,sCAAsC,GACvC,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,KAAK,0BAA0B,EAC/B,2BAA2B,GAC5B,MAAM,8BAA8B,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { safeAuthorizationHandler, } from './authorization-handler.js';
|
|
2
|
+
export { safeClientRegistrationHandler, } from './client-registration-handler.js';
|
|
3
|
+
export { runLegacyOAuthRedirectInventoryCommand, } from './legacy-inventory.js';
|
|
4
|
+
export { stageALegacyRedirectRollout, } from './legacy-redirect-rollout.js';
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,wBAAwB,GACzB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAGL,6BAA6B,GAC9B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAEL,sCAAsC,GACvC,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAEL,2BAA2B,GAC5B,MAAM,8BAA8B,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Pool } from 'pg';
|
|
2
|
+
type InventoryFormat = 'json' | 'text';
|
|
3
|
+
interface FingerprintedClassSummary {
|
|
4
|
+
count: number;
|
|
5
|
+
clientFingerprints: string[];
|
|
6
|
+
}
|
|
7
|
+
interface LegacyOAuthRedirectInventoryCounts {
|
|
8
|
+
readonly scannedClientCount: number;
|
|
9
|
+
readonly normalizedCount: number;
|
|
10
|
+
readonly legacyClasses: {
|
|
11
|
+
readonly safe_https: {
|
|
12
|
+
readonly count: number;
|
|
13
|
+
};
|
|
14
|
+
readonly safe_loopback_legacy: FingerprintedClassSummary;
|
|
15
|
+
readonly unsafe_legacy: FingerprintedClassSummary;
|
|
16
|
+
readonly malformed_legacy: FingerprintedClassSummary;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export interface LegacyOAuthRedirectInventorySummary {
|
|
20
|
+
readonly schemaVersion: 1;
|
|
21
|
+
readonly complete: true;
|
|
22
|
+
readonly scannedClientCount: number;
|
|
23
|
+
readonly normalizedCount: number;
|
|
24
|
+
readonly legacyClasses: {
|
|
25
|
+
readonly safe_https: {
|
|
26
|
+
readonly count: number;
|
|
27
|
+
};
|
|
28
|
+
readonly safe_loopback_legacy: FingerprintedClassSummary;
|
|
29
|
+
readonly unsafe_legacy: FingerprintedClassSummary;
|
|
30
|
+
readonly malformed_legacy: FingerprintedClassSummary;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
interface WritableOutput {
|
|
34
|
+
write(value: string): unknown;
|
|
35
|
+
}
|
|
36
|
+
export interface LegacyOAuthRedirectInventoryCommandOptions {
|
|
37
|
+
readonly argv?: readonly string[];
|
|
38
|
+
readonly env?: Readonly<Record<string, string | undefined>>;
|
|
39
|
+
readonly stdout?: WritableOutput;
|
|
40
|
+
readonly stderr?: WritableOutput;
|
|
41
|
+
readonly poolFactory?: (databaseUrl: string) => Pool;
|
|
42
|
+
}
|
|
43
|
+
/** Loads the one-run correlation key without exposing its contents or location in errors. */
|
|
44
|
+
export declare function readOAuthInventoryFingerprintKey(path: string): Promise<Buffer>;
|
|
45
|
+
/** Produces a run-key-bound identifier that cannot be correlated after key rotation. */
|
|
46
|
+
export declare function fingerprintOAuthClientId(clientId: string, key: Buffer): string;
|
|
47
|
+
/** Reads one complete database snapshot and returns only private, incomplete inventory counts. */
|
|
48
|
+
export declare function collectLegacyOAuthRedirectInventory(pool: Pool, fingerprintKey: Buffer): Promise<LegacyOAuthRedirectInventoryCounts>;
|
|
49
|
+
/** Internal operator command entry point. It emits a summary only after scan, commit, and pool shutdown. */
|
|
50
|
+
export declare function runLegacyOAuthRedirectInventoryCommand(options?: LegacyOAuthRedirectInventoryCommandOptions): Promise<number>;
|
|
51
|
+
/** Serializes only the documented, privacy-bounded summary fields. */
|
|
52
|
+
export declare function formatLegacyOAuthRedirectInventory(summary: LegacyOAuthRedirectInventorySummary, format: InventoryFormat): string;
|
|
53
|
+
export {};
|
|
54
|
+
//# sourceMappingURL=legacy-inventory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"legacy-inventory.d.ts","sourceRoot":"","sources":["../src/legacy-inventory.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,IAAI,EAAyC,MAAM,IAAI,CAAC;AAgCjE,KAAK,eAAe,GAAG,MAAM,GAAG,MAAM,CAAC;AAevC,UAAU,yBAAyB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,kBAAkB,EAAE,MAAM,EAAE,CAAC;CAC9B;AAED,UAAU,kCAAkC;IAC1C,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,aAAa,EAAE;QACtB,QAAQ,CAAC,UAAU,EAAE;YAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC;QAChD,QAAQ,CAAC,oBAAoB,EAAE,yBAAyB,CAAC;QACzD,QAAQ,CAAC,aAAa,EAAE,yBAAyB,CAAC;QAClD,QAAQ,CAAC,gBAAgB,EAAE,yBAAyB,CAAC;KACtD,CAAC;CACH;AAED,MAAM,WAAW,mCAAmC;IAClD,QAAQ,CAAC,aAAa,EAAE,CAAC,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC;IACxB,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,aAAa,EAAE;QACtB,QAAQ,CAAC,UAAU,EAAE;YAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC;QAChD,QAAQ,CAAC,oBAAoB,EAAE,yBAAyB,CAAC;QACzD,QAAQ,CAAC,aAAa,EAAE,yBAAyB,CAAC;QAClD,QAAQ,CAAC,gBAAgB,EAAE,yBAAyB,CAAC;KACtD,CAAC;CACH;AAED,UAAU,cAAc;IACtB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;CAC/B;AAED,MAAM,WAAW,0CAA0C;IACzD,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;IAC5D,QAAQ,CAAC,MAAM,CAAC,EAAE,cAAc,CAAC;IACjC,QAAQ,CAAC,MAAM,CAAC,EAAE,cAAc,CAAC;IACjC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;CACtD;AAED,6FAA6F;AAC7F,wBAAsB,gCAAgC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAuBpF;AAED,wFAAwF;AACxF,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAG9E;AAED,kGAAkG;AAClG,wBAAsB,mCAAmC,CACvD,IAAI,EAAE,IAAI,EACV,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,kCAAkC,CAAC,CAyC7C;AAED,4GAA4G;AAC5G,wBAAsB,sCAAsC,CAC1D,OAAO,GAAE,0CAA+C,GACvD,OAAO,CAAC,MAAM,CAAC,CA2BjB;AAED,sEAAsE;AACtE,wBAAgB,kCAAkC,CAChD,OAAO,EAAE,mCAAmC,EAC5C,MAAM,EAAE,eAAe,GACtB,MAAM,CAoBR"}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { createHmac } from 'node:crypto';
|
|
2
|
+
import { constants, open } from 'node:fs/promises';
|
|
3
|
+
import { isAbsolute } from 'node:path';
|
|
4
|
+
import { classifyStoredOAuthRedirectPolicy, } from '@noodle-borg/auth';
|
|
5
|
+
import { Pool } from 'pg';
|
|
6
|
+
const INVENTORY_PAGE_SIZE = 100;
|
|
7
|
+
const INVENTORY_APPLICATION_NAME = 'noodle-oauth-redirect-inventory';
|
|
8
|
+
const FAILED_MESSAGE = 'OAuth redirect inventory failed; no summary was emitted.\n';
|
|
9
|
+
const INVENTORY_PAGE_QUERY = `
|
|
10
|
+
SELECT client_id,
|
|
11
|
+
jsonb_build_object(
|
|
12
|
+
'present', client ? 'application_type',
|
|
13
|
+
'value', client -> 'application_type'
|
|
14
|
+
) AS application_type,
|
|
15
|
+
jsonb_build_object(
|
|
16
|
+
'present', client ? 'redirect_uris',
|
|
17
|
+
'value', client -> 'redirect_uris'
|
|
18
|
+
) AS redirect_uris,
|
|
19
|
+
jsonb_build_object(
|
|
20
|
+
'present', client ? 'token_endpoint_auth_method',
|
|
21
|
+
'value', client -> 'token_endpoint_auth_method'
|
|
22
|
+
) AS token_endpoint_auth_method,
|
|
23
|
+
jsonb_build_object(
|
|
24
|
+
'present', client ? 'noodle_redirect_policy_version',
|
|
25
|
+
'value', client -> 'noodle_redirect_policy_version'
|
|
26
|
+
) AS noodle_redirect_policy_version
|
|
27
|
+
FROM oauth_clients
|
|
28
|
+
WHERE ($1::text IS NULL OR client_id COLLATE "C" > $1::text COLLATE "C")
|
|
29
|
+
ORDER BY client_id COLLATE "C" ASC
|
|
30
|
+
LIMIT $2
|
|
31
|
+
`;
|
|
32
|
+
/** Loads the one-run correlation key without exposing its contents or location in errors. */
|
|
33
|
+
export async function readOAuthInventoryFingerprintKey(path) {
|
|
34
|
+
if (!isAbsolute(path))
|
|
35
|
+
throw invalidFingerprintKey();
|
|
36
|
+
let handle;
|
|
37
|
+
try {
|
|
38
|
+
handle = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
39
|
+
const stats = await handle.stat();
|
|
40
|
+
if (!stats.isFile() || (stats.mode & 0o7777) !== 0o600)
|
|
41
|
+
throw invalidFingerprintKey();
|
|
42
|
+
const boundedContent = Buffer.alloc(67);
|
|
43
|
+
const { bytesRead } = await handle.read(boundedContent, 0, boundedContent.length, 0);
|
|
44
|
+
const content = boundedContent.subarray(0, bytesRead);
|
|
45
|
+
const encoded = removeOneTerminalLineEnding(content);
|
|
46
|
+
if (encoded.length !== 64 || !/^[0-9a-fA-F]{64}$/.test(encoded.toString('ascii'))) {
|
|
47
|
+
throw invalidFingerprintKey();
|
|
48
|
+
}
|
|
49
|
+
const key = Buffer.from(encoded.toString('ascii'), 'hex');
|
|
50
|
+
if (key.length !== 32)
|
|
51
|
+
throw invalidFingerprintKey();
|
|
52
|
+
return key;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
throw invalidFingerprintKey();
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
await handle?.close().catch(() => undefined);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/** Produces a run-key-bound identifier that cannot be correlated after key rotation. */
|
|
62
|
+
export function fingerprintOAuthClientId(clientId, key) {
|
|
63
|
+
if (key.length !== 32)
|
|
64
|
+
throw invalidFingerprintKey();
|
|
65
|
+
return createHmac('sha256', key).update(clientId, 'utf8').digest('hex');
|
|
66
|
+
}
|
|
67
|
+
/** Reads one complete database snapshot and returns only private, incomplete inventory counts. */
|
|
68
|
+
export async function collectLegacyOAuthRedirectInventory(pool, fingerprintKey) {
|
|
69
|
+
if (fingerprintKey.length !== 32)
|
|
70
|
+
throw invalidFingerprintKey();
|
|
71
|
+
const client = await pool.connect();
|
|
72
|
+
let released = false;
|
|
73
|
+
try {
|
|
74
|
+
await client.query('BEGIN ISOLATION LEVEL REPEATABLE READ READ ONLY');
|
|
75
|
+
const counts = mutableCounts();
|
|
76
|
+
let cursor = null;
|
|
77
|
+
for (;;) {
|
|
78
|
+
const page = await client.query(INVENTORY_PAGE_QUERY, [cursor, INVENTORY_PAGE_SIZE]);
|
|
79
|
+
if (page.rows.length > INVENTORY_PAGE_SIZE)
|
|
80
|
+
throw new Error('invalid inventory page');
|
|
81
|
+
for (const row of page.rows)
|
|
82
|
+
addRowToCounts(counts, row, fingerprintKey);
|
|
83
|
+
if (page.rows.length === 0)
|
|
84
|
+
break;
|
|
85
|
+
const nextCursor = page.rows.at(-1)?.client_id;
|
|
86
|
+
if (typeof nextCursor !== 'string' || nextCursor === cursor) {
|
|
87
|
+
throw new Error('invalid inventory cursor');
|
|
88
|
+
}
|
|
89
|
+
cursor = nextCursor;
|
|
90
|
+
if (page.rows.length < INVENTORY_PAGE_SIZE)
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
await client.query('COMMIT');
|
|
94
|
+
return counts;
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
let destroy = false;
|
|
98
|
+
try {
|
|
99
|
+
await client.query('ROLLBACK');
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
destroy = true;
|
|
103
|
+
}
|
|
104
|
+
client.release(destroy);
|
|
105
|
+
released = true;
|
|
106
|
+
throw error;
|
|
107
|
+
}
|
|
108
|
+
finally {
|
|
109
|
+
if (!released)
|
|
110
|
+
client.release();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/** Internal operator command entry point. It emits a summary only after scan, commit, and pool shutdown. */
|
|
114
|
+
export async function runLegacyOAuthRedirectInventoryCommand(options = {}) {
|
|
115
|
+
const argv = options.argv ?? process.argv.slice(2);
|
|
116
|
+
const env = options.env ?? process.env;
|
|
117
|
+
const stdout = options.stdout ?? process.stdout;
|
|
118
|
+
const stderr = options.stderr ?? process.stderr;
|
|
119
|
+
let pool;
|
|
120
|
+
try {
|
|
121
|
+
const parsed = parseArguments(argv);
|
|
122
|
+
const databaseUrl = env.NOODLE_OAUTH_INVENTORY_DATABASE_URL;
|
|
123
|
+
if (databaseUrl === undefined || databaseUrl.length === 0)
|
|
124
|
+
throw new Error('missing database URL');
|
|
125
|
+
const fingerprintKey = await readOAuthInventoryFingerprintKey(parsed.fingerprintKeyFile);
|
|
126
|
+
const poolFactory = options.poolFactory ?? defaultPoolFactory;
|
|
127
|
+
pool = poolFactory(databaseUrl);
|
|
128
|
+
const counts = await collectLegacyOAuthRedirectInventory(pool, fingerprintKey);
|
|
129
|
+
await pool.end();
|
|
130
|
+
pool = undefined;
|
|
131
|
+
const summary = completeInventorySummary(counts);
|
|
132
|
+
const output = formatLegacyOAuthRedirectInventory(summary, parsed.format);
|
|
133
|
+
stdout.write(output);
|
|
134
|
+
return 0;
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
await pool?.end().catch(() => undefined);
|
|
138
|
+
stderr.write(FAILED_MESSAGE);
|
|
139
|
+
return 1;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/** Serializes only the documented, privacy-bounded summary fields. */
|
|
143
|
+
export function formatLegacyOAuthRedirectInventory(summary, format) {
|
|
144
|
+
if (format === 'json')
|
|
145
|
+
return `${JSON.stringify(summary)}\n`;
|
|
146
|
+
const { legacyClasses } = summary;
|
|
147
|
+
return [
|
|
148
|
+
`schema_version: ${summary.schemaVersion}`,
|
|
149
|
+
`complete: ${summary.complete}`,
|
|
150
|
+
`scanned_client_count: ${summary.scannedClientCount}`,
|
|
151
|
+
`normalized_count: ${summary.normalizedCount}`,
|
|
152
|
+
`safe_https_count: ${legacyClasses.safe_https.count}`,
|
|
153
|
+
`safe_loopback_legacy_count: ${legacyClasses.safe_loopback_legacy.count}`,
|
|
154
|
+
...fingerprintLines('safe_loopback_legacy', legacyClasses.safe_loopback_legacy.clientFingerprints),
|
|
155
|
+
`unsafe_legacy_count: ${legacyClasses.unsafe_legacy.count}`,
|
|
156
|
+
...fingerprintLines('unsafe_legacy', legacyClasses.unsafe_legacy.clientFingerprints),
|
|
157
|
+
`malformed_legacy_count: ${legacyClasses.malformed_legacy.count}`,
|
|
158
|
+
...fingerprintLines('malformed_legacy', legacyClasses.malformed_legacy.clientFingerprints),
|
|
159
|
+
'',
|
|
160
|
+
].join('\n');
|
|
161
|
+
}
|
|
162
|
+
function defaultPoolFactory(databaseUrl) {
|
|
163
|
+
return new Pool({
|
|
164
|
+
connectionString: databaseUrl,
|
|
165
|
+
max: 1,
|
|
166
|
+
application_name: INVENTORY_APPLICATION_NAME,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
function parseArguments(argv) {
|
|
170
|
+
const commandArguments = argv[0] === '--' ? argv.slice(1) : argv;
|
|
171
|
+
let fingerprintKeyFile;
|
|
172
|
+
let format = 'text';
|
|
173
|
+
let formatSeen = false;
|
|
174
|
+
for (let index = 0; index < commandArguments.length; index += 2) {
|
|
175
|
+
const flag = commandArguments[index];
|
|
176
|
+
const value = commandArguments[index + 1];
|
|
177
|
+
if (value === undefined)
|
|
178
|
+
throw new Error('invalid arguments');
|
|
179
|
+
if (flag === '--fingerprint-key-file' && fingerprintKeyFile === undefined) {
|
|
180
|
+
fingerprintKeyFile = value;
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
if (flag === '--format' && !formatSeen && (value === 'json' || value === 'text')) {
|
|
184
|
+
format = value;
|
|
185
|
+
formatSeen = true;
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
throw new Error('invalid arguments');
|
|
189
|
+
}
|
|
190
|
+
if (fingerprintKeyFile === undefined)
|
|
191
|
+
throw new Error('invalid arguments');
|
|
192
|
+
return { fingerprintKeyFile, format };
|
|
193
|
+
}
|
|
194
|
+
function removeOneTerminalLineEnding(content) {
|
|
195
|
+
if (content.at(-1) !== 0x0a)
|
|
196
|
+
return content;
|
|
197
|
+
const withoutLf = content.subarray(0, -1);
|
|
198
|
+
return withoutLf.at(-1) === 0x0d ? withoutLf.subarray(0, -1) : withoutLf;
|
|
199
|
+
}
|
|
200
|
+
function invalidFingerprintKey() {
|
|
201
|
+
return new Error('OAuth inventory fingerprint key is invalid');
|
|
202
|
+
}
|
|
203
|
+
function mutableCounts() {
|
|
204
|
+
return {
|
|
205
|
+
scannedClientCount: 0,
|
|
206
|
+
normalizedCount: 0,
|
|
207
|
+
legacyClasses: {
|
|
208
|
+
safe_https: { count: 0 },
|
|
209
|
+
safe_loopback_legacy: { count: 0, clientFingerprints: [] },
|
|
210
|
+
unsafe_legacy: { count: 0, clientFingerprints: [] },
|
|
211
|
+
malformed_legacy: { count: 0, clientFingerprints: [] },
|
|
212
|
+
},
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
function addRowToCounts(counts, row, fingerprintKey) {
|
|
216
|
+
if (typeof row.client_id !== 'string')
|
|
217
|
+
throw new Error('invalid inventory row');
|
|
218
|
+
const metadata = {};
|
|
219
|
+
addInventoryField(metadata, 'application_type', row.application_type);
|
|
220
|
+
addInventoryField(metadata, 'redirect_uris', row.redirect_uris);
|
|
221
|
+
addInventoryField(metadata, 'token_endpoint_auth_method', row.token_endpoint_auth_method);
|
|
222
|
+
addInventoryField(metadata, 'noodle_redirect_policy_version', row.noodle_redirect_policy_version);
|
|
223
|
+
const policyClass = classifyStoredOAuthRedirectPolicy(metadata);
|
|
224
|
+
counts.scannedClientCount += 1;
|
|
225
|
+
if (policyClass === 'normalized') {
|
|
226
|
+
counts.normalizedCount += 1;
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
counts.legacyClasses[policyClass].count += 1;
|
|
230
|
+
if (policyClass !== 'safe_https') {
|
|
231
|
+
counts.legacyClasses[policyClass].clientFingerprints.push(fingerprintOAuthClientId(row.client_id, fingerprintKey));
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
function addInventoryField(metadata, field, envelope) {
|
|
235
|
+
if (typeof envelope !== 'object' ||
|
|
236
|
+
envelope === null ||
|
|
237
|
+
typeof envelope.present !== 'boolean' ||
|
|
238
|
+
!Object.hasOwn(envelope, 'value')) {
|
|
239
|
+
throw new Error('invalid inventory row');
|
|
240
|
+
}
|
|
241
|
+
if (envelope.present)
|
|
242
|
+
metadata[field] = envelope.value;
|
|
243
|
+
}
|
|
244
|
+
function completeInventorySummary(counts) {
|
|
245
|
+
return {
|
|
246
|
+
schemaVersion: 1,
|
|
247
|
+
complete: true,
|
|
248
|
+
scannedClientCount: counts.scannedClientCount,
|
|
249
|
+
normalizedCount: counts.normalizedCount,
|
|
250
|
+
legacyClasses: counts.legacyClasses,
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
function fingerprintLines(policyClass, fingerprints) {
|
|
254
|
+
return fingerprints.map((fingerprint) => `${policyClass}_fingerprint: ${fingerprint}`);
|
|
255
|
+
}
|
|
256
|
+
//# sourceMappingURL=legacy-inventory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"legacy-inventory.js","sourceRoot":"","sources":["../src/legacy-inventory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface OAuthLegacyRedirectRollout {
|
|
2
|
+
readonly unsafeLegacyMode: 'observe' | 'deny';
|
|
3
|
+
readonly loopbackPortMode: 'observe' | 'exact';
|
|
4
|
+
}
|
|
5
|
+
/** Stage A is observation-only for client records created before redirect-policy normalization. */
|
|
6
|
+
export declare const stageALegacyRedirectRollout: OAuthLegacyRedirectRollout;
|
|
7
|
+
//# sourceMappingURL=legacy-redirect-rollout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"legacy-redirect-rollout.d.ts","sourceRoot":"","sources":["../src/legacy-redirect-rollout.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,gBAAgB,EAAE,SAAS,GAAG,MAAM,CAAC;IAC9C,QAAQ,CAAC,gBAAgB,EAAE,SAAS,GAAG,OAAO,CAAC;CAChD;AAED,mGAAmG;AACnG,eAAO,MAAM,2BAA2B,EAAE,0BAGzC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"legacy-redirect-rollout.js","sourceRoot":"","sources":["../src/legacy-redirect-rollout.ts"],"names":[],"mappings":"AAKA,mGAAmG;AACnG,MAAM,CAAC,MAAM,2BAA2B,GAA+B;IACrE,gBAAgB,EAAE,SAAS;IAC3B,gBAAgB,EAAE,SAAS;CAC5B,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@noodle-borg/oauth-client-registry",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=24"
|
|
9
|
+
},
|
|
10
|
+
"main": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"import": "./dist/index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsc -p tsconfig.json",
|
|
23
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
27
|
+
"@noodle-borg/auth": "0.0.0",
|
|
28
|
+
"cors": "^2.8.6"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/cors": "^2.8.19",
|
|
32
|
+
"@types/express": "^5.0.0",
|
|
33
|
+
"@types/node": "^24.13.1",
|
|
34
|
+
"@types/pg": "^8.20.0"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ArtifactTool, RuntimeArtifact } from '@noodle-borg/compiler';
|
|
2
|
+
import type { ConnectorCompileError, SecretBinding } from '@noodle-borg/connector-defs';
|
|
3
|
+
/** Join keys for caller-derived bindings: `connectorId|operation`, `connectorId|*` for defaults. */
|
|
4
|
+
export declare function delegatedAuthOperationKeys(bindings: readonly SecretBinding[]): ReadonlySet<string>;
|
|
5
|
+
/** Whether any operation this tool fulfils through is bound to caller-derived connector auth. */
|
|
6
|
+
export declare function toolTouchesDelegatedAuth(tool: Pick<ArtifactTool, 'fulfilment'>, keys: ReadonlySet<string>): boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Reject delegated-auth tools projected to `public` surfaces. A `mixed` surface deliberately
|
|
9
|
+
* projects them — reaching one raises the sign-in card — so only pure `public` is an error.
|
|
10
|
+
*/
|
|
11
|
+
export declare function publicSurfaceDelegatedAuthErrors(artifact: Pick<RuntimeArtifact, 'tools' | 'server'>, bindings: readonly SecretBinding[]): readonly ConnectorCompileError[];
|
|
12
|
+
//# sourceMappingURL=assistant-delegated-projection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assistant-delegated-projection.d.ts","sourceRoot":"","sources":["../src/assistant-delegated-projection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAsB,YAAY,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC/F,OAAO,KAAK,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAqBxF,oGAAoG;AACpG,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,SAAS,aAAa,EAAE,GACjC,WAAW,CAAC,MAAM,CAAC,CAOrB;AAOD,iGAAiG;AACjG,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,YAAY,CAAC,EACtC,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,GACxB,OAAO,CAMT;AAOD;;;GAGG;AACH,wBAAgB,gCAAgC,CAC9C,QAAQ,EAAE,IAAI,CAAC,eAAe,EAAE,OAAO,GAAG,QAAQ,CAAC,EACnD,QAAQ,EAAE,SAAS,aAAa,EAAE,GACjC,SAAS,qBAAqB,EAAE,CAuBlC"}
|