UNPKG

@grouparoo/core

Version:
180 lines (179 loc) 7.34 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ChatRoomMiddleware = exports.OptionallyAuthenticatedActionMiddleware = exports.AuthenticatedActionMiddleware = void 0; const actionhero_1 = require("actionhero"); const cls_1 = require("../cls"); const ApiKey_1 = require("../../models/ApiKey"); const Team_1 = require("../../models/Team"); const TeamMember_1 = require("../../models/TeamMember"); const errors_1 = require("../errors"); const configUser_1 = require("../configUser"); const Permission_1 = require("../../models/Permission"); const runMode_1 = require("../runMode"); exports.AuthenticatedActionMiddleware = { name: "authenticated-action", global: false, priority: 1000, preProcessor: async (data) => { parseHeaders(data); if (data.params.apiKey) { return authenticateApiKey(data); } else { return authenticateTeamMember(data, false); } }, }; exports.OptionallyAuthenticatedActionMiddleware = { name: "optionally-authenticated-action", global: false, priority: 1000, preProcessor: async (data) => { parseHeaders(data); if (data.params.apiKey) { return authenticateApiKey(data); } else { return authenticateTeamMember(data, true); } }, }; exports.ChatRoomMiddleware = { name: "model chat room middleware", priority: 1000, join: async (connection, room) => { return authenticateTeamMemberInRoom(connection, room); }, }; // authenticate a web user with session cookie & csrfToken async function authenticateTeamMemberFromSession(data, optional) { return await cls_1.CLS.wrap(async () => { const session = await actionhero_1.api.session.load(data.connection); if (!session && optional) return; if (!session || !session.id) { const teamsCount = await Team_1.Team.count(); if (teamsCount === 0) { throw new errors_1.Errors.AuthenticationError("Please create the first team", "NO_TEAMS_ERROR"); } else { throw new errors_1.Errors.AuthenticationError("Please sign in to continue"); } } else if ((data.params.csrfToken && data.params.csrfToken !== session.id) || (!data.params.csrfToken && data.params.serverToken !== actionhero_1.config.general.serverToken)) { throw new errors_1.Errors.AuthenticationError("CSRF error"); } else { const teamMember = await TeamMember_1.TeamMember.findOne({ where: { id: session.teamMemberId }, include: [{ model: Team_1.Team, include: [Permission_1.Permission] }], }); if (!teamMember) throw new errors_1.Errors.AuthenticationError("Team member not found"); const authorized = await teamMember.team.authorizeAction(data.actionTemplate.permission.topic, data.actionTemplate.permission.mode); if (!authorized) { throw new errors_1.Errors.AuthorizationError(data.actionTemplate.permission.mode, data.actionTemplate.permission.topic); } data.session.data = session; data.session.teamMember = teamMember; } }, { catchError: true }); } // Authenticate user from file in .local directory async function authenticateConfigUser(data, optional) { if (optional) return; try { const isAuthenticated = await configUser_1.ConfigUser.isAuthenticated(); if (!isAuthenticated) { const error = new Error("Config user not set."); error["code"] = "AUTHENTICATION_ERROR"; throw error; } } catch (err) { return err; } } // Conditionally choose auth method based on run mode. async function authenticateTeamMember(data, optional) { let error; if ((0, runMode_1.getGrouparooRunMode)() === "cli:config" && ["development", "test"].includes(actionhero_1.env)) { error = await authenticateConfigUser(data, optional); } else { error = await authenticateTeamMemberFromSession(data, optional); } if (error) { if (error["code"] === "AUTHENTICATION_ERROR") { await cls_1.CLS.wrap(async () => { await actionhero_1.api.session.destroy(data.connection); }, { write: true, priority: true }); } throw error; } } // authenticate an API Request async function authenticateApiKey(data) { await cls_1.CLS.wrap(async () => { const apiKey = await ApiKey_1.ApiKey.findOne({ where: { apiKey: data.params.apiKey }, include: [Permission_1.Permission], }); if (!apiKey) throw new errors_1.Errors.AuthenticationError("apiKey not found"); const authorized = await apiKey.authorizeAction(data.actionTemplate.permission.topic, data.actionTemplate.permission.mode); if (!authorized) { throw new errors_1.Errors.AuthorizationError(data.actionTemplate.permission.mode, data.actionTemplate.permission.topic); } data.session.apiKey = apiKey; }); } // authenticate a teamMember against an already-existing session in a WS room async function authenticateTeamMemberInRoom(connection, room) { if (!room.match(/^model:/) && !room.match(/^system:/)) { return; } const roomNameParts = room.split(":"); const mode = "read"; const topic = (roomNameParts[0] === "model" ? roomNameParts[1] : roomNameParts[0]); if ((0, runMode_1.getGrouparooRunMode)() === "cli:config" && actionhero_1.env === "development") return; await cls_1.CLS.wrap(async () => { const session = await actionhero_1.api.session.load(connection); if (!session || !session.id) { throw new errors_1.Errors.AuthenticationError("Please sign in to continue"); } else { const teamMember = await TeamMember_1.TeamMember.findOne({ where: { id: session.teamMemberId }, include: [{ model: Team_1.Team, include: [Permission_1.Permission] }], }); if (!teamMember) throw new errors_1.Errors.AuthenticationError("Team member not found"); const authorized = await teamMember.team.authorizeAction(topic, mode); if (!authorized) { throw new errors_1.Errors.AuthorizationError(mode, topic); } } }); } // check if the apiKey was sent via the header function parseHeaders(data) { if (data.connection.type !== "web") return; if (data.connection.rawConnection.req.headers["authorization"]) { const [scheme, token] = data.connection.rawConnection.req.headers["authorization"].split(" "); // should resemble `Bearer: abc123` if (scheme.toLowerCase() !== "bearer") { throw new Error(`APIKeys should be sent with the \`Authorization: Bearer <token>\` scheme`); } data.params.apiKey = token; } if (data.connection.rawConnection.req.headers["x-grouparoo-server-token"]) { data.params.serverToken = data.connection.rawConnection.req.headers["x-grouparoo-server-token"]; } }