@cerbos/embedded
Version:
Client library for interacting with embedded Cerbos policy decision points generated by Cerbos Hub from server-side Node.js and browser-based applications
160 lines • 6.03 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Bundle = void 0;
exports.download = download;
const core_1 = require("@cerbos/core");
const epdp_1 = require("./protobuf/cerbos/cloud/epdp/v1/epdp");
const request_1 = require("./protobuf/cerbos/request/v1/request");
const response_1 = require("./protobuf/cerbos/response/v1/response");
const response_2 = require("./response");
const slice_1 = require("./slice");
class Bundle {
etag;
exports;
decodeJWTPayload;
logger;
static async from(source, logger, userAgent, { decodeJWTPayload = cannotDecodeJWTPayload, defaultPolicyVersion, globals, lenientScopeSearch, now = Date.now, }) {
if (typeof source === "string" || source instanceof URL) {
source = await download(source, userAgent);
}
else {
source = await source;
}
const etag = source instanceof Response
? (source.headers.get("ETag") ?? undefined)
: undefined;
const exports = await instantiate(source, {
env: {
now: () => secondsSinceUnixEpoch(now()),
},
});
if (defaultPolicyVersion) {
const slice = slice_1.Slice.ofString(exports, defaultPolicyVersion);
exports.set_default_policy_version(slice.offset, slice.length);
}
if (globals) {
const slice = slice_1.Slice.ofJSON(exports, globals);
try {
exports.set_globals(slice.offset, slice.length);
}
finally {
slice.deallocate();
}
}
if (lenientScopeSearch) {
exports.set_lenient_scope_search(1);
}
return new Bundle(etag, exports, decodeJWTPayload, logger);
}
_metadata;
constructor(etag, exports, decodeJWTPayload, logger) {
this.etag = etag;
this.exports = exports;
this.decodeJWTPayload = decodeJWTPayload;
this.logger = logger;
}
get metadata() {
if (!this._metadata) {
const { commitHash, version, buildTimestamp, policies, sourceAttributes, } = epdp_1.Metadata.fromJSON(JSON.parse(slice_1.Slice.from(this.exports, this.exports.metadata()).text()));
this._metadata = {
commit: commitHash || version,
builtAt: new Date(buildTimestamp * 1000),
policies,
sourceAttributes: Object.fromEntries(Object.entries(sourceAttributes).map(([id, { attributes }]) => [
id,
attributes,
])),
};
}
return this._metadata;
}
async checkResources(request, headers) {
let response = undefined;
let auxData = undefined;
let error = undefined;
try {
const requestJSON = request_1.CheckResourcesRequest.toJSON(request);
if (requestJSON.auxData?.jwt) {
const jwt = requestJSON.auxData.jwt;
if (!jwt.keySetId) {
delete jwt.keySetId;
}
auxData = { jwt: await this.decodeJWTPayload(jwt) };
requestJSON.auxData = auxData;
}
const requestSlice = slice_1.Slice.ofJSON(this.exports, requestJSON);
let responseSlice;
try {
responseSlice = slice_1.Slice.from(this.exports, this.exports.check(requestSlice.offset, requestSlice.length));
}
finally {
requestSlice.deallocate();
}
let responseText;
try {
responseText = responseSlice.text();
}
finally {
responseSlice.deallocate();
}
try {
response = response_1.CheckResourcesResponse.fromJSON(JSON.parse(responseText));
}
catch {
throw core_1.NotOK.fromJSON(responseText);
}
return response;
}
catch (caught) {
error = caught;
throw caught;
}
finally {
if (this.logger) {
await this.logger.logCheckResources(request, auxData, headers, response, this.metadata, error);
}
if (response && !request.includeMeta) {
for (const result of response.results) {
result.meta = undefined;
}
}
}
}
}
exports.Bundle = Bundle;
function cannotDecodeJWTPayload() {
throw new Error("To decode JWTs from auxiliary data, you must provide a `decodeJWTPayload` function");
}
function secondsSinceUnixEpoch(date) {
const millisecondsSinceUnixEpoch = date instanceof Date ? date.getTime() : date;
return BigInt(Math.floor(millisecondsSinceUnixEpoch / 1000));
}
async function download(url, userAgent, request) {
const headers = new Headers(request?.headers);
headers.set("User-Agent", userAgent);
try {
return await fetch(url, { ...request, headers });
}
catch (error) {
const message = `Failed to download from ${url.toString()}`;
throw new Error(error instanceof Error ? `${message}: ${error.message}` : message, { cause: error });
}
}
async function instantiate(source, imports) {
if (source instanceof Response) {
return await instantiateStreaming(source, imports);
}
return instantiated(await WebAssembly.instantiate(source, imports));
}
async function instantiateStreaming(response, imports) {
if (!response.ok) {
(0, response_2.cancelBody)(response);
throw new Error(`Failed to download from ${response.url}: HTTP ${response.status}`);
}
return instantiated(await WebAssembly.instantiateStreaming(response, imports));
}
function instantiated(result) {
const { exports } = result instanceof WebAssembly.Instance ? result : result.instance;
return exports;
}
//# sourceMappingURL=bundle.js.map