@grouparoo/core
Version:
The Grouparoo Core
180 lines (179 loc) • 7.34 kB
JavaScript
;
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"];
}
}