@decodo/mcp-server 1.2.6 → 1.3.1
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/build/auth/credential.js +4 -1
- package/build/auth/credential.js.map +1 -1
- package/build/clients/hosts.js +10 -0
- package/build/clients/hosts.js.map +1 -0
- package/build/clients/scraper-api-client.js +16 -6
- package/build/clients/scraper-api-client.js.map +1 -1
- package/build/index.js +2 -2
- package/build/index.js.map +1 -1
- package/build/oauth/backend.js +3 -0
- package/build/oauth/backend.js.map +1 -0
- package/build/oauth/backends/decodo/index.js +71 -0
- package/build/oauth/backends/decodo/index.js.map +1 -0
- package/build/oauth/backends/decodo/request-jwt.js +62 -0
- package/build/oauth/backends/decodo/request-jwt.js.map +1 -0
- package/build/oauth/backends/decodo/token-exchange.js +88 -0
- package/build/oauth/backends/decodo/token-exchange.js.map +1 -0
- package/build/oauth/backends/mock/dashboard.js +84 -0
- package/build/oauth/backends/mock/dashboard.js.map +1 -0
- package/build/oauth/backends/mock/index.js +42 -0
- package/build/oauth/backends/mock/index.js.map +1 -0
- package/build/oauth/backends/mock/subscription-api.js +130 -0
- package/build/oauth/backends/mock/subscription-api.js.map +1 -0
- package/build/oauth/bounded-body.js +29 -0
- package/build/oauth/bounded-body.js.map +1 -0
- package/build/oauth/clients-store.js +142 -0
- package/build/oauth/clients-store.js.map +1 -0
- package/build/oauth/config.js +77 -0
- package/build/oauth/config.js.map +1 -0
- package/build/oauth/cookies.js +25 -0
- package/build/oauth/cookies.js.map +1 -0
- package/build/oauth/index.js +46 -0
- package/build/oauth/index.js.map +1 -0
- package/build/oauth/provider.js +172 -0
- package/build/oauth/provider.js.map +1 -0
- package/build/oauth/redirect-uris.js +17 -0
- package/build/oauth/redirect-uris.js.map +1 -0
- package/build/oauth/router.js +68 -0
- package/build/oauth/router.js.map +1 -0
- package/build/oauth/sealer.js +55 -0
- package/build/oauth/sealer.js.map +1 -0
- package/build/oauth/token-exchange.js +17 -0
- package/build/oauth/token-exchange.js.map +1 -0
- package/build/oauth/ttl-store.js +47 -0
- package/build/oauth/ttl-store.js.map +1 -0
- package/build/server/app.js +77 -0
- package/build/server/app.js.map +1 -0
- package/build/server/revoked-credentials.js +25 -0
- package/build/server/revoked-credentials.js.map +1 -0
- package/build/server/sapi-base-server.js +2 -2
- package/build/server/sapi-base-server.js.map +1 -1
- package/build/server/sapi-http-server.js +2 -2
- package/build/server/sapi-http-server.js.map +1 -1
- package/build/server/trust-proxy.js +19 -0
- package/build/server/trust-proxy.js.map +1 -0
- package/build/server.js +6 -44
- package/build/server.js.map +1 -1
- package/package.json +3 -9
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DecodoOAuthProvider = exports.UnknownAuthorizationRequestError = exports.callbackQueryFrom = exports.MAX_PENDING_COOKIE_LENGTH = exports.MAX_CODE_CHALLENGE_LENGTH = exports.MAX_STATE_LENGTH = exports.PENDING_COOKIE = void 0;
|
|
4
|
+
const node_crypto_1 = require("node:crypto");
|
|
5
|
+
const errors_js_1 = require("@modelcontextprotocol/sdk/server/auth/errors.js");
|
|
6
|
+
const logger_1 = require("../logger");
|
|
7
|
+
const clients_store_1 = require("./clients-store");
|
|
8
|
+
const token_exchange_1 = require("./token-exchange");
|
|
9
|
+
exports.PENDING_COOKIE = 'decodo_oauth_pending';
|
|
10
|
+
const PENDING_TTL_MS = 10 * 60 * 1000;
|
|
11
|
+
const CODE_TTL_MS = 60 * 1000;
|
|
12
|
+
exports.MAX_STATE_LENGTH = 1024;
|
|
13
|
+
exports.MAX_CODE_CHALLENGE_LENGTH = 128;
|
|
14
|
+
exports.MAX_PENDING_COOKIE_LENGTH = 3072;
|
|
15
|
+
const MAX_CALLBACK_PARAM_LENGTH = { code: 512, state: 256, error: 64, error_description: 512 };
|
|
16
|
+
const SEAL = {
|
|
17
|
+
PENDING: 'pending',
|
|
18
|
+
CODE: 'code',
|
|
19
|
+
};
|
|
20
|
+
const callbackQueryFrom = (query) => {
|
|
21
|
+
const picked = {};
|
|
22
|
+
for (const [key, max] of Object.entries(MAX_CALLBACK_PARAM_LENGTH)) {
|
|
23
|
+
const value = query[key];
|
|
24
|
+
if (typeof value === 'string' && value.length > 0) {
|
|
25
|
+
picked[key] = value.slice(0, max);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return picked;
|
|
29
|
+
};
|
|
30
|
+
exports.callbackQueryFrom = callbackQueryFrom;
|
|
31
|
+
class UnknownAuthorizationRequestError extends Error {
|
|
32
|
+
constructor() {
|
|
33
|
+
super('This sign-in request is unknown or has expired. Start again from your MCP client.');
|
|
34
|
+
this.name = 'UnknownAuthorizationRequestError';
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
exports.UnknownAuthorizationRequestError = UnknownAuthorizationRequestError;
|
|
38
|
+
const EXCHANGE_ERROR_TO_OAUTH_ERROR = {
|
|
39
|
+
[token_exchange_1.TOKEN_EXCHANGE_ERROR.INVALID_GRANT]: errors_js_1.InvalidGrantError,
|
|
40
|
+
[token_exchange_1.TOKEN_EXCHANGE_ERROR.INVALID_CLIENT]: errors_js_1.ServerError,
|
|
41
|
+
[token_exchange_1.TOKEN_EXCHANGE_ERROR.SERVER_ERROR]: errors_js_1.ServerError,
|
|
42
|
+
};
|
|
43
|
+
const randomToken = () => (0, node_crypto_1.randomBytes)(32).toString('base64url');
|
|
44
|
+
const pkceChallenge = (verifier) => (0, node_crypto_1.createHash)('sha256').update(verifier).digest('base64url');
|
|
45
|
+
class DecodoOAuthProvider {
|
|
46
|
+
constructor({ clientsStore, backend, sealer, callbackUrl, onTokenIssued, }) {
|
|
47
|
+
this.clientsStore = clientsStore;
|
|
48
|
+
this.backend = backend;
|
|
49
|
+
this.sealer = sealer;
|
|
50
|
+
this.onTokenIssued = onTokenIssued;
|
|
51
|
+
this.cookieOptions = {
|
|
52
|
+
httpOnly: true,
|
|
53
|
+
secure: callbackUrl.protocol === 'https:',
|
|
54
|
+
sameSite: 'lax',
|
|
55
|
+
path: callbackUrl.pathname,
|
|
56
|
+
maxAge: PENDING_TTL_MS,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
async authorize(client, params, res) {
|
|
60
|
+
var _a, _b;
|
|
61
|
+
if (params.state && params.state.length > exports.MAX_STATE_LENGTH) {
|
|
62
|
+
throw new errors_js_1.InvalidRequestError(`state must be at most ${exports.MAX_STATE_LENGTH} characters`);
|
|
63
|
+
}
|
|
64
|
+
if (params.codeChallenge.length > exports.MAX_CODE_CHALLENGE_LENGTH) {
|
|
65
|
+
throw new errors_js_1.InvalidRequestError(`code_challenge must be at most ${exports.MAX_CODE_CHALLENGE_LENGTH} characters`);
|
|
66
|
+
}
|
|
67
|
+
if (((_a = params.scopes) !== null && _a !== void 0 ? _a : []).join(' ').length > clients_store_1.MAX_SCOPE_LENGTH) {
|
|
68
|
+
throw new errors_js_1.InvalidRequestError(`scope must be at most ${clients_store_1.MAX_SCOPE_LENGTH} characters`);
|
|
69
|
+
}
|
|
70
|
+
const pending = {
|
|
71
|
+
requestId: randomToken(),
|
|
72
|
+
state: randomToken(),
|
|
73
|
+
codeVerifier: randomToken(),
|
|
74
|
+
clientId: client.client_id,
|
|
75
|
+
redirectUri: params.redirectUri,
|
|
76
|
+
codeChallenge: params.codeChallenge,
|
|
77
|
+
scopes: (_b = params.scopes) !== null && _b !== void 0 ? _b : [],
|
|
78
|
+
clientState: params.state,
|
|
79
|
+
};
|
|
80
|
+
const cookie = this.sealer.seal(SEAL.PENDING, pending, PENDING_TTL_MS);
|
|
81
|
+
if (cookie.length > exports.MAX_PENDING_COOKIE_LENGTH) {
|
|
82
|
+
throw new errors_js_1.InvalidRequestError('authorization request is too large');
|
|
83
|
+
}
|
|
84
|
+
const url = await this.backend.authorizationUrl({
|
|
85
|
+
state: pending.state,
|
|
86
|
+
codeChallenge: pkceChallenge(pending.codeVerifier),
|
|
87
|
+
});
|
|
88
|
+
(0, logger_1.log)('info', 'oauth.authorize', { clientId: client.client_id, requestId: pending.requestId });
|
|
89
|
+
res.cookie(exports.PENDING_COOKIE, cookie, this.cookieOptions);
|
|
90
|
+
res.redirect(302, url.href);
|
|
91
|
+
}
|
|
92
|
+
handleCallback({ query, pendingCookie, res }) {
|
|
93
|
+
const pending = pendingCookie ? this.sealer.unseal(SEAL.PENDING, pendingCookie) : undefined;
|
|
94
|
+
if (!pending || !query.state || query.state !== pending.state) {
|
|
95
|
+
throw new UnknownAuthorizationRequestError();
|
|
96
|
+
}
|
|
97
|
+
res.clearCookie(exports.PENDING_COOKIE, this.cookieOptions);
|
|
98
|
+
const redirect = new URL(pending.redirectUri);
|
|
99
|
+
if (pending.clientState) {
|
|
100
|
+
redirect.searchParams.set('state', pending.clientState);
|
|
101
|
+
}
|
|
102
|
+
if (query.error || !query.code) {
|
|
103
|
+
const error = query.error || errors_js_1.InvalidRequestError.errorCode;
|
|
104
|
+
redirect.searchParams.set('error', error);
|
|
105
|
+
if (query.error_description) {
|
|
106
|
+
redirect.searchParams.set('error_description', query.error_description);
|
|
107
|
+
}
|
|
108
|
+
(0, logger_1.log)('info', 'oauth.callback.denied', { requestId: pending.requestId, error });
|
|
109
|
+
return redirect.href;
|
|
110
|
+
}
|
|
111
|
+
const issued = {
|
|
112
|
+
requestId: pending.requestId,
|
|
113
|
+
clientId: pending.clientId,
|
|
114
|
+
redirectUri: pending.redirectUri,
|
|
115
|
+
codeChallenge: pending.codeChallenge,
|
|
116
|
+
scopes: pending.scopes,
|
|
117
|
+
codeVerifier: pending.codeVerifier,
|
|
118
|
+
upstreamCode: query.code,
|
|
119
|
+
};
|
|
120
|
+
redirect.searchParams.set('code', this.sealer.seal(SEAL.CODE, issued, CODE_TTL_MS));
|
|
121
|
+
(0, logger_1.log)('info', 'oauth.callback.approved', { requestId: pending.requestId });
|
|
122
|
+
return redirect.href;
|
|
123
|
+
}
|
|
124
|
+
async challengeForAuthorizationCode(client, authorizationCode) {
|
|
125
|
+
return this.issuedCode(client, authorizationCode).codeChallenge;
|
|
126
|
+
}
|
|
127
|
+
async exchangeAuthorizationCode(client, authorizationCode, _codeVerifier, redirectUri) {
|
|
128
|
+
var _a;
|
|
129
|
+
const issued = this.issuedCode(client, authorizationCode);
|
|
130
|
+
if (redirectUri && redirectUri !== issued.redirectUri) {
|
|
131
|
+
throw new errors_js_1.InvalidGrantError('redirect_uri does not match the authorization request');
|
|
132
|
+
}
|
|
133
|
+
const scraperApiKey = await this.redeem(issued);
|
|
134
|
+
(0, logger_1.log)('info', 'oauth.token.issued', { requestId: issued.requestId, clientId: client.client_id });
|
|
135
|
+
(_a = this.onTokenIssued) === null || _a === void 0 ? void 0 : _a.call(this, scraperApiKey);
|
|
136
|
+
return {
|
|
137
|
+
access_token: scraperApiKey,
|
|
138
|
+
token_type: 'bearer',
|
|
139
|
+
scope: issued.scopes.length > 0 ? issued.scopes.join(' ') : undefined,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
async exchangeRefreshToken() {
|
|
143
|
+
throw new errors_js_1.UnsupportedGrantTypeError('refresh tokens are not issued; reconnect to get a new key');
|
|
144
|
+
}
|
|
145
|
+
async verifyAccessToken(token) {
|
|
146
|
+
if (!token.trim()) {
|
|
147
|
+
throw new errors_js_1.InvalidTokenError('empty access token');
|
|
148
|
+
}
|
|
149
|
+
return { token, clientId: 'unknown', scopes: [] };
|
|
150
|
+
}
|
|
151
|
+
issuedCode(client, authorizationCode) {
|
|
152
|
+
const issued = this.sealer.unseal(SEAL.CODE, authorizationCode);
|
|
153
|
+
if (!issued || issued.clientId !== client.client_id) {
|
|
154
|
+
throw new errors_js_1.InvalidGrantError('unknown or expired authorization code');
|
|
155
|
+
}
|
|
156
|
+
return issued;
|
|
157
|
+
}
|
|
158
|
+
async redeem(issued) {
|
|
159
|
+
try {
|
|
160
|
+
return await this.backend.exchange({ code: issued.upstreamCode, codeVerifier: issued.codeVerifier });
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
if (error instanceof token_exchange_1.TokenExchangeError) {
|
|
164
|
+
(0, logger_1.log)('warn', 'oauth.token_exchange.failed', { requestId: issued.requestId, code: error.code, error: error.message });
|
|
165
|
+
throw new EXCHANGE_ERROR_TO_OAUTH_ERROR[error.code](error.message);
|
|
166
|
+
}
|
|
167
|
+
throw error;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
exports.DecodoOAuthProvider = DecodoOAuthProvider;
|
|
172
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/oauth/provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.disallowedRedirectUris = exports.isAllowedRedirectUri = exports.isLoopbackRedirectUri = void 0;
|
|
4
|
+
const LOOPBACK_HOSTS = new Set(['localhost', '127.0.0.1', '[::1]']);
|
|
5
|
+
const isLoopbackRedirectUri = (uri) => {
|
|
6
|
+
if (!URL.canParse(uri)) {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
const url = new URL(uri);
|
|
10
|
+
return url.protocol === 'http:' && LOOPBACK_HOSTS.has(url.hostname);
|
|
11
|
+
};
|
|
12
|
+
exports.isLoopbackRedirectUri = isLoopbackRedirectUri;
|
|
13
|
+
const isAllowedRedirectUri = (uri, allowed) => allowed.includes(uri) || (0, exports.isLoopbackRedirectUri)(uri);
|
|
14
|
+
exports.isAllowedRedirectUri = isAllowedRedirectUri;
|
|
15
|
+
const disallowedRedirectUris = (uris, allowed) => uris.filter(uri => !(0, exports.isAllowedRedirectUri)(uri, allowed));
|
|
16
|
+
exports.disallowedRedirectUris = disallowedRedirectUris;
|
|
17
|
+
//# sourceMappingURL=redirect-uris.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redirect-uris.js","sourceRoot":"","sources":["../../src/oauth/redirect-uris.ts"],"names":[],"mappings":";;;AAAA,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC;AAE7D,MAAM,qBAAqB,GAAG,CAAC,GAAW,EAAW,EAAE;IAC5D,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IAEzB,OAAO,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AACtE,CAAC,CAAC;AARW,QAAA,qBAAqB,yBAQhC;AAEK,MAAM,oBAAoB,GAAG,CAAC,GAAW,EAAE,OAAiB,EAAW,EAAE,CAC9E,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,IAAA,6BAAqB,EAAC,GAAG,CAAC,CAAC;AADzC,QAAA,oBAAoB,wBACqB;AAE/C,MAAM,sBAAsB,GAAG,CAAC,IAAc,EAAE,OAAiB,EAAY,EAAE,CACpF,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,IAAA,4BAAoB,EAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC;AAD7C,QAAA,sBAAsB,0BACuB"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.oauthRouter = void 0;
|
|
7
|
+
const express_1 = __importDefault(require("express"));
|
|
8
|
+
const authorize_js_1 = require("@modelcontextprotocol/sdk/server/auth/handlers/authorize.js");
|
|
9
|
+
const register_js_1 = require("@modelcontextprotocol/sdk/server/auth/handlers/register.js");
|
|
10
|
+
const token_js_1 = require("@modelcontextprotocol/sdk/server/auth/handlers/token.js");
|
|
11
|
+
const router_js_1 = require("@modelcontextprotocol/sdk/server/auth/router.js");
|
|
12
|
+
const logger_1 = require("../logger");
|
|
13
|
+
const config_1 = require("./config");
|
|
14
|
+
const cookies_1 = require("./cookies");
|
|
15
|
+
const provider_1 = require("./provider");
|
|
16
|
+
const provider_2 = require("./provider");
|
|
17
|
+
const RESOURCE_NAME = 'Decodo MCP Server';
|
|
18
|
+
const DOCUMENTATION_URL = new URL('https://github.com/Decodo/mcp-server#readme');
|
|
19
|
+
const RATE_LIMIT_WINDOW_MS = 15 * 60 * 1000;
|
|
20
|
+
const RATE_LIMITS = {
|
|
21
|
+
register: { windowMs: RATE_LIMIT_WINDOW_MS, max: 500 },
|
|
22
|
+
token: { windowMs: RATE_LIMIT_WINDOW_MS, max: 2000 },
|
|
23
|
+
authorize: { windowMs: RATE_LIMIT_WINDOW_MS, max: 200 },
|
|
24
|
+
};
|
|
25
|
+
const errorPage = (message) => `<!doctype html>
|
|
26
|
+
<html lang="en"><head><meta charset="utf-8"><title>Decodo sign-in</title></head>
|
|
27
|
+
<body style="font-family: system-ui, sans-serif; max-width: 32rem; margin: 3rem auto; padding: 0 1rem;">
|
|
28
|
+
<h1>Sign-in could not be completed</h1>
|
|
29
|
+
<p>${message}</p>
|
|
30
|
+
</body></html>`;
|
|
31
|
+
const buildOAuthMetadata = ({ provider, issuerUrl, }) => (Object.assign(Object.assign({}, (0, router_js_1.createOAuthMetadata)({ provider, issuerUrl, serviceDocumentationUrl: DOCUMENTATION_URL })), { grant_types_supported: ['authorization_code'], token_endpoint_auth_methods_supported: ['none'], client_id_metadata_document_supported: true }));
|
|
32
|
+
const oauthRouter = ({ provider, issuerUrl, resourceServerUrl, }) => {
|
|
33
|
+
const metadata = buildOAuthMetadata({ provider, issuerUrl });
|
|
34
|
+
const router = express_1.default.Router();
|
|
35
|
+
router.use(new URL(metadata.authorization_endpoint).pathname, (0, authorize_js_1.authorizationHandler)({ provider, rateLimit: RATE_LIMITS.authorize }));
|
|
36
|
+
router.use(new URL(metadata.token_endpoint).pathname, (0, token_js_1.tokenHandler)({ provider, rateLimit: RATE_LIMITS.token }));
|
|
37
|
+
if (metadata.registration_endpoint) {
|
|
38
|
+
router.use(new URL(metadata.registration_endpoint).pathname, (0, register_js_1.clientRegistrationHandler)({ clientsStore: provider.clientsStore, rateLimit: RATE_LIMITS.register }));
|
|
39
|
+
}
|
|
40
|
+
router.use((0, router_js_1.mcpAuthMetadataRouter)({
|
|
41
|
+
oauthMetadata: metadata,
|
|
42
|
+
resourceServerUrl,
|
|
43
|
+
resourceName: RESOURCE_NAME,
|
|
44
|
+
serviceDocumentationUrl: DOCUMENTATION_URL,
|
|
45
|
+
}));
|
|
46
|
+
router.get(config_1.CALLBACK_PATH, (req, res) => {
|
|
47
|
+
res.setHeader('Cache-Control', 'no-store');
|
|
48
|
+
try {
|
|
49
|
+
const redirect = provider.handleCallback({
|
|
50
|
+
query: (0, provider_2.callbackQueryFrom)(req.query),
|
|
51
|
+
pendingCookie: (0, cookies_1.cookieValue)(req.headers.cookie, provider_1.PENDING_COOKIE),
|
|
52
|
+
res,
|
|
53
|
+
});
|
|
54
|
+
res.redirect(302, redirect);
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
if (error instanceof provider_1.UnknownAuthorizationRequestError) {
|
|
58
|
+
res.status(400).send(errorPage(error.message));
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
(0, logger_1.log)('error', 'oauth.callback.failed', { error: error instanceof Error ? error.message : String(error) });
|
|
62
|
+
res.status(500).send(errorPage('Something went wrong on our side. Try connecting again.'));
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
return router;
|
|
66
|
+
};
|
|
67
|
+
exports.oauthRouter = oauthRouter;
|
|
68
|
+
//# sourceMappingURL=router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/oauth/router.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Sealer = void 0;
|
|
4
|
+
const node_crypto_1 = require("node:crypto");
|
|
5
|
+
const ALGORITHM = 'aes-256-gcm';
|
|
6
|
+
const IV_BYTES = 12;
|
|
7
|
+
const TAG_BYTES = 16;
|
|
8
|
+
class Sealer {
|
|
9
|
+
constructor(secret, now = Date.now) {
|
|
10
|
+
this.now = now;
|
|
11
|
+
this.key = (0, node_crypto_1.createHash)('sha256').update(secret).digest();
|
|
12
|
+
}
|
|
13
|
+
static randomSecret() {
|
|
14
|
+
return (0, node_crypto_1.randomBytes)(32).toString('base64url');
|
|
15
|
+
}
|
|
16
|
+
seal(purpose, payload, ttlMs) {
|
|
17
|
+
const iv = (0, node_crypto_1.randomBytes)(IV_BYTES);
|
|
18
|
+
const cipher = (0, node_crypto_1.createCipheriv)(ALGORITHM, this.key, iv);
|
|
19
|
+
cipher.setAAD(Buffer.from(purpose));
|
|
20
|
+
const body = ttlMs === undefined ? Object.assign({}, payload) : Object.assign(Object.assign({}, payload), { exp: this.now() + ttlMs });
|
|
21
|
+
const encrypted = Buffer.concat([cipher.update(JSON.stringify(body), 'utf8'), cipher.final()]);
|
|
22
|
+
return Buffer.concat([iv, encrypted, cipher.getAuthTag()]).toString('base64url');
|
|
23
|
+
}
|
|
24
|
+
unseal(purpose, token) {
|
|
25
|
+
let buffer;
|
|
26
|
+
try {
|
|
27
|
+
buffer = Buffer.from(token, 'base64url');
|
|
28
|
+
}
|
|
29
|
+
catch (_a) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (buffer.length <= IV_BYTES + TAG_BYTES) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const iv = buffer.subarray(0, IV_BYTES);
|
|
36
|
+
const tag = buffer.subarray(buffer.length - TAG_BYTES);
|
|
37
|
+
const encrypted = buffer.subarray(IV_BYTES, buffer.length - TAG_BYTES);
|
|
38
|
+
try {
|
|
39
|
+
const decipher = (0, node_crypto_1.createDecipheriv)(ALGORITHM, this.key, iv);
|
|
40
|
+
decipher.setAAD(Buffer.from(purpose));
|
|
41
|
+
decipher.setAuthTag(tag);
|
|
42
|
+
const body = JSON.parse(Buffer.concat([decipher.update(encrypted), decipher.final()]).toString('utf8'));
|
|
43
|
+
if (body.exp !== undefined && body.exp <= this.now()) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
delete body.exp;
|
|
47
|
+
return body;
|
|
48
|
+
}
|
|
49
|
+
catch (_b) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
exports.Sealer = Sealer;
|
|
55
|
+
//# sourceMappingURL=sealer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sealer.js","sourceRoot":"","sources":["../../src/oauth/sealer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TokenExchangeError = exports.TOKEN_EXCHANGE_ERROR = void 0;
|
|
4
|
+
exports.TOKEN_EXCHANGE_ERROR = {
|
|
5
|
+
INVALID_GRANT: 'invalid_grant',
|
|
6
|
+
INVALID_CLIENT: 'invalid_client',
|
|
7
|
+
SERVER_ERROR: 'server_error',
|
|
8
|
+
};
|
|
9
|
+
class TokenExchangeError extends Error {
|
|
10
|
+
constructor(code, message) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.code = code;
|
|
13
|
+
this.name = 'TokenExchangeError';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.TokenExchangeError = TokenExchangeError;
|
|
17
|
+
//# sourceMappingURL=token-exchange.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-exchange.js","sourceRoot":"","sources":["../../src/oauth/token-exchange.ts"],"names":[],"mappings":";;;AAAa,QAAA,oBAAoB,GAAG;IAClC,aAAa,EAAE,eAAe;IAC9B,cAAc,EAAE,gBAAgB;IAChC,YAAY,EAAE,cAAc;CACpB,CAAC;AAIX,MAAa,kBAAmB,SAAQ,KAAK;IAC3C,YACW,IAA4B,EACrC,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;QAHN,SAAI,GAAJ,IAAI,CAAwB;QAIrC,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF;AARD,gDAQC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TtlStore = void 0;
|
|
4
|
+
class TtlStore {
|
|
5
|
+
constructor(ttlMs, now = Date.now) {
|
|
6
|
+
this.ttlMs = ttlMs;
|
|
7
|
+
this.now = now;
|
|
8
|
+
this.entries = new Map();
|
|
9
|
+
}
|
|
10
|
+
set(key, value) {
|
|
11
|
+
this.sweep();
|
|
12
|
+
this.entries.set(key, { value, expiresAt: this.now() + this.ttlMs });
|
|
13
|
+
}
|
|
14
|
+
get(key) {
|
|
15
|
+
const entry = this.entries.get(key);
|
|
16
|
+
if (!entry) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (entry.expiresAt <= this.now()) {
|
|
20
|
+
this.entries.delete(key);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
return entry.value;
|
|
24
|
+
}
|
|
25
|
+
take(key) {
|
|
26
|
+
const value = this.get(key);
|
|
27
|
+
this.entries.delete(key);
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
30
|
+
delete(key) {
|
|
31
|
+
this.entries.delete(key);
|
|
32
|
+
}
|
|
33
|
+
get size() {
|
|
34
|
+
this.sweep();
|
|
35
|
+
return this.entries.size;
|
|
36
|
+
}
|
|
37
|
+
sweep() {
|
|
38
|
+
const now = this.now();
|
|
39
|
+
for (const [key, entry] of this.entries) {
|
|
40
|
+
if (entry.expiresAt <= now) {
|
|
41
|
+
this.entries.delete(key);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.TtlStore = TtlStore;
|
|
47
|
+
//# sourceMappingURL=ttl-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ttl-store.js","sourceRoot":"","sources":["../../src/oauth/ttl-store.ts"],"names":[],"mappings":";;;AAKA,MAAa,QAAQ;IAGnB,YACmB,KAAa,EACb,MAAoB,IAAI,CAAC,GAAG;QAD5B,UAAK,GAAL,KAAK,CAAQ;QACb,QAAG,GAAH,GAAG,CAAyB;QAJ9B,YAAO,GAAG,IAAI,GAAG,EAAoB,CAAC;IAKpD,CAAC;IAEJ,GAAG,CAAC,GAAW,EAAE,KAAQ;QACvB,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IACvE,CAAC;IAED,GAAG,CAAC,GAAW;QACb,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAEpC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO;QACT,CAAC;QAED,IAAI,KAAK,CAAC,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;YAClC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACzB,OAAO;QACT,CAAC;QAED,OAAO,KAAK,CAAC,KAAK,CAAC;IACrB,CAAC;IAED,IAAI,CAAC,GAAW;QACd,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACzB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,CAAC,GAAW;QAChB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAED,IAAI,IAAI;QACN,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IAC3B,CAAC;IAEO,KAAK;QACX,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEvB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACxC,IAAI,KAAK,CAAC,SAAS,IAAI,GAAG,EAAE,CAAC;gBAC3B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;IACH,CAAC;CACF;AApDD,4BAoDC"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createApp = void 0;
|
|
7
|
+
const cors_1 = __importDefault(require("cors"));
|
|
8
|
+
const express_1 = __importDefault(require("express"));
|
|
9
|
+
const streamableHttp_js_1 = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
|
|
10
|
+
const auth_1 = require("../auth");
|
|
11
|
+
const oauth_1 = require("../oauth");
|
|
12
|
+
const utils_1 = require("../utils");
|
|
13
|
+
const cors_2 = require("./cors");
|
|
14
|
+
const revoked_credentials_1 = require("./revoked-credentials");
|
|
15
|
+
const sapi_http_server_1 = require("./sapi-http-server");
|
|
16
|
+
const wwwAuthenticate = (resourceMetadataUrl, error) => error
|
|
17
|
+
? `Bearer error="${error}", resource_metadata="${resourceMetadataUrl}"`
|
|
18
|
+
: `Bearer resource_metadata="${resourceMetadataUrl}"`;
|
|
19
|
+
const createApp = ({ oauth: oauthConfig, trustProxy = false, revokedCredentials = new revoked_credentials_1.RevokedCredentials(), fetch, }) => {
|
|
20
|
+
const app = (0, express_1.default)();
|
|
21
|
+
const oauth = (0, oauth_1.createOAuth)(oauthConfig, {
|
|
22
|
+
fetch,
|
|
23
|
+
onTokenIssued: scraperApiKey => {
|
|
24
|
+
const credential = (0, auth_1.credentialFromValue)(scraperApiKey);
|
|
25
|
+
if (credential) {
|
|
26
|
+
revokedCredentials.remove(credential);
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
app.set('trust proxy', trustProxy);
|
|
31
|
+
app.use((0, cors_1.default)(cors_2.corsOptions));
|
|
32
|
+
app.use(express_1.default.json());
|
|
33
|
+
app.use(oauth.router);
|
|
34
|
+
app.get('/mcp', (_req, res) => {
|
|
35
|
+
res.status(200).send('server up, use POST /mcp to see available tools');
|
|
36
|
+
});
|
|
37
|
+
app.post('/mcp', async (req, res) => {
|
|
38
|
+
const auth = req.headers.authorization;
|
|
39
|
+
if (!auth) {
|
|
40
|
+
res.set('WWW-Authenticate', wwwAuthenticate(oauth.resourceMetadataUrl));
|
|
41
|
+
res.status(401).send('Unauthorized');
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const credential = (0, auth_1.credentialFromAuthHeader)(auth);
|
|
45
|
+
if (!credential) {
|
|
46
|
+
res.set('WWW-Authenticate', wwwAuthenticate(oauth.resourceMetadataUrl, 'invalid_token'));
|
|
47
|
+
res.status(401).send("Valid 'Basic' or 'Bearer' authorization required");
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (revokedCredentials.has(credential)) {
|
|
51
|
+
res.set('WWW-Authenticate', wwwAuthenticate(oauth.resourceMetadataUrl, 'invalid_token'));
|
|
52
|
+
res.status(401).send('The Scraping API rejected this credential; sign in again');
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const toolsets = (0, utils_1.resolveToolsets)(req.query.toolsets);
|
|
56
|
+
const server = new sapi_http_server_1.ScraperAPIHttpServer({
|
|
57
|
+
toolsets,
|
|
58
|
+
auth: credential,
|
|
59
|
+
onAuthenticationError: rejected => revokedCredentials.add(rejected),
|
|
60
|
+
});
|
|
61
|
+
const transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
|
|
62
|
+
sessionIdGenerator: undefined,
|
|
63
|
+
enableJsonResponse: false,
|
|
64
|
+
});
|
|
65
|
+
res.on('close', () => {
|
|
66
|
+
transport.close();
|
|
67
|
+
});
|
|
68
|
+
await server.connect(transport);
|
|
69
|
+
await transport.handleRequest(req, res, req.body);
|
|
70
|
+
});
|
|
71
|
+
app.get('/healthz', (_req, res) => {
|
|
72
|
+
res.status(200).send('ok');
|
|
73
|
+
});
|
|
74
|
+
return app;
|
|
75
|
+
};
|
|
76
|
+
exports.createApp = createApp;
|
|
77
|
+
//# sourceMappingURL=app.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/server/app.ts"],"names":[],"mappings":";;;;;;AAAA,gDAAwB;AACxB,sDAA8B;AAC9B,0FAAmG;AACnG,kCAAwE;AACxE,oCAAuC;AAEvC,oCAA2C;AAC3C,iCAAqC;AACrC,+DAA2D;AAC3D,yDAA0D;AAK1D,MAAM,eAAe,GAAG,CAAC,mBAA2B,EAAE,KAAc,EAAU,EAAE,CAC9E,KAAK;IACH,CAAC,CAAC,iBAAiB,KAAK,yBAAyB,mBAAmB,GAAG;IACvE,CAAC,CAAC,6BAA6B,mBAAmB,GAAG,CAAC;AAEnD,MAAM,SAAS,GAAG,CAAC,EACxB,KAAK,EAAE,WAAW,EAClB,UAAU,GAAG,KAAK,EAClB,kBAAkB,GAAG,IAAI,wCAAkB,EAAE,EAC7C,KAAK,GAMN,EAAmB,EAAE;IACpB,MAAM,GAAG,GAAG,IAAA,iBAAO,GAAE,CAAC;IACtB,MAAM,KAAK,GAAG,IAAA,mBAAW,EAAC,WAAW,EAAE;QACrC,KAAK;QACL,aAAa,EAAE,aAAa,CAAC,EAAE;YAC7B,MAAM,UAAU,GAAG,IAAA,0BAAmB,EAAC,aAAa,CAAC,CAAC;YAEtD,IAAI,UAAU,EAAE,CAAC;gBACf,kBAAkB,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YACxC,CAAC;QACH,CAAC;KACF,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;IAEnC,GAAG,CAAC,GAAG,CAAC,IAAA,cAAI,EAAC,kBAAW,CAAC,CAAC,CAAC;IAC3B,GAAG,CAAC,GAAG,CAAC,iBAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IAExB,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAEtB,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;QAC5B,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QAClC,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC;QAEvC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,GAAG,CAAC,GAAG,CAAC,kBAAkB,EAAE,eAAe,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC,CAAC;YACxE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;YACrC,OAAO;QACT,CAAC;QAED,MAAM,UAAU,GAAG,IAAA,+BAAwB,EAAC,IAAI,CAAC,CAAC;QAElD,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,GAAG,CAAC,GAAG,CAAC,kBAAkB,EAAE,eAAe,CAAC,KAAK,CAAC,mBAAmB,EAAE,eAAe,CAAC,CAAC,CAAC;YACzF,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,kDAAkD,CAAC,CAAC;YACzE,OAAO;QACT,CAAC;QAED,IAAI,kBAAkB,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;YACvC,GAAG,CAAC,GAAG,CAAC,kBAAkB,EAAE,eAAe,CAAC,KAAK,CAAC,mBAAmB,EAAE,eAAe,CAAC,CAAC,CAAC;YACzF,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,0DAA0D,CAAC,CAAC;YACjF,OAAO;QACT,CAAC;QAED,MAAM,QAAQ,GAAG,IAAA,uBAAe,EAAC,GAAG,CAAC,KAAK,CAAC,QAAkB,CAAC,CAAC;QAE/D,MAAM,MAAM,GAAG,IAAI,uCAAoB,CAAC;YACtC,QAAQ;YACR,IAAI,EAAE,UAAU;YAChB,qBAAqB,EAAE,QAAQ,CAAC,EAAE,CAAC,kBAAkB,CAAC,GAAG,CAAC,QAAQ,CAAC;SACpE,CAAC,CAAC;QAEH,MAAM,SAAS,GAAG,IAAI,iDAA6B,CAAC;YAClD,kBAAkB,EAAE,SAAS;YAC7B,kBAAkB,EAAE,KAAK;SAC1B,CAAC,CAAC;QAEH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACnB,SAAS,CAAC,KAAK,EAAE,CAAC;QACpB,CAAC,CAAC,CAAC;QAEH,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAEhC,MAAM,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;QAChC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC;AACb,CAAC,CAAC;AApFW,QAAA,SAAS,aAoFpB"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RevokedCredentials = void 0;
|
|
4
|
+
const node_crypto_1 = require("node:crypto");
|
|
5
|
+
const ttl_store_1 = require("../oauth/ttl-store");
|
|
6
|
+
const REMEMBER_MS = 5 * 60 * 1000;
|
|
7
|
+
class RevokedCredentials {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.rejected = new ttl_store_1.TtlStore(REMEMBER_MS);
|
|
10
|
+
}
|
|
11
|
+
add(credential) {
|
|
12
|
+
this.rejected.set(RevokedCredentials.fingerprint(credential), true);
|
|
13
|
+
}
|
|
14
|
+
has(credential) {
|
|
15
|
+
return this.rejected.get(RevokedCredentials.fingerprint(credential)) === true;
|
|
16
|
+
}
|
|
17
|
+
remove(credential) {
|
|
18
|
+
this.rejected.delete(RevokedCredentials.fingerprint(credential));
|
|
19
|
+
}
|
|
20
|
+
static fingerprint({ type, value }) {
|
|
21
|
+
return (0, node_crypto_1.createHash)('sha256').update(`${type}:${value}`).digest('hex');
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.RevokedCredentials = RevokedCredentials;
|
|
25
|
+
//# sourceMappingURL=revoked-credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"revoked-credentials.js","sourceRoot":"","sources":["../../src/server/revoked-credentials.ts"],"names":[],"mappings":";;;AAAA,6CAAyC;AAEzC,kDAA8C;AAE9C,MAAM,WAAW,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AAElC,MAAa,kBAAkB;IAA/B;QACmB,aAAQ,GAAG,IAAI,oBAAQ,CAAO,WAAW,CAAC,CAAC;IAiB9D,CAAC;IAfC,GAAG,CAAC,UAA0B;QAC5B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,kBAAkB,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC,CAAC;IACtE,CAAC;IAED,GAAG,CAAC,UAA0B;QAC5B,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,kBAAkB,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,KAAK,IAAI,CAAC;IAChF,CAAC;IAED,MAAM,CAAC,UAA0B;QAC/B,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,kBAAkB,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC;IACnE,CAAC;IAEO,MAAM,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,KAAK,EAAkB;QACxD,OAAO,IAAA,wBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACvE,CAAC;CACF;AAlBD,gDAkBC"}
|
|
@@ -6,12 +6,12 @@ const scraper_api_client_1 = require("../clients/scraper-api-client");
|
|
|
6
6
|
const version_1 = require("../version");
|
|
7
7
|
const tools_1 = require("../tools");
|
|
8
8
|
class ScraperAPIBaseServer {
|
|
9
|
-
constructor({ auth, toolsets = [] }) {
|
|
9
|
+
constructor({ auth, toolsets = [], onAuthenticationError, integrationHeader, }) {
|
|
10
10
|
this.server = new mcp_js_1.McpServer({
|
|
11
11
|
name: 'decodo',
|
|
12
12
|
version: version_1.PACKAGE_VERSION,
|
|
13
13
|
});
|
|
14
|
-
this.sapiClient = new scraper_api_client_1.ScraperApiClient({});
|
|
14
|
+
this.sapiClient = new scraper_api_client_1.ScraperApiClient({ onAuthenticationError, integrationHeader });
|
|
15
15
|
this.auth = auth;
|
|
16
16
|
this.registerTools({ toolsets });
|
|
17
17
|
this.registerResources();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sapi-base-server.js","sourceRoot":"","sources":["../../src/server/sapi-base-server.ts"],"names":[],"mappings":";;;AAAA,oEAAoE;AAGpE,sEAAiE;
|
|
1
|
+
{"version":3,"file":"sapi-base-server.js","sourceRoot":"","sources":["../../src/server/sapi-base-server.ts"],"names":[],"mappings":";;;AAAA,oEAAoE;AAGpE,sEAAiE;AAEjE,wCAA6C;AAC7C,oCA+BkB;AAKlB,MAAa,oBAAoB;IAO/B,YAAY,EACV,IAAI,EACJ,QAAQ,GAAG,EAAE,EACb,qBAAqB,EACrB,iBAAiB,GAMlB;QACC,IAAI,CAAC,MAAM,GAAG,IAAI,kBAAS,CAAC;YAC1B,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,yBAAe;SACzB,CAAC,CAAC;QACH,IAAI,CAAC,UAAU,GAAG,IAAI,qCAAgB,CAAC,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,CAAC,CAAC;QAErF,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QAEjB,IAAI,CAAC,aAAa,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;QAEjC,IAAI,CAAC,iBAAiB,EAAE,CAAC;IAC3B,CAAC;IAED,OAAO,CAAC,SAA+D;QACrE,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACjC,CAAC;IAmCD,aAAa,CAAC,EAAE,QAAQ,EAA2B;QACjD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACxB,OAAO;QACT,CAAC;QAED,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,KAAK,GAAG,oBAAoB,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC;YACrF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,IAAI,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;YACvF,CAAC;QACH,CAAC;IACH,CAAC;IAED,gBAAgB;QACd,KAAK,MAAM,IAAI,IAAI,oBAAoB,CAAC,QAAQ,EAAE,CAAC;YACjD,IAAI,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACvF,CAAC;IACH,CAAC;IAED,iBAAiB;QACf,gDAAgD;IAClD,CAAC;;AA1FH,oDA2FC;AAxDQ,6BAAQ,GAAW;IACxB,IAAI,4BAAoB,EAAE;IAC1B,IAAI,sBAAc,EAAE;IACpB,IAAI,wBAAgB,EAAE;IACtB,IAAI,qBAAa,EAAE;IACnB,IAAI,sBAAc,EAAE;IACpB,IAAI,wBAAgB,EAAE;IACtB,IAAI,8BAAsB,EAAE;IAC5B,IAAI,wBAAgB,EAAE;IACtB,IAAI,yBAAiB,EAAE;IACvB,IAAI,yBAAiB,EAAE;IACvB,IAAI,yBAAiB,EAAE;IACvB,IAAI,6BAAqB,EAAE;IAC3B,IAAI,yBAAiB,EAAE;IACvB,IAAI,0BAAkB,EAAE;IACxB,IAAI,wBAAgB,EAAE;IACtB,IAAI,yBAAiB,EAAE;IACvB,IAAI,sBAAc,EAAE;IACpB,IAAI,4BAAoB,EAAE;IAC1B,IAAI,6BAAqB,EAAE;IAC3B,IAAI,yBAAiB,EAAE;IACvB,IAAI,2BAAmB,EAAE;IACzB,IAAI,0BAAkB,EAAE;IACxB,IAAI,4BAAoB,EAAE;IAC1B,IAAI,yBAAiB,EAAE;IACvB,IAAI,sBAAc,EAAE;IACpB,IAAI,2BAAmB,EAAE;IACzB,IAAI,sBAAc,EAAE;IACpB,IAAI,sBAAc,EAAE;IACpB,IAAI,mBAAW,EAAE;IACjB,IAAI,sBAAc,EAAE;CACrB,CAAC"}
|
|
@@ -3,8 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ScraperAPIHttpServer = void 0;
|
|
4
4
|
const sapi_base_server_1 = require("./sapi-base-server");
|
|
5
5
|
class ScraperAPIHttpServer extends sapi_base_server_1.ScraperAPIBaseServer {
|
|
6
|
-
constructor({ toolsets = [], auth }) {
|
|
7
|
-
super({ auth, toolsets });
|
|
6
|
+
constructor({ toolsets = [], auth, onAuthenticationError, }) {
|
|
7
|
+
super({ auth, toolsets, onAuthenticationError, integrationHeader: 'mcp-hosted' });
|
|
8
8
|
}
|
|
9
9
|
}
|
|
10
10
|
exports.ScraperAPIHttpServer = ScraperAPIHttpServer;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sapi-http-server.js","sourceRoot":"","sources":["../../src/server/sapi-http-server.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"sapi-http-server.js","sourceRoot":"","sources":["../../src/server/sapi-http-server.ts"],"names":[],"mappings":";;;AAIA,yDAA0D;AAG1D,MAAa,oBAAqB,SAAQ,uCAAoB;IAK5D,YAAY,EACV,QAAQ,GAAG,EAAE,EACb,IAAI,EACJ,qBAAqB,GAKtB;QACC,KAAK,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,YAAY,EAAE,CAAC,CAAC;IACpF,CAAC;CACF;AAhBD,oDAgBC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.trustProxyFromEnv = void 0;
|
|
4
|
+
const trustProxyFromEnv = (value) => {
|
|
5
|
+
var _a;
|
|
6
|
+
const trimmed = (_a = value === null || value === void 0 ? void 0 : value.trim()) !== null && _a !== void 0 ? _a : '';
|
|
7
|
+
if (!trimmed || trimmed === 'false') {
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
if (trimmed === 'true') {
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
if (/^\d+$/.test(trimmed)) {
|
|
14
|
+
return Number(trimmed);
|
|
15
|
+
}
|
|
16
|
+
return trimmed;
|
|
17
|
+
};
|
|
18
|
+
exports.trustProxyFromEnv = trustProxyFromEnv;
|
|
19
|
+
//# sourceMappingURL=trust-proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trust-proxy.js","sourceRoot":"","sources":["../../src/server/trust-proxy.ts"],"names":[],"mappings":";;;AAEO,MAAM,iBAAiB,GAAG,CAAC,KAAyB,EAAc,EAAE;;IACzE,MAAM,OAAO,GAAG,MAAA,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,IAAI,EAAE,mCAAI,EAAE,CAAC;IAEpC,IAAI,CAAC,OAAO,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;QACpC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAC1B,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC;AAhBW,QAAA,iBAAiB,qBAgB5B"}
|