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);
+ }
});