UNPKG

@qelos/auth

Version:

Express Passport authentication service

359 lines (358 loc) 15.3 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.getUsersStats = exports.removeUser = exports.updateUser = exports.createUser = exports.setUserEncryptedData = exports.getUserEncryptedData = exports.getUser = exports.getUsers = exports.getUsersForAdmin = void 0; const api_kit_1 = require("@qelos/api-kit"); const user_1 = __importDefault(require("../models/user")); const user_internal_metadata_1 = __importDefault(require("../models/user-internal-metadata")); const encrypted_data_1 = require("../services/encrypted-data"); const logger_1 = __importDefault(require("../services/logger")); const mongo_utils_1 = require("../../helpers/mongo-utils"); const UsersService = __importStar(require("../services/users")); const mongoose_1 = require("mongoose"); var ObjectId = mongoose_1.Types.ObjectId; const users_1 = require("../services/users"); const workspace_1 = __importDefault(require("../models/workspace")); const privilegedUserFields = 'username phone fullName firstName lastName birthDate roles profileImage socialLogins emailVerified lastLogin'; function getUserIdIfExists(_id, tenant) { return user_1.default.findOne({ _id, tenant }).select('_id').lean().exec(); } function getUsersForAdmin(req, res) { var _a; try { // support old versions const username = ((_a = req.query.username) === null || _a === void 0 ? void 0 : _a.toString().toLowerCase().trim().replace(/ /g, '+')) || undefined; const query = { tenant: req.headers.tenant, username: req.query.exact ? username ? new RegExp(username, 'i') : undefined : username ? new RegExp(username, 'i') : undefined, }; if (typeof req.query.roles === 'string') { query.roles = { $in: req.query.roles.split(',').map((role) => role.trim()) }; } if (req.query._id) { query._id = { $in: req.query._id.split(',').map(id => new ObjectId(id.trim())) }; } if (!query.username) { delete query.username; } logger_1.default.log('admin db query', query); user_1.default .find(query) .select(req.query.select ? req.query.select.toString().replace(/,/g, ' ') : privilegedUserFields) .lean() .exec() .then((users = []) => { res.json(users).end(); }) .catch((err) => { logger_1.default.error('failed to load users for admin', req.query, err); res.json([]).end(); }); } catch (err) { logger_1.default.error('failed to load users for admin', req.query, err); res.json([]).end(); } } exports.getUsersForAdmin = getUsersForAdmin; function getUsers(req, res) { var _a; if (!req.query.users) { getUsersForAdmin(req, res); return; } const users = (req.query.users || '') .split(',') .map(id => { const val = id.trim(); if ((0, mongo_utils_1.isObjectId)(val)) { return new ObjectId(val); } return false; }) .filter(Boolean); if (!users.length) { res.status(200) .setHeader('x-tenant', req.headers.tenant) .setHeader('x-user', ((_a = req.userPayload) === null || _a === void 0 ? void 0 : _a.sub) || '-') .set('Content-Type', 'application/json').end('[]'); return; } user_1.default .getUsersList(req.headers.tenant, users.filter(Boolean), privilegedUserFields) .then(list => { res.status(200) .setHeader('x-tenant', req.headers.tenant) .setHeader('x-user', 'p-' + req.userPayload.sub) .set('Content-Type', 'application/json').end(list); }) .catch(() => res.status(404).json({ message: 'could not load users' }).end()); } exports.getUsers = getUsers; function getUser(req, res) { const isPrivileged = !!(req.userPayload && req.userPayload.isPrivileged); const promises = [ user_1.default.findOne({ _id: req.params.userId, tenant: req.headers.tenant }) .select(isPrivileged ? privilegedUserFields : 'fullName') .lean().exec() ]; if (isPrivileged) { promises.push(user_internal_metadata_1.default.findOne({ user: req.params.userId, tenant: req.headers.tenant }).lean().exec().catch(() => null)); } Promise.all(promises) .then(([user, internalMetadata]) => { if (!user) { return Promise.reject(null); } if (isPrivileged) { user.internalMetadata = (internalMetadata === null || internalMetadata === void 0 ? void 0 : internalMetadata.metadata) || {}; } res.status(200).json(user).end(); }) .catch(() => res.status(404).json({ message: 'user not exists' }).end()); return; } exports.getUser = getUser; function getUserEncryptedData(req, res) { return __awaiter(this, void 0, void 0, function* () { const tenant = req.headers.tenant; if (!tenant) { return res.status(401).end(); } try { const user = yield getUserIdIfExists(req.params.userId, tenant); if (!user) { throw new Error('user not found'); } const encryptedId = req.headers['x-encrypted-id']; const id = user._id + (encryptedId ? ('-' + encryptedId) : ''); const { value } = yield (0, encrypted_data_1.getEncryptedData)(tenant, id); res.status(200).set('Content-Type', 'application/json').end(value); } catch (e) { res.status(200).json(null).end(); } }); } exports.getUserEncryptedData = getUserEncryptedData; function setUserEncryptedData(req, res) { return __awaiter(this, void 0, void 0, function* () { const tenant = req.headers.tenant; if (!tenant) { return res.status(401).end(); } try { const user = yield getUserIdIfExists(req.params.userId, tenant); if (!user) { throw new Error('user not found'); } const encryptedId = req.headers['x-encrypted-id']; const id = user._id + (encryptedId ? ('-' + encryptedId) : ''); yield (0, encrypted_data_1.setEncryptedData)(tenant, id, JSON.stringify(req.body)); res.status(200).set('Content-Type', 'application/json').end('{}'); } catch (e) { res.status(400).json({ message: 'failed to set encrypted data for user' }).end(); } }); } exports.setUserEncryptedData = setUserEncryptedData; function createUser(req, res) { return __awaiter(this, void 0, void 0, function* () { const _a = req.body, { tenant, name, internalMetadata, metadata } = _a, userData = __rest(_a, ["tenant", "name", "internalMetadata", "metadata"]); const user = new user_1.default(userData); if (req.authConfig.treatUsernameAs === 'email') { user.username = user.username.toLowerCase().trim().replace(/ /g, '+'); user.email = user.username; if (!user.username.includes('@')) { res.status(400).json({ message: 'username should be an email address' }).end(); return; } } user.tenant = req.headers.tenant; if (!user.fullName && name) { user.fullName = name; } if (metadata) { try { user.metadata = (0, users_1.getValidMetadata)(metadata, req.authConfig.additionalUserFields); } catch (_b) { // nothing } } try { if (!user.tenant) { throw new Error('tenant is missing'); } const { _id, fullName, firstName, lastName, birthDate, username, roles } = yield user.save(); const userInternalMetadata = new user_internal_metadata_1.default({ tenant: req.headers.tenant, user: _id, metadata: internalMetadata || {} }); yield userInternalMetadata.save(); const response = { _id, name: fullName, firstName, lastName, birthDate, username, roles, internalMetadata }; (0, api_kit_1.emitPlatformEvent)({ tenant: req.headers.tenant, user: _id, source: 'auth', kind: 'users', eventName: 'user-created', description: 'user created by admin endpoint', metadata: { user: response } }); res.status(200).json(response).end(); } catch (e) { logger_1.default.log('internal user create error', e); res.status(400).json({ message: 'user creation failed' }).end(); } }); } exports.createUser = createUser; function updateUser(req, res) { var _a, _b; return __awaiter(this, void 0, void 0, function* () { const { username, roles, name, password, fullName, firstName, lastName, birthDate, profileImage, internalMetadata } = req.body || {}; let metadata; let newInternalMetadata; try { if ((_a = req.body) === null || _a === void 0 ? void 0 : _a.metadata) { metadata = (0, users_1.getValidMetadata)((_b = req.body) === null || _b === void 0 ? void 0 : _b.metadata, req.authConfig.additionalUserFields); } } catch (_c) { metadata = null; } try { yield UsersService.updateUser({ _id: req.params.userId, tenant: req.headers.tenant }, { username, roles, password, fullName: fullName || name, firstName, lastName, birthDate, metadata, profileImage }, req.authConfig); if (internalMetadata) { const userInternalMetadata = (yield user_internal_metadata_1.default.findOne({ user: req.params.userId, tenant: req.headers.tenant }).exec()) || new user_internal_metadata_1.default({ user: req.params.userId, tenant: req.headers.tenant }); newInternalMetadata = userInternalMetadata.metadata = Object.assign(userInternalMetadata.metadata || {}, internalMetadata); userInternalMetadata.markModified('metadata'); yield userInternalMetadata.save(); } const response = { username, name: fullName || name, fullName: fullName || name, firstName, lastName, birthDate, profileImage, roles, internalMetadata: newInternalMetadata || internalMetadata, _id: req.params.userId }; (0, api_kit_1.emitPlatformEvent)({ tenant: req.headers.tenant, user: req.params.userId, source: 'auth', kind: 'users', eventName: 'user-updated', description: 'user updated by admin endpoint', metadata: { user: response } }); res.status(200).json(response).end(); } catch (e) { res.status(500).json({ message: 'user update failed', info: e === null || e === void 0 ? void 0 : e.info }).end(); } }); } exports.updateUser = updateUser; function removeUser(req, res) { return __awaiter(this, void 0, void 0, function* () { try { yield UsersService.deleteUser(req.params.userId, req.headers.tenant); (0, api_kit_1.emitPlatformEvent)({ tenant: req.headers.tenant, user: req.params.userId, source: 'auth', kind: 'users', eventName: 'user-removed', description: 'user removed by admin endpoint', metadata: null }); res.status(200).json({ _id: req.params.userId, tenant: req.headers.tenant }).end(); } catch (e) { res.status(400).json({ message: 'user deletion failed' }).end(); } }); } exports.removeUser = removeUser; function getUsersStats(req, res) { return __awaiter(this, void 0, void 0, function* () { try { const [users, workspaces] = yield Promise.all([ user_1.default.countDocuments({ tenant: req.headers.tenant }).exec(), workspace_1.default.countDocuments({ tenant: req.headers.tenant }).exec() ]); res.status(200).json({ users, workspaces }).end(); } catch (e) { res.status(500).json({ message: 'could not load users stats' }).end(); } }); } exports.getUsersStats = getUsersStats;