From dbcbad95a4eb195006b2b8c040af3028af1a9bf4 Mon Sep 17 00:00:00 2001 From: Trent Larson Date: Fri, 15 Mar 2024 16:40:51 -0600 Subject: [PATCH] add "image-limits" and "ping" endpoints --- server.js | 190 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 116 insertions(+), 74 deletions(-) diff --git a/server.js b/server.js index 40e0741..14fee11 100644 --- a/server.js +++ b/server.js @@ -53,6 +53,23 @@ const s3Client = new S3Client({ const uploadDir = 'uploads'; const uploadMulter = multer({ dest: uploadDir + '/' }); +app.get('/ping', async (req, res) => { + res.send('pong'); +}); + +app.get('/image-limits', async (req, res) => { + limitsResult = await retrievelimits(req, res); + if (!limitsResult.success) { + return limitsResult.result; + } + return res.status(200).send(JSON.stringify({ + success: true, + doneImagesThisWeek: limitsResult.doneImagesThisWeek, + maxImagesPerWeek: limitsResult.maxImagesPerWeek, + nextWeekBeginDateTime: limitsResult.nextWeekBeginDateTime + })); +}); + // POST endpoint to upload an image app.post('/image', uploadMulter.single('image'), async (req, res) => { const reqFile = req.file; @@ -69,78 +86,16 @@ app.post('/image', uploadMulter.single('image'), async (req, res) => { } try { - const decoded = await decodeJwt(req, res) - if (!decoded.success) { - return decoded.result; - } - const issuerDid = decoded.issuerDid; - const jwt = decoded.jwt; - - // Check the user's limits, first from the DB and then from the server - let limitPerWeek = await new Promise((resolve, reject) => { - db.get( - 'SELECT per_week FROM user WHERE did = ?', - [ issuerDid ], - (dbErr, row) => { - if (dbErr) { - console.error('Error getting user record from database (but continuing):', dbErr) - // may not matter, so continue - } - resolve(row?.per_week); - } - ); - }); - if (limitPerWeek == null) { - const headers = { - 'Authorization': `Bearer ${jwt}`, - 'Content-Type': 'application/json' - } - const response = await fetch(endorserApiUrl + '/api/report/rateLimits', { headers }); - if (response.status !== 200) { - console.error("Got bad response of", response.status, "when checking rate limits for", issuerDid); - return res.status(400).send(JSON.stringify({ success: false, message: 'Got bad status of ' + response.status + ' when checking limits with endorser server. Verify that the account exists and that the JWT works for that server.'})); - } else { - const body = await response.json(); - limitPerWeek = body.maxClaimsPerWeek / 4; // allowing fewer images than claims - - await new Promise((resolve, reject) => { - db.run( - 'INSERT INTO user (did, per_week) VALUES (?, ?)', - [issuerDid, limitPerWeek], - (dbErr) => { - if (dbErr) { - console.error("Error inserting user record for", issuerDid, "into database (but continuing):", dbErr); - // we can continue... it just means we'll check the endorser server again next time - } - resolve(); - } - ); - }); - } - } - - if (limitPerWeek == null) { - return res.status(400).send(JSON.stringify({ success: false, message: 'Unable to determine rate limits for this user. Verify that the account exists and that the JWT works for that server.' })); + limitsResult = await retrievelimits(req, res); + if (!limitsResult.success) { + return limitsResult.result; } + const doneImagesThisWeek = limitsResult.doneImagesThisWeek; + const maxImagesPerWeek = limitsResult.maxImagesPerWeek; + const issuerDid = limitsResult.issuerDid; - // check the user's claims so far this week - const startOfWeekDate = DateTime.utc().startOf('week') // luxon weeks start on Mondays - const startOfWeekString = startOfWeekDate.toISO() - const imagesCount = await new Promise((resolve, reject) => { - db.get( - 'SELECT COUNT(*) AS week_count FROM image WHERE did = ? AND time >= ?', - [issuerDid, startOfWeekString], - (dbErr, row) => { - if (dbErr) { - console.error(currentDate, "Error counting records for", issuerDid, "into database (but continuing):", dbErr); - // we can continue... it just means we'll check the endorser server again next time - } - resolve(row?.week_count); - } - ); - }); - if (imagesCount >= limitPerWeek) { - return res.status(400).send(JSON.stringify({ success: false, message: 'You have reached your weekly limit of ' + limitPerWeek + ' images.' })); + if (doneImagesThisWeek >= maxImagesPerWeek) { + return res.status(400).send(JSON.stringify({ success: false, message: 'You have reached your weekly limit of ' + maxImagesPerWeek + ' images.' })); } // Read the file from the temporary location @@ -350,6 +305,96 @@ app.delete('/image/:url', async (req, res) => { } }); +async function retrievelimits(req, res) { + const decoded = await decodeJwt(req, res) + if (!decoded.success) { + return decoded.result; + } + const issuerDid = decoded.issuerDid; + const jwt = decoded.jwt; + + // Check the user's limits, first from the DB and then from the server + let maxImagesPerWeek = await new Promise((resolve, reject) => { + db.get( + 'SELECT per_week FROM user WHERE did = ?', + [ issuerDid ], + (dbErr, row) => { + if (dbErr) { + console.error('Error getting user record from database (but continuing):', dbErr) + // may not matter, so continue + } + resolve(row?.per_week); + } + ); + }); + if (maxImagesPerWeek == null) { + const headers = { + 'Authorization': `Bearer ${jwt}`, + 'Content-Type': 'application/json' + } + const response = await fetch(endorserApiUrl + '/api/report/rateLimits', { headers }); + if (response.status !== 200) { + console.error("Got bad response of", response.status, "when checking rate limits for", issuerDid); + return { + success: false, + result: res.status(400).send(JSON.stringify({ success: false, message: 'Got bad status of ' + response.status + ' when checking limits with endorser server. Verify that the account exists and that the JWT works for that server.'})) + }; + } else { + const body = await response.json(); + maxImagesPerWeek = body.maxClaimsPerWeek / 4; // allowing fewer images than claims + + await new Promise((resolve, reject) => { + db.run( + 'INSERT INTO user (did, per_week) VALUES (?, ?)', + [issuerDid, maxImagesPerWeek], + (dbErr) => { + if (dbErr) { + console.error("Error inserting user record for", issuerDid, "into database (but continuing):", dbErr); + // we can continue... it just means we'll check the endorser server again next time + } + resolve(); + } + ); + }); + } + } + + if (maxImagesPerWeek == null) { + return { + success: false, + result: res.status(400).send(JSON.stringify({ success: false, message: 'Unable to determine rate limits for this user. Verify that the account exists and that the JWT works for that server.' })) + }; + } + + // check the user's claims so far this week + const startOfWeekDate = DateTime.utc().startOf('week') // luxon weeks start on Mondays + const startOfWeekString = startOfWeekDate.toISO() + const imagesCount = await new Promise((resolve, reject) => { + db.get( + 'SELECT COUNT(*) AS week_count FROM image WHERE did = ? AND time >= ?', + [issuerDid, startOfWeekString], + (dbErr, row) => { + if (dbErr) { + console.error(currentDate, "Error counting records for", issuerDid, "into database (but continuing):", dbErr); + // we can continue... it just means we'll check the endorser server again next time + } + resolve(row?.week_count); + } + ); + }); + + const nextWeekBeginDateTime = startOfWeekDate.plus({ week: 1 }); // luxon weeks start on Mondays + const nextWeekBeginDateTimeString = nextWeekBeginDateTime.toISO() + + return { + success: true, + doneImagesThisWeek: imagesCount, + maxImagesPerWeek: maxImagesPerWeek, + nextWeekBeginDateTime: nextWeekBeginDateTimeString, + issuerDid: issuerDid, + }; +} + /** * retrieve Bearer JWT from Authorization header and return either: * { success: true, issuerDid: string, jwt: string } @@ -371,10 +416,7 @@ async function decodeJwt(req, res) { console.error(errorTime, 'Got invalid JWT in Authorization header:', verified); return { success: false, - result: res.status(401).send(JSON.stringify({ - success: false, - message: 'Got invalid JWT in Authorization header. See server logs at ' + errorTime - })) + result: res.status(401).send(JSON.stringify({ success: false, message: 'Got invalid JWT in Authorization header. See server logs at ' + errorTime })) }; } return { success: true, issuerDid: verified.issuer, jwt: jwt };