From be8643e923e1f04ed451de4c211f64801b216ef3 Mon Sep 17 00:00:00 2001 From: Bruno Bernardino Date: Mon, 1 May 2023 11:35:53 +0100 Subject: [PATCH] Validate basic email requirements + cleanup expired accounts sooner --- crons/cleanup.ts | 6 +++--- pages/api/user.ts | 6 +++++- public/ts/utils.ts | 12 ++++++++++++ public/ts/utils_test.ts | 18 +++++++++++++++++- 4 files changed, 37 insertions(+), 5 deletions(-) diff --git a/crons/cleanup.ts b/crons/cleanup.ts index 1e07ad0..15f43a8 100644 --- a/crons/cleanup.ts +++ b/crons/cleanup.ts @@ -24,13 +24,13 @@ async function cleanupSessions() { } async function cleanupInactiveUsers() { - const thirtyDaysAgo = new Date(new Date().setUTCDate(new Date().getUTCDate() - 30)); + const sevenDaysAgo = new Date(new Date().setUTCDate(new Date().getUTCDate() - 7)); try { const result = await db.query>( - sql`SELECT "id" FROM "budgetzen_users" WHERE "status" = 'inactive' AND "subscription" ->> 'expires_at' <= $1`, + sql`SELECT "id" FROM "budgetzen_users" WHERE "status" IN ('inactive', 'trial') AND "subscription" ->> 'expires_at' <= $1`, [ - thirtyDaysAgo.toISOString().substring(0, 10), + sevenDaysAgo.toISOString().substring(0, 10), ], ); diff --git a/pages/api/user.ts b/pages/api/user.ts index 4b25e15..a624339 100644 --- a/pages/api/user.ts +++ b/pages/api/user.ts @@ -18,7 +18,7 @@ import { sendVerifyUpdateEmailEmail, sendVerifyUpdatePasswordEmail, } from '/lib/providers/postmark.ts'; -import { SupportedCurrencySymbol } from '/public/ts/utils.ts'; +import { SupportedCurrencySymbol, validateEmail } from '/public/ts/utils.ts'; async function createUserAction(request: Request) { const { email, encrypted_key_pair }: { email: string; encrypted_key_pair: EncryptedData } = await request.json(); @@ -27,6 +27,10 @@ async function createUserAction(request: Request) { return new Response('Bad Request', { status: 400 }); } + if (!validateEmail(email)) { + return new Response('Bad Request', { status: 400 }); + } + const existingUserByEmail = await getUserByEmail(email); if (existingUserByEmail) { diff --git a/public/ts/utils.ts b/public/ts/utils.ts index e7908a1..a76e71d 100644 --- a/public/ts/utils.ts +++ b/public/ts/utils.ts @@ -975,3 +975,15 @@ export function debounce(callback: any, waitInMs: number) { }, waitInMs); }; } + +export function validateEmail(email: string) { + const trimmedEmail = (email || '').trim().toLocaleLowerCase(); + if (!trimmedEmail) { + return false; + } + + const requiredCharsNotInEdges = ['@', '.']; + return requiredCharsNotInEdges.every((char) => + trimmedEmail.includes(char) && !trimmedEmail.startsWith(char) && !trimmedEmail.endsWith(char) + ); +} diff --git a/public/ts/utils_test.ts b/public/ts/utils_test.ts index 2019b24..34f37eb 100644 --- a/public/ts/utils_test.ts +++ b/public/ts/utils_test.ts @@ -1,5 +1,5 @@ import { assertEquals } from 'std/testing/asserts.ts'; -import { dateDiffInDays, formatNumber, SupportedCurrencySymbol } from './utils.ts'; +import { dateDiffInDays, formatNumber, SupportedCurrencySymbol, validateEmail } from './utils.ts'; Deno.test('that dateDiffInDays works', () => { const tests = [ @@ -53,3 +53,19 @@ Deno.test('that formatNumber works', () => { assertEquals(result, test.expected); } }); + +Deno.test('that validateEmail works', () => { + const tests: { email: string; expected: boolean }[] = [ + { email: 'user@example.com', expected: true }, + { email: 'u@e.c', expected: true }, + { email: 'user@example.', expected: false }, + { email: '@example.com', expected: false }, + { email: 'user@example.', expected: false }, + { email: 'ABC', expected: false }, + ]; + + for (const test of tests) { + const result = validateEmail(test.email); + assertEquals(result, test.expected); + } +});