UNPKG

smc-hub

Version:

CoCalc: Backend webserver component

77 lines (66 loc) 1.91 kB
/* * This file is part of CoCalc: Copyright © 2020 Sagemath, Inc. * License: AGPLv3 s.t. "Commons Clause" – see LICENSE.md for details */ /* Authentication. */ import { List, Map } from "immutable"; import basic_auth from "basic-auth"; import { verify } from "password-hash"; import { startswith } from "smc-util/misc"; import { Logger } from "./types"; export function is_authenticated(opts: { req: any; res: any; path: string; auth?: Map<string, any>; // immutable.js map -- {path:[{name:[string], pass:[password-hash]}, ...], ...} logger?: Logger; }): boolean { if (opts.auth == null) { return true; // no authentication needed } // strip any /'s from beginning of opts.path (auth path's are assumed relative) while (opts.path[0] === "/") { opts.path = opts.path.slice(1); } let auth_info: any = undefined; opts.auth.forEach(function (info, path: string): boolean | undefined { if (startswith(opts.path, path)) { auth_info = info; return false; } }); // break if (auth_info == null) { // don't need auth for this path return true; } if (!List.isList(auth_info)) { opts.res.statusCode = 401; opts.res.end( "auth is misconfigured -- invalid auth field in the public_paths database." ); return false; } const credentials = basic_auth(opts.req); let fail = true; if (credentials != null && credentials.name && credentials.pass) { for (let i = 0; i < auth_info.size; i++) { const x = auth_info.get(i); if (x.get("name") === credentials.name) { if (verify(credentials.pass, x.get("pass"))) { fail = false; } break; } } } if (fail) { opts.res.statusCode = 401; opts.res.setHeader("WWW-Authenticate", 'Basic realm="cocalc.com"'); opts.res.end("Access denied"); return false; } // access granted return true; }