@m-ld/gateway
Version:
m-ld gateway for services
86 lines • 7.62 kB
JavaScript
import { ClassicLevel } from 'classic-level';
import { clone as meldClone, propertyValue } from '@m-ld/m-ld';
import { AuthKey } from './AuthKey.js';
import { gatewayVocab } from '../data/index.js';
import { UserKey } from '../data/UserKey.js';
export class CloneFactory {
async clone(config, dataDir, principal) {
// noinspection JSCheckFunctionSignatures
const backend = new ClassicLevel(dataDir, { valueEncoding: 'buffer' });
const clone = await meldClone(backend, await this.remotes(config), config, new GatewayApp(config['@domain'], principal));
return [clone, backend];
}
/**
* @returns the subset of configuration that can be re-used by other engines
* cloning the same domains
*/
async reusableConfig(config, remotesAuth, who) {
const { networkTimeout, maxOperationSize, logLevel } = config;
return { networkTimeout, maxOperationSize, logLevel };
}
}
export class GatewayPrincipal {
/**
* @param id absolute principal IRI
* @param config
*/
constructor(id, config) {
/** We do not implement sign, it's delegated to the userKey */
this.sign = undefined;
this['@id'] = id;
this.authKey = AuthKey.fromString(config.auth.key);
this.userKey = UserKey.fromConfig(config);
this.signer = {
signData: data => this.userKey.sign(data, this.authKey),
signJwt: (payload, options) => this.userKey.signJwt(payload, this.authKey, options),
/** @returns Arguments for HTTP signing */
getSignHttpArgs: () => this.userKey.getSignHttpArgs(this.authKey)
};
}
}
export class GatewayApp {
constructor(domain, principal) {
this.principal = principal;
this.sign = (data) => ({
sig: this.principal.signer.signData(data),
pid: this.principal['@id']
});
if (principal?.signer != null) {
this.transportSecurity = {
wire: data => data,
sign: this.sign,
verify: GatewayApp.verify(domain)
};
}
// TODO: Security constraint: only gateway can add/remove users
}
/**
* @param {string} domain name
* @returns import('@m-ld/m-ld').MeldTransportSecurity['verify']
*/
static verify(domain) {
return async (data, attr, state) => {
// Load the declared user info from the data
const [keyid] = UserKey.splitSignature(attr.sig);
if (keyid == null)
throw new Error('Signature has no keyid');
// Gotcha: verify is called without a context; all IRIs must be absolute
const keyRef = UserKey.refFromKeyid(keyid, domain);
const exists = await state.ask({
'@where': { '@id': attr.pid, [gatewayVocab('key')]: keyRef }
});
if (!exists)
throw new Error(`Principal ${attr.pid} not found`);
const keySrc = await state.get(keyRef['@id']);
if (keySrc == null)
throw new Error('Signature key not found');
const userKey = new UserKey({
keyid: UserKey.keyidFromRef(keySrc),
publicKey: propertyValue(keySrc, gatewayVocab('public'), Uint8Array)
});
if (!userKey.verify(attr.sig, data))
throw new Error('Signature not valid');
};
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ2xvbmVGYWN0b3J5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2xpYi9DbG9uZUZhY3RvcnkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUM3QyxPQUFPLEVBQ3NCLEtBQUssSUFBSSxTQUFTLEVBQ0ssYUFBYSxFQUNoRSxNQUFNLFlBQVksQ0FBQztBQUNwQixPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQ3ZDLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUNoRCxPQUFPLEVBQUUsT0FBTyxFQUFpQixNQUFNLG9CQUFvQixDQUFDO0FBVTVELE1BQU0sT0FBZ0IsWUFBWTtJQUNoQyxLQUFLLENBQUMsS0FBSyxDQUNULE1BQXlCLEVBQ3pCLE9BQWUsRUFDZixTQUE0QjtRQUU1Qix5Q0FBeUM7UUFDekMsTUFBTSxPQUFPLEdBQUcsSUFBSSxZQUFZLENBQzlCLE9BQU8sRUFBRSxFQUFFLGFBQWEsRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDO1FBQ3hDLE1BQU0sS0FBSyxHQUFHLE1BQU0sU0FBUyxDQUMzQixPQUFPLEVBQ1AsTUFBTSxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxFQUMxQixNQUFNLEVBQ04sSUFBSSxVQUFVLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxFQUFFLFNBQVMsQ0FBQyxDQUFDLENBQUM7UUFDaEQsT0FBTyxDQUFDLEtBQUssRUFBRSxPQUFPLENBQUMsQ0FBQztJQUMxQixDQUFDO0lBY0Q7OztPQUdHO0lBQ0gsS0FBSyxDQUFDLGNBQWMsQ0FDbEIsTUFBeUIsRUFDekIsV0FBOEIsRUFDOUIsR0FBUztRQUVULE1BQU0sRUFBRSxjQUFjLEVBQUUsZ0JBQWdCLEVBQUUsUUFBUSxFQUFFLEdBQUcsTUFBTSxDQUFDO1FBQzlELE9BQU8sRUFBRSxjQUFjLEVBQUUsZ0JBQWdCLEVBQUUs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