import * as bcrypt from 'bcrypt-nodejs'; import { check, validationResult } from 'express-validator'; import { Utils } from '../../Utils'; import { Opt } from '../../fields/Doc'; import { DashVersion } from '../../fields/DocSymbols'; import { msToTime } from '../ActionUtilities'; import { Method } from '../RouteManager'; import { resolvedPorts, socketMap, timeMap } from '../SocketData'; import { Database } from '../database'; import ApiManager, { Registration } from './ApiManager'; interface ActivityUnit { user: string; duration: number; } export default class UserManager extends ApiManager { protected initialize(register: Registration): void { register({ method: Method.GET, subscription: '/getUsers', secureHandler: async ({ res }) => { const cursor = await Database.Instance.query({}, { email: 1, linkDatabaseId: 1, sharingDocumentId: 1 }, 'users'); const results = await cursor.toArray(); // eslint-disable-next-line @typescript-eslint/no-explicit-any res.send(results.map((user: any) => ({ email: user.email, linkDatabaseId: user.linkDatabaseId, sharingDocumentId: user.sharingDocumentId }))); }, }); register({ method: Method.POST, subscription: '/setCacheDocumentIds', secureHandler: async ({ user, req, res }) => { const userModel = user; const result: { error?: unknown } = {}; userModel.cacheDocumentIds = req.body.cacheDocumentIds; // eslint-disable-next-line @typescript-eslint/no-explicit-any userModel.save?.().then(undefined, (err: any) => { if (err) { result.error = [{ msg: 'Error while caching documents' }]; } }); // Database.Instance.update(id, { "$set": { "fields.cacheDocumentIds": cacheDocumentIds } }, e => { // console.log(e); // }); res.send(result); }, }); register({ method: Method.GET, subscription: '/getUserDocumentIds', secureHandler: ({ res, user }) => res.send({ userDocumentId: user.userDocumentId, linkDatabaseId: user.linkDatabaseId, sharingDocumentId: user.sharingDocumentId }), publicHandler: ({ res }) => res.send({ userDocumentId: Utils.GuestID(), linkDatabaseId: 3, sharingDocumentId: 2 }), }); register({ method: Method.GET, subscription: '/getSharingDocumentId', secureHandler: ({ res, user }) => res.send(user.sharingDocumentId), publicHandler: ({ res }) => res.send(2), }); register({ method: Method.GET, subscription: '/getLinkDatabaseId', secureHandler: ({ res, user }) => res.send(user.linkDatabaseId), publicHandler: ({ res }) => res.send(3), }); register({ method: Method.GET, subscription: '/getCurrentUser', secureHandler: ({ res, user }) => res.send( JSON.stringify({ version: DashVersion, userDocumentId: user.userDocumentId, linkDatabaseId: user.linkDatabaseId, sharingDocumentId: user.sharingDocumentId, email: user.email, cacheDocumentIds: user.cacheDocumentIds, resolvedPorts, }) ), publicHandler: ({ res }) => res.send(JSON.stringify({ userDocumentId: Utils.GuestID(), email: 'guest', resolvedPorts })), }); register({ method: Method.POST, subscription: '/internalResetPassword', secureHandler: async ({ user, req, res }) => { const userModel = user; const result: { error?: unknown } = {}; const { curr_pass, new_pass } = req.body; // perhaps should assert whether curr password is entered correctly const validated = await new Promise>(resolve => { userModel.password && bcrypt.compare(curr_pass, userModel.password, (err, passwordsMatch) => { if (err || !passwordsMatch) { res.send({ error: [{ msg: 'Incorrect current password' }] }); resolve(undefined); } else { resolve(passwordsMatch); } }); }); if (validated === undefined) { return; } check('new_pass', 'Password must be at least 4 characters long') .run(req) .then(chcekcres => console.log(chcekcres)); // .len({ min: 4 }); check('new_confirm', 'Passwords do not match') .run(req) .then(theres => console.log(theres)); // .equals(new_pass); // eslint-disable-next-line camelcase if (curr_pass === new_pass) { result.error = [{ msg: 'Current and new password are the same' }]; } if (validationResult(req).array().length) { // was there error in validating new passwords? result.error = validationResult(req); } // will only change password if there are no errors. if (!result.error) { // eslint-disable-next-line camelcase userModel.password = new_pass; userModel.passwordResetToken = undefined; userModel.passwordResetExpires = undefined; } userModel.save?.().then(undefined, err => { if (err) { result.error = [{ msg: 'Error while saving new password' }]; } }); res.send(result); }, }); register({ method: Method.GET, subscription: '/activity', secureHandler: ({ res }) => { const now = Date.now(); const activeTimes: ActivityUnit[] = []; const inactiveTimes: ActivityUnit[] = []; // eslint-disable-next-line no-restricted-syntax for (const user in timeMap) { if (Object.prototype.hasOwnProperty.call(timeMap, user)) { const time = timeMap[user]; const socketPair = Array.from(socketMap).find(pair => pair[1] === user); if (socketPair && !socketPair[0].disconnected) { const duration = now - time; const target = duration / 1000 < 60 * 5 ? activeTimes : inactiveTimes; target.push({ user, duration }); } } } const process = (target: { user: string; duration: number }[]) => { const comparator = (first: ActivityUnit, second: ActivityUnit) => first.duration - second.duration; const sorted = target.sort(comparator); return sorted.map(({ user, duration }) => `${user} (${msToTime(duration)})`); }; res.render('user_activity.pug', { title: 'User Activity', active: process(activeTimes), inactive: process(inactiveTimes), }); }, }); } }