From 8578d0f2fc173a98d536775ccaa71462b85fbc1c Mon Sep 17 00:00:00 2001 From: Anselm Date: Mon, 7 Aug 2023 17:52:58 +0100 Subject: [PATCH] Introduce coValue nicknames and change how agentIDs work --- src/coValue.test.ts | 12 +++--- src/coValue.ts | 36 +++++++++-------- src/contentType.test.ts | 10 ++--- src/crypto.test.ts | 36 ++++++++--------- src/node.ts | 1 + src/permissions.test.ts | 75 ++++++++++++++++++++--------------- src/permissions.ts | 3 +- src/sync.test.ts | 88 +++++++++++++++++++++++++++++++---------- 8 files changed, 161 insertions(+), 100 deletions(-) diff --git a/src/coValue.test.ts b/src/coValue.test.ts index fc78fba8c..618eaaaea 100644 --- a/src/coValue.test.ts +++ b/src/coValue.test.ts @@ -10,7 +10,7 @@ import { LocalNode } from "./node"; import { sign } from "./crypto"; test("Can create coValue with new agent credentials and add transaction to it", () => { - const agentCredential = newRandomAgentCredential(); + const agentCredential = newRandomAgentCredential("agent1"); const node = new LocalNode( agentCredential, newRandomSessionID(getAgentID(getAgent(agentCredential))) @@ -48,9 +48,8 @@ test("Can create coValue with new agent credentials and add transaction to it", }); test("transactions with wrong signature are rejected", () => { - const agent = newRandomAgentCredential(); - const wrongAgent = newRandomAgentCredential(); - const agentCredential = newRandomAgentCredential(); + const wrongAgent = newRandomAgentCredential("wrongAgent"); + const agentCredential = newRandomAgentCredential("agent1"); const node = new LocalNode( agentCredential, newRandomSessionID(getAgentID(getAgent(agentCredential))) @@ -88,8 +87,7 @@ test("transactions with wrong signature are rejected", () => { }); test("transactions with correctly signed, but wrong hash are rejected", () => { - const agent = newRandomAgentCredential(); - const agentCredential = newRandomAgentCredential(); + const agentCredential = newRandomAgentCredential("agent1"); const node = new LocalNode( agentCredential, newRandomSessionID(getAgentID(getAgent(agentCredential))) @@ -131,7 +129,7 @@ test("transactions with correctly signed, but wrong hash are rejected", () => { node.ownSessionID, [transaction], expectedNewHash, - sign(agent.signatorySecret, expectedNewHash) + sign(agentCredential.signatorySecret, expectedNewHash) ) ).toBe(false); }); diff --git a/src/coValue.ts b/src/coValue.ts index a6edc8753..5b2093de7 100644 --- a/src/coValue.ts +++ b/src/coValue.ts @@ -33,27 +33,32 @@ import { import { LocalNode } from "./node"; import { CoValueKnownState, NewContentMessage } from "./sync"; -export type RawCoValueID = `coval_${string}`; +export type RawCoValueID = `co_z${string}` | `co_${string}_z${string}`; export type CoValueHeader = { type: ContentType["type"]; ruleset: RulesetDef; meta: JsonValue; + publicNickname?: string; }; function coValueIDforHeader(header: CoValueHeader): RawCoValueID { const hash = shortHash(header); - return `coval_${hash.slice("shortHash_".length)}`; + if (header.publicNickname) { + return `co_${header.publicNickname}_z${hash.slice("shortHash_z".length)}`; + } else { + return `co_z${hash.slice("shortHash_z".length)}`; + } } -export type SessionID = `session_${string}_${AgentID}`; +export type SessionID = `${AgentID}_session_z${string}`; export function agentIDfromSessionID(sessionID: SessionID): AgentID { - return `agent_${sessionID.substring(sessionID.lastIndexOf("_") + 1)}`; + return sessionID.split("_session")[0] as AgentID; } export function newRandomSessionID(agentID: AgentID): SessionID { - return `session_${base58.encode(randomBytes(8))}_${agentID}`; + return `${agentID}_session_z${base58.encode(randomBytes(8))}`; } type SessionLog = { @@ -482,25 +487,26 @@ export class CoValue { return this.header.ruleset.type === "team" ? expectTeamContent(this.getCurrentContent()) .keys() - .filter((k): k is AgentID => k.startsWith("agent_")) - .map((agent) => agentIDAsCoValueID(agent)) + .filter((k): k is AgentID => k.startsWith("co_agent")) : this.header.ruleset.type === "ownedByTeam" ? [this.header.ruleset.team] : []; } } -export type AgentID = `agent_${string}`; +export type AgentID = `co_agent${string}_z${string}`; export type Agent = { signatoryID: SignatoryID; recipientID: RecipientID; + publicNickname?: string; }; export function getAgent(agentCredential: AgentCredential) { return { signatoryID: getSignatoryID(agentCredential.signatorySecret), recipientID: getRecipientID(agentCredential.recipientSecret), + publicNickname: agentCredential.publicNickname, }; } @@ -513,28 +519,24 @@ export function getAgentCoValueHeader(agent: Agent): CoValueHeader { initialRecipientID: agent.recipientID, }, meta: null, + publicNickname: "agent" + agent.publicNickname?.slice(0, 1).toUpperCase() + agent.publicNickname?.slice(1), }; } export function getAgentID(agent: Agent): AgentID { - return `agent_${coValueIDforHeader(getAgentCoValueHeader(agent)).slice( - "coval_".length - )}`; -} - -export function agentIDAsCoValueID(agentID: AgentID): RawCoValueID { - return `coval_${agentID.substring("agent_".length)}`; + return coValueIDforHeader(getAgentCoValueHeader(agent)) as AgentID; } export type AgentCredential = { signatorySecret: SignatorySecret; recipientSecret: RecipientSecret; + publicNickname?: string; }; -export function newRandomAgentCredential(): AgentCredential { +export function newRandomAgentCredential(publicNickname: string): AgentCredential { const signatorySecret = newRandomSignatory(); const recipientSecret = newRandomRecipient(); - return { signatorySecret, recipientSecret }; + return { signatorySecret, recipientSecret, publicNickname }; } // type Role = "admin" | "writer" | "reader"; diff --git a/src/contentType.test.ts b/src/contentType.test.ts index c1f313a89..53f253e30 100644 --- a/src/contentType.test.ts +++ b/src/contentType.test.ts @@ -8,7 +8,7 @@ import { import { LocalNode } from "./node"; test("Empty COJSON Map works", () => { - const agentCredential = newRandomAgentCredential(); + const agentCredential = newRandomAgentCredential("agent1"); const node = new LocalNode( agentCredential, newRandomSessionID(getAgentID(getAgent(agentCredential))) @@ -32,7 +32,7 @@ test("Empty COJSON Map works", () => { }); test("Can insert and delete Map entries in edit()", () => { - const agentCredential = newRandomAgentCredential(); + const agentCredential = newRandomAgentCredential("agent1"); const node = new LocalNode( agentCredential, newRandomSessionID(getAgentID(getAgent(agentCredential))) @@ -64,7 +64,7 @@ test("Can insert and delete Map entries in edit()", () => { }); test("Can get map entry values at different points in time", () => { - const agentCredential = newRandomAgentCredential(); + const agentCredential = newRandomAgentCredential("agent1"); const node = new LocalNode( agentCredential, newRandomSessionID(getAgentID(getAgent(agentCredential))) @@ -103,7 +103,7 @@ test("Can get map entry values at different points in time", () => { }); test("Can get all historic values of key", () => { - const agentCredential = newRandomAgentCredential(); + const agentCredential = newRandomAgentCredential("agent1"); const node = new LocalNode( agentCredential, newRandomSessionID(getAgentID(getAgent(agentCredential))) @@ -160,7 +160,7 @@ test("Can get all historic values of key", () => { }); test("Can get last tx ID for a key", () => { - const agentCredential = newRandomAgentCredential(); + const agentCredential = newRandomAgentCredential("agent1"); const node = new LocalNode( agentCredential, newRandomSessionID(getAgentID(getAgent(agentCredential))) diff --git a/src/crypto.test.ts b/src/crypto.test.ts index 3226ff6b0..fa04d4695 100644 --- a/src/crypto.test.ts +++ b/src/crypto.test.ts @@ -49,8 +49,8 @@ test("Sealing round-trips, but invalid receiver can't unseal", () => { const recipient3 = newRandomRecipient(); const nOnceMaterial = { - in: "coval_zTEST", - tx: { sessionID: "session_zTEST_agent_zTEST", txIndex: 0 }, + in: "co_zTEST", + tx: { sessionID: "co_agent_zTEST_session_zTEST", txIndex: 0 }, } as const; const sealed = seal( @@ -106,23 +106,23 @@ test("Encryption for transactions round-trips", () => { const { secret } = newRandomKeySecret(); const encrypted1 = encryptForTransaction({ a: "hello" }, secret, { - in: "coval_zTEST", - tx: { sessionID: "session_zTEST_agent_zTEST", txIndex: 0 }, + in: "co_zTEST", + tx: { sessionID: "co_agent_zTEST_session_zTEST", txIndex: 0 }, }); const encrypted2 = encryptForTransaction({ b: "world" }, secret, { - in: "coval_zTEST", - tx: { sessionID: "session_zTEST_agent_zTEST", txIndex: 1 }, + in: "co_zTEST", + tx: { sessionID: "co_agent_zTEST_session_zTEST", txIndex: 1 }, }); const decrypted1 = decryptForTransaction(encrypted1, secret, { - in: "coval_zTEST", - tx: { sessionID: "session_zTEST_agent_zTEST", txIndex: 0 }, + in: "co_zTEST", + tx: { sessionID: "co_agent_zTEST_session_zTEST", txIndex: 0 }, }); const decrypted2 = decryptForTransaction(encrypted2, secret, { - in: "coval_zTEST", - tx: { sessionID: "session_zTEST_agent_zTEST", txIndex: 1 }, + in: "co_zTEST", + tx: { sessionID: "co_agent_zTEST_session_zTEST", txIndex: 1 }, }); expect([decrypted1, decrypted2]).toEqual([{ a: "hello" }, { b: "world" }]); @@ -133,23 +133,23 @@ test("Encryption for transactions doesn't decrypt with a wrong key", () => { const { secret: secret2 } = newRandomKeySecret(); const encrypted1 = encryptForTransaction({ a: "hello" }, secret, { - in: "coval_zTEST", - tx: { sessionID: "session_zTEST_agent_zTEST", txIndex: 0 }, + in: "co_zTEST", + tx: { sessionID: "co_agent_zTEST_session_zTEST", txIndex: 0 }, }); const encrypted2 = encryptForTransaction({ b: "world" }, secret, { - in: "coval_zTEST", - tx: { sessionID: "session_zTEST_agent_zTEST", txIndex: 1 }, + in: "co_zTEST", + tx: { sessionID: "co_agent_zTEST_session_zTEST", txIndex: 1 }, }); const decrypted1 = decryptForTransaction(encrypted1, secret2, { - in: "coval_zTEST", - tx: { sessionID: "session_zTEST_agent_zTEST", txIndex: 0 }, + in: "co_zTEST", + tx: { sessionID: "co_agent_zTEST_session_zTEST", txIndex: 0 }, }); const decrypted2 = decryptForTransaction(encrypted2, secret2, { - in: "coval_zTEST", - tx: { sessionID: "session_zTEST_agent_zTEST", txIndex: 1 }, + in: "co_zTEST", + tx: { sessionID: "co_agent_zTEST_session_zTEST", txIndex: 1 }, }); expect([decrypted1, decrypted2]).toEqual([undefined, undefined]); diff --git a/src/node.ts b/src/node.ts index df50bd0f9..729171ce5 100644 --- a/src/node.ts +++ b/src/node.ts @@ -89,6 +89,7 @@ export class LocalNode { type: "comap", ruleset: { type: "team", initialAdmin: this.agentID }, meta: null, + publicNickname: "team", }); let teamContent = expectTeamContent(teamCoValue.getCurrentContent()); diff --git a/src/permissions.test.ts b/src/permissions.test.ts index 270c267b0..24742d980 100644 --- a/src/permissions.test.ts +++ b/src/permissions.test.ts @@ -17,7 +17,7 @@ import { function teamWithTwoAdmins() { const { team, admin, adminID } = newTeam(); - const otherAdmin = newRandomAgentCredential(); + const otherAdmin = newRandomAgentCredential("otherAdmin"); const otherAdminID = getAgentID(getAgent(otherAdmin)); let content = expectTeamContent(team.getCurrentContent()); @@ -38,7 +38,7 @@ function teamWithTwoAdmins() { } function newTeam() { - const admin = newRandomAgentCredential(); + const admin = newRandomAgentCredential("admin"); const adminID = getAgentID(getAgent(admin)); const node = new LocalNode(admin, newRandomSessionID(adminID)); @@ -47,6 +47,7 @@ function newTeam() { type: "comap", ruleset: { type: "team", initialAdmin: adminID }, meta: null, + publicNickname: "team" }); const teamContent = expectTeamContent(team.getCurrentContent()); @@ -64,7 +65,7 @@ test("Initial admin can add another admin to a team", () => { }); function newTeamHighLevel() { - const admin = newRandomAgentCredential(); + const admin = newRandomAgentCredential("admin"); const adminID = getAgentID(getAgent(admin)); const node = new LocalNode(admin, newRandomSessionID(adminID)); @@ -77,7 +78,7 @@ function newTeamHighLevel() { function teamWithTwoAdminsHighLevel() { const { admin, adminID, node, team } = newTeamHighLevel(); - const otherAdmin = newRandomAgentCredential(); + const otherAdmin = newRandomAgentCredential("otherAdmin"); const otherAdminID = getAgentID(getAgent(otherAdmin)); node.addKnownAgent(getAgent(otherAdmin)); @@ -103,7 +104,7 @@ test("Added admin can add a third admin to a team", () => { expect(otherContent.get(otherAdminID)).toEqual("admin"); - const thirdAdmin = newRandomAgentCredential(); + const thirdAdmin = newRandomAgentCredential("admin"); const thirdAdminID = getAgentID(getAgent(thirdAdmin)); otherContent.edit((editable) => { @@ -125,7 +126,7 @@ test("Added adming can add a third admin to a team (high level)", () => { newRandomSessionID(otherAdminID) ); - const thirdAdmin = newRandomAgentCredential(); + const thirdAdmin = newRandomAgentCredential("admin"); const thirdAdminID = getAgentID(getAgent(thirdAdmin)); node.addKnownAgent(getAgent(thirdAdmin)); @@ -187,7 +188,7 @@ test("Admins can't demote other admins in a team (high level)", () => { test("Admins an add writers to a team, who can't add admins, writers, or readers", () => { const { team } = newTeam(); - const writer = newRandomAgentCredential(); + const writer = newRandomAgentCredential("writer"); const writerID = getAgentID(getAgent(writer)); let teamContent = expectTeamContent(team.getCurrentContent()); @@ -211,7 +212,7 @@ test("Admins an add writers to a team, who can't add admins, writers, or readers expect(teamContentAsWriter.get(writerID)).toEqual("writer"); - const otherAgent = newRandomAgentCredential(); + const otherAgent = newRandomAgentCredential("otherAgent"); const otherAgentID = getAgentID(getAgent(otherAgent)); teamContentAsWriter.edit((editable) => { @@ -233,7 +234,7 @@ test("Admins an add writers to a team, who can't add admins, writers, or readers test("Admins an add writers to a team, who can't add admins, writers, or readers (high level)", () => { const { team, node } = newTeamHighLevel(); - const writer = newRandomAgentCredential(); + const writer = newRandomAgentCredential("writer"); const writerID = getAgentID(getAgent(writer)); node.addKnownAgent(getAgent(writer)); @@ -248,7 +249,7 @@ test("Admins an add writers to a team, who can't add admins, writers, or readers expect(teamAsWriter.teamMap.get(writerID)).toEqual("writer"); - const otherAgent = newRandomAgentCredential(); + const otherAgent = newRandomAgentCredential("otherAgent"); const otherAgentID = getAgentID(getAgent(otherAgent)); node.addKnownAgent(getAgent(otherAgent)); @@ -268,7 +269,7 @@ test("Admins an add writers to a team, who can't add admins, writers, or readers test("Admins can add readers to a team, who can't add admins, writers, or readers", () => { const { team } = newTeam(); - const reader = newRandomAgentCredential(); + const reader = newRandomAgentCredential("reader"); const readerID = getAgentID(getAgent(reader)); let teamContent = expectTeamContent(team.getCurrentContent()); @@ -292,7 +293,7 @@ test("Admins can add readers to a team, who can't add admins, writers, or reader expect(teamContentAsReader.get(readerID)).toEqual("reader"); - const otherAgent = newRandomAgentCredential(); + const otherAgent = newRandomAgentCredential("otherAgent"); const otherAgentID = getAgentID(getAgent(otherAgent)); teamContentAsReader.edit((editable) => { @@ -314,7 +315,7 @@ test("Admins can add readers to a team, who can't add admins, writers, or reader test("Admins can add readers to a team, who can't add admins, writers, or readers (high level)", () => { const { team, node } = newTeamHighLevel(); - const reader = newRandomAgentCredential(); + const reader = newRandomAgentCredential("reader"); const readerID = getAgentID(getAgent(reader)); node.addKnownAgent(getAgent(reader)); @@ -329,7 +330,7 @@ test("Admins can add readers to a team, who can't add admins, writers, or reader expect(teamAsReader.teamMap.get(readerID)).toEqual("reader"); - const otherAgent = newRandomAgentCredential(); + const otherAgent = newRandomAgentCredential("otherAgent"); const otherAgentID = getAgentID(getAgent(otherAgent)); node.addKnownAgent(getAgent(otherAgent)); @@ -354,6 +355,7 @@ test("Admins can write to an object that is owned by their team", () => { type: "comap", ruleset: { type: "ownedByTeam", team: team.id }, meta: null, + publicNickname: "childObject" }); let childContent = expectMap(childObject.getCurrentContent()); @@ -384,7 +386,7 @@ test("Admins can write to an object that is owned by their team (high level)", ( test("Writers can write to an object that is owned by their team", () => { const { node, team } = newTeam(); - const writer = newRandomAgentCredential(); + const writer = newRandomAgentCredential("writer"); const writerID = getAgentID(getAgent(writer)); expectTeamContent(team.getCurrentContent()).edit((editable) => { @@ -396,6 +398,7 @@ test("Writers can write to an object that is owned by their team", () => { type: "comap", ruleset: { type: "ownedByTeam", team: team.id }, meta: null, + publicNickname: "childObject" }); const childObjectAsWriter = childObject.testWithDifferentCredentials( @@ -420,7 +423,7 @@ test("Writers can write to an object that is owned by their team", () => { test("Writers can write to an object that is owned by their team (high level)", () => { const { node, team } = newTeamHighLevel(); - const writer = newRandomAgentCredential(); + const writer = newRandomAgentCredential("writer"); const writerID = getAgentID(getAgent(writer)); node.addKnownAgent(getAgent(writer)); @@ -446,7 +449,7 @@ test("Writers can write to an object that is owned by their team (high level)", test("Readers can not write to an object that is owned by their team", () => { const { node, team } = newTeam(); - const reader = newRandomAgentCredential(); + const reader = newRandomAgentCredential("reader"); const readerID = getAgentID(getAgent(reader)); expectTeamContent(team.getCurrentContent()).edit((editable) => { @@ -458,6 +461,7 @@ test("Readers can not write to an object that is owned by their team", () => { type: "comap", ruleset: { type: "ownedByTeam", team: team.id }, meta: null, + publicNickname: "childObject" }); const childObjectAsReader = childObject.testWithDifferentCredentials( @@ -482,7 +486,7 @@ test("Readers can not write to an object that is owned by their team", () => { test("Readers can not write to an object that is owned by their team (high level)", () => { const { node, team } = newTeamHighLevel(); - const reader = newRandomAgentCredential(); + const reader = newRandomAgentCredential("reader"); const readerID = getAgentID(getAgent(reader)); node.addKnownAgent(getAgent(reader)); @@ -533,6 +537,7 @@ test("Admins can set team read key and then use it to create and read private tr type: "comap", ruleset: { type: "ownedByTeam", team: team.id }, meta: null, + publicNickname: "childObject" }); let childContent = expectMap(childObject.getCurrentContent()); @@ -562,7 +567,7 @@ test("Admins can set team read key and then use it to create and read private tr test("Admins can set team read key and then writers can use it to create and read private transactions in owned objects", () => { const { node, team, admin } = newTeam(); - const writer = newRandomAgentCredential(); + const writer = newRandomAgentCredential("writer"); const writerID = getAgentID(getAgent(writer)); const { secret: readKey, id: readKeyID } = newRandomKeySecret(); @@ -591,6 +596,7 @@ test("Admins can set team read key and then writers can use it to create and rea type: "comap", ruleset: { type: "ownedByTeam", team: team.id }, meta: null, + publicNickname: "childObject" }); const childObjectAsWriter = childObject.testWithDifferentCredentials( @@ -617,7 +623,7 @@ test("Admins can set team read key and then writers can use it to create and rea test("Admins can set team read key and then writers can use it to create and read private transactions in owned objects (high level)", () => { const { node, team, admin } = newTeamHighLevel(); - const writer = newRandomAgentCredential(); + const writer = newRandomAgentCredential("writer"); const writerID = getAgentID(getAgent(writer)); node.addKnownAgent(getAgent(writer)); @@ -643,7 +649,7 @@ test("Admins can set team read key and then writers can use it to create and rea test("Admins can set team read key and then use it to create private transactions in owned objects, which readers can read", () => { const { node, team, admin } = newTeam(); - const reader = newRandomAgentCredential(); + const reader = newRandomAgentCredential("reader"); const readerID = getAgentID(getAgent(reader)); const { secret: readKey, id: readKeyID } = newRandomKeySecret(); @@ -672,6 +678,7 @@ test("Admins can set team read key and then use it to create private transaction type: "comap", ruleset: { type: "ownedByTeam", team: team.id }, meta: null, + publicNickname: "childObject" }); expectMap(childObject.getCurrentContent()).edit((editable) => { @@ -696,7 +703,7 @@ test("Admins can set team read key and then use it to create private transaction test("Admins can set team read key and then use it to create private transactions in owned objects, which readers can read (high level)", () => { const { node, team, admin } = newTeamHighLevel(); - const reader = newRandomAgentCredential(); + const reader = newRandomAgentCredential("reader"); const readerID = getAgentID(getAgent(reader)); node.addKnownAgent(getAgent(reader)); @@ -722,9 +729,9 @@ test("Admins can set team read key and then use it to create private transaction test("Admins can set team read key and then use it to create private transactions in owned objects, which readers can read, even with a separate later revelation for the same read key", () => { const { node, team, admin } = newTeam(); - const reader1 = newRandomAgentCredential(); + const reader1 = newRandomAgentCredential("reader1"); const reader1ID = getAgentID(getAgent(reader1)); - const reader2 = newRandomAgentCredential(); + const reader2 = newRandomAgentCredential("reader2"); const reader2ID = getAgentID(getAgent(reader2)); const { secret: readKey, id: readKeyID } = newRandomKeySecret(); @@ -772,6 +779,7 @@ test("Admins can set team read key and then use it to create private transaction type: "comap", ruleset: { type: "ownedByTeam", team: team.id }, meta: null, + publicNickname: "childObject" }); expectMap(childObject.getCurrentContent()).edit((editable) => { @@ -809,9 +817,9 @@ test("Admins can set team read key and then use it to create private transaction test("Admins can set team read key and then use it to create private transactions in owned objects, which readers can read, even with a separate later revelation for the same read key (high level)", () => { const { node, team, admin } = newTeamHighLevel(); - const reader1 = newRandomAgentCredential(); + const reader1 = newRandomAgentCredential("reader1"); const reader1ID = getAgentID(getAgent(reader1)); - const reader2 = newRandomAgentCredential(); + const reader2 = newRandomAgentCredential("reader2"); const reader2ID = getAgentID(getAgent(reader2)); node.addKnownAgent(getAgent(reader1)); @@ -872,6 +880,7 @@ test("Admins can set team read key, make a private transaction in an owned objec type: "comap", ruleset: { type: "ownedByTeam", team: team.id }, meta: null, + publicNickname: "childObject" }); let childContent = expectMap(childObject.getCurrentContent()); @@ -951,6 +960,7 @@ test("Admins can set team read key, make a private transaction in an owned objec type: "comap", ruleset: { type: "ownedByTeam", team: team.id }, meta: null, + publicNickname: "childObject" }); const teamContent = expectTeamContent(team.getCurrentContent()); @@ -984,7 +994,7 @@ test("Admins can set team read key, make a private transaction in an owned objec childContent = expectMap(childObject.getCurrentContent()); expect(childContent.get("foo")).toEqual("bar"); - const reader = newRandomAgentCredential(); + const reader = newRandomAgentCredential("reader"); const readerID = getAgentID(getAgent(reader)); const { secret: readKey2, id: readKeyID2 } = newRandomKeySecret(); @@ -1064,7 +1074,7 @@ test("Admins can set team read key, make a private transaction in an owned objec expect(childObject.coValue.getCurrentReadKey()).not.toEqual(firstReadKey); - const reader = newRandomAgentCredential(); + const reader = newRandomAgentCredential("reader"); const readerID = getAgentID(getAgent(reader)); node.addKnownAgent(getAgent(reader)); @@ -1093,13 +1103,14 @@ test("Admins can set team read rey, make a private transaction in an owned objec type: "comap", ruleset: { type: "ownedByTeam", team: team.id }, meta: null, + publicNickname: "childObject" }); const teamContent = expectTeamContent(team.getCurrentContent()); const { secret: readKey, id: readKeyID } = newRandomKeySecret(); - const reader = newRandomAgentCredential(); + const reader = newRandomAgentCredential("reader"); const readerID = getAgentID(getAgent(reader)); - const reader2 = newRandomAgentCredential(); + const reader2 = newRandomAgentCredential("reader2"); const reader2ID = getAgentID(getAgent(reader)); teamContent.edit((editable) => { @@ -1229,9 +1240,9 @@ test("Admins can set team read rey, make a private transaction in an owned objec const secondReadKey = childObject.coValue.getCurrentReadKey(); - const reader = newRandomAgentCredential(); + const reader = newRandomAgentCredential("reader"); const readerID = getAgentID(getAgent(reader)); - const reader2 = newRandomAgentCredential(); + const reader2 = newRandomAgentCredential("reader2"); const reader2ID = getAgentID(getAgent(reader2)); node.addKnownAgent(getAgent(reader)); diff --git a/src/permissions.ts b/src/permissions.ts index 8f0a0d0bc..214e11942 100644 --- a/src/permissions.ts +++ b/src/permissions.ts @@ -271,7 +271,7 @@ export class Team { rotateReadKey() { const currentlyPermittedReaders = this.teamMap.keys().filter((key) => { - if (key.startsWith("agent_")) { + if (key.startsWith("co_agent")) { const role = this.teamMap.get(key); return ( role === "admin" || role === "writer" || role === "reader" @@ -342,6 +342,7 @@ export class Team { team: this.teamMap.id, }, meta: meta || null, + publicNickname: "map", }) .getCurrentContent() as CoMap; } diff --git a/src/sync.test.ts b/src/sync.test.ts index 4bd41715d..248947761 100644 --- a/src/sync.test.ts +++ b/src/sync.test.ts @@ -1,6 +1,5 @@ import { AgentID, - agentIDAsCoValueID, getAgent, getAgentID, newRandomAgentCredential, @@ -19,7 +18,7 @@ import { test( "Node replies with initial tx and header to empty subscribe", async () => { - const admin = newRandomAgentCredential(); + const admin = newRandomAgentCredential("admin"); const adminID = getAgentID(getAgent(admin)); const node = new LocalNode(admin, newRandomSessionID(adminID)); @@ -74,6 +73,7 @@ test( type: "comap", ruleset: { type: "ownedByTeam", team: team.id }, meta: null, + publicNickname: "map", }, newContent: { [node.ownSessionID]: { @@ -103,7 +103,7 @@ test( ); test("Node replies with only new tx to subscribe with some known state", async () => { - const admin = newRandomAgentCredential(); + const admin = newRandomAgentCredential("admin"); const adminID = getAgentID(getAgent(admin)); const node = new LocalNode(admin, newRandomSessionID(adminID)); @@ -188,7 +188,7 @@ test.todo( ); test("After subscribing, node sends own known state and new txs to peer", async () => { - const admin = newRandomAgentCredential(); + const admin = newRandomAgentCredential("admin"); const adminID = getAgentID(getAgent(admin)); const node = new LocalNode(admin, newRandomSessionID(adminID)); @@ -309,7 +309,7 @@ test("After subscribing, node sends own known state and new txs to peer", async }); test("Client replies with known new content to tellKnownState from server", async () => { - const admin = newRandomAgentCredential(); + const admin = newRandomAgentCredential("admin"); const adminID = getAgentID(getAgent(admin)); const node = new LocalNode(admin, newRandomSessionID(adminID)); @@ -391,7 +391,7 @@ test("Client replies with known new content to tellKnownState from server", asyn }); test("No matter the optimistic known state, node respects invalid known state messages and resyncs", async () => { - const admin = newRandomAgentCredential(); + const admin = newRandomAgentCredential("admin"); const adminID = getAgentID(getAgent(admin)); const node = new LocalNode(admin, newRandomSessionID(adminID)); @@ -496,7 +496,7 @@ test("No matter the optimistic known state, node respects invalid known state me }); test("If we add a peer, but it never subscribes to a coValue, it won't get any messages", async () => { - const admin = newRandomAgentCredential(); + const admin = newRandomAgentCredential("admin"); const adminID = getAgentID(getAgent(admin)); const node = new LocalNode(admin, newRandomSessionID(adminID)); @@ -525,7 +525,7 @@ test("If we add a peer, but it never subscribes to a coValue, it won't get any m }); test("If we add a server peer, all updates to all coValues are sent to it, even if it doesn't subscribe", async () => { - const admin = newRandomAgentCredential(); + const admin = newRandomAgentCredential("admin"); const adminID = getAgentID(getAgent(admin)); const node = new LocalNode(admin, newRandomSessionID(adminID)); @@ -547,7 +547,7 @@ test("If we add a server peer, all updates to all coValues are sent to it, even const reader = outRx.getReader(); expect((await reader.read()).value).toMatchObject({ action: "subscribe", - coValueID: agentIDAsCoValueID(adminID), + coValueID: adminID, }); expect((await reader.read()).value).toMatchObject({ action: "subscribe", @@ -602,7 +602,7 @@ test("If we add a server peer, all updates to all coValues are sent to it, even }); test("If we add a server peer, newly created coValues are auto-subscribed to", async () => { - const admin = newRandomAgentCredential(); + const admin = newRandomAgentCredential("admin"); const adminID = getAgentID(getAgent(admin)); const node = new LocalNode(admin, newRandomSessionID(adminID)); @@ -624,7 +624,7 @@ test("If we add a server peer, newly created coValues are auto-subscribed to", a const reader = outRx.getReader(); expect((await reader.read()).value).toMatchObject({ action: "subscribe", - coValueID: agentIDAsCoValueID(adminID), + coValueID: adminID, }); expect((await reader.read()).value).toMatchObject({ action: "subscribe", @@ -658,7 +658,7 @@ test.todo( ); test("When we connect a new server peer, we try to sync all existing coValues to it", async () => { - const admin = newRandomAgentCredential(); + const admin = newRandomAgentCredential("admin"); const adminID = getAgentID(getAgent(admin)); const node = new LocalNode(admin, newRandomSessionID(adminID)); @@ -696,7 +696,7 @@ test("When we connect a new server peer, we try to sync all existing coValues to }); test("When receiving a subscribe with a known state that is ahead of our own, peers should respond with a corresponding subscribe response message", async () => { - const admin = newRandomAgentCredential(); + const admin = newRandomAgentCredential("admin"); const adminID = getAgentID(getAgent(admin)); const node = new LocalNode(admin, newRandomSessionID(adminID)); @@ -740,7 +740,7 @@ test("When receiving a subscribe with a known state that is ahead of our own, pe test.skip("When replaying creation and transactions of a coValue as new content, the receiving peer integrates this information", async () => { // TODO: this test is mostly correct but also slightly unrealistic, make sure we pass all messages back and forth as expected and then it should work - const admin = newRandomAgentCredential(); + const admin = newRandomAgentCredential("admin"); const adminID = getAgentID(getAgent(admin)); const node1 = new LocalNode(admin, newRandomSessionID(adminID)); @@ -778,7 +778,7 @@ test.skip("When replaying creation and transactions of a coValue as new content, const adminSubscribeMessage = await from1.read(); expect(adminSubscribeMessage.value).toMatchObject({ action: "subscribe", - coValueID: agentIDAsCoValueID(adminID), + coValueID: adminID, }); const teamSubscribeMsg = await from1.read(); expect(teamSubscribeMsg.value).toMatchObject({ @@ -862,7 +862,7 @@ test.skip("When replaying creation and transactions of a coValue as new content, test.skip("When loading a coValue on one node, the server node it is requested from replies with all the necessary depended on coValues to make it work", async () => { // TODO: this test is mostly correct but also slightly unrealistic, make sure we pass all messages back and forth as expected and then it should work - const admin = newRandomAgentCredential(); + const admin = newRandomAgentCredential("admin"); const adminID = getAgentID(getAgent(admin)); const node1 = new LocalNode(admin, newRandomSessionID(adminID)); @@ -891,7 +891,7 @@ test.skip("When loading a coValue on one node, the server node it is requested f }); test("Can sync a coValue through a server to another client", async () => { - const admin = newRandomAgentCredential(); + const admin = newRandomAgentCredential("admin"); const adminID = getAgentID(getAgent(admin)); const client1 = new LocalNode(admin, newRandomSessionID(adminID)); @@ -903,7 +903,55 @@ test("Can sync a coValue through a server to another client", async () => { editable.set("hello", "world", "trusting"); }); - const server = new LocalNode(admin, newRandomSessionID(adminID)); + const serverUser = newRandomAgentCredential("serverUser"); + const serverUserID = getAgentID(getAgent(serverUser)); + + const server = new LocalNode(serverUser, newRandomSessionID(serverUserID)); + + const [serverAsPeer, client1AsPeer] = connectedPeers("server", "client1", { + trace: true, + peer1role: "server", + peer2role: "client", + }); + + client1.sync.addPeer(serverAsPeer); + server.sync.addPeer(client1AsPeer); + + const client2 = new LocalNode(admin, newRandomSessionID(adminID)); + + const [serverAsOtherPeer, client2AsPeer] = connectedPeers( + "server", + "client2", + { trace: true, peer1role: "server", peer2role: "client" } + ); + + client2.sync.addPeer(serverAsOtherPeer); + server.sync.addPeer(client2AsPeer); + + const mapOnClient2 = await client2.loadCoValue(map.coValue.id); + + expect(expectMap(mapOnClient2.getCurrentContent()).get("hello")).toEqual( + "world" + ); +}); + +test("Can sync a coValue with private transactions through a server to another client", async () => { + const admin = newRandomAgentCredential("admin"); + const adminID = getAgentID(getAgent(admin)); + + const client1 = new LocalNode(admin, newRandomSessionID(adminID)); + + const team = client1.createTeam(); + + const map = team.createMap(); + map.edit((editable) => { + editable.set("hello", "world", "private"); + }); + + const serverUser = newRandomAgentCredential("serverUser"); + const serverUserID = getAgentID(getAgent(serverUser)); + + const server = new LocalNode(serverUser, newRandomSessionID(serverUserID)); const [serverAsPeer, client1AsPeer] = connectedPeers("server", "client1", { trace: true, @@ -942,7 +990,7 @@ function teamContentEx(team: Team) { function admContEx(adminID: AgentID) { return { action: "newContent", - coValueID: agentIDAsCoValueID(adminID), + coValueID: adminID, }; } @@ -956,7 +1004,7 @@ function teamStateEx(team: Team) { function admStateEx(adminID: AgentID) { return { action: "tellKnownState", - coValueID: agentIDAsCoValueID(adminID), + coValueID: adminID, }; }