@cocalc/server
Version:
CoCalc server functionality: functions used by either the hub and the next.js server
69 lines (59 loc) • 1.91 kB
text/typescript
import getPool from "@cocalc/database/pool";
import { generate } from "random-key";
import siteURL from "@cocalc/server/settings/site-url";
export async function getVerifyEmail(
email_address: string
): Promise<{ html: string; text: string }> {
const token = await getToken(email_address);
const site_url = await siteURL();
const url = `${site_url}/auth/verify/${token}?email=${encodeURIComponent(
email_address
)}`;
return body(url);
}
async function getToken(email_address: string): Promise<string> {
const pool = getPool();
const { rows } = await pool.query(
"SELECT account_id, email_address_challenge FROM accounts WHERE email_address=$1",
[email_address]
);
if (rows.length == 0) {
throw Error(`no account with email address "${email_address}"`);
}
const { account_id, email_address_challenge } = rows[0];
if (
email_address_challenge?.token &&
email_address_challenge.email == email_address
) {
// return the same token if there is one for the same email
return email_address_challenge.token;
}
const token = generate(16).toLowerCase();
const data = { email: email_address, token, time: new Date() };
await pool.query(
"UPDATE accounts SET email_address_challenge = $1::JSONB WHERE account_id = $2::UUID",
[data, account_id]
);
return token;
}
function body(url: string): { html: string; text: string } {
const html = `
<p style="margin-top:0;margin-bottom:20px;">
<strong>
Please <a href="${url}">verify your email address</a>!
</strong>
</p>
<p style="margin-top:0;margin-bottom:20px;">
If the above link does not work, please copy and paste the following
URL into a new browser tab:
</p>
<pre style="margin-top:10px;margin-bottom:10px;font-size:11px;">
${url}
</pre>
`;
const text = `
Please verify your email address by visiting the following URL in your web browser:
${url}
`;
return { html, text };
}