From 495698f33e73d9488a591fac8d35ae9e10ee7c14 Mon Sep 17 00:00:00 2001 From: Ean Milligan Date: Thu, 9 Apr 2026 16:58:15 -0400 Subject: [PATCH] wrap whole thing in a try catch to try to be safe --- mod.ts | 269 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 137 insertions(+), 132 deletions(-) diff --git a/mod.ts b/mod.ts index 6c075a8..fec7612 100644 --- a/mod.ts +++ b/mod.ts @@ -20,161 +20,166 @@ const genericResponse = (status: StatusCode, customText = '') => new Response(customText || STATUS_TEXT[status], { status: status, statusText: STATUS_TEXT[status] }); Deno.serve({ port: config.api.port }, async (req) => { - const urlPath = req.url.split('?')[0] ?? ''; - let rawPath = (urlPath.split('api')[1] ?? '').trim(); - if (rawPath.endsWith('/')) rawPath = rawPath.slice(0, -1); - const path = rawPath; - console.log(urlPath, path); + try { + const urlPath = req.url.split('?')[0] ?? ''; + let rawPath = (urlPath.split('api')[1] ?? '').trim(); + if (rawPath.endsWith('/')) rawPath = rawPath.slice(0, -1); + const path = rawPath; + console.log(urlPath, path); - let failed = false; - if (req.method === 'GET') { - // handle all gets - } else if (req.method === 'POST' && path === '/enroll') { - const body = await req.json(); + let failed = false; + if (req.method === 'GET') { + // handle all gets + } else if (req.method === 'POST' && path === '/enroll') { + const body = await req.json(); - const userNameMatches = await dbClient.query('SELECT name FROM users WHERE name = ?', [body.name]).catch(() => { - failed = true; - }); - if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't read DB."); - - if (userNameMatches.length === 0) { - if (body.name.length < 4 || body.name.length > 20) return genericResponse(STATUS_CODE.BadRequest, `Name too ${body.name.length < 4 ? 'short' : 'long'}.`); - if (body.pin.length < 4 || body.pin.length > 20) return genericResponse(STATUS_CODE.BadRequest, `PIN too ${body.pin.length < 4 ? 'short' : 'long'}.`); - if (body.email.length > 255) return genericResponse(STATUS_CODE.BadRequest, `Email too long.`); - - const id = nanoid(); - - await dbClient.execute('INSERT INTO users(id,name,pin,email) values(?,?,?,?)', [id, body.name, body.pin, body.email]).catch(() => { + const userNameMatches = await dbClient.query('SELECT name FROM users WHERE name = ?', [body.name]).catch(() => { failed = true; }); + if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't read DB."); - if (failed) { - return genericResponse(STATUS_CODE.InternalServerError, "Couldn't write DB."); + if (userNameMatches.length === 0) { + if (body.name.length < 4 || body.name.length > 20) + return genericResponse(STATUS_CODE.BadRequest, `Name too ${body.name.length < 4 ? 'short' : 'long'}.`); + if (body.pin.length < 4 || body.pin.length > 20) return genericResponse(STATUS_CODE.BadRequest, `PIN too ${body.pin.length < 4 ? 'short' : 'long'}.`); + if (body.email.length > 255) return genericResponse(STATUS_CODE.BadRequest, `Email too long.`); + + const id = nanoid(); + + await dbClient.execute('INSERT INTO users(id,name,pin,email) values(?,?,?,?)', [id, body.name, body.pin, body.email]).catch(() => { + failed = true; + }); + + if (failed) { + return genericResponse(STATUS_CODE.InternalServerError, "Couldn't write DB."); + } else { + return genericResponse(STATUS_CODE.OK, JSON.stringify({ id })); + } } else { - return genericResponse(STATUS_CODE.OK, JSON.stringify({ id })); + return genericResponse(STATUS_CODE.BadRequest, 'Username Taken.'); } } else { - return genericResponse(STATUS_CODE.BadRequest, 'Username Taken.'); - } - } else { - const body = await req.json(); + const body = await req.json(); - const loginMatch = await dbClient.query('SELECT id, email, deleteCode FROM users WHERE name = ? AND pin = ?', [body.name, body.pin]).catch(() => { - failed = true; - }); - if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't read DB."); - if (loginMatch.length === 0) return genericResponse(STATUS_CODE.Forbidden, 'Invalid name/PIN combination.'); - const id = loginMatch[0].id; - const email = loginMatch[0].email; - const hasEmail = email.length > 0; - const deleteCode = loginMatch[0].deleteCode; + const loginMatch = await dbClient.query('SELECT id, email, deleteCode FROM users WHERE name = ? AND pin = ?', [body.name, body.pin]).catch(() => { + failed = true; + }); + if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't read DB."); + if (loginMatch.length === 0) return genericResponse(STATUS_CODE.Forbidden, 'Invalid name/PIN combination.'); + const id = loginMatch[0].id; + const email = loginMatch[0].email; + const hasEmail = email.length > 0; + const deleteCode = loginMatch[0].deleteCode; - switch (req.method) { - case 'POST': - if (path === '/auth') { - return genericResponse(STATUS_CODE.OK, JSON.stringify({ id, hasEmail })); - } - break; - case 'PUT': - if (path.startsWith('/undelete/')) { - const planId = path.replace('/undelete/', ''); - const planMatch = await dbClient.query('SELECT ownerId FROM plans WHERE id = ?', [planId]).catch(() => { - failed = true; - }); - if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't read DB."); - if (!planMatch.length) return genericResponse(STATUS_CODE.NotFound, 'Plan ID does not exist.'); - if (planMatch[0].ownerId !== id) return genericResponse(STATUS_CODE.Forbidden, "You don't own this plan."); - - await dbClient.execute('UPDATE plans SET deleted = 0 WHERE id = ?', [planId]).catch(() => { - failed = true; - }); - if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't update DB."); - return genericResponse(STATUS_CODE.OK, 'Plan deleted.'); - } - break; - case 'DELETE': - if (path === '/unenroll') { - if (!hasEmail || body.deleteCode.trim() === deleteCode) { - await dbClient.execute('DELETE FROM plans WHERE ownerId = ?', [id]).catch(() => { + switch (req.method) { + case 'POST': + if (path === '/auth') { + return genericResponse(STATUS_CODE.OK, JSON.stringify({ id, hasEmail })); + } + break; + case 'PUT': + if (path.startsWith('/undelete/')) { + const planId = path.replace('/undelete/', ''); + const planMatch = await dbClient.query('SELECT ownerId FROM plans WHERE id = ?', [planId]).catch(() => { failed = true; }); - if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't delete plans."); + if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't read DB."); + if (!planMatch.length) return genericResponse(STATUS_CODE.NotFound, 'Plan ID does not exist.'); + if (planMatch[0].ownerId !== id) return genericResponse(STATUS_CODE.Forbidden, "You don't own this plan."); - await dbClient.execute('DELETE FROM users WHERE id = ?', [id]).catch(() => { + await dbClient.execute('UPDATE plans SET deleted = 0 WHERE id = ?', [planId]).catch(() => { failed = true; }); - if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't delete user."); - - return genericResponse(STATUS_CODE.OK, 'Deleted user and plans.'); - } else if (hasEmail && !deleteCode) { - const newDeleteCode = nanoid(); - await dbClient.execute('UPDATE users SET deleteCode = ? WHERE id = ?', [newDeleteCode, id]).catch(() => { - failed = true; - }); - if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't set deleteCode."); - - const nowDT = new Date().getTime(); - if (zohoAuthExpireDT < nowDT) { - const getNewAuthToken = await fetch( - `https://accounts.zoho.com/oauth/v2/token?client_id=${config.email.clientId}&client_secret=${config.email.clientSecret}&grant_type=client_credentials&scope=ZohoMail.messages.CREATE`, - { method: 'POST' }, - ).catch(() => { + if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't update DB."); + return genericResponse(STATUS_CODE.OK, 'Plan deleted.'); + } + break; + case 'DELETE': + if (path === '/unenroll') { + if (!hasEmail || body.deleteCode.trim() === deleteCode) { + await dbClient.execute('DELETE FROM plans WHERE ownerId = ?', [id]).catch(() => { failed = true; }); - if (failed || !getNewAuthToken) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't get auth token."); + if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't delete plans."); - const newAuthToken = await getNewAuthToken.json(); - zohoHeaders.set('Authorization', `Zoho-oauthtoken ${newAuthToken.access_token}`); - zohoAuthExpireDT = nowDT + newAuthToken.expires_in * 1000 - 600000; + await dbClient.execute('DELETE FROM users WHERE id = ?', [id]).catch(() => { + failed = true; + }); + if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't delete user."); + + return genericResponse(STATUS_CODE.OK, 'Deleted user and plans.'); + } else if (hasEmail && !deleteCode) { + const newDeleteCode = nanoid(); + await dbClient.execute('UPDATE users SET deleteCode = ? WHERE id = ?', [newDeleteCode, id]).catch(() => { + failed = true; + }); + if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't set deleteCode."); + + const nowDT = new Date().getTime(); + if (zohoAuthExpireDT < nowDT) { + const getNewAuthToken = await fetch( + `https://accounts.zoho.com/oauth/v2/token?client_id=${config.email.clientId}&client_secret=${config.email.clientSecret}&grant_type=client_credentials&scope=ZohoMail.messages.CREATE`, + { method: 'POST' }, + ).catch(() => { + failed = true; + }); + if (failed || !getNewAuthToken) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't get auth token."); + + const newAuthToken = await getNewAuthToken.json(); + zohoHeaders.set('Authorization', `Zoho-oauthtoken ${newAuthToken.access_token}`); + zohoAuthExpireDT = nowDT + newAuthToken.expires_in * 1000 - 600000; + } + + const sendEmailReq = await fetch(`https://mail.zoho.com/api/accounts/${config.email.accountId}/messages`, { + method: 'POST', + headers: zohoHeaders, + body: JSON.stringify({ + fromAddress: config.email.address, + toAddress: email, + subject: 'XIVPlan+DB Delete Code', + content: `Notice: account deletion is permanent and will delete all plans saved under your account.

Please use the following Delete Code to delete your account:

${newDeleteCode}`, + }), + }).catch(() => { + failed = true; + }); + if (failed || !sendEmailReq) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't send email."); + + const sentEmail = await sendEmailReq.json(); + if (sentEmail.status.code !== 200) return genericResponse(STATUS_CODE.InternalServerError, 'Failed to send email.'); + + const maskedEmail = `${email.slice(0, 2)}***@***${email.slice(-5)}`; + fetch(config.discordWebhook, { + method: 'POST', + headers: discordHeaders, + body: JSON.stringify({ content: `Delete code email has been sent to \`${maskedEmail}\`.` }), + }).catch(() => {}); + return genericResponse(STATUS_CODE.PreconditionFailed, `Please resubmit with the confirmation code emailed to "${maskedEmail}".`); + } else if (hasEmail && body.deleteCode !== deleteCode) { + return genericResponse(STATUS_CODE.BadRequest, 'Invalid delete code.'); + } else { + return genericResponse(STATUS_CODE.InternalServerError, 'How are you here?'); } - - const sendEmailReq = await fetch(`https://mail.zoho.com/api/accounts/${config.email.accountId}/messages`, { - method: 'POST', - headers: zohoHeaders, - body: JSON.stringify({ - fromAddress: config.email.address, - toAddress: email, - subject: 'XIVPlan+DB Delete Code', - content: `Notice: account deletion is permanent and will delete all plans saved under your account.

Please use the following Delete Code to delete your account:

${newDeleteCode}`, - }), - }).catch(() => { + } else if (path.startsWith('/delete/')) { + const planId = path.replace('/delete/', ''); + const planMatch = await dbClient.query('SELECT ownerId FROM plans WHERE id = ?', [planId]).catch(() => { failed = true; }); - if (failed || !sendEmailReq) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't send email."); + if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't read DB."); + if (!planMatch.length) return genericResponse(STATUS_CODE.NotFound, 'Plan ID does not exist.'); + if (planMatch[0].ownerId !== id) return genericResponse(STATUS_CODE.Forbidden, "You don't own this plan."); - const sentEmail = await sendEmailReq.json(); - if (sentEmail.status.code !== 200) return genericResponse(STATUS_CODE.InternalServerError, 'Failed to send email.'); - - const maskedEmail = `${email.slice(0, 2)}***@***${email.slice(-5)}`; - fetch(config.discordWebhook, { - method: 'POST', - headers: discordHeaders, - body: JSON.stringify({ content: `Delete code email has been sent to \`${maskedEmail}\`.` }), - }).catch(() => {}); - return genericResponse(STATUS_CODE.PreconditionFailed, `Please resubmit with the confirmation code emailed to "${maskedEmail}".`); - } else if (hasEmail && body.deleteCode !== deleteCode) { - return genericResponse(STATUS_CODE.BadRequest, 'Invalid delete code.'); - } else { - return genericResponse(STATUS_CODE.InternalServerError, 'How are you here?'); + await dbClient.execute('UPDATE plans SET deleted = 1 WHERE id = ?', [planId]).catch(() => { + failed = true; + }); + if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't update DB."); + return genericResponse(STATUS_CODE.OK, 'Plan deleted.'); } - } else if (path.startsWith('/delete/')) { - const planId = path.replace('/delete/', ''); - const planMatch = await dbClient.query('SELECT ownerId FROM plans WHERE id = ?', [planId]).catch(() => { - failed = true; - }); - if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't read DB."); - if (!planMatch.length) return genericResponse(STATUS_CODE.NotFound, 'Plan ID does not exist.'); - if (planMatch[0].ownerId !== id) return genericResponse(STATUS_CODE.Forbidden, "You don't own this plan."); - - await dbClient.execute('UPDATE plans SET deleted = 1 WHERE id = ?', [planId]).catch(() => { - failed = true; - }); - if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't update DB."); - return genericResponse(STATUS_CODE.OK, 'Plan deleted.'); - } - break; + break; + } } - } - return genericResponse(STATUS_CODE.NotImplemented); + return genericResponse(STATUS_CODE.NotImplemented); + } catch (_e) { + return genericResponse(STATUS_CODE.InternalServerError); + } });