Ctrl K
ComunidadGuías…

lib/mcp-oauth.js

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
var crypto = require('crypto');
var http = require('http');
var assertPublicUrl = require('./mcp-network').assertPublicUrl;

function createOAuthProvider(record, persist, flow, authorize) {
  record.auth = record.auth || {};
  var auth = record.auth;
  function guard() { if (flow && flow.cancelled) throw new Error('Sign-in expired.'); if (authorize) authorize(); }
  function save() { persist(); }
  return {
    get redirectUrl() { return flow ? flow.redirectUrl : auth.redirectUrl; },
    get clientMetadata() { return { client_name: 'Clay', redirect_uris: [flow ? flow.redirectUrl : auth.redirectUrl],
      grant_types: ['authorization_code', 'refresh_token'], response_types: ['code'], token_endpoint_auth_method: 'none' }; },
    state: function () { return flow ? flow.state : crypto.randomBytes(32).toString('hex'); },
    clientInformation: function () { guard(); return auth.client; },
    saveClientInformation: function (value) { guard(); auth.client = value; save(); },
    tokens: function () { guard(); return auth.tokens; },
    saveTokens: function (value) { guard(); auth.tokens = value; save(); },
    saveCodeVerifier: function (value) { guard(); if (flow) flow.verifier = value; },
    codeVerifier: function () { if (!flow || !flow.verifier) throw new Error('Sign in again.'); return flow.verifier; },
    redirectToAuthorization: async function (url) {
      if (!flow) { var required = new Error('Sign in to connect this server.'); required.name = 'UnauthorizedError'; throw required; }
      await (flow.validateUrl || assertPublicUrl)(url.href);
      guard();
      if (url.searchParams.get('state') !== flow.state || url.searchParams.get('redirect_uri') !== flow.redirectUrl || !url.searchParams.get('code_challenge')) throw new Error('Invalid sign-in request.');
      flow.authorizationUrl = url.href;
    },
    discoveryState: function () { guard(); return auth.discovery; },
    saveDiscoveryState: function (value) {
      guard();
      // Bind client credentials to the discovered issuer.
      if (auth.discovery && auth.discovery.authorizationServerUrl !== value.authorizationServerUrl) { delete auth.client; delete auth.tokens; }
      guard(); auth.discovery = value; save();
    },
    invalidateCredentials: function (which) {
      guard();
      if (which === 'all' || which === 'client') delete auth.client;
      if (which === 'all' || which === 'tokens') delete auth.tokens;
      if (which === 'all' || which === 'discovery') delete auth.discovery;
      if (flow && (which === 'all' || which === 'verifier')) flow.verifier = null;
      save();
    },
  };
}
async function createCallback(onCode) {
  var flow = { state: crypto.randomBytes(32).toString('hex'), used: false };
  var server = http.createServer(function (req, res) {
    var url = new URL(req.url, flow.redirectUrl);
    res.setHeader('Content-Type', 'text/plain; charset=utf-8');
    res.setHeader('Cache-Control', 'no-store');
    res.setHeader('Referrer-Policy', 'no-referrer');
    if (req.method !== 'GET' || url.pathname !== '/callback' || flow.used || url.searchParams.getAll('state').length !== 1 || url.searchParams.getAll('code').length !== 1 || url.searchParams.getAll('iss').length > 1 || url.searchParams.get('state') !== flow.state) {
      res.writeHead(400); res.end('Invalid or expired sign-in.'); return;
    }
    var code = url.searchParams.get('code');
    if (!code || code.length > 8192 || url.searchParams.has('error')) { res.writeHead(400); res.end('Sign-in was not completed. Return to Clay and retry.'); return; }
    flow.used = true;
    Promise.resolve().then(function () { return onCode(code, url.searchParams.get('iss')); }).then(function () {
      res.end('Connected. You can return to Clay.');
    }, function () { res.writeHead(400); res.end('Sign-in failed. Return to Clay and retry.'); });
  });
  await new Promise(function (resolve, reject) { server.once('error', reject); server.listen(0, '127.0.0.1', resolve); });
  flow.redirectUrl = 'http://127.0.0.1:' + server.address().port + '/callback';
  flow.close = function () { server.close(); server.closeAllConnections(); flow.verifier = null; };
  return flow;
}
module.exports = { createOAuthProvider: createOAuthProvider, createCallback: createCallback };