From 1c4cc4920aa18c174ef872287d34cc1faa74ea14 Mon Sep 17 00:00:00 2001 From: joostdecock Date: Mon, 21 Aug 2023 10:34:02 +0200 Subject: [PATCH] feat(backend): Track api calls per key --- sites/backend/prisma/schema.prisma | 2 ++ sites/backend/src/middleware.mjs | 2 +- sites/backend/src/models/user.mjs | 24 ++++++++++++++++++++++-- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/sites/backend/prisma/schema.prisma b/sites/backend/prisma/schema.prisma index c470965ce9f..9dfc3af8ca7 100644 --- a/sites/backend/prisma/schema.prisma +++ b/sites/backend/prisma/schema.prisma @@ -11,9 +11,11 @@ datasource db { model Apikey { id String @id @default(uuid()) aud String @default("") + calls Int @default(0) createdAt DateTime @default(now()) expiresAt DateTime name String @default("") + lastSeen DateTime? level Int @default(0) secret String user User @relation(fields: [userId], references: [id]) diff --git a/sites/backend/src/middleware.mjs b/sites/backend/src/middleware.mjs index e1ddbea66e9..0727f8d61b5 100644 --- a/sites/backend/src/middleware.mjs +++ b/sites/backend/src/middleware.mjs @@ -19,7 +19,7 @@ async function checkAccess(payload, tools, type) { if (payload.aud !== `${api}/${instance}`) return false const User = new UserModel(tools) const uid = payload.userId || payload._id - const ok = await User.papersPlease(uid, type) + const ok = await User.papersPlease(uid, type, payload) return ok } diff --git a/sites/backend/src/models/user.mjs b/sites/backend/src/models/user.mjs index c032dc41518..b045b2a2103 100644 --- a/sites/backend/src/models/user.mjs +++ b/sites/backend/src/models/user.mjs @@ -1526,7 +1526,7 @@ UserModel.prototype.isLusernameAvailable = async function (lusername) { } /* - * Helper method that is called by middleware to verifu whether the user + * Helper method that is called by middleware to verify whether the user * is allowed in. It will update the `lastSeen` field of the user as * well as increase the call counter for either JWT or KEY. * It will also check whether the user status is ok and consent granted. @@ -1535,9 +1535,10 @@ UserModel.prototype.isLusernameAvailable = async function (lusername) { * * @param {id} string - The user ID * @param {type} string - The authentication type (one of 'jwt' or 'key') + * @param {type} string - The middleware auth payload * @returns {success} boolean - True if it worked, false if not */ -UserModel.prototype.papersPlease = async function (id, type) { +UserModel.prototype.papersPlease = async function (id, type, payload) { /* * Construct data object for update operation */ @@ -1558,6 +1559,25 @@ UserModel.prototype.papersPlease = async function (id, type) { return false } + /* + * If it's an API key, update the call call and lastSeen field too + */ + if (type === 'key') { + const keyData = { + calls: { increment: 1 }, + lastSeen: new Date(), + } + try { + await this.prisma.apikey.update({ where: { id: payload.id }, data: keyData }) + } catch (err) { + /* + * An error means it's not good. Return false + */ + log.warn({ id }, 'Could not update apikey lastSeen field from middleware') + return false + } + } + /* * Verify the consent and status */