@n8n/n8n-nodes-langchain
Version:
239 lines • 10.1 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateAuth = validateAuth;
exports.establishChatSessionIdentity = establishChatSessionIdentity;
exports.handleChatTokenRefresh = handleChatTokenRefresh;
exports.resolveInnerFrameIdentity = resolveInnerFrameIdentity;
const basic_auth_1 = __importDefault(require("basic-auth"));
const n8n_workflow_1 = require("n8n-workflow");
const error_1 = require("./error");
const shell_1 = require("./shell");
function expiryFrom(expiresIn) {
return Date.now() + expiresIn * 1000;
}
function secondsUntil(expiresAt) {
return Math.max(0, (expiresAt - Date.now()) / 1000);
}
function getCookie(cookieHeader, name) {
const value = `; ${cookieHeader ?? ''}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) {
return parts.pop()?.split(';').shift() ?? '';
}
return '';
}
async function resolveCurrentSessionUserId(context) {
const authCookie = getCookie(context.getHeaderData()?.cookie, 'n8n-auth');
if (!authCookie)
return null;
try {
const user = await context.validateCookieAuth(authCookie);
return user.id;
}
catch {
return null;
}
}
async function validateAuth(context) {
const authentication = context.getNodeParameter('authentication', 'none');
const req = context.getRequestObject();
const headers = context.getHeaderData();
if (authentication === 'none') {
return;
}
else if (authentication === 'basicAuth') {
let expectedAuth;
try {
expectedAuth = await context.getCredentials('httpBasicAuth');
}
catch { }
if (expectedAuth === undefined || !expectedAuth.user || !expectedAuth.password) {
throw new error_1.ChatTriggerAuthorizationError(500, 'No authentication data defined on node!');
}
const providedAuth = (0, basic_auth_1.default)(req);
if (!providedAuth)
throw new error_1.ChatTriggerAuthorizationError(401);
if (providedAuth.name !== expectedAuth.user || providedAuth.pass !== expectedAuth.password) {
throw new error_1.ChatTriggerAuthorizationError(403);
}
}
else if (authentication === 'n8nUserAuth') {
const webhookName = context.getWebhookName();
if (webhookName !== 'setup') {
const mode = context.getNodeParameter('mode', 'hostedChat');
if (mode === 'hostedChat') {
const chatToken = headers['x-auth-token'];
if (typeof chatToken === 'string' && chatToken) {
const resourceUrl = context.getWebhookResourceUrl('default');
if (resourceUrl) {
const validation = await context.validateN8nOAuth2Token(chatToken, resourceUrl);
if (validation.valid) {
await context.establishTriggerIdentity(chatToken, resourceUrl, validation.user.id);
return validation.user;
}
}
throw new error_1.ChatTriggerAuthorizationError(401, 'Invalid authentication token');
}
}
const authCookie = getCookie(headers.cookie, 'n8n-auth');
if (!authCookie) {
throw new error_1.ChatTriggerAuthorizationError(401, 'User not authenticated!');
}
try {
return await context.validateCookieAuth(authCookie);
}
catch {
throw new error_1.ChatTriggerAuthorizationError(401, 'Invalid authentication token');
}
}
}
return;
}
async function establishChatSessionIdentity(context, resourceUrl) {
const req = context.getRequestObject();
const res = context.getResponseObject();
const { code, state } = req.query;
if (typeof req.query.error === 'string') {
context.logger.warn('Chat OAuth2 authorization was denied or failed', {
error: req.query.error,
});
res.status(403).send('Access denied');
res.end();
return null;
}
if (typeof code === 'string' && typeof state === 'string') {
try {
const result = await context.completeN8nOAuth2Flow(code, state);
if (result.valid) {
(0, shell_1.setChatOAuthToken)(res, req, resourceUrl, {
token: result.token,
expiresAt: expiryFrom(result.expiresIn),
});
(0, shell_1.setChatRefreshToken)(res, req, resourceUrl, result.refreshToken);
const redirectPath = req.originalUrl.split('?')[0];
res.writeHead(302, { Location: redirectPath });
res.end();
return null;
}
context.logger.warn('Chat OAuth2 flow failed, restarting', { reason: result.reason });
}
catch (error) {
context.logger.warn('Chat OAuth2 flow failed, restarting', { error });
}
}
else {
const currentUserId = await resolveCurrentSessionUserId(context);
const session = (0, shell_1.readChatOAuthToken)(req);
if (session) {
const validation = await context.validateN8nOAuth2Token(session.token, resourceUrl);
if (validation.valid) {
if (currentUserId === null || validation.user.id === currentUserId) {
await context.establishTriggerIdentity(session.token, resourceUrl, validation.user.id);
return {
visitor: validation.user,
authToken: session.token,
expiresIn: secondsUntil(session.expiresAt),
};
}
(0, shell_1.clearChatOAuthToken)(res, req, resourceUrl);
(0, shell_1.clearChatRefreshToken)(res, req, resourceUrl);
}
}
else {
const refreshed = await refreshChatSession(context, resourceUrl);
if (refreshed) {
const validation = await context.validateN8nOAuth2Token(refreshed.token, resourceUrl);
if (validation.valid) {
if (currentUserId === null || validation.user.id === currentUserId) {
await context.establishTriggerIdentity(refreshed.token, resourceUrl, validation.user.id);
return {
visitor: validation.user,
authToken: refreshed.token,
expiresIn: refreshed.expiresIn,
};
}
(0, shell_1.clearChatOAuthToken)(res, req, resourceUrl);
(0, shell_1.clearChatRefreshToken)(res, req, resourceUrl);
}
}
}
}
try {
const authorizationUrl = await context.beginN8nOAuth2Flow(resourceUrl);
res.writeHead(302, { Location: authorizationUrl });
res.end();
}
catch (error) {
context.logger.warn('Chat OAuth2 flow failed', { error });
throw new n8n_workflow_1.UnexpectedError('Chat OAuth2 flow failed');
}
return null;
}
async function refreshChatSession(context, resourceUrl) {
const req = context.getRequestObject();
const res = context.getResponseObject();
const refreshToken = (0, shell_1.readChatRefreshToken)(req);
if (!refreshToken)
return null;
try {
const result = await context.refreshN8nOAuth2Flow(refreshToken, resourceUrl);
if (!result.valid) {
context.logger.warn('Chat OAuth2 refresh rejected', { reason: result.reason });
return null;
}
const expiresAt = expiryFrom(result.expiresIn);
(0, shell_1.setChatOAuthToken)(res, req, resourceUrl, { token: result.token, expiresAt });
(0, shell_1.setChatRefreshToken)(res, req, resourceUrl, result.refreshToken);
return { token: result.token, expiresIn: result.expiresIn };
}
catch (error) {
context.logger.warn('Chat OAuth2 refresh failed', { error });
return null;
}
}
async function handleChatTokenRefresh(context, resourceUrl) {
const req = context.getRequestObject();
const res = context.getResponseObject();
res.setHeader('Cache-Control', 'no-store');
if (!(0, shell_1.readChatRefreshToken)(req)) {
res.status(401).json({ error: 'invalid_grant' });
res.end();
return;
}
const refreshed = await refreshChatSession(context, resourceUrl);
if (!refreshed) {
res.status(401).json({ error: 'invalid_grant' });
res.end();
return;
}
const currentUserId = await resolveCurrentSessionUserId(context);
if (currentUserId !== null) {
const validation = await context.validateN8nOAuth2Token(refreshed.token, resourceUrl);
if (!validation.valid || validation.user.id !== currentUserId) {
(0, shell_1.clearChatOAuthToken)(res, req, resourceUrl);
(0, shell_1.clearChatRefreshToken)(res, req, resourceUrl);
res.status(401).json({ error: 'invalid_grant' });
res.end();
return;
}
}
res.status(200).json({ token: refreshed.token, expiresIn: refreshed.expiresIn }).end();
}
async function resolveInnerFrameIdentity(context, resourceUrl) {
const req = context.getRequestObject();
const res = context.getResponseObject();
const session = (0, shell_1.readChatOAuthToken)(req);
if (!session) {
return null;
}
(0, shell_1.clearChatOAuthToken)(res, req, resourceUrl);
const validation = await context.validateN8nOAuth2Token(session.token, resourceUrl);
if (!validation.valid) {
return null;
}
return { visitor: validation.user, authToken: session.token };
}
//# sourceMappingURL=GenericFunctions.js.map