ValeriaVG/nomocms

View on GitHub
modules/account/lib/permissions.ts

Summary

Maintainability
A
0 mins
Test Coverage
B
84%
import { IncomingMessage } from "http";
import { BadRequest, UnauthorizedError } from "lib/errors";
import { Pool } from "pg";
import { getCurrentToken, getUserByToken } from "./token";
import { User } from "../types";
import { Ctx } from "api/http/router";

export enum Permission {
  all = 0b11111,
  delete = 0b10000,
  update = 0b01000,
  create = 0b00100,
  list = 0b00010,
  read = 0b00001,
  view = 0b00011,
}

export const checkPermission = async (
  db: Pool,
  {
    user,
    scope,
    permission,
  }: { user: User; scope: string; permission: Permission }
): Promise<boolean> => {
  if (user.isSuperUser) return true;
  const result = await db.query(
    `SELECT permissions FROM account_permissions WHERE account_id=$1 AND (scope=$2 OR scope='*')`,
    [user.id, scope]
  );
  if (!result.rowCount) return false;
  const [{ permissions }] = result.rows;
  return Boolean(permissions & permission);
};

export const ensureAccountPermission = async (
  {
    db,
    req,
  }: {
    db: Pool;
    req: IncomingMessage;
  },
  scope: string,
  permission: Permission
) => {
  const user = await ensureLoggedIn({ db, req });
  const hasPermission = await checkPermission(db, { user, scope, permission });
  if (!hasPermission) throw UnauthorizedError;
  return user;
};

export const ensureLoggedIn = async ({
  db,
  req,
}: {
  db: Pool;
  req: IncomingMessage;
}) => {
  const token = getCurrentToken(req);
  const user = await getUserByToken(db, token);
  if (!user) throw UnauthorizedError;
  return user;
};

export const ensureSelfOrAllowed = async (
  { db, req }: Ctx,
  id: string,
  permission: Permission
) => {
  if (!id) throw BadRequest;
  const user = await ensureLoggedIn({ db, req });
  const isAllowed =
    user.id === id ||
    (await checkPermission(db, {
      user,
      scope: "account",
      permission,
    }));
  if (!isAllowed) throw UnauthorizedError;
  return user;
};