UNPKG

ts-mls

Version:

[![CI](https://github.com/LukaJCB/ts-mls/actions/workflows/ci.yml/badge.svg)](https://github.com/LukaJCB/ts-mls/actions/workflows/ci.yml) [![npm version](https://badge.fury.io/js/ts-mls.svg)](https://badge.fury.io/js/ts-mls) [![Coverage Status](https://co

73 lines 3.79 kB
import { flatMapDecoder, mapDecoder, mapDecoders, succeedDecoder } from "./codec/tlsDecoder.js"; import { contramapEncoders } from "./codec/tlsEncoder.js"; import { decodeVarLenData, encodeVarLenData } from "./codec/variableLength.js"; import { decodeExternalSender } from "./externalSender.js"; import { decodeFramedContent, decodeFramedContentAuthData, encodeFramedContent, encodeFramedContentAuthData, } from "./framedContent.js"; import { CodecError, ValidationError } from "./mlsError.js"; import { getSignaturePublicKeyFromLeafIndex } from "./ratchetTree.js"; import { toLeafIndex } from "./treemath.js"; export const encodePublicMessageInfo = (info) => { switch (info.senderType) { case "member": return encodeVarLenData(info.membershipTag); case "external": case "new_member_proposal": case "new_member_commit": return new Uint8Array(); } }; export function decodePublicMessageInfo(senderType) { switch (senderType) { case "member": return mapDecoder(decodeVarLenData, (membershipTag) => ({ senderType, membershipTag, })); case "external": case "new_member_proposal": case "new_member_commit": return succeedDecoder({ senderType }); } } export const encodePublicMessage = contramapEncoders([encodeFramedContent, encodeFramedContentAuthData, encodePublicMessageInfo], (msg) => [msg.content, msg.auth, msg]); export const decodePublicMessage = flatMapDecoder(decodeFramedContent, (content) => mapDecoders([decodeFramedContentAuthData(content.contentType), decodePublicMessageInfo(content.sender.senderType)], (auth, info) => ({ ...info, content, auth, }))); export function findSignaturePublicKey(ratchetTree, groupContext, framedContent) { switch (framedContent.sender.senderType) { case "member": return getSignaturePublicKeyFromLeafIndex(ratchetTree, toLeafIndex(framedContent.sender.leafIndex)); case "external": { const sender = senderFromExtension(groupContext.extensions, framedContent.sender.senderIndex); if (sender === undefined) throw new ValidationError("Received external but no external_sender extension"); return sender.signaturePublicKey; } case "new_member_proposal": if (framedContent.contentType !== "proposal") throw new ValidationError("Received new_member_proposal but contentType is not proposal"); if (framedContent.proposal.proposalType !== "add") throw new ValidationError("Received new_member_proposal but proposalType was not add"); return framedContent.proposal.add.keyPackage.leafNode.signaturePublicKey; case "new_member_commit": { if (framedContent.contentType !== "commit") throw new ValidationError("Received new_member_commit but contentType is not commit"); if (framedContent.commit.path === undefined) throw new ValidationError("Commit contains no update path"); return framedContent.commit.path.leafNode.signaturePublicKey; } } } export function senderFromExtension(extensions, senderIndex) { const externalSenderExtensions = extensions.filter((ex) => ex.extensionType === "external_senders"); const externalSenderExtension = externalSenderExtensions[senderIndex]; if (externalSenderExtension !== undefined) { const externalSender = decodeExternalSender(externalSenderExtension.extensionData, 0); if (externalSender === undefined) throw new CodecError("Could not decode ExternalSender"); return externalSender[0]; } } //# sourceMappingURL=publicMessage.js.map