agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
91 lines • 4.38 kB
JavaScript
;
/**
* hosting/signin/hostSignIn — a host's `signIn` option, judged once at
* construction, plus the conversation door's per-socket sign-in watch.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.signInStillLive = exports.checkHandshake = exports.checkHostSignIn = void 0;
const errors_js_1 = require("../errors.js");
const identityVerification_js_1 = require("../identityVerification.js");
const doorGuard_js_1 = require("../doorGuard.js");
const types_js_1 = require("./types.js");
/** RFC 6265 cookie-name characters (an HTTP token). */
const COOKIE_NAME = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
/** Refuse a half-spelled `signIn` by name, before a socket exists. */
function checkHostSignIn(hostName, option, door = {}) {
if (option === undefined)
return undefined;
refuseOpenBrowserRules(hostName, door);
const cookieName = option.cookieName ?? types_js_1.SIGN_IN_COOKIE;
if (typeof cookieName !== 'string' || !COOKIE_NAME.test(cookieName)) {
throw new TypeError(`[hosting] ${hostName}: signIn.cookieName ${JSON.stringify(cookieName)} is not a cookie ` +
`name (an HTTP token: letters, digits and !#$%&'*+-.^_\`|~).`);
}
const identity = option.identity;
if (identity === undefined ||
identity === null ||
(typeof identity.verify !== 'function' && typeof identity.signIn?.identify !== 'function')) {
throw new TypeError(`[hosting] ${hostName}: signIn needs 'identity' — the same object standingAgent takes — ` +
`so the conversation door can verify a handshake before the 101. A door that stripped ` +
`the cookie and checked nothing would hand a socket to anybody who asked.`);
}
return { cookieName, identity };
}
exports.checkHostSignIn = checkHostSignIn;
/**
* Verify a handshake: the same funnel a request goes through. Resolves the
* refusal, or `undefined` when the caller is proven.
*/
async function checkHandshake(signIn, headers, signInKey) {
try {
await (0, identityVerification_js_1.verifyRequestIdentity)(signIn.identity, headers, undefined, signInKey);
return undefined;
}
catch (err) {
if (err instanceof errors_js_1.VerifierUnavailableError)
return { status: 503, error: err };
if (err instanceof errors_js_1.IdentityNotVerifiedError)
return { status: 401, error: err };
return { status: 401, error: new errors_js_1.IdentityNotVerifiedError('unverifiable', false) };
}
}
exports.checkHandshake = checkHandshake;
/**
* Is the sign-in behind this socket still live? `'live'`, `'ended'`, or
* `'unknown'` when the store could not answer (the frame is held back either
* way; an unknown answer closes as an outage, never as a sign-out).
*/
async function signInStillLive(source, key) {
try {
return (await source.identify(key)) === undefined ? 'ended' : 'live';
}
catch {
return 'unknown';
}
}
exports.signInStillLive = signInStillLive;
/**
* H1 on the host (review idI34 S-7): a host that carries a sign-in cookie must
* keep the browser rules on. A cookie rides along on every forged request, and
* `SameSite=Strict` does not stop a same-site sibling page — the door guard is
* the defence. So, with `signIn`: never `allowedOrigins: 'any'` (unset means
* this door's own host, an allowlist of one), never `requireJsonContentType:
* false`, never `allowedHosts: 'any'`, and `allowedHosts` set unless the host
* binds a loopback address.
*/
function refuseOpenBrowserRules(hostName, door) {
const refuse = (sentence) => {
throw new TypeError(`[hosting] ${hostName}: signIn needs the browser rules on — ${sentence}. A sign-in cookie ` +
`rides along on every forged request, and the door guard is what refuses them.`);
};
if (door.allowedOrigins === 'any')
refuse(`allowedOrigins may not be 'any'`);
if (door.requireJsonContentType === false)
refuse('requireJsonContentType may not be false');
if (door.allowedHosts === 'any')
refuse(`allowedHosts may not be 'any'`);
if (door.allowedHosts === undefined && !(0, doorGuard_js_1.isLoopbackBind)(door.bindHost)) {
refuse('allowedHosts must list the names people use (the host does not bind a loopback address)');
}
}
//# sourceMappingURL=hostSignIn.js.map