From d62138e3b31e56054518f59ab2cbd761d85640a7 Mon Sep 17 00:00:00 2001 From: rijkvanzanten Date: Mon, 29 Jun 2020 16:52:57 -0400 Subject: [PATCH 1/2] Setup useCollection middleware, record login activity --- src/app.ts | 1 + src/middleware/use-collection.ts | 13 +++++++++++ src/middleware/validate-query.ts | 6 +++--- src/routes/activity.ts | 3 +++ src/routes/auth.ts | 37 ++++++++++++++++++++++++-------- src/routes/collection-presets.ts | 6 ++++++ src/routes/files.ts | 7 +++++- src/routes/folders.ts | 6 ++++++ src/routes/permissions.ts | 6 ++++++ src/routes/relations.ts | 6 ++++++ src/routes/revisions.ts | 3 +++ src/routes/roles.ts | 6 ++++++ src/routes/settings.ts | 3 +++ src/routes/users.ts | 8 +++++++ src/routes/webhooks.ts | 6 ++++++ src/services/activity.ts | 18 ++++++++++++++-- src/services/auth.ts | 2 +- 17 files changed, 121 insertions(+), 16 deletions(-) create mode 100644 src/middleware/use-collection.ts diff --git a/src/app.ts b/src/app.ts index 919ecd60ef..15a16bff60 100644 --- a/src/app.ts +++ b/src/app.ts @@ -31,6 +31,7 @@ import notFoundHandler from './routes/not-found'; const app = express() .disable('x-powered-by') + .set('trust proxy', true) .use(logger()) .use(bodyParser.json()) .use(extractToken) diff --git a/src/middleware/use-collection.ts b/src/middleware/use-collection.ts new file mode 100644 index 0000000000..732999b9eb --- /dev/null +++ b/src/middleware/use-collection.ts @@ -0,0 +1,13 @@ +/** + * Set req.collection for use in other middleware. Used as an alternative on validate-collection for + * system collections + */ +import asyncHandler from 'express-async-handler'; + +const useCollection = (collection: string) => + asyncHandler(async (req, res, next) => { + req.collection = collection; + next(); + }); + +export default useCollection; diff --git a/src/middleware/validate-query.ts b/src/middleware/validate-query.ts index 2d95da3687..51dd85d2ce 100644 --- a/src/middleware/validate-query.ts +++ b/src/middleware/validate-query.ts @@ -12,10 +12,10 @@ import asyncHandler from 'express-async-handler'; import { InvalidQueryException } from '../exceptions'; const validateQuery: RequestHandler = asyncHandler(async (req, res, next) => { - if (!req.params.collection) return next(); - if (!res.locals.query) return next(); + if (!req.collection) return next(); + if (!req.query) return next(); - const query: Query = res.locals.query; + const query: Query = req.query; await Promise.all([ validateParams(req.params.collection, query), diff --git a/src/routes/activity.ts b/src/routes/activity.ts index f926ea16cc..0bd15f97df 100644 --- a/src/routes/activity.ts +++ b/src/routes/activity.ts @@ -3,11 +3,13 @@ import asyncHandler from 'express-async-handler'; import sanitizeQuery from '../middleware/sanitize-query'; import validateQuery from '../middleware/validate-query'; import { readActivities, readActivity } from '../services/activity'; +import useCollection from '../middleware/use-collection'; const router = express.Router(); router.get( '/', + useCollection('directus_activity'), sanitizeQuery, validateQuery, asyncHandler(async (req, res) => { @@ -20,6 +22,7 @@ router.get( router.get( '/:pk', + useCollection('directus_activity'), sanitizeQuery, validateQuery, asyncHandler(async (req, res) => { diff --git a/src/routes/auth.ts b/src/routes/auth.ts index 60a1add323..b2182fda43 100644 --- a/src/routes/auth.ts +++ b/src/routes/auth.ts @@ -6,6 +6,8 @@ import * as AuthService from '../services/auth'; import grant from 'grant'; import getGrantConfig from '../utils/get-grant-config'; import getEmailFromProfile from '../utils/get-email-from-profile'; +import { InvalidPayloadException } from '../exceptions/invalid-payload'; +import * as ActivityService from '../services/activity'; const router = Router(); @@ -17,16 +19,21 @@ const loginSchema = Joi.object({ router.post( '/authenticate', asyncHandler(async (req, res) => { - await loginSchema.validateAsync(req.body); + const { error } = loginSchema.validate(req.body); + if (error) throw new InvalidPayloadException(error.message); + const { email, password } = req.body; - /** - * @TODO - * Make sure to validate the payload. AuthService.authenticate's password is optional which - * means there's a possible problem when req.body.password is undefined - */ + const { token, id } = await AuthService.authenticate(email, password); - const token = await AuthService.authenticate(email, password); + ActivityService.createActivity({ + action: ActivityService.Action.AUTHENTICATE, + collection: 'directus_users', + item: id, + ip: req.ip, + user_agent: req.get('user-agent'), + action_by: id, + }); return res.status(200).json({ data: { token }, @@ -34,7 +41,10 @@ router.post( }) ); -router.use('/sso', session({ secret: process.env.SECRET, saveUninitialized: true, resave: false })); +router.use( + '/sso', + session({ secret: process.env.SECRET, saveUninitialized: false, resave: false }) +); router.use(grant.express()(getGrantConfig())); @@ -43,7 +53,16 @@ router.get( asyncHandler(async (req, res) => { const email = getEmailFromProfile(req.params.provider, req.session.grant.response.profile); - const token = await AuthService.authenticate(email); + const { token, id } = await AuthService.authenticate(email); + + ActivityService.createActivity({ + action: ActivityService.Action.AUTHENTICATE, + collection: 'directus_users', + item: id, + ip: req.ip, + user_agent: req.get('user-agent'), + action_by: id, + }); return res.status(200).json({ data: { token }, diff --git a/src/routes/collection-presets.ts b/src/routes/collection-presets.ts index d9a4040369..689420fd8e 100644 --- a/src/routes/collection-presets.ts +++ b/src/routes/collection-presets.ts @@ -3,11 +3,13 @@ import asyncHandler from 'express-async-handler'; import sanitizeQuery from '../middleware/sanitize-query'; import validateQuery from '../middleware/validate-query'; import * as CollectionPresetsService from '../services/collection-presets'; +import useCollection from '../middleware/use-collection'; const router = express.Router(); router.post( '/', + useCollection('directus_collection_presets'), asyncHandler(async (req, res) => { const records = await CollectionPresetsService.createCollectionPreset( req.body, @@ -19,6 +21,7 @@ router.post( router.get( '/', + useCollection('directus_collection_presets'), sanitizeQuery, validateQuery, asyncHandler(async (req, res) => { @@ -29,6 +32,7 @@ router.get( router.get( '/:pk', + useCollection('directus_collection_presets'), sanitizeQuery, validateQuery, asyncHandler(async (req, res) => { @@ -42,6 +46,7 @@ router.get( router.patch( '/:pk', + useCollection('directus_collection_presets'), asyncHandler(async (req, res) => { const records = await CollectionPresetsService.updateCollectionPreset( req.params.pk, @@ -54,6 +59,7 @@ router.patch( router.delete( '/:pk', + useCollection('directus_collection_presets'), asyncHandler(async (req, res) => { await CollectionPresetsService.deleteCollectionPreset(req.params.pk); return res.status(200).end(); diff --git a/src/routes/files.ts b/src/routes/files.ts index 33c9e2bb8e..84e3427f6a 100644 --- a/src/routes/files.ts +++ b/src/routes/files.ts @@ -6,6 +6,7 @@ import validateQuery from '../middleware/validate-query'; import * as FilesService from '../services/files'; import logger from '../logger'; import { InvalidPayloadException } from '../exceptions'; +import useCollection from '../middleware/use-collection'; const router = express.Router(); @@ -72,10 +73,11 @@ const multipartHandler = (operation: 'create' | 'update') => return req.pipe(busboy); }); -router.post('/', multipartHandler('create')); +router.post('/', useCollection('directus_files'), multipartHandler('create')); router.get( '/', + useCollection('directus_files'), sanitizeQuery, validateQuery, asyncHandler(async (req, res) => { @@ -86,6 +88,7 @@ router.get( router.get( '/:pk', + useCollection('directus_files'), sanitizeQuery, validateQuery, asyncHandler(async (req, res) => { @@ -96,6 +99,7 @@ router.get( router.patch( '/:pk', + useCollection('directus_files'), asyncHandler(async (req, res, next) => { if (req.is('multipart/form-data')) { await multipartHandler('update')(req, res, next); @@ -109,6 +113,7 @@ router.patch( router.delete( '/:pk', + useCollection('directus_files'), asyncHandler(async (req, res) => { await FilesService.deleteFile(req.params.pk); return res.status(200).end(); diff --git a/src/routes/folders.ts b/src/routes/folders.ts index 47f382790f..732766b8bf 100644 --- a/src/routes/folders.ts +++ b/src/routes/folders.ts @@ -3,11 +3,13 @@ import asyncHandler from 'express-async-handler'; import sanitizeQuery from '../middleware/sanitize-query'; import validateQuery from '../middleware/validate-query'; import * as FoldersService from '../services/folders'; +import useCollection from '../middleware/use-collection'; const router = express.Router(); router.post( '/', + useCollection('directus_folders'), asyncHandler(async (req, res) => { const records = await FoldersService.createFolder(req.body, res.locals.query); return res.json({ data: records }); @@ -16,6 +18,7 @@ router.post( router.get( '/', + useCollection('directus_folders'), sanitizeQuery, validateQuery, asyncHandler(async (req, res) => { @@ -26,6 +29,7 @@ router.get( router.get( '/:pk', + useCollection('directus_folders'), sanitizeQuery, validateQuery, asyncHandler(async (req, res) => { @@ -36,6 +40,7 @@ router.get( router.patch( '/:pk', + useCollection('directus_folders'), asyncHandler(async (req, res) => { const records = await FoldersService.updateFolder( req.params.pk, @@ -48,6 +53,7 @@ router.patch( router.delete( '/:pk', + useCollection('directus_folders'), asyncHandler(async (req, res) => { await FoldersService.deleteFolder(req.params.pk); return res.status(200).end(); diff --git a/src/routes/permissions.ts b/src/routes/permissions.ts index 45371ede90..121dec7834 100644 --- a/src/routes/permissions.ts +++ b/src/routes/permissions.ts @@ -3,11 +3,13 @@ import asyncHandler from 'express-async-handler'; import sanitizeQuery from '../middleware/sanitize-query'; import validateQuery from '../middleware/validate-query'; import * as PermissionsService from '../services/permissions'; +import useCollection from '../middleware/use-collection'; const router = express.Router(); router.post( '/', + useCollection('directus_permissions'), asyncHandler(async (req, res) => { const records = await PermissionsService.createPermission(req.body, res.locals.query); return res.json({ data: records }); @@ -16,6 +18,7 @@ router.post( router.get( '/', + useCollection('directus_permissions'), sanitizeQuery, validateQuery, asyncHandler(async (req, res) => { @@ -26,6 +29,7 @@ router.get( router.get( '/:pk', + useCollection('directus_permissions'), sanitizeQuery, validateQuery, asyncHandler(async (req, res) => { @@ -36,6 +40,7 @@ router.get( router.patch( '/:pk', + useCollection('directus_permissions'), asyncHandler(async (req, res) => { const records = await PermissionsService.updatePermission( req.params.pk, @@ -48,6 +53,7 @@ router.patch( router.delete( '/:pk', + useCollection('directus_permissions'), asyncHandler(async (req, res) => { await PermissionsService.deletePermission(req.params.pk); return res.status(200).end(); diff --git a/src/routes/relations.ts b/src/routes/relations.ts index 0fbd00bad4..83a1c5e2b1 100644 --- a/src/routes/relations.ts +++ b/src/routes/relations.ts @@ -3,11 +3,13 @@ import asyncHandler from 'express-async-handler'; import sanitizeQuery from '../middleware/sanitize-query'; import validateQuery from '../middleware/validate-query'; import * as RelationsService from '../services/relations'; +import useCollection from '../middleware/use-collection'; const router = express.Router(); router.post( '/', + useCollection('directus_relations'), asyncHandler(async (req, res) => { const records = await RelationsService.createRelation(req.body, res.locals.query); return res.json({ data: records }); @@ -16,6 +18,7 @@ router.post( router.get( '/', + useCollection('directus_relations'), sanitizeQuery, validateQuery, asyncHandler(async (req, res) => { @@ -26,6 +29,7 @@ router.get( router.get( '/:pk', + useCollection('directus_relations'), sanitizeQuery, validateQuery, asyncHandler(async (req, res) => { @@ -36,6 +40,7 @@ router.get( router.patch( '/:pk', + useCollection('directus_relations'), asyncHandler(async (req, res) => { const records = await RelationsService.updateRelation( req.params.pk, @@ -48,6 +53,7 @@ router.patch( router.delete( '/:pk', + useCollection('directus_relations'), asyncHandler(async (req, res) => { await RelationsService.deleteRelation(req.params.pk); return res.status(200).end(); diff --git a/src/routes/revisions.ts b/src/routes/revisions.ts index eb14c044f6..a44b198f93 100644 --- a/src/routes/revisions.ts +++ b/src/routes/revisions.ts @@ -3,11 +3,13 @@ import asyncHandler from 'express-async-handler'; import sanitizeQuery from '../middleware/sanitize-query'; import validateQuery from '../middleware/validate-query'; import * as RevisionsService from '../services/revisions'; +import useCollection from '../middleware/use-collection'; const router = express.Router(); router.get( '/', + useCollection('directus_revisions'), sanitizeQuery, validateQuery, asyncHandler(async (req, res) => { @@ -18,6 +20,7 @@ router.get( router.get( '/:pk', + useCollection('directus_revisions'), sanitizeQuery, validateQuery, asyncHandler(async (req, res) => { diff --git a/src/routes/roles.ts b/src/routes/roles.ts index 05036876e6..9427405df7 100644 --- a/src/routes/roles.ts +++ b/src/routes/roles.ts @@ -3,11 +3,13 @@ import asyncHandler from 'express-async-handler'; import sanitizeQuery from '../middleware/sanitize-query'; import validateQuery from '../middleware/validate-query'; import * as RolesService from '../services/roles'; +import useCollection from '../middleware/use-collection'; const router = express.Router(); router.post( '/', + useCollection('directus_roles'), asyncHandler(async (req, res) => { const records = await RolesService.createRole(req.body, res.locals.query); return res.json({ data: records }); @@ -16,6 +18,7 @@ router.post( router.get( '/', + useCollection('directus_roles'), sanitizeQuery, validateQuery, asyncHandler(async (req, res) => { @@ -26,6 +29,7 @@ router.get( router.get( '/:pk', + useCollection('directus_roles'), sanitizeQuery, validateQuery, asyncHandler(async (req, res) => { @@ -36,6 +40,7 @@ router.get( router.patch( '/:pk', + useCollection('directus_roles'), asyncHandler(async (req, res) => { const records = await RolesService.updateRole(req.params.pk, req.body, res.locals.query); return res.json({ data: records }); @@ -44,6 +49,7 @@ router.patch( router.delete( '/:pk', + useCollection('directus_roles'), asyncHandler(async (req, res) => { await RolesService.deleteRole(req.params.pk); return res.status(200).end(); diff --git a/src/routes/settings.ts b/src/routes/settings.ts index 5596d8bbaf..2274160dc2 100644 --- a/src/routes/settings.ts +++ b/src/routes/settings.ts @@ -3,11 +3,13 @@ import asyncHandler from 'express-async-handler'; import sanitizeQuery from '../middleware/sanitize-query'; import validateQuery from '../middleware/validate-query'; import * as SettingsService from '../services/settings'; +import useCollection from '../middleware/use-collection'; const router = express.Router(); router.get( '/', + useCollection('directus_settings'), sanitizeQuery, validateQuery, asyncHandler(async (req, res) => { @@ -18,6 +20,7 @@ router.get( router.patch( '/', + useCollection('directus_settings'), asyncHandler(async (req, res) => { const records = await SettingsService.updateSettings( req.params.pk /** @TODO Singleton */, diff --git a/src/routes/users.ts b/src/routes/users.ts index 75de62a992..ba6097dcbf 100644 --- a/src/routes/users.ts +++ b/src/routes/users.ts @@ -5,11 +5,13 @@ import validateQuery from '../middleware/validate-query'; import * as UsersService from '../services/users'; import Joi from '@hapi/joi'; import { InvalidPayloadException } from '../exceptions'; +import useCollection from '../middleware/use-collection'; const router = express.Router(); router.post( '/', + useCollection('directus_users'), asyncHandler(async (req, res) => { const records = await UsersService.createUser(req.body, res.locals.query); return res.json({ data: records }); @@ -18,6 +20,7 @@ router.post( router.get( '/', + useCollection('directus_users'), sanitizeQuery, validateQuery, asyncHandler(async (req, res) => { @@ -28,6 +31,7 @@ router.get( router.get( '/:pk', + useCollection('directus_users'), sanitizeQuery, validateQuery, asyncHandler(async (req, res) => { @@ -38,6 +42,7 @@ router.get( router.patch( '/:pk', + useCollection('directus_users'), asyncHandler(async (req, res) => { const records = await UsersService.updateUser(req.params.pk, req.body, res.locals.query); return res.json({ data: records }); @@ -46,6 +51,7 @@ router.patch( router.delete( '/:pk', + useCollection('directus_users'), asyncHandler(async (req, res) => { await UsersService.deleteUser(req.params.pk); return res.status(200).end(); @@ -59,6 +65,7 @@ const inviteSchema = Joi.object({ router.post( '/invite', + useCollection('directus_users'), asyncHandler(async (req, res) => { const { error } = inviteSchema.validate(req.body); if (error) throw new InvalidPayloadException(error.message); @@ -74,6 +81,7 @@ const acceptInviteSchema = Joi.object({ router.post( '/invite/accept', + useCollection('directus_users'), asyncHandler(async (req, res) => { const { error } = acceptInviteSchema.validate(req.body); if (error) throw new InvalidPayloadException(error.message); diff --git a/src/routes/webhooks.ts b/src/routes/webhooks.ts index f03157ab7f..fe72666a17 100644 --- a/src/routes/webhooks.ts +++ b/src/routes/webhooks.ts @@ -3,11 +3,13 @@ import asyncHandler from 'express-async-handler'; import sanitizeQuery from '../middleware/sanitize-query'; import validateQuery from '../middleware/validate-query'; import * as WebhooksService from '../services/webhooks'; +import useCollection from '../middleware/use-collection'; const router = express.Router(); router.post( '/', + useCollection('directus_webhooks'), asyncHandler(async (req, res) => { const records = await WebhooksService.createWebhook(req.body, res.locals.query); return res.json({ data: records }); @@ -16,6 +18,7 @@ router.post( router.get( '/', + useCollection('directus_webhooks'), sanitizeQuery, validateQuery, asyncHandler(async (req, res) => { @@ -26,6 +29,7 @@ router.get( router.get( '/:pk', + useCollection('directus_webhooks'), sanitizeQuery, validateQuery, asyncHandler(async (req, res) => { @@ -36,6 +40,7 @@ router.get( router.patch( '/:pk', + useCollection('directus_webhooks'), asyncHandler(async (req, res) => { const records = await WebhooksService.updateWebhook( req.params.pk, @@ -48,6 +53,7 @@ router.patch( router.delete( '/:pk', + useCollection('directus_webhooks'), asyncHandler(async (req, res) => { await WebhooksService.deleteWebhook(req.params.pk); return res.status(200).end(); diff --git a/src/services/activity.ts b/src/services/activity.ts index 2b8e317b12..d96c7c034a 100644 --- a/src/services/activity.ts +++ b/src/services/activity.ts @@ -1,10 +1,24 @@ import { Query } from '../types/query'; import * as ItemsService from './items'; -export const readActivities = async (query: Query) => { +export enum Action { + CREATE = 'create', + UPDATE = 'update', + DELETE = 'delete', + REVERT = 'revert', + COMMENT = 'comment', + UPLOAD = 'upload', + AUTHENTICATE = 'authenticate', +} + +export const createActivity = async (data: Record, query?: Query) => { + return await ItemsService.createItem('directus_activity', data, query); +}; + +export const readActivities = async (query?: Query) => { return await ItemsService.readItems('directus_activity', query); }; -export const readActivity = async (pk: string | number, query: Query) => { +export const readActivity = async (pk: string | number, query?: Query) => { return await ItemsService.readItem('directus_activity', pk, query); }; diff --git a/src/services/auth.ts b/src/services/auth.ts index 36ded9e920..13fa68aad5 100644 --- a/src/services/auth.ts +++ b/src/services/auth.ts @@ -38,5 +38,5 @@ export const authenticate = async (email: string, password?: string) => { expiresIn: process.env.ACCESS_TOKEN_EXPIRY_TIME, }); - return token; + return { token, id: user.id }; }; From 6ffa1661676bc5300e72863830aedad694356ada Mon Sep 17 00:00:00 2001 From: rijkvanzanten Date: Mon, 29 Jun 2020 18:26:47 -0400 Subject: [PATCH 2/2] Track activity --- package-lock.json | 92 +++++++++++++++++--------------- package.json | 3 +- src/routes/collection-presets.ts | 39 ++++++++++++-- src/routes/files.ts | 47 +++++++++++++--- src/routes/folders.ts | 49 +++++++++++++---- src/routes/items.ts | 40 ++++++++++++-- src/routes/permissions.ts | 43 ++++++++++++--- src/routes/relations.ts | 39 ++++++++++++-- src/routes/roles.ts | 39 ++++++++++++-- src/routes/users.ts | 39 ++++++++++++-- src/routes/webhooks.ts | 47 ++++++++++++---- src/services/auth.ts | 4 +- src/services/files.ts | 10 +++- src/services/items.ts | 3 +- src/services/payload.ts | 8 +-- src/services/users.ts | 4 +- 16 files changed, 401 insertions(+), 105 deletions(-) diff --git a/package-lock.json b/package-lock.json index d1d9ee8f26..b52e27d91f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -231,6 +231,14 @@ "@hapi/hoek": "^9.0.0" } }, + "@phc/format": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@phc/format/-/format-0.5.0.tgz", + "integrity": "sha512-JWtZ5P1bfXU0bAtTzCpOLYHDXuxSVdtL/oqz4+xa97h8w9E5IlVN333wugXVFv8vZ1hbXObKQf1ptXmFFcMByg==", + "requires": { + "safe-buffer": "^5.1.2" + } + }, "@slynova/flydrive": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@slynova/flydrive/-/flydrive-1.0.1.tgz", @@ -267,12 +275,6 @@ "integrity": "sha512-8GAYQ1jDRUQkSpHzJUqXwAkYFOxuWAOGLhIR4aPd/Y/yL12Q/9m7LsKpHKlfKdNE/362Hc9wPI1Yh6opDfxVJg==", "dev": true }, - "@types/bcrypt": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-3.0.0.tgz", - "integrity": "sha512-nohgNyv+1ViVcubKBh0+XiNJ3dO8nYu///9aJ4cgSqv70gBL+94SNy/iC2NLzKPT2Zt/QavrOkBVbZRLZmw6NQ==", - "dev": true - }, "@types/body-parser": { "version": "1.19.0", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", @@ -647,6 +649,48 @@ "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" }, + "argon2": { + "version": "0.26.2", + "resolved": "https://registry.npmjs.org/argon2/-/argon2-0.26.2.tgz", + "integrity": "sha512-Tk9I/r3KIHCIHU5x2UawKsPi+g7MByAYnUZghXztQDXRp/997P31wa4qvdvokTaFBpsu6jOZACd+2qkBGGssRA==", + "requires": { + "@phc/format": "^0.5.0", + "node-addon-api": "^2.0.0", + "node-pre-gyp": "^0.14.0" + }, + "dependencies": { + "node-addon-api": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.1.tgz", + "integrity": "sha512-2WVfwRfIr1AVn3dRq4yRc2Hn35ND+mPJH6inC6bjpYCZVrpXPB4j3T6i//OGVfqVsR1t/X/axRulDsheq4F0LQ==" + }, + "node-pre-gyp": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.14.0.tgz", + "integrity": "sha512-+CvDC7ZttU/sSt9rFjix/P05iS43qHCOOGzcr3Ry99bXG7VX953+vFyEuph/tfqoYu8dttBkE86JSKBO2OzcxA==", + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4.4.2" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + } + } + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -882,42 +926,6 @@ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" }, - "bcrypt": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.0.0.tgz", - "integrity": "sha512-jB0yCBl4W/kVHM2whjfyqnxTmOHkCX4kHEa5nYKSoGeYe8YrjTYTc87/6bwt1g8cmV0QrbhKriETg9jWtcREhg==", - "requires": { - "node-addon-api": "^3.0.0", - "node-pre-gyp": "0.15.0" - }, - "dependencies": { - "node-pre-gyp": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.15.0.tgz", - "integrity": "sha512-7QcZa8/fpaU/BKenjcaeFF9hLz2+7S9AqyXFhlH/rilsQ/hPZKK32RtR5EQHJElgu+q5RfbJ34KriI79UWaorA==", - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.3", - "needle": "^2.5.0", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4.4.2" - } - }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "requires": { - "glob": "^7.1.3" - } - } - } - }, "bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", diff --git a/package.json b/package.json index 5a15cbd902..5c61b2cb99 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,6 @@ "homepage": "https://github.com/directus/api-node#readme", "devDependencies": { "@types/atob": "^2.1.2", - "@types/bcrypt": "^3.0.0", "@types/busboy": "^0.2.3", "@types/express": "^4.17.6", "@types/express-pino-logger": "^4.0.2", @@ -68,8 +67,8 @@ "@slynova/flydrive": "^1.0.1", "@slynova/flydrive-gcs": "^1.0.1", "@slynova/flydrive-s3": "^1.0.1", + "argon2": "^0.26.2", "atob": "^2.1.2", - "bcrypt": "^5.0.0", "body-parser": "^1.19.0", "busboy": "^0.3.1", "camelcase": "^6.0.0", diff --git a/src/routes/collection-presets.ts b/src/routes/collection-presets.ts index 689420fd8e..052972c67e 100644 --- a/src/routes/collection-presets.ts +++ b/src/routes/collection-presets.ts @@ -4,6 +4,7 @@ import sanitizeQuery from '../middleware/sanitize-query'; import validateQuery from '../middleware/validate-query'; import * as CollectionPresetsService from '../services/collection-presets'; import useCollection from '../middleware/use-collection'; +import * as ActivityService from '../services/activity'; const router = express.Router(); @@ -11,11 +12,21 @@ router.post( '/', useCollection('directus_collection_presets'), asyncHandler(async (req, res) => { - const records = await CollectionPresetsService.createCollectionPreset( + const record = await CollectionPresetsService.createCollectionPreset( req.body, res.locals.query ); - return res.json({ data: records }); + + ActivityService.createActivity({ + action: ActivityService.Action.CREATE, + collection: 'directus_collection_presets', + item: record.id, + ip: req.ip, + user_agent: req.get('user-agent'), + action_by: req.user, + }); + + return res.json({ data: record }); }) ); @@ -48,12 +59,22 @@ router.patch( '/:pk', useCollection('directus_collection_presets'), asyncHandler(async (req, res) => { - const records = await CollectionPresetsService.updateCollectionPreset( + const record = await CollectionPresetsService.updateCollectionPreset( req.params.pk, req.body, res.locals.query ); - return res.json({ data: records }); + + ActivityService.createActivity({ + action: ActivityService.Action.UPDATE, + collection: 'directus_collection_presets', + item: record.id, + ip: req.ip, + user_agent: req.get('user-agent'), + action_by: req.user, + }); + + return res.json({ data: record }); }) ); @@ -62,6 +83,16 @@ router.delete( useCollection('directus_collection_presets'), asyncHandler(async (req, res) => { await CollectionPresetsService.deleteCollectionPreset(req.params.pk); + + ActivityService.createActivity({ + action: ActivityService.Action.DELETE, + collection: 'directus_collection_presets', + item: req.params.pk, + ip: req.ip, + user_agent: req.get('user-agent'), + action_by: req.user, + }); + return res.status(200).end(); }) ); diff --git a/src/routes/files.ts b/src/routes/files.ts index 84e3427f6a..b03ac0417a 100644 --- a/src/routes/files.ts +++ b/src/routes/files.ts @@ -7,12 +7,14 @@ import * as FilesService from '../services/files'; import logger from '../logger'; import { InvalidPayloadException } from '../exceptions'; import useCollection from '../middleware/use-collection'; +import * as ActivityService from '../services/activity'; const router = express.Router(); const multipartHandler = (operation: 'create' | 'update') => asyncHandler(async (req, res, next) => { const busboy = new Busboy({ headers: req.headers }); + const savedFiles: Record = []; /** * The order of the fields in multipart/form-data is important. We require that all fields @@ -53,9 +55,31 @@ const multipartHandler = (operation: 'create' | 'update') => try { if (operation === 'create') { - await FilesService.createFile(payload, fileStream); + const file = await FilesService.createFile(payload, fileStream); + + ActivityService.createActivity({ + action: ActivityService.Action.UPLOAD, + collection: 'directus_files', + item: file.id, + ip: req.ip, + user_agent: req.get('user-agent'), + action_by: req.user, + }); + + savedFiles.push(file); } else { - await FilesService.updateFile(req.params.pk, payload, fileStream); + const file = await FilesService.updateFile(req.params.pk, payload, fileStream); + + ActivityService.createActivity({ + action: ActivityService.Action.UPDATE, + collection: 'directus_files', + item: file.id, + ip: req.ip, + user_agent: req.get('user-agent'), + action_by: req.user, + }); + + savedFiles.push(file); } } catch (err) { busboy.emit('error', err); @@ -67,7 +91,7 @@ const multipartHandler = (operation: 'create' | 'update') => }); busboy.on('finish', () => { - res.status(200).end(); + res.status(200).json({ data: savedFiles }); }); return req.pipe(busboy); @@ -101,13 +125,24 @@ router.patch( '/:pk', useCollection('directus_files'), asyncHandler(async (req, res, next) => { + let file: Record; + if (req.is('multipart/form-data')) { - await multipartHandler('update')(req, res, next); + file = await multipartHandler('update')(req, res, next); } else { - await FilesService.updateFile(req.params.pk, req.body); + file = await FilesService.updateFile(req.params.pk, req.body); + + ActivityService.createActivity({ + action: ActivityService.Action.UPDATE, + collection: 'directus_files', + item: file.id, + ip: req.ip, + user_agent: req.get('user-agent'), + action_by: req.user, + }); } - return res.status(200).end(); + return res.status(200).json({ data: file }); }) ); diff --git a/src/routes/folders.ts b/src/routes/folders.ts index 732766b8bf..f61836264b 100644 --- a/src/routes/folders.ts +++ b/src/routes/folders.ts @@ -2,8 +2,10 @@ import express from 'express'; import asyncHandler from 'express-async-handler'; import sanitizeQuery from '../middleware/sanitize-query'; import validateQuery from '../middleware/validate-query'; -import * as FoldersService from '../services/folders'; import useCollection from '../middleware/use-collection'; +import * as FoldersService from '../services/folders'; +import * as ActivityService from '../services/activity'; +import * as PayloadService from '../services/payload'; const router = express.Router(); @@ -11,8 +13,19 @@ router.post( '/', useCollection('directus_folders'), asyncHandler(async (req, res) => { - const records = await FoldersService.createFolder(req.body, res.locals.query); - return res.json({ data: records }); + const payload = await PayloadService.processValues('create', req.collection, req.body); + const record = await FoldersService.createFolder(payload, res.locals.query); + + ActivityService.createActivity({ + action: ActivityService.Action.CREATE, + collection: req.collection, + item: record.id, + ip: req.ip, + user_agent: req.get('user-agent'), + action_by: req.user, + }); + + return res.json({ data: record }); }) ); @@ -42,12 +55,20 @@ router.patch( '/:pk', useCollection('directus_folders'), asyncHandler(async (req, res) => { - const records = await FoldersService.updateFolder( - req.params.pk, - req.body, - res.locals.query - ); - return res.json({ data: records }); + const payload = await PayloadService.processValues('create', req.collection, req.body); + + const record = await FoldersService.updateFolder(req.params.pk, payload, res.locals.query); + + ActivityService.createActivity({ + action: ActivityService.Action.UPDATE, + collection: req.collection, + item: record.id, + ip: req.ip, + user_agent: req.get('user-agent'), + action_by: req.user, + }); + + return res.json({ data: record }); }) ); @@ -56,6 +77,16 @@ router.delete( useCollection('directus_folders'), asyncHandler(async (req, res) => { await FoldersService.deleteFolder(req.params.pk); + + ActivityService.createActivity({ + action: ActivityService.Action.DELETE, + collection: req.collection, + item: req.params.pk, + ip: req.ip, + user_agent: req.get('user-agent'), + action_by: req.user, + }); + return res.status(200).end(); }) ); diff --git a/src/routes/items.ts b/src/routes/items.ts index dfecda47be..6231963252 100644 --- a/src/routes/items.ts +++ b/src/routes/items.ts @@ -7,6 +7,7 @@ import validateSingleton from '../middleware/validate-singleton'; import validateQuery from '../middleware/validate-query'; import * as MetaService from '../services/meta'; import * as PayloadService from '../services/payload'; +import * as ActivityService from '../services/activity'; const router = express.Router(); @@ -16,8 +17,19 @@ router.post( validateSingleton, asyncHandler(async (req, res) => { const payload = await PayloadService.processValues('create', req.collection, req.body); - await createItem(req.params.collection, payload); - res.status(200).end(); + const item = await createItem(req.params.collection, payload); + + ActivityService.createActivity({ + action: ActivityService.Action.CREATE, + collection: req.collection, + /** @TODO don't forget to use real primary key here */ + item: item.id, + ip: req.ip, + user_agent: req.get('user-agent'), + action_by: req.user, + }); + + res.json({ data: item }); }) ); @@ -56,8 +68,18 @@ router.patch( validateCollection, asyncHandler(async (req, res) => { const payload = await PayloadService.processValues('update', req.collection, req.body); - await updateItem(req.params.collection, req.params.pk, payload); - return res.status(200).end(); + const item = await updateItem(req.params.collection, req.params.pk, payload); + + ActivityService.createActivity({ + action: ActivityService.Action.UPDATE, + collection: req.collection, + item: item.id, + ip: req.ip, + user_agent: req.get('user-agent'), + action_by: req.user, + }); + + return res.json({ data: item }); }) ); @@ -66,6 +88,16 @@ router.delete( validateCollection, asyncHandler(async (req, res) => { await deleteItem(req.params.collection, req.params.pk); + + ActivityService.createActivity({ + action: ActivityService.Action.DELETE, + collection: req.collection, + item: req.params.pk, + ip: req.ip, + user_agent: req.get('user-agent'), + action_by: req.user, + }); + return res.status(200).end(); }) ); diff --git a/src/routes/permissions.ts b/src/routes/permissions.ts index 121dec7834..9d2a1a7802 100644 --- a/src/routes/permissions.ts +++ b/src/routes/permissions.ts @@ -3,6 +3,7 @@ import asyncHandler from 'express-async-handler'; import sanitizeQuery from '../middleware/sanitize-query'; import validateQuery from '../middleware/validate-query'; import * as PermissionsService from '../services/permissions'; +import * as ActivityService from '../services/activity'; import useCollection from '../middleware/use-collection'; const router = express.Router(); @@ -11,8 +12,18 @@ router.post( '/', useCollection('directus_permissions'), asyncHandler(async (req, res) => { - const records = await PermissionsService.createPermission(req.body, res.locals.query); - return res.json({ data: records }); + const item = await PermissionsService.createPermission(req.body, res.locals.query); + + ActivityService.createActivity({ + action: ActivityService.Action.CREATE, + collection: req.collection, + item: item.id, + ip: req.ip, + user_agent: req.get('user-agent'), + action_by: req.user, + }); + + return res.json({ data: item }); }) ); @@ -22,8 +33,8 @@ router.get( sanitizeQuery, validateQuery, asyncHandler(async (req, res) => { - const records = await PermissionsService.readPermissions(res.locals.query); - return res.json({ data: records }); + const item = await PermissionsService.readPermissions(res.locals.query); + return res.json({ data: item }); }) ); @@ -42,12 +53,22 @@ router.patch( '/:pk', useCollection('directus_permissions'), asyncHandler(async (req, res) => { - const records = await PermissionsService.updatePermission( + const item = await PermissionsService.updatePermission( req.params.pk, req.body, res.locals.query ); - return res.json({ data: records }); + + ActivityService.createActivity({ + action: ActivityService.Action.UPDATE, + collection: req.collection, + item: item.id, + ip: req.ip, + user_agent: req.get('user-agent'), + action_by: req.user, + }); + + return res.json({ data: item }); }) ); @@ -56,6 +77,16 @@ router.delete( useCollection('directus_permissions'), asyncHandler(async (req, res) => { await PermissionsService.deletePermission(req.params.pk); + + ActivityService.createActivity({ + action: ActivityService.Action.DELETE, + collection: req.collection, + item: req.params.pk, + ip: req.ip, + user_agent: req.get('user-agent'), + action_by: req.user, + }); + return res.status(200).end(); }) ); diff --git a/src/routes/relations.ts b/src/routes/relations.ts index 83a1c5e2b1..0df8e0ad9e 100644 --- a/src/routes/relations.ts +++ b/src/routes/relations.ts @@ -4,6 +4,7 @@ import sanitizeQuery from '../middleware/sanitize-query'; import validateQuery from '../middleware/validate-query'; import * as RelationsService from '../services/relations'; import useCollection from '../middleware/use-collection'; +import * as ActivityService from '../services/activity'; const router = express.Router(); @@ -11,8 +12,18 @@ router.post( '/', useCollection('directus_relations'), asyncHandler(async (req, res) => { - const records = await RelationsService.createRelation(req.body, res.locals.query); - return res.json({ data: records }); + const item = await RelationsService.createRelation(req.body, res.locals.query); + + ActivityService.createActivity({ + action: ActivityService.Action.CREATE, + collection: req.collection, + item: item.id, + ip: req.ip, + user_agent: req.get('user-agent'), + action_by: req.user, + }); + + return res.json({ data: item }); }) ); @@ -42,12 +53,22 @@ router.patch( '/:pk', useCollection('directus_relations'), asyncHandler(async (req, res) => { - const records = await RelationsService.updateRelation( + const item = await RelationsService.updateRelation( req.params.pk, req.body, res.locals.query ); - return res.json({ data: records }); + + ActivityService.createActivity({ + action: ActivityService.Action.UPDATE, + collection: req.collection, + item: item.id, + ip: req.ip, + user_agent: req.get('user-agent'), + action_by: req.user, + }); + + return res.json({ data: item }); }) ); @@ -56,6 +77,16 @@ router.delete( useCollection('directus_relations'), asyncHandler(async (req, res) => { await RelationsService.deleteRelation(req.params.pk); + + ActivityService.createActivity({ + action: ActivityService.Action.DELETE, + collection: req.collection, + item: req.params.pk, + ip: req.ip, + user_agent: req.get('user-agent'), + action_by: req.user, + }); + return res.status(200).end(); }) ); diff --git a/src/routes/roles.ts b/src/routes/roles.ts index 9427405df7..582c30801a 100644 --- a/src/routes/roles.ts +++ b/src/routes/roles.ts @@ -4,6 +4,7 @@ import sanitizeQuery from '../middleware/sanitize-query'; import validateQuery from '../middleware/validate-query'; import * as RolesService from '../services/roles'; import useCollection from '../middleware/use-collection'; +import * as ActivityService from '../services/activity'; const router = express.Router(); @@ -11,8 +12,18 @@ router.post( '/', useCollection('directus_roles'), asyncHandler(async (req, res) => { - const records = await RolesService.createRole(req.body, res.locals.query); - return res.json({ data: records }); + const item = await RolesService.createRole(req.body, res.locals.query); + + ActivityService.createActivity({ + action: ActivityService.Action.CREATE, + collection: req.collection, + item: item.id, + ip: req.ip, + user_agent: req.get('user-agent'), + action_by: req.user, + }); + + return res.json({ data: item }); }) ); @@ -42,8 +53,18 @@ router.patch( '/:pk', useCollection('directus_roles'), asyncHandler(async (req, res) => { - const records = await RolesService.updateRole(req.params.pk, req.body, res.locals.query); - return res.json({ data: records }); + const item = await RolesService.updateRole(req.params.pk, req.body, res.locals.query); + + ActivityService.createActivity({ + action: ActivityService.Action.UPDATE, + collection: req.collection, + item: item.id, + ip: req.ip, + user_agent: req.get('user-agent'), + action_by: req.user, + }); + + return res.json({ data: item }); }) ); @@ -52,6 +73,16 @@ router.delete( useCollection('directus_roles'), asyncHandler(async (req, res) => { await RolesService.deleteRole(req.params.pk); + + ActivityService.createActivity({ + action: ActivityService.Action.DELETE, + collection: req.collection, + item: req.params.pk, + ip: req.ip, + user_agent: req.get('user-agent'), + action_by: req.user, + }); + return res.status(200).end(); }) ); diff --git a/src/routes/users.ts b/src/routes/users.ts index ba6097dcbf..3957276c08 100644 --- a/src/routes/users.ts +++ b/src/routes/users.ts @@ -6,6 +6,7 @@ import * as UsersService from '../services/users'; import Joi from '@hapi/joi'; import { InvalidPayloadException } from '../exceptions'; import useCollection from '../middleware/use-collection'; +import * as ActivityService from '../services/activity'; const router = express.Router(); @@ -13,8 +14,18 @@ router.post( '/', useCollection('directus_users'), asyncHandler(async (req, res) => { - const records = await UsersService.createUser(req.body, res.locals.query); - return res.json({ data: records }); + const item = await UsersService.createUser(req.body, res.locals.query); + + ActivityService.createActivity({ + action: ActivityService.Action.CREATE, + collection: req.collection, + item: item.id, + ip: req.ip, + user_agent: req.get('user-agent'), + action_by: req.user, + }); + + return res.json({ data: item }); }) ); @@ -24,8 +35,18 @@ router.get( sanitizeQuery, validateQuery, asyncHandler(async (req, res) => { - const records = await UsersService.readUsers(res.locals.query); - return res.json({ data: records }); + const item = await UsersService.readUsers(res.locals.query); + + ActivityService.createActivity({ + action: ActivityService.Action.UPDATE, + collection: req.collection, + item: item.id, + ip: req.ip, + user_agent: req.get('user-agent'), + action_by: req.user, + }); + + return res.json({ data: item }); }) ); @@ -54,6 +75,16 @@ router.delete( useCollection('directus_users'), asyncHandler(async (req, res) => { await UsersService.deleteUser(req.params.pk); + + ActivityService.createActivity({ + action: ActivityService.Action.DELETE, + collection: req.collection, + item: req.params.pk, + ip: req.ip, + user_agent: req.get('user-agent'), + action_by: req.user, + }); + return res.status(200).end(); }) ); diff --git a/src/routes/webhooks.ts b/src/routes/webhooks.ts index fe72666a17..4c93138906 100644 --- a/src/routes/webhooks.ts +++ b/src/routes/webhooks.ts @@ -4,6 +4,7 @@ import sanitizeQuery from '../middleware/sanitize-query'; import validateQuery from '../middleware/validate-query'; import * as WebhooksService from '../services/webhooks'; import useCollection from '../middleware/use-collection'; +import * as ActivityService from '../services/activity'; const router = express.Router(); @@ -11,8 +12,18 @@ router.post( '/', useCollection('directus_webhooks'), asyncHandler(async (req, res) => { - const records = await WebhooksService.createWebhook(req.body, res.locals.query); - return res.json({ data: records }); + const item = await WebhooksService.createWebhook(req.body, req.query); + + ActivityService.createActivity({ + action: ActivityService.Action.CREATE, + collection: req.collection, + item: item.id, + ip: req.ip, + user_agent: req.get('user-agent'), + action_by: req.user, + }); + + return res.json({ data: item }); }) ); @@ -22,7 +33,7 @@ router.get( sanitizeQuery, validateQuery, asyncHandler(async (req, res) => { - const records = await WebhooksService.readWebhooks(res.locals.query); + const records = await WebhooksService.readWebhooks(req.query); return res.json({ data: records }); }) ); @@ -33,7 +44,7 @@ router.get( sanitizeQuery, validateQuery, asyncHandler(async (req, res) => { - const record = await WebhooksService.readWebhook(req.params.pk, res.locals.query); + const record = await WebhooksService.readWebhook(req.params.pk, req.query); return res.json({ data: record }); }) ); @@ -42,12 +53,18 @@ router.patch( '/:pk', useCollection('directus_webhooks'), asyncHandler(async (req, res) => { - const records = await WebhooksService.updateWebhook( - req.params.pk, - req.body, - res.locals.query - ); - return res.json({ data: records }); + const item = await WebhooksService.updateWebhook(req.params.pk, req.body, req.query); + + ActivityService.createActivity({ + action: ActivityService.Action.UPDATE, + collection: req.collection, + item: item.id, + ip: req.ip, + user_agent: req.get('user-agent'), + action_by: req.user, + }); + + return res.json({ data: item }); }) ); @@ -56,6 +73,16 @@ router.delete( useCollection('directus_webhooks'), asyncHandler(async (req, res) => { await WebhooksService.deleteWebhook(req.params.pk); + + ActivityService.createActivity({ + action: ActivityService.Action.DELETE, + collection: req.collection, + item: req.params.pk, + ip: req.ip, + user_agent: req.get('user-agent'), + action_by: req.user, + }); + return res.status(200).end(); }) ); diff --git a/src/services/auth.ts b/src/services/auth.ts index 13fa68aad5..31325ee1d5 100644 --- a/src/services/auth.ts +++ b/src/services/auth.ts @@ -1,6 +1,6 @@ import database from '../database'; import jwt from 'jsonwebtoken'; -import bcrypt from 'bcrypt'; +import argon2 from 'argon2'; import { InvalidCredentialsException } from '../exceptions'; export const authenticate = async (email: string, password?: string) => { @@ -21,7 +21,7 @@ export const authenticate = async (email: string, password?: string) => { * email to leak anywhere else.. We might have to make a dedicated "copy" of this function to * signal the difference */ - if (password !== undefined && (await bcrypt.compare(password, user.password)) === false) { + if (password !== undefined && (await argon2.verify(password, user.password)) === false) { throw new InvalidCredentialsException(); } diff --git a/src/services/files.ts b/src/services/files.ts index 47f6a1ee90..21ed0c0712 100644 --- a/src/services/files.ts +++ b/src/services/files.ts @@ -45,7 +45,7 @@ export const createFile = async ( } await storage.disk(data.storage).put(data.filename_disk, stream as any); - await ItemsService.createItem('directus_files', payload, query); + return await ItemsService.createItem('directus_files', payload, query); }; export const readFiles = async (query: Query) => { @@ -64,13 +64,17 @@ export const updateFile = async ( query?: Query ) => { const payload = await PayloadService.processValues('update', 'directus_files', data); - await ItemsService.updateItem('directus_files', pk, payload, query); /** * @TODO * Handle changes in storage adapter -> going from local to S3 needs to delete from one, upload to the other */ + /** + * @TODO + * Extract metadata here too + */ + if (stream) { const file = await database .select('storage', 'filename_disk') @@ -81,6 +85,8 @@ export const updateFile = async ( // @todo type of stream in flydrive is wrong: https://github.com/Slynova-Org/flydrive/issues/145 await storage.disk(file.storage).put(file.filename_disk, stream as any); } + + return await ItemsService.updateItem('directus_files', pk, payload, query); }; export const deleteFile = async (pk: string | number) => { diff --git a/src/services/items.ts b/src/services/items.ts index d33f483c68..25ba488f04 100644 --- a/src/services/items.ts +++ b/src/services/items.ts @@ -76,7 +76,8 @@ export const updateItem = async ( data: Record, query: Query = {} ) => { - return await database(collection).update(data).where({ id: pk }); + const result = await database(collection).update(data).where({ id: pk }).returning('id'); + return readItem(collection, result[0], query); }; export const deleteItem = async (collection: string, pk: number | string) => { diff --git a/src/services/payload.ts b/src/services/payload.ts index 5a99765781..17dcb969a5 100644 --- a/src/services/payload.ts +++ b/src/services/payload.ts @@ -6,7 +6,7 @@ */ import { FieldInfo } from '../types/field'; -import bcrypt from 'bcrypt'; +import argon2 from 'argon2'; import { v4 as uuidv4 } from 'uuid'; import database from '../database'; import { clone } from 'lodash'; @@ -51,8 +51,10 @@ async function processField( } } -async function genHash(value: string | number) { - return await bcrypt.hash(value, Number(process.env.SALT_ROUNDS)); +async function genHash(value?: string | number) { + if (!value) return; + + return await argon2.hash(String(value)); } async function genUUID(operation: 'create' | 'update') { diff --git a/src/services/users.ts b/src/services/users.ts index ca2d43c50c..913d07276d 100644 --- a/src/services/users.ts +++ b/src/services/users.ts @@ -3,7 +3,7 @@ import * as ItemsService from './items'; import jwt from 'jsonwebtoken'; import { sendInviteMail } from '../mail'; import database from '../database'; -import bcrypt from 'bcrypt'; +import argon2 from 'argon2'; import * as PayloadService from '../services/payload'; import { InvalidPayloadException } from '../exceptions'; @@ -55,7 +55,7 @@ export const acceptInvite = async (token: string, password: string) => { throw new InvalidPayloadException(`Email address ${email} hasn't been invited.`); } - const passwordHashed = await bcrypt.hash(password, Number(process.env.SALT_ROUNDS)); + const passwordHashed = await argon2.hash(password); await database('directus_users') .update({ password: passwordHashed, status: 'active' })