UNPKG

http-up

Version:

Simple share folder via http with upload

117 lines (87 loc) 3.72 kB
/* const auth = require('basic-auth') const assert = require('assert') const timingSafeEqual = require('crypto').timingSafeEqual */ import auth from 'basic-auth'; import assert from 'assert'; let crypto; try { crypto = await import('node:crypto'); } catch (err) { console.error('node:crypto support is disabled!'); } // Credits for the actual algorithm go to github/@Bruce17 // Thanks to github/@hraban for making me implement this function safeCompare(userInput, secret) { const userInputLength = Buffer.byteLength(userInput); const secretLength = Buffer.byteLength(secret); const userInputBuffer = Buffer.alloc(userInputLength, 0, 'utf8'); userInputBuffer.write(userInput); const secretBuffer = Buffer.alloc(userInputLength, 0, 'utf8'); secretBuffer.write(secret); return !!(crypto.timingSafeEqual(userInputBuffer, secretBuffer) & (userInputLength === secretLength)); } function ensureFunction(option, defaultValue) { if (option == undefined) return function () { return defaultValue; }; if (typeof option != 'function') return function () { return option; }; return option; } // function buildMiddleware(options) { export function basicAuth3(options) { var challenge = options.challenge != undefined ? !!options.challenge : false; var users = options.users || {}; var authorizer = options.authorizer || staticUsersAuthorizer; var isAsync = options.authorizeAsync != undefined ? !!options.authorizeAsync : false; var getResponseBody = ensureFunction(options.unauthorizedResponse, ''); var realm = ensureFunction(options.realm); var disablePrefixUrls = options.disablePrefixUrls || []; assert(typeof users == 'object', 'Expected an object for the basic auth users, found ' + typeof users + ' instead'); assert(typeof authorizer == 'function', 'Expected a function for the basic auth authorizer, found ' + typeof authorizer + ' instead'); function staticUsersAuthorizer(username, password) { for (var i in users) if (safeCompare(username, i) & safeCompare(password, users[i])) return true; return false; } return function authMiddleware(req, res, next) { var authentication = auth(req); for (var i = 0; i < disablePrefixUrls.length; i++) { var s = disablePrefixUrls[i]; if (req.path.startsWith(s)) { return next(); } } if (!authentication) return unauthorized(); req.auth = { user: authentication.name, password: authentication.pass, }; if (isAsync) return authorizer(authentication.name, authentication.pass, authorizerCallback); else if (!authorizer(authentication.name, authentication.pass)) return unauthorized(); return next(); function unauthorized() { if (challenge) { var challengeString = 'Basic'; var realmName = realm(req); if (realmName) challengeString += ' realm="' + realmName + '"'; res.set('WWW-Authenticate', challengeString); } //TODO: Allow response body to be JSON (maybe autodetect?) const response = getResponseBody(req, res); if (typeof response == 'string') return res.status(401).send(response); return res.status(401).json(response); } function authorizerCallback(err, approved) { assert.ifError(err); if (approved) return next(); return unauthorized(); } }; } //buildMiddleware.safeCompare = safeCompare //module.exports = buildMiddleware