UNPKG

jinaga

Version:

Data management for web and mobile applications.

103 lines 5.39 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AuthorizationEngine = exports.Forbidden = void 0; const hash_1 = require("../fact/hash"); const sorter_1 = require("../fact/sorter"); const storage_1 = require("../storage"); const fn_1 = require("../util/fn"); const trace_1 = require("../util/trace"); class Forbidden extends Error { constructor(message) { const trueProto = new.target.prototype; super(message); this.__proto__ = trueProto; } } exports.Forbidden = Forbidden; class AuthorizationEngine { constructor(authorizationRules, store) { this.authorizationRules = authorizationRules; this.store = store; } authorizeFacts(factEnvelopes, userFact) { return __awaiter(this, void 0, void 0, function* () { const facts = factEnvelopes.map(e => e.fact); const existing = yield this.store.whichExist(facts); const sorter = new sorter_1.TopologicalSorter(); const userKeys = (userFact && userFact.fields.hasOwnProperty("publicKey")) ? [userFact.fields.publicKey] : []; const results = yield (0, fn_1.mapAsync)(sorter.sort(facts, (p, f) => this.visit(p, f, userKeys, facts, factEnvelopes, existing)), x => x); const rejected = results.filter(r => r.verdict === "Reject"); if (rejected.length > 0) { const distinctTypes = rejected .map(r => r.fact.type) .filter(fn_1.distinct) .join(", "); const count = rejected.length === 1 ? "1 fact" : `${rejected.length} facts`; const message = `Rejected ${count} of type ${distinctTypes}.`; throw new Forbidden(message); } return results; }); } visit(predecessors, fact, userKeys, factRecords, factEnvelopes, existing) { return __awaiter(this, void 0, void 0, function* () { const predecessorResults = yield (0, fn_1.mapAsync)(predecessors, p => p); if (predecessorResults.some(p => p.verdict === "Reject")) { const predecessor = predecessorResults .filter(p => p.verdict === "Reject") .map(p => p.fact.type) .join(', '); trace_1.Trace.warn(`The fact ${fact.type} cannot be authorized because its predecessor ${predecessor} is not authorized.`); return { fact, verdict: "Reject" }; } if (!(0, hash_1.verifyHash)(fact)) { const computedHash = (0, hash_1.computeHash)(fact.fields, fact.predecessors); trace_1.Trace.warn(`The hash of ${fact.type} does not match: computed ${computedHash}, provided ${fact.hash}.`); return { fact, verdict: "Reject" }; } if (existing.some((0, storage_1.factReferenceEquals)(fact))) { return { fact, verdict: "Existing" }; } const envelope = factEnvelopes.find((0, storage_1.factEnvelopeEquals)(fact)); const envelopeKeys = envelope ? envelope.signatures.map(s => s.publicKey) : []; const candidateKeys = envelopeKeys.concat(userKeys); const population = yield this.authorizationRules.getAuthorizedPopulation(candidateKeys, fact, factRecords, this.store); if (population.quantifier === "none") { if (this.authorizationRules.hasRule(fact.type)) { trace_1.Trace.warn(`The user is not authorized to create a fact of type ${fact.type}.`); } else { trace_1.Trace.warn(`The fact ${fact.type} has no authorization rules.`); } return { fact, verdict: "Reject" }; } else if (population.quantifier === "some") { if (population.authorizedKeys.length === 0) { trace_1.Trace.warn(`The user is not authorized to create a fact of type ${fact.type}.`); return { fact, verdict: "Reject" }; } return { fact, verdict: "Accept", newPublicKeys: population.authorizedKeys }; } else if (population.quantifier === "everyone") { return { fact, verdict: "Accept", newPublicKeys: [] }; } else { const _exhaustiveCheck = population; throw new Error(`Unknown quantifier ${_exhaustiveCheck.quantifier}.`); } }); } } exports.AuthorizationEngine = AuthorizationEngine; //# sourceMappingURL=authorization-engine.js.map