@qelos/auth
Version:
Express Passport authentication service
359 lines (358 loc) • 15.3 kB
JavaScript
;
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;