syndicate-js/packages/core/src/transport/sturdy.ts

77 lines
2.8 KiB
TypeScript

//---------------------------------------------------------------------------
// @syndicate-lang/core, an implementation of Syndicate dataspaces for JS.
// Copyright (C) 2016-2021 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//---------------------------------------------------------------------------
// Basically Macaroons [1] in a Dataspace context
//
// [1]: Birgisson, Arnar, Joe Gibbs Politz, Úlfar Erlingsson, Ankur
// Taly, Michael Vrable, and Mark Lentczner. “Macaroons: Cookies with
// Contextual Caveats for Decentralized Authorization in the Cloud.”
// In Network and Distributed System Security Symposium. San Diego,
// California: Internet Society, 2014.
import { mac } from './cryptography.js';
import { Bytes, decode, encode, is, neverEmbeddedType, Value } from '@preserves/core';
import * as S from '../gen/sturdy.js';
export * from '../gen/sturdy.js';
export type SturdyValue = Value<S._embedded>;
export const KEY_LENGTH = 16; // 128 bits
export function embeddedNotAllowed(): never {
throw new Error("Embedded Ref not permitted in SturdyRef");
}
export function sturdyEncode(v: SturdyValue): Bytes {
return encode<S._embedded>(v, {
canonical: true,
includeAnnotations: false,
embeddedEncode: neverEmbeddedType,
});
}
export function sturdyDecode(bs: Bytes): SturdyValue {
return decode<S._embedded>(bs, {
includeAnnotations: false,
embeddedDecode: neverEmbeddedType,
});
}
export async function mint(oid: SturdyValue, secretKey: Bytes): Promise<S.SturdyRef> {
return S.SturdyRef({
oid,
caveatChain: [],
sig: await mac(secretKey, sturdyEncode(oid)),
});
}
export async function attenuate(r: S.SturdyRef, ... a: S.Attenuation): Promise<S.SturdyRef> {
return S.SturdyRef({
oid: r.oid,
caveatChain: [... r.caveatChain, a],
sig: await mac(r.sig, sturdyEncode(S.fromAttenuation(a)))
});
}
export async function validate(r: S.SturdyRef, secretKey: Bytes): Promise<boolean> {
const sig = await r.caveatChain.reduce(
async (sig, a) => mac(await sig, sturdyEncode(S.fromAttenuation(a))),
mac(secretKey, sturdyEncode(r.oid)));
return is(sig, r.sig);
}