<commit_before>var debug = require('debug')('upcache:scope');

var jwt = require('jsonwebtoken');
var cookie = require('cookie');
var HttpError = require('http-errors');

var common = require('./common');

module.exports = function(obj) {
	return new Scope(obj);
};

function Scope(obj) {
	this.publicKeySent = false;
	this.config = Object.assign({
		algorithm: 'RS256'
	}, obj);
	this.init = this.init.bind(this);
	this.handshake = this.handshake.bind(this);
	this.parse = this.parse.bind(this);
}

Scope.headerHandshake = common.prefixHeader + '-Key-Handshake';
Scope.headerScope = common.prefixHeader + '-Scope';

function restrictionsByAction(action, list) {
	if (!action) return [];
	if (!Array.isArray(list)) list = [list];
	var metaAction = action == "read" ? "read" : "write";
	var i, item, hash = {};
	for (i=0; i < list.length; i++) {
		item = list[i];
		if (typeof item == "object") {
			if (item[action]) item = item[action];
			else if (item[metaAction]) item = item[metaAction];
			else continue;
		}
		if (item === true) return; // return nothing - an empty list would deny access
		hash[item] = true;
	}
	return Object.keys(hash);
}

function authorize(action, restrictions, user) {
	if (!action) return false;
	if (!restrictions) return true;
	var scopes = user && user.scopes;
	if (!scopes) scopes = {"": true};
	var failure = false;
	var i, label, grant, scope, mandatory, regstr;
	var grants = {};
	for (i=0; i < restrictions.length; i++) {
		grant = label = restrictions[i];
		mandatory = false;
		if (label[0] == "&") {
			mandatory = true;
			label = label.substring(1);
		}
		regstr = label.replace(/\*/g, '.*');
		if (regstr.length != label.length) {
			// wildcard
			var reg = new RegExp("^" + regstr + "$");
			if (Object.keys(scopes).some(function(scope) {
				var scopeObj = scopes[scope];
				if (scopeObj == true || scopeObj != null && scopeObj[action] == true) {
					return reg.test(scope);
				}
			})) {
				grants[grant] = true;
				continue;
			}
		} else {
			scope = scopes[label];
			if (scope === true || scope && scope[action]) {
				grants[grant] = true;
				continue;
			}
		}
		if (mandatory) {
			failure = true;
			break;
		}
	}
	grants = Object.keys(grants);
	if (failure || !grants.length) return false;
	// might be useful for optimizing first proxy response key
	// by sending actual scopes being granted, since the response key
	// will do the same job, given request bearer and restrictions list
	return grants;
}

Scope.prototype.headers = function(res, list) {
	if (list == null) list = [];
	else if (!Array.isArray(list)) list = [list];
	var cur = res.get(Scope.headerScope);
	if (cur) cur = cur.split(',').map(function(str) {
		return str.trim();
	});
	else cur = [];
	list.forEach(function(str) {
		str = str.trim();
		if (str && cur.includes(str) == false) cur.push(str);
	});
	res.set(Scope.headerScope, cur.join(', '));<commit_msg>scope.headers allows an object to get the list of keys<commit_after>var debug = require('debug')('upcache:scope');

var jwt = require('jsonwebtoken');
var cookie = require('cookie');
var HttpError = require('http-errors');

var common = require('./common');

module.exports = function(obj) {
	return new Scope(obj);
};

function Scope(obj) {
	this.publicKeySent = false;
	this.config = Object.assign({
		algorithm: 'RS256'
	}, obj);
	this.init = this.init.bind(this);
	this.handshake = this.handshake.bind(this);
	this.parse = this.parse.bind(this);
}

Scope.headerHandshake = common.prefixHeader + '-Key-Handshake';
Scope.headerScope = common.prefixHeader + '-Scope';

function restrictionsByAction(action, list) {
	if (!action) return [];
	if (!Array.isArray(list)) list = [list];
	var metaAction = action == "read" ? "read" : "write";
	var i, item, hash = {};
	for (i=0; i < list.length; i++) {
		item = list[i];
		if (typeof item == "object") {
			if (item[action]) item = item[action];
			else if (item[metaAction]) item = item[metaAction];
			else continue;
		}
		if (item === true) return; // return nothing - an empty list would deny access
		hash[item] = true;
	}
	return Object.keys(hash);
}

function authorize(action, restrictions, user) {
	if (!action) return false;
	if (!restrictions) return true;
	var scopes = user && user.scopes;
	if (!scopes) scopes = {"": true};
	var failure = false;
	var i, label, grant, scope, mandatory, regstr;
	var grants = {};
	for (i=0; i < restrictions.length; i++) {
		grant = label = restrictions[i];
		mandatory = false;
		if (label[0] == "&") {
			mandatory = true;
			label = label.substring(1);
		}
		regstr = label.replace(/\*/g, '.*');
		if (regstr.length != label.length) {
			// wildcard
			var reg = new RegExp("^" + regstr + "$");
			if (Object.keys(scopes).some(function(scope) {
				var scopeObj = scopes[scope];
				if (scopeObj == true || scopeObj != null && scopeObj[action] == true) {
					return reg.test(scope);
				}
			})) {
				grants[grant] = true;
				continue;
			}
		} else {
			scope = scopes[label];
			if (scope === true || scope && scope[action]) {
				grants[grant] = true;
				continue;
			}
		}
		if (mandatory) {
			failure = true;
			break;
		}
	}
	grants = Object.keys(grants);
	if (failure || !grants.length) return false;
	// might be useful for optimizing first proxy response key
	// by sending actual scopes being granted, since the response key
	// will do the same job, given request bearer and restrictions list
	return grants;
}

Scope.prototype.headers = function(res, list) {
	if (list == null) list = [];
	else if (typeof list == "string") list = [list];
	else if (typeof list == "object" && !Array.isArray(list)) list = Object.keys(list);
	var cur = res.get(Scope.headerScope);
	if (cur) cur = cur.split(',').map(function(str) {
		return str.trim();
	});
	else cur = [];
	list.forEach(function(str) {
		str = str.trim();
		if (str && cur.includes(str) == false) cur.push(str);
	});
	res.set(Scope.headerScope, cur.join(', '));
{'fraction_non_alphanumeric': 0.17413355874894337, 'fraction_numerical': 0.002366863905325444, 'mean_word_length': 3.72146847565842, 'pattern_counts': {'":': 2, '<': 7, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2286252', 'n_tokens_mistral': 2167, 'n_tokens_neox': 2008, 'n_words': 545}