💾 Archived View for iich.space › src › util › tokens.ts captured on 2022-03-01 at 16:00:15.

View Raw

More Information

⬅️ Previous capture (2021-12-03)

-=-=-=-=-=-=-

import { createHash } from 'crypto';

import { Status } from '@/gemini';
import { createLogger } from '@/log';
import { Handler } from '@/mission-control';

import db from '~/db';

const insertToken = db.prepare(
  'INSERT INTO tokens (token, timestamp) VALUES (?, ?)',
);
const queryToken = db.prepare('SELECT token FROM tokens WHERE token = ?');
const tokenCount = db.prepare('SELECT COUNT(*) AS count FROM tokens');
const removeToken = db.prepare('DELETE FROM tokens WHERE token = ?');
const removeTokens = db.prepare('DELETE FROM tokens WHERE timestamp < ?');

export const createToken = (): string => {
  const hash = createHash('sha256');
  hash.update(process.env.SALT! + Date.now() + Math.random());
  const token = hash.digest('hex').slice(0, 8);
  insertToken.run(token, Math.floor(Date.now() / 1000));
  return token;
};

export const useToken = (token: string): boolean => {
  const tokenExists = queryToken.get(token) !== undefined;

  if (tokenExists) {
    removeToken.run(token);
    return true;
  }
  return false;
};

export const withValidToken: Handler = (_, res, { params }) => {
  if (useToken(params.token) === false) {
    res.sendStatus(Status.PERMANENT_FAILURE, 'Invalid Token');
    return res.end();
  }
};

const log = createLogger();

export const purgeStaleTokens = (): void => {
  const stale = Date.now() / 1000 - 6 * 60 * 60;
  const count = tokenCount.get().count;
  const query = removeTokens.run(stale);

  log.info(`purged ${query.changes}/${count} tokens`);
};

let interval: NodeJS.Timer;

export const startPurgeJob = (): void => {
  log.info('starting job');
  interval = setInterval(purgeStaleTokens, 30 * 60 * 1000);
};

export const stopPurgeJob = (): void => {
  clearInterval(interval);
};