UNPKG

@cocalc/server

Version:

CoCalc server functionality: functions used by either the hub and the next.js server

61 lines (54 loc) 2.29 kB
/* * This file is part of CoCalc: Copyright © 2021 Sagemath, Inc. * License: AGPLv3 s.t. "Commons Clause" – see LICENSE.md for details */ /* Enforce limits on the number of that a user can cause to be sent. For now starting with a simple limit: at most XXX messages per day. */ const DAILY_LIMIT = 1000; import { pii_retention_to_future } from "@cocalc/database/postgres/pii"; import getPool from "@cocalc/database/pool"; import { getServerSettings } from "@cocalc/server/settings"; // Call this function whenever an email will be sent on behalf of the given account. // It will increment a counter for each day, and if it goes too high it throws // an exceptions, which prevents further emais from being sent for that user. export default async function sendEmailThrottle( id?: string // account_id or project_id or organization_id... ): Promise<void> { if (!id) return; // not associated to a particular user const day = startOfToday(); // get current count const pool = getPool("short"); // a few seconds old is ok... const { rows } = await pool.query( "SELECT count FROM email_counter WHERE time=$1 AND id=$2", [day, id] ); if (rows.length > 0 && rows[0].count > DAILY_LIMIT) { throw Error( `You may send at most ${DAILY_LIMIT} emails per day, and you have reached that limit.` ); } // Increment the counter. if (rows.length > 0) { // This will always work with no race conditions, since the given entry exists. await pool.query( "UPDATE email_counter SET count = count + 1 WHERE id=$1 AND time=$2", [id, day] ); } else { const settings = await getServerSettings(); const expire = pii_retention_to_future(settings.pii_retention ?? false); // It's possible another server created email_counter in the meantime, // hence the "ON CONFLICT". await pool.query( "INSERT INTO email_counter (id,time,count,expire) VALUES($1,$2,1,$3) ON CONFLICT (id, time) DO UPDATE SET count = excluded.count + 1", [id, day, expire] ); } } function startOfToday(): Date { // https://stackoverflow.com/questions/7195513/how-do-you-get-the-unix-timestamp-for-the-start-of-today-in-javascript const now = new Date(); return new Date(now.getFullYear(), now.getMonth(), now.getDate()); }