import { Scope } from "../types"; export default class AuthenticationHelper { /** * The mapping of method names to their scopes, anything not listed here * defaults to `Scope.Write`. * * - `documents.create` -> `Scope.Create` * - `documents.list` -> `Scope.Read` * - `documents.info` -> `Scope.Read` */ private static methodToScope = { create: Scope.Create, config: Scope.Read, list: Scope.Read, info: Scope.Read, search: Scope.Read, documents: Scope.Read, export: Scope.Read, }; /** * Returns whether the given path can be accessed with any of the scopes. We * support scopes in the formats of: * * - `/api/namespace.method` * - `namespace:scope` * - `scope` * * @param path The path to check * @param scopes The scopes to check * @returns True if the path can be accessed */ public static canAccess = (path: string, scopes: string[]) => { // strip any query string, this is never used as part of scope matching path = path.split("?")[0]; const resource = path.split("/").pop() ?? ""; const [namespace, method] = resource.split("."); return scopes.some((scope) => { const [scopeNamespace, scopeMethod] = scope.match(/[:\.]/g) ? scope.replace("/api/", "").split(/[:\.]/g) : ["*", scope]; const isRouteScope = scope.startsWith("/api/"); if (isRouteScope) { return ( (namespace === scopeNamespace || scopeNamespace === "*") && (method === scopeMethod || scopeMethod === "*") ); } return ( (namespace === scopeNamespace || scopeNamespace === "*") && (scopeMethod === Scope.Write || this.methodToScope[method as keyof typeof this.methodToScope] === scopeMethod) ); }); }; }