Repair noise session introduction

This commit is contained in:
Tony Garnock-Jones 2024-03-28 16:30:27 +01:00
parent bfef60eaa9
commit cbcd4b9ad9
1 changed files with 89 additions and 81 deletions

View File

@ -232,33 +232,90 @@ export function boot(ds = Dataspace.global, debug: boolean = false, WebSocketCon
if (!origin0 || !isEmbedded(origin0)) return;
const origin = origin0;
const spec = Q.drop_lit(detailPatValue, N.toNoisePathStepDetail);
if (!spec) return;
const spec0 = Q.drop_lit(detailPatValue, N.toNoisePathStepDetail);
if (!spec0) return;
const spec = spec0;
const algorithms = SaltyCrypto.Noise_25519_ChaChaPoly_BLAKE2s;
const protocol =
spec.protocol._variant === "present" ? spec.protocol.protocol :
spec.protocol._variant === "absent" ? N.fromDefaultProtocol(N.DefaultProtocol()) as string :
(() => { throw new Error("Invalid noise protocol name"); })();
const patternName = SaltyCrypto.matchPattern(algorithms, protocol);
if (patternName === null) throw new Error("Unsupported protocol " + protocol);
const patternName0 = SaltyCrypto.matchPattern(algorithms, protocol);
if (patternName0 === null) throw new Error("Unsupported protocol " + protocol);
const patternName = patternName0;
const preSharedKeys =
spec.preSharedKeys._variant === "present" ? spec.preSharedKeys.preSharedKeys :
spec.preSharedKeys._variant === "absent" ? [] :
(() => { throw new Error("Invalid pre-shared keys"); })();
const prologue = underlying(canonicalEncode(spec.service));
let H: SaltyCrypto.Handshake | null = null;
let transportState: SaltyCrypto.TransportState | null = null;
let responderSession: Ref | null = null;
let relay: Relay.Relay | null = null;
function maybeTransition(s: SaltyCrypto.TransportState | null) {
if (transportState !== null) {
throw new Error("Unexpected double-transition to transport state");
react {
at origin {
assert G.Resolve({
"step": G.Step({
"stepType": N.$noise,
"detail": fromJS(N.ServiceSelector(spec.service)),
}),
"observer": create assertionFacetObserver(e => {
const response = G.toResolved(e);
if (!response) return;
switch (response._variant) {
case "accepted":
runSession(response.responderSession);
break;
case "Rejected":
stop {
at ds {
assert G.ResolvedPathStep<Ref>({
"origin": origin,
"pathStep": G.PathStep({
"stepType": N.$noise,
"detail": fromJS(N.NoisePathStepDetail(spec)),
}),
"resolved": response,
});
}
}
}
}),
});
}
transportState = s;
if (transportState !== null) {
}
function runSession(responderSession: Ref) {
const H = new SaltyCrypto.Handshake(
algorithms,
patternName,
'initiator',
{
prologue,
remoteStaticPublicKey: underlying(spec.key),
preSharedKeys: preSharedKeys.map(underlying),
});
let transportState: SaltyCrypto.TransportState | null = null;
let relay: Relay.Relay | null = null;
const { packet, finished } = H.writeMessage(new Uint8Array());
at responderSession {
assert N.Initiator(create ({ message: handlePacket }));
send message Bytes.from(packet);
}
maybeTransition(finished);
function maybeTransition(s: SaltyCrypto.TransportState | null) {
if (transportState !== null) {
throw new Error("Unexpected double-transition to transport state");
}
transportState = s;
if (transportState !== null) {
actuallyTransition();
}
}
function actuallyTransition() {
const noiseSessionFacet = Turn.activeFacet;
const peer = new Relay.Relay({
debug,
@ -283,74 +340,25 @@ export function boot(ds = Dataspace.global, debug: boolean = false, WebSocketCon
"resolved": G.Resolved.accepted(peer),
});
}
}
react {
at origin {
assert G.Resolve({
"step": G.Step({
"stepType": N.$noise,
"detail": fromJS(N.ServiceSelector(spec.service)),
}),
"observer": create ({
... assertionFacetObserver(e => {
const response = G.toResolved(e);
if (!response) return;
switch (response._variant) {
case "accepted":
H = new SaltyCrypto.Handshake(
algorithms,
patternName,
'initiator',
{
prologue,
remoteStaticPublicKey: underlying(spec.key),
preSharedKeys: preSharedKeys.map(underlying),
});
transportState = null;
responderSession = response.responderSession;
const { packet, finished } = H.writeMessage(new Uint8Array());
at responderSession {
send message Bytes.from(packet);
}
maybeTransition(finished);
break;
case "Rejected":
stop {
at ds {
assert G.ResolvedPathStep<Ref>({
"origin": origin,
"pathStep": G.PathStep({
"stepType": N.$noise,
"detail": fromJS(N.NoisePathStepDetail(spec)),
}),
"resolved": response,
});
}
}
}
}),
message(body: Assertion) {
const p = N.asPacket(body);
if (transportState) {
const packet = transportState.recv.decrypt_large(
p._variant === 'complete'
? [underlying(p.value)]
: p.value.map(underlying));
relay!.accept(packet);
} else {
if (p._variant !== 'complete') {
throw new Error("Unexpected fragmentation in handshake");
}
const { message, finished } = H!.readMessage(underlying(p.value));
if (message.byteLength !== 0) {
throw new Error("Unexpected payload during handshake");
}
maybeTransition(finished);
}
},
}),
});
function handlePacket(body: Assertion) {
const p = N.asPacket(body);
if (transportState) {
const packet = transportState.recv.decrypt_large(
p._variant === 'complete'
? [underlying(p.value)]
: p.value.map(underlying));
relay!.accept(packet);
} else {
if (p._variant !== 'complete') {
throw new Error("Unexpected fragmentation in handshake");
}
const { message, finished } = H!.readMessage(underlying(p.value));
if (message.byteLength !== 0) {
throw new Error("Unexpected payload during handshake");
}
maybeTransition(finished);
}
}
}
}