@adapt-toolkit/a2adapt 0.11.2 → 0.11.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/dist/index.js +11 -11
- package/dist/mufl_code/264E6E0FF6F2C1587AD5725F9B2E788CE792B617B6141D097F38CBB41EF3AB6A.muflo +0 -0
- package/dist/mufl_code/actor.mu +169 -576
- package/dist/mufl_code/config.mufl +15 -10
- package/package.json +1 -1
- package/dist/mufl_code/A24622D9BD2CB0DCFE943995DCCCA6D6E7890A4977286A3C6C776B78A9A8BF2E.muflo +0 -0
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"name": "a2adapt",
|
|
4
4
|
"displayName": "a2adapt",
|
|
5
5
|
"description": "Secure agent-to-agent communication channel over ADAPT: self-sovereign pubkey identity, end-to-end encryption, plan-first execution.",
|
|
6
|
-
"version": "0.11.
|
|
6
|
+
"version": "0.11.4",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "Adapt Toolkit"
|
|
9
9
|
},
|
package/dist/index.js
CHANGED
|
@@ -22512,7 +22512,7 @@ function writeIdentityFile(target, opts, overwrite = false) {
|
|
|
22512
22512
|
}
|
|
22513
22513
|
|
|
22514
22514
|
// src/index.ts
|
|
22515
|
-
var VERSION = true ? "0.11.
|
|
22515
|
+
var VERSION = true ? "0.11.4" : "0.0.0-dev";
|
|
22516
22516
|
var CONFIG = loadConfig();
|
|
22517
22517
|
var STATE_DIR = CONFIG.stateDir;
|
|
22518
22518
|
var BROKER_URL = CONFIG.brokerUrl;
|
|
@@ -22962,7 +22962,7 @@ async function provisionIdentity(name, opts = { exposeLocal: true, localAutoAcce
|
|
|
22962
22962
|
const seed = randomBytes(24).toString("hex");
|
|
22963
22963
|
fs2.writeFileSync(seedPath(dir), seed, { mode: 384 });
|
|
22964
22964
|
const id = await createPacket(name, seed, dir);
|
|
22965
|
-
await mutatingTx(id, "::
|
|
22965
|
+
await mutatingTx(id, "::a2a_messaging::set_my_name", { name });
|
|
22966
22966
|
await pinRegistrar(id);
|
|
22967
22967
|
if (!opts.localAutoAccept) {
|
|
22968
22968
|
await mutatingTx(id, "::actor::set_local_policy", { auto_accept: false });
|
|
@@ -23174,7 +23174,7 @@ function createMcpServer(getSessionId) {
|
|
|
23174
23174
|
if (identities.has(name)) return textResult(`create_identity failed: an identity named "${name}" already exists.`, true);
|
|
23175
23175
|
try {
|
|
23176
23176
|
const id = await provisionIdentity(name, { exposeLocal: expose_local, localAutoAccept: local_auto_accept });
|
|
23177
|
-
if (bio) await mutatingTx(id, "::
|
|
23177
|
+
if (bio) await mutatingTx(id, "::a2a_messaging::set_my_bio", { bio });
|
|
23178
23178
|
let hierarchy = "";
|
|
23179
23179
|
const root = rootName ? identities.get(rootName) : void 0;
|
|
23180
23180
|
if (root) {
|
|
@@ -23216,7 +23216,7 @@ Ask the user: do you want to arm a message monitor for "${name}"? If yes, use: M
|
|
|
23216
23216
|
}
|
|
23217
23217
|
try {
|
|
23218
23218
|
const id = await provisionIdentity(name, { exposeLocal: expose_local, localAutoAccept: local_auto_accept });
|
|
23219
|
-
if (bio) await mutatingTx(id, "::
|
|
23219
|
+
if (bio) await mutatingTx(id, "::a2a_messaging::set_my_bio", { bio });
|
|
23220
23220
|
rootName = name;
|
|
23221
23221
|
writeRootMarker(name);
|
|
23222
23222
|
const adopted = [];
|
|
@@ -23444,7 +23444,7 @@ ${inbox.map((m) => fmtMsg(m)).join("\n")}`;
|
|
|
23444
23444
|
try {
|
|
23445
23445
|
const targ = {};
|
|
23446
23446
|
if (name) targ.name = name;
|
|
23447
|
-
const data = await mutatingTx(id, "::
|
|
23447
|
+
const data = await mutatingTx(id, "::a2a_messaging::generate_invite", targ);
|
|
23448
23448
|
const blob = packInvite(Buffer.from(data.Reduce("invite").GetBinary()));
|
|
23449
23449
|
const heading = name ? `Invite for "${name}" created.` : "Invite created \u2014 the contact will be registered under the name the recipient announces when accepting.";
|
|
23450
23450
|
return textResult(
|
|
@@ -23478,7 +23478,7 @@ ${blob}`
|
|
|
23478
23478
|
const blobValue = id.pw.packet.NewBinaryFromBuffer(buf);
|
|
23479
23479
|
const targ = { invite: blobValue };
|
|
23480
23480
|
if (name) targ.name = name;
|
|
23481
|
-
const data = await mutatingTx(id, "::
|
|
23481
|
+
const data = await mutatingTx(id, "::a2a_messaging::add_contact", targ);
|
|
23482
23482
|
const added = data.Reduce("added").Visualize();
|
|
23483
23483
|
const cid = data.Reduce("container_id").Visualize();
|
|
23484
23484
|
const roleId = data.Reduce("role_id").Visualize();
|
|
@@ -23499,9 +23499,9 @@ ${blob}`
|
|
|
23499
23499
|
const { id, err } = boundOr();
|
|
23500
23500
|
if (err) return err;
|
|
23501
23501
|
try {
|
|
23502
|
-
const contacts = renderContacts(readonlyTx(id, "::
|
|
23502
|
+
const contacts = renderContacts(readonlyTx(id, "::a2a_messaging::list_contacts"));
|
|
23503
23503
|
const pending = renderPending(readonlyTx(id, "::actor::list_pending_introductions"));
|
|
23504
|
-
const roots = renderContactRoots(readonlyTx(id, "::
|
|
23504
|
+
const roots = renderContactRoots(readonlyTx(id, "::a2a_messaging::list_contact_roots"));
|
|
23505
23505
|
const lines = [];
|
|
23506
23506
|
lines.push(
|
|
23507
23507
|
contacts.length === 0 ? "No contacts yet." : `Contacts (${contacts.length}):
|
|
@@ -23576,7 +23576,7 @@ ${lines.join("\n")}`);
|
|
|
23576
23576
|
const { id, err } = boundOr();
|
|
23577
23577
|
if (err) return err;
|
|
23578
23578
|
try {
|
|
23579
|
-
await mutatingTx(id, "::
|
|
23579
|
+
await mutatingTx(id, "::a2a_messaging::set_my_bio", { bio });
|
|
23580
23580
|
let refreshed = 0;
|
|
23581
23581
|
if (id.name === rootName) {
|
|
23582
23582
|
for (const other of identities.values()) {
|
|
@@ -23638,7 +23638,7 @@ ${lines.join("\n")}`);
|
|
|
23638
23638
|
const { id, err } = boundOr();
|
|
23639
23639
|
if (err) return err;
|
|
23640
23640
|
try {
|
|
23641
|
-
await mutatingTx(id, "::
|
|
23641
|
+
await mutatingTx(id, "::a2a_messaging::send_message", { contact, text });
|
|
23642
23642
|
return textResult(`Message sent to "${contact}".`);
|
|
23643
23643
|
} catch (e) {
|
|
23644
23644
|
if (!/Unknown contact/.test(String(e))) {
|
|
@@ -23662,7 +23662,7 @@ ${lines.join("\n")}`);
|
|
|
23662
23662
|
const { id, err } = boundOr();
|
|
23663
23663
|
if (err) return err;
|
|
23664
23664
|
try {
|
|
23665
|
-
const data = await mutatingTx(id, "::
|
|
23665
|
+
const data = await mutatingTx(id, "::a2a_messaging::remove_contact", { contact });
|
|
23666
23666
|
const name = data.Reduce("removed").Visualize();
|
|
23667
23667
|
const cid = data.Reduce("container_id").Visualize();
|
|
23668
23668
|
return textResult(`Removed contact "${name}" (${cid}).`);
|
|
Binary file
|
package/dist/mufl_code/actor.mu
CHANGED
|
@@ -5,14 +5,39 @@
|
|
|
5
5
|
// encrypted; the key exchange is handled for us by the stdlib `encrypted_channel`
|
|
6
6
|
// library — we only ever address peers by their container id.
|
|
7
7
|
//
|
|
8
|
+
// The shared transaction logic lives in the a2adapt-mufl-core repo (checked
|
|
9
|
+
// out as the core/ subfolder of this directory): `a2a_protocol` (wire shapes +
|
|
10
|
+
// verification), `a2a_messaging` (contact + message wire path, addressed
|
|
11
|
+
// ::a2a_messaging::<name> by the host), and `version`. They are shared with
|
|
12
|
+
// the web messenger — change them there, bump core_version, and recompile
|
|
13
|
+
// every consumer.
|
|
14
|
+
//
|
|
15
|
+
// This packet keeps only what is agent-specific:
|
|
16
|
+
// - the inbox message store with its lifecycle (unread -> processed ->
|
|
17
|
+
// ready_to_delete -> deleted; see get_messages / gc / defer_messages)
|
|
18
|
+
// - the local contact book + identity hierarchy transactions (host-fired)
|
|
19
|
+
// - export_state / import_state wrappers composing the core helpers with
|
|
20
|
+
// the app-side fields (including the legacy-blob migrations)
|
|
21
|
+
// - ::actor:: compat shims for the network-visible inbound transactions
|
|
22
|
+
// (accept_contact, receive_message) — pre-migration peers send to these
|
|
23
|
+
// names, and the core keeps SENDING to them too (Option A: zero network
|
|
24
|
+
// break; drop both only when no old clients remain)
|
|
25
|
+
//
|
|
26
|
+
// Storage is wired into the core via a2a_messaging::init hooks (see the
|
|
27
|
+
// hidden block): on_message_received deposits into the inbox (or the
|
|
28
|
+
// pending-introduction queue for unknown senders); send/remove hooks are
|
|
29
|
+
// agent no-ops.
|
|
30
|
+
//
|
|
8
31
|
// User transactions (each backs one MCP tool, except gc which the host fires):
|
|
9
|
-
// set_my_name
|
|
10
|
-
// set_my_bio
|
|
11
|
-
// generate_invite
|
|
12
|
-
// add_contact
|
|
13
|
-
// send_message
|
|
14
|
-
// remove_contact
|
|
15
|
-
// list_contacts
|
|
32
|
+
// ::a2a_messaging::set_my_name — set the display name peers see for me
|
|
33
|
+
// ::a2a_messaging::set_my_bio — set my profile bio (free-text, self-asserted)
|
|
34
|
+
// ::a2a_messaging::generate_invite — make an invite blob for a named peer
|
|
35
|
+
// ::a2a_messaging::add_contact — join via an invite blob, reply to the inviter
|
|
36
|
+
// ::a2a_messaging::send_message — send an e2e-encrypted message to a contact
|
|
37
|
+
// ::a2a_messaging::remove_contact — forget a contact
|
|
38
|
+
// ::a2a_messaging::list_contacts — (readonly) my contacts
|
|
39
|
+
// ::a2a_messaging::list_contact_roots — (readonly) verified root linkage per contact
|
|
40
|
+
// ::a2a_messaging::get_version — (readonly) shared-core version
|
|
16
41
|
// list_incoming_messages — (readonly) my inbox, with per-message id + status
|
|
17
42
|
// get_messages — return unread messages + mark them processed (sole body egress)
|
|
18
43
|
// defer_messages — flip processed/ready_to_delete messages back to unread
|
|
@@ -23,7 +48,6 @@
|
|
|
23
48
|
// export_root_profile — root-only in practice: my self-signed root profile blob
|
|
24
49
|
// set_delegation — role: store my verified delegation cert + root material
|
|
25
50
|
// describe_identity — (readonly) name/bio/hierarchy position
|
|
26
|
-
// list_contact_roots — (readonly) verified root linkage per contact
|
|
27
51
|
// connect_sibling — register an intra-root peer + send sibling_introduce
|
|
28
52
|
//
|
|
29
53
|
// Local contact book (host-fired transactions; see the design notes above
|
|
@@ -39,17 +63,10 @@
|
|
|
39
63
|
// list_pending_introductions — (readonly) pending introductions (names + queue sizes)
|
|
40
64
|
//
|
|
41
65
|
// External transactions (inbound, not exposed as tools):
|
|
42
|
-
// accept_contact — inviter learns the joiner's identity + name
|
|
43
|
-
// receive_message — store a decrypted inbound message
|
|
66
|
+
// accept_contact — inviter learns the joiner's identity + name (core shim)
|
|
67
|
+
// receive_message — store a decrypted inbound message (core shim)
|
|
44
68
|
// local_introduce — same-host peer connects via the local contact book
|
|
45
69
|
// sibling_introduce — intra-root peer connects, authorized by its delegation cert
|
|
46
|
-
//
|
|
47
|
-
// Naming model (personal invites): generate_invite('Bob') tags a pending invite
|
|
48
|
-
// with the peer-name "Bob"; whoever redeems it is registered under "Bob" (the
|
|
49
|
-
// inviter's assigned name wins). Generating WITHOUT a name tags the invite with
|
|
50
|
-
// "" — then the joiner's self-announced name wins (falling back to its container
|
|
51
|
-
// id if the joiner never set one). The joiner, in turn, sees the inviter under
|
|
52
|
-
// the inviter's own self-name (set via set_my_name), unless the joiner overrides it.
|
|
53
70
|
|
|
54
71
|
application actor loads libraries
|
|
55
72
|
identity_proof_document,
|
|
@@ -62,25 +79,14 @@ application actor loads libraries
|
|
|
62
79
|
key_storage,
|
|
63
80
|
continuation,
|
|
64
81
|
encrypted_channel,
|
|
65
|
-
current_transaction_info
|
|
82
|
+
current_transaction_info,
|
|
83
|
+
a2a_protocol,
|
|
84
|
+
a2a_messaging,
|
|
85
|
+
version
|
|
66
86
|
uses transactions
|
|
67
87
|
{
|
|
68
88
|
hidden
|
|
69
89
|
{
|
|
70
|
-
metadef contact_t: ($name -> str, $container_id -> global_id).
|
|
71
|
-
// Slim invite. Short keys (no field-name bloat), no outer wrapper, and
|
|
72
|
-
// only the cryptographically load-bearing parts travel: the inviter's
|
|
73
|
-
// signed identity (public keys) + its self-signatures. inviter_id is NOT
|
|
74
|
-
// carried separately — it is the identity's own container_id. version is
|
|
75
|
-
// a constant reconstructed on the receiver. (See generate_invite /
|
|
76
|
-
// add_contact: the embedded identity is kept byte-for-byte so its
|
|
77
|
-
// _value_id — what the signatures are over — stays valid.)
|
|
78
|
-
// $d invite_id $n inviter_name $c container_id
|
|
79
|
-
// $k public keys $a authorizations
|
|
80
|
-
// default_keys is NOT carried — the receiver rebuilds it from the keys
|
|
81
|
-
// (each key knows its own function + id), so the reconstructed identity is
|
|
82
|
-
// byte-identical to the signed one and the self-signatures still verify.
|
|
83
|
-
metadef invite_t: ($d -> global_id, $n -> str, $c -> global_id, $k -> key_utils::t_publickey(,), $a -> crypto_signature(,)).
|
|
84
90
|
// A received message carries a stable per-packet id and a lifecycle status:
|
|
85
91
|
// "unread" (just arrived) -> "processed" (handed to the agent via
|
|
86
92
|
// get_messages) -> "ready_to_delete" (first gc tick) -> deleted (next gc
|
|
@@ -92,71 +98,13 @@ application actor loads libraries
|
|
|
92
98
|
// migrates blobs in this shape forward — see below.
|
|
93
99
|
metadef legacy_message_t: ($sender_id -> global_id, $sender_name -> str, $text -> str, $date -> time).
|
|
94
100
|
|
|
95
|
-
// ---- local contact book wire shapes ---------------------------------
|
|
96
|
-
// Introduction credential, minted PER CONNECT ATTEMPT by the host's
|
|
97
|
-
// registrar packet (never stored in the book). It binds the joiner's
|
|
98
|
-
// identity AND address document to one target, with freshness + a nonce,
|
|
99
|
-
// so possession of book material alone authorizes nothing: only the
|
|
100
|
-
// registrar (whose key never leaves the host) can mint one, which is
|
|
101
|
-
// what makes "local" a cryptographic property rather than a convention.
|
|
102
|
-
metadef intro_t: (
|
|
103
|
-
$version -> int,
|
|
104
|
-
$joiner_cid -> global_id,
|
|
105
|
-
$joiner_ad_hash -> hash_code,
|
|
106
|
-
$target_cid -> global_id,
|
|
107
|
-
$iat -> time,
|
|
108
|
-
$nonce -> global_id
|
|
109
|
-
).
|
|
110
|
-
metadef signed_intro_t: ($i -> intro_t, $s -> crypto_signature).
|
|
111
|
-
// What the registrar signs for a contact-book entry (tamper-evidence for
|
|
112
|
-
// the host-side book file; verified by the SENDER in connect_local).
|
|
113
|
-
metadef book_entry_t: ($version -> int, $name -> str, $ad_hash -> hash_code).
|
|
114
101
|
// A not-yet-approved local introduction, with its bounded message queue.
|
|
102
|
+
// (The local-book WIRE shapes — intro_t, signed_intro_t, book_entry_t —
|
|
103
|
+
// live in a2a_protocol; these three are packet-local state/view shapes.)
|
|
115
104
|
metadef pending_msg_t: ($text -> str, $date -> time).
|
|
116
105
|
metadef pending_intro_t: ($name -> str, $ad -> address_document_types::t_address_document, $messages -> pending_msg_t[]).
|
|
117
106
|
metadef pending_view_t: ($name -> str, $queued -> int).
|
|
118
107
|
|
|
119
|
-
// ---- identity hierarchy wire shapes ---------------------------------
|
|
120
|
-
// Delegation certificate: "role X belongs to root Y, signed by Y". The
|
|
121
|
-
// signature is over the core's _value_id, binding the role's container
|
|
122
|
-
// id AND its full key material (the address-document hash) to one root.
|
|
123
|
-
// An identity carrying NIL here is a root (or a legacy flat identity) —
|
|
124
|
-
// detection is structural, not a flag. v1 revocation == delete the role.
|
|
125
|
-
metadef delegation_core_t: (
|
|
126
|
-
$version -> int,
|
|
127
|
-
$role_cid -> global_id,
|
|
128
|
-
$role_ad_hash -> hash_code,
|
|
129
|
-
$role_id -> str,
|
|
130
|
-
$root_cid -> global_id,
|
|
131
|
-
$issued_at -> time
|
|
132
|
-
).
|
|
133
|
-
metadef delegation_cert_t: ($c -> delegation_core_t, $s -> crypto_signature).
|
|
134
|
-
// Self-signed root profile, carried in role invites so an external peer
|
|
135
|
-
// learns WHO is behind the role. It includes the root's key list, so the
|
|
136
|
-
// receiver can verify both this signature and the delegation cert with
|
|
137
|
-
// no prior knowledge of the root.
|
|
138
|
-
metadef root_profile_core_t: (
|
|
139
|
-
$version -> int,
|
|
140
|
-
$root_cid -> global_id,
|
|
141
|
-
$name -> str,
|
|
142
|
-
$bio -> str,
|
|
143
|
-
$keys -> key_utils::t_publickey(,)
|
|
144
|
-
).
|
|
145
|
-
metadef root_profile_t: ($p -> root_profile_core_t, $s -> crypto_signature).
|
|
146
|
-
// Verified root linkage learned about a contact (from its role invite or
|
|
147
|
-
// a sibling introduction). Kept beside `contacts` so old state blobs
|
|
148
|
-
// (whose contact_t has no such fields) import unchanged.
|
|
149
|
-
metadef contact_root_t: ($root_cid -> global_id, $root_name -> str, $role_id -> str).
|
|
150
|
-
// Role invite: the slim invite plus the delegation chain and the role's
|
|
151
|
-
// self-asserted bio. Roots and legacy identities keep emitting the old
|
|
152
|
-
// invite_t shape byte-for-byte, so their invites stay redeemable by old
|
|
153
|
-
// clients; only role invites require a hierarchy-aware receiver.
|
|
154
|
-
metadef invite_role_t: (
|
|
155
|
-
$d -> global_id, $n -> str, $c -> global_id,
|
|
156
|
-
$k -> key_utils::t_publickey(,), $a -> crypto_signature(,),
|
|
157
|
-
$b -> str, $dc -> delegation_cert_t, $rp -> root_profile_t
|
|
158
|
-
).
|
|
159
|
-
|
|
160
108
|
// Acceptance window for an introduction credential (seconds since mint;
|
|
161
109
|
// small negative slack for clock oddities) and the matching nonce-table
|
|
162
110
|
// retention horizon (window + slack, so a nonce outlives its credential).
|
|
@@ -171,27 +119,19 @@ application actor loads libraries
|
|
|
171
119
|
encrypted_channel::init ($_read_or_abort -> _read_or_abort).
|
|
172
120
|
|
|
173
121
|
// ---- packet state ---------------------------------------------------
|
|
174
|
-
// The
|
|
175
|
-
|
|
176
|
-
//
|
|
177
|
-
|
|
178
|
-
//
|
|
179
|
-
pending_invites is (global_id ->> str) = (,).
|
|
122
|
+
// (The shared contact/profile/hierarchy state — my_name, contacts,
|
|
123
|
+
// pending_invites, peer_ads, my_bio, delegation_cert, root_ad,
|
|
124
|
+
// root_profile, contact_roots — lives in a2a_messaging and is read /
|
|
125
|
+
// assigned as a2a_messaging::<field> below.)
|
|
126
|
+
//
|
|
180
127
|
// Received messages. Each carries its own lifecycle status (see
|
|
181
|
-
// message_t / get_messages /
|
|
128
|
+
// message_t / get_messages / gc / defer_messages), so the
|
|
182
129
|
// packet is the single authority on what has been read or processed —
|
|
183
130
|
// no host-side cursor, safe across concurrent sessions.
|
|
184
131
|
inbox is message_t[] = [].
|
|
185
132
|
// Monotonic source of per-message ids (the stable handle the agent uses
|
|
186
133
|
// to mark a message processed or defer it).
|
|
187
134
|
next_msg_seq is int = 1.
|
|
188
|
-
// Peer address documents, captured when a contact is established. These are
|
|
189
|
-
// self-signed, code-independent, and seed-stable, so on a code upgrade the
|
|
190
|
-
// host re-creates this packet from the same seed and import_state replays
|
|
191
|
-
// them through address_document::process_address_document — re-registering
|
|
192
|
-
// every peer's keys in key_storage so encrypted channels survive the upgrade
|
|
193
|
-
// with no re-handshake. Only peer PUBLIC keys travel here, never secrets.
|
|
194
|
-
peer_ads is (global_id ->> address_document_types::t_address_document) = (,).
|
|
195
135
|
// The host registrar's address document (pinned once at identity
|
|
196
136
|
// creation / injected on upgrade) — its $identity $key_list is what
|
|
197
137
|
// introduction credentials are verified against. NIL means this identity
|
|
@@ -206,18 +146,6 @@ application actor loads libraries
|
|
|
206
146
|
// Verified-but-unapproved local introductions (when auto-accept is off),
|
|
207
147
|
// each with a bounded queue of messages awaiting approval.
|
|
208
148
|
pending_introductions is (global_id ->> pending_intro_t) = (,).
|
|
209
|
-
// ---- identity hierarchy state ----
|
|
210
|
-
// My profile bio (free-text, self-asserted; carried in role invites).
|
|
211
|
-
my_bio is str = "".
|
|
212
|
-
// My delegation cert. NIL == I am a root or a legacy flat identity.
|
|
213
|
-
delegation_cert is delegation_cert_t+ = NIL.
|
|
214
|
-
// My root's address document (set with the cert; its key list is what
|
|
215
|
-
// sibling introductions and my own cert are verified against).
|
|
216
|
-
root_ad is address_document_types::t_address_document+ = NIL.
|
|
217
|
-
// My root's self-signed profile, embedded in the invites I generate.
|
|
218
|
-
root_profile is root_profile_t+ = NIL.
|
|
219
|
-
// Verified root linkage per contact, keyed by the contact's container id.
|
|
220
|
-
contact_roots is (global_id ->> contact_root_t) = (,).
|
|
221
149
|
|
|
222
150
|
// Signal the host to persist the packet. Only emitted at the end of a
|
|
223
151
|
// complete procedure — intermediate states (e.g. channel handshake) are
|
|
@@ -226,19 +154,6 @@ application actor loads libraries
|
|
|
226
154
|
fn _return_data (payload: any) = (transaction::action::return_data ($kind -> $data, $payload -> payload)).
|
|
227
155
|
fn _notify_agent (payload: any) = (transaction::action::return_data ($kind -> $notify_agent, $payload -> payload)).
|
|
228
156
|
|
|
229
|
-
// Resolve a contact reference (a display name or stringified container id)
|
|
230
|
-
// to a container id; aborts if no contact matches.
|
|
231
|
-
fn resolve_contact (ref: str) -> global_id
|
|
232
|
-
{
|
|
233
|
-
found is global_id+ = NIL.
|
|
234
|
-
sc contacts -- (cid -> c) ?? found == NIL && ((c $name) == ref || (_str cid) == ref)
|
|
235
|
-
{
|
|
236
|
-
found -> cid.
|
|
237
|
-
}
|
|
238
|
-
abort "Unknown contact: " + ref when found == NIL.
|
|
239
|
-
return found?.
|
|
240
|
-
}
|
|
241
|
-
|
|
242
157
|
// Append a message to the inbox under a fresh id; returns the id.
|
|
243
158
|
fn deposit_message (sender_id: global_id, sender_name: str, text: str, msg_date: time) -> int
|
|
244
159
|
{
|
|
@@ -255,25 +170,6 @@ application actor loads libraries
|
|
|
255
170
|
return mid.
|
|
256
171
|
}
|
|
257
172
|
|
|
258
|
-
// Verify a delegation chain presented by a peer: the root profile is
|
|
259
|
-
// internally consistent and the cert binds the peer's container id AND
|
|
260
|
-
// its address document to that root, both signed by the root's keys.
|
|
261
|
-
// The chain is self-contained (the profile carries the root's key list),
|
|
262
|
-
// so it proves "this role belongs to the root that signed it" — it does
|
|
263
|
-
// NOT vouch for who the root is (root verification is deferred to v2).
|
|
264
|
-
// Aborts on any mismatch; returns the linkage to record.
|
|
265
|
-
fn verify_peer_delegation (peer_cid: global_id, peer_ad_hash: hash_code, cert: delegation_cert_t, rp: root_profile_t) -> contact_root_t
|
|
266
|
-
{
|
|
267
|
-
abort "Unsupported delegation certificate version." when (cert $c $version) != 1.
|
|
268
|
-
abort "Unsupported root profile version." when (rp $p $version) != 1.
|
|
269
|
-
abort "Delegation certificate was issued for a different identity." when (cert $c $role_cid) != peer_cid.
|
|
270
|
-
abort "Delegation certificate does not match the peer's address document." when (cert $c $role_ad_hash) != peer_ad_hash.
|
|
271
|
-
abort "Root profile does not match the delegation certificate's root." when (rp $p $root_cid) != (cert $c $root_cid).
|
|
272
|
-
abort "Root profile signature is invalid." when key_storage::check_signature_new_container (_value_id (rp $p)) (rp $s) (rp $p $keys) != TRUE.
|
|
273
|
-
abort "Delegation certificate was not signed by its root." when key_storage::check_signature_new_container (_value_id (cert $c)) (cert $s) (rp $p $keys) != TRUE.
|
|
274
|
-
return ($root_cid -> cert $c $root_cid, $root_name -> rp $p $name, $role_id -> cert $c $role_id).
|
|
275
|
-
}
|
|
276
|
-
|
|
277
173
|
// Resolve a pending introduction by joiner name or stringified container
|
|
278
174
|
// id; aborts when nothing matches.
|
|
279
175
|
fn resolve_pending (ref: str) -> global_id
|
|
@@ -286,245 +182,52 @@ application actor loads libraries
|
|
|
286
182
|
abort "No pending introduction matches: " + ref when found == NIL.
|
|
287
183
|
return found?.
|
|
288
184
|
}
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
// ---- user transactions --------------------------------------------------
|
|
292
|
-
|
|
293
|
-
trn set_my_name _:($name -> name: str)
|
|
294
|
-
{
|
|
295
|
-
current_transaction_info::validate_origin_or_abort (transaction::envelope::origin::user,).
|
|
296
|
-
my_name -> name.
|
|
297
|
-
return transaction::success [
|
|
298
|
-
_return_data ($name -> name),
|
|
299
|
-
_save_state NIL
|
|
300
|
-
].
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
trn set_my_bio _:($bio -> bio: str)
|
|
304
|
-
{
|
|
305
|
-
current_transaction_info::validate_origin_or_abort (transaction::envelope::origin::user,).
|
|
306
|
-
my_bio -> bio.
|
|
307
|
-
return transaction::success [
|
|
308
|
-
_return_data ($bio -> bio),
|
|
309
|
-
_save_state NIL
|
|
310
|
-
].
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
trn generate_invite _:($name -> name: str+)
|
|
314
|
-
{
|
|
315
|
-
current_transaction_info::validate_origin_or_abort (transaction::envelope::origin::user,).
|
|
316
|
-
|
|
317
|
-
invite_id = _new_id "a2adapt invite".
|
|
318
|
-
// Remember the name I'm assigning to whoever redeems this invite. An
|
|
319
|
-
// empty string is the "no assigned name" sentinel: accept_contact then
|
|
320
|
-
// registers the joiner under its self-announced name instead.
|
|
321
|
-
assigned = (name == NIL ?? "" ; name?).
|
|
322
|
-
pending_invites invite_id -> assigned.
|
|
323
|
-
|
|
324
|
-
// Carry only my signed identity (public keys) + its self-signatures. The
|
|
325
|
-
// joiner rebuilds my address document from these (version is constant, my
|
|
326
|
-
// container_id is the identity's own field) and stores it so it can
|
|
327
|
-
// re-register me after a code upgrade (see peer_ads / import_state). The
|
|
328
|
-
// identity sub-record is passed through untouched so its _value_id — what
|
|
329
|
-
// the authorizations sign over — survives the round trip unchanged.
|
|
330
|
-
my_ad = address_document::get_my_address_document().
|
|
331
|
-
my_identity = my_ad $identity.
|
|
332
185
|
|
|
333
|
-
//
|
|
334
|
-
//
|
|
335
|
-
//
|
|
336
|
-
//
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
$
|
|
347
|
-
$
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
),
|
|
373
|
-
|
|
374
|
-
].
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
trn add_contact _:($invite -> invite_blob: bin, $name -> custom_name: str+)
|
|
378
|
-
{
|
|
379
|
-
current_transaction_info::validate_origin_or_abort (transaction::envelope::origin::user,).
|
|
380
|
-
|
|
381
|
-
// Parse field-by-field rather than via one `safe invite_t` cast: the
|
|
382
|
-
// shared fields are identical between invite_t and invite_role_t, so
|
|
383
|
-
// this one path redeems both the legacy shape and the role shape (the
|
|
384
|
-
// hierarchy fields are simply NIL on a legacy invite).
|
|
385
|
-
raw = _read_or_abort invite_blob.
|
|
386
|
-
inviter_id = (raw $c) safe global_id.
|
|
387
|
-
abort "This invite is your own — you cannot add yourself." when inviter_id == _get_container_id().
|
|
388
|
-
invite_id = (raw $d) safe global_id.
|
|
389
|
-
inviter_name = (raw $n) safe str.
|
|
390
|
-
inviter_keys = (raw $k) safe (key_utils::t_publickey(,)).
|
|
391
|
-
inviter_auths = (raw $a) safe (crypto_signature(,)).
|
|
392
|
-
|
|
393
|
-
// Rebuild default_keys from the carried public keys: each key reports its
|
|
394
|
-
// own function and id, so this reproduces the inviter's default-key map
|
|
395
|
-
// exactly. With it we reconstruct the full identity (and hence its
|
|
396
|
-
// _value_id, which the self-signatures sign over) byte-for-byte, then the
|
|
397
|
-
// full address document. import_state later replays this reconstructed
|
|
398
|
-
// document through process_address_document to re-register the inviter's
|
|
399
|
-
// keys after a code upgrade — so it must validate, and it does.
|
|
400
|
-
inviter_default_keys is (key_utils::t_function ->> key_utils::t_key_id) = (,).
|
|
401
|
-
sc inviter_keys -- (key -> )
|
|
402
|
-
{
|
|
403
|
-
inviter_default_keys (key_utils::key_get_function key) -> (_crypto_get_key_id key).
|
|
404
|
-
}
|
|
405
|
-
inviter_identity is key_storage::t_container_identity = (
|
|
406
|
-
$key_list -> inviter_keys,
|
|
407
|
-
$default_keys -> inviter_default_keys,
|
|
408
|
-
$container_id -> inviter_id
|
|
409
|
-
).
|
|
410
|
-
inviter_ad is address_document_types::t_address_document = (
|
|
411
|
-
$version -> 1,
|
|
412
|
-
$identity -> inviter_identity,
|
|
413
|
-
$authorizations -> inviter_auths
|
|
186
|
+
// Wire the agent's storage into the shared messaging core. The receive
|
|
187
|
+
// hook owns everything app-specific about an inbound message: known
|
|
188
|
+
// senders deposit into the inbox; an unknown sender may be a verified-
|
|
189
|
+
// but-unapproved local introduction messaging before approval — queue
|
|
190
|
+
// (bounded) inside its pending entry, approval flushes the queue into
|
|
191
|
+
// the inbox in order; anything else from an unknown sender is rejected.
|
|
192
|
+
// The notification deliberately carries NO message body — only that a
|
|
193
|
+
// message arrived, from whom, and its id. The body stays in the packet
|
|
194
|
+
// and only leaves through get_messages.
|
|
195
|
+
a2a_messaging::init (
|
|
196
|
+
$_read_or_abort -> _read_or_abort,
|
|
197
|
+
$on_message_received -> fn (arg: any) -> transaction::action::type[]
|
|
198
|
+
{
|
|
199
|
+
sender_id = (arg $sender_id) safe global_id.
|
|
200
|
+
text = (arg $text) safe str.
|
|
201
|
+
msg_date = (arg $date) safe time.
|
|
202
|
+
|
|
203
|
+
if (arg $sender_name) == NIL
|
|
204
|
+
{
|
|
205
|
+
p = pending_introductions sender_id.
|
|
206
|
+
abort "Message from an unknown sender was rejected." when p == NIL.
|
|
207
|
+
entry = p?.
|
|
208
|
+
queued = entry $messages.
|
|
209
|
+
abort "Pending-introduction message queue is full; awaiting approval." when (_count queued|) >= pending_queue_cap.
|
|
210
|
+
queued (_count queued|) -> ($text -> text, $date -> msg_date).
|
|
211
|
+
pending_introductions sender_id -> ($name -> entry $name, $ad -> entry $ad, $messages -> queued).
|
|
212
|
+
return [
|
|
213
|
+
_notify_agent ($event -> $pending_message, $sender_name -> entry $name, $queued -> _count queued|),
|
|
214
|
+
_save_state NIL
|
|
215
|
+
].
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
sender_name = (arg $sender_name) safe str.
|
|
219
|
+
mid = deposit_message sender_id sender_name text msg_date.
|
|
220
|
+
return [
|
|
221
|
+
_notify_agent ($event -> $message_received, $sender_name -> sender_name, $msg_id -> mid, $date -> msg_date),
|
|
222
|
+
_save_state NIL
|
|
223
|
+
].
|
|
224
|
+
},
|
|
225
|
+
$on_message_sent -> fn (_: any) -> transaction::action::type[] { return []. },
|
|
226
|
+
$on_contact_removed -> fn (_: any) -> transaction::action::type[] { return []. }
|
|
414
227
|
).
|
|
415
|
-
|
|
416
|
-
// A role invite carries a delegation chain — verify it BEFORE anything
|
|
417
|
-
// is registered (an invalid chain rejects the whole invite), and record
|
|
418
|
-
// the root linkage. A legacy/root invite has no chain; nothing to check.
|
|
419
|
-
inviter_root is contact_root_t+ = NIL.
|
|
420
|
-
inviter_bio is str = "".
|
|
421
|
-
if (raw $dc) != NIL
|
|
422
|
-
{
|
|
423
|
-
cert = (raw $dc) safe delegation_cert_t.
|
|
424
|
-
rp = (raw $rp) safe root_profile_t.
|
|
425
|
-
inviter_root -> verify_peer_delegation inviter_id (_value_id inviter_ad) cert rp.
|
|
426
|
-
inviter_bio -> (raw $b) safe str.
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
// Register the inviter under my chosen name, or the name they embedded.
|
|
430
|
-
contact_name = (custom_name == NIL ?? inviter_name ; custom_name?).
|
|
431
|
-
contacts inviter_id -> ($name -> contact_name, $container_id -> inviter_id).
|
|
432
|
-
// Remember the inviter's address document so I can re-register them after
|
|
433
|
-
// an upgrade (their keys are seed-stable, so this stays valid).
|
|
434
|
-
peer_ads inviter_id -> inviter_ad.
|
|
435
|
-
if inviter_root != NIL
|
|
436
|
-
{
|
|
437
|
-
contact_roots inviter_id -> inviter_root?.
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
my_self_name = my_name.
|
|
441
|
-
my_ad = address_document::get_my_address_document().
|
|
442
|
-
// If I am a delegated role myself, carry my own chain in the reply so
|
|
443
|
-
// the inviter learns my root linkage symmetrically.
|
|
444
|
-
my_cert_blob is bin+ = NIL.
|
|
445
|
-
my_rp_blob is bin+ = NIL.
|
|
446
|
-
if delegation_cert != NIL && root_profile != NIL
|
|
447
|
-
{
|
|
448
|
-
my_cert_blob -> (_write delegation_cert?).
|
|
449
|
-
my_rp_blob -> (_write root_profile?).
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
root_name_out is str = "".
|
|
453
|
-
role_id_out is str = "".
|
|
454
|
-
if inviter_root != NIL
|
|
455
|
-
{
|
|
456
|
-
root_name_out -> inviter_root? $root_name.
|
|
457
|
-
role_id_out -> inviter_root? $role_id.
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
// Establish the encrypted channel with the inviter (handshake happens
|
|
461
|
-
// transparently if we haven't talked before), then tell them I redeemed
|
|
462
|
-
// their invite, what my own name is, and my address document, so they can
|
|
463
|
-
// finish the handshake and remember me for future upgrades.
|
|
464
|
-
return encrypted_channel::execute_transaction inviter_id (fn (_) -> transaction::results::type {
|
|
465
|
-
return transaction::success [
|
|
466
|
-
encrypted_channel::send_encrypted_tx inviter_id (
|
|
467
|
-
$name -> "::actor::accept_contact",
|
|
468
|
-
$targ -> (
|
|
469
|
-
$invite_id -> invite_id,
|
|
470
|
-
$joiner_name -> my_self_name,
|
|
471
|
-
$joiner_ad -> my_ad,
|
|
472
|
-
$joiner_cert -> my_cert_blob,
|
|
473
|
-
$joiner_root_profile -> my_rp_blob
|
|
474
|
-
)
|
|
475
|
-
),
|
|
476
|
-
_return_data (
|
|
477
|
-
$added -> contact_name,
|
|
478
|
-
$container_id -> inviter_id,
|
|
479
|
-
$root_name -> root_name_out,
|
|
480
|
-
$role_id -> role_id_out,
|
|
481
|
-
$bio -> inviter_bio
|
|
482
|
-
),
|
|
483
|
-
_save_state NIL
|
|
484
|
-
].
|
|
485
|
-
}).
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
trn send_message _:($contact -> contact_ref: str, $text -> text: str)
|
|
489
|
-
{
|
|
490
|
-
current_transaction_info::validate_origin_or_abort (transaction::envelope::origin::user,).
|
|
491
|
-
|
|
492
|
-
target_id = resolve_contact contact_ref.
|
|
493
|
-
|
|
494
|
-
return encrypted_channel::execute_transaction target_id (fn (_) -> transaction::results::type {
|
|
495
|
-
return transaction::success [
|
|
496
|
-
encrypted_channel::send_encrypted_tx target_id (
|
|
497
|
-
$name -> "::actor::receive_message",
|
|
498
|
-
$targ -> ($text -> text)
|
|
499
|
-
),
|
|
500
|
-
_return_data ($sent_to -> target_id, $text -> text),
|
|
501
|
-
_save_state NIL
|
|
502
|
-
].
|
|
503
|
-
}).
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
trn remove_contact _:($contact -> contact_ref: str)
|
|
507
|
-
{
|
|
508
|
-
current_transaction_info::validate_origin_or_abort (transaction::envelope::origin::user,).
|
|
509
|
-
|
|
510
|
-
target_id = resolve_contact contact_ref.
|
|
511
|
-
removed = contacts target_id.
|
|
512
|
-
removed_name = removed? $name.
|
|
513
|
-
|
|
514
|
-
delete contacts target_id.
|
|
515
|
-
if peer_ads target_id != NIL { delete peer_ads target_id. }
|
|
516
|
-
if contact_roots target_id != NIL { delete contact_roots target_id. }
|
|
517
|
-
|
|
518
|
-
return transaction::success [
|
|
519
|
-
_return_data ($removed -> removed_name, $container_id -> target_id),
|
|
520
|
-
_save_state NIL
|
|
521
|
-
].
|
|
522
228
|
}
|
|
523
229
|
|
|
524
|
-
|
|
525
|
-
{
|
|
526
|
-
return contacts.
|
|
527
|
-
}
|
|
230
|
+
// ---- message store --------------------------------------------------------
|
|
528
231
|
|
|
529
232
|
trn readonly list_incoming_messages _
|
|
530
233
|
{
|
|
@@ -720,7 +423,7 @@ application actor loads libraries
|
|
|
720
423
|
|
|
721
424
|
joiner_ad = (_read_or_abort joiner_ad_blob) safe address_document_types::t_address_document.
|
|
722
425
|
target_ad = (_read_or_abort target_ad_blob) safe address_document_types::t_address_document.
|
|
723
|
-
intro is intro_t = (
|
|
426
|
+
intro is a2a_protocol::intro_t = (
|
|
724
427
|
$version -> 1,
|
|
725
428
|
$joiner_cid -> joiner_ad $identity $container_id,
|
|
726
429
|
$joiner_ad_hash -> _value_id joiner_ad,
|
|
@@ -728,7 +431,7 @@ application actor loads libraries
|
|
|
728
431
|
$iat -> (current_transaction_info::get_transaction_time())?,
|
|
729
432
|
$nonce -> _new_id "a2adapt local introduction"
|
|
730
433
|
).
|
|
731
|
-
signed is signed_intro_t = ($i -> intro, $s -> key_storage::default_sign (_value_id intro)).
|
|
434
|
+
signed is a2a_protocol::signed_intro_t = ($i -> intro, $s -> key_storage::default_sign (_value_id intro)).
|
|
732
435
|
return transaction::success [
|
|
733
436
|
_return_data ($intro -> (_write signed))
|
|
734
437
|
].
|
|
@@ -742,7 +445,7 @@ application actor loads libraries
|
|
|
742
445
|
current_transaction_info::validate_origin_or_abort (transaction::envelope::origin::user,).
|
|
743
446
|
|
|
744
447
|
ad = (_read_or_abort ad_blob) safe address_document_types::t_address_document.
|
|
745
|
-
entry is book_entry_t = ($version -> 1, $name -> name, $ad_hash -> _value_id ad).
|
|
448
|
+
entry is a2a_protocol::book_entry_t = ($version -> 1, $name -> name, $ad_hash -> _value_id ad).
|
|
746
449
|
return transaction::success [
|
|
747
450
|
_return_data ($sig -> (_write (key_storage::default_sign (_value_id entry))))
|
|
748
451
|
].
|
|
@@ -763,14 +466,14 @@ application actor loads libraries
|
|
|
763
466
|
target_id = target_ad $identity $container_id.
|
|
764
467
|
abort "This contact-book entry is your own identity." when target_id == _get_container_id().
|
|
765
468
|
|
|
766
|
-
entry is book_entry_t = ($version -> 1, $name -> name, $ad_hash -> _value_id target_ad).
|
|
469
|
+
entry is a2a_protocol::book_entry_t = ($version -> 1, $name -> name, $ad_hash -> _value_id target_ad).
|
|
767
470
|
entry_sig = (_read_or_abort entry_sig_blob) safe crypto_signature.
|
|
768
471
|
abort "Contact-book entry failed registrar verification." when key_storage::check_signature_new_container (_value_id entry) entry_sig (registrar_ad? $identity $key_list) != TRUE.
|
|
769
472
|
|
|
770
|
-
contacts target_id -> ($name -> name, $container_id -> target_id).
|
|
771
|
-
peer_ads target_id -> target_ad.
|
|
473
|
+
a2a_messaging::contacts target_id -> ($name -> name, $container_id -> target_id).
|
|
474
|
+
a2a_messaging::peer_ads target_id -> target_ad.
|
|
772
475
|
|
|
773
|
-
my_self_name = my_name.
|
|
476
|
+
my_self_name = a2a_messaging::my_name.
|
|
774
477
|
my_ad = address_document::get_my_address_document().
|
|
775
478
|
return encrypted_channel::execute_transaction target_id (fn (_) -> transaction::results::type {
|
|
776
479
|
return transaction::success [
|
|
@@ -790,8 +493,8 @@ application actor loads libraries
|
|
|
790
493
|
|
|
791
494
|
pid = resolve_pending ref.
|
|
792
495
|
entry = (pending_introductions pid)?.
|
|
793
|
-
contacts pid -> ($name -> entry $name, $container_id -> pid).
|
|
794
|
-
peer_ads pid -> entry $ad.
|
|
496
|
+
a2a_messaging::contacts pid -> ($name -> entry $name, $container_id -> pid).
|
|
497
|
+
a2a_messaging::peer_ads pid -> entry $ad.
|
|
795
498
|
|
|
796
499
|
queued = entry $messages.
|
|
797
500
|
flushed is int = 0.
|
|
@@ -850,13 +553,13 @@ application actor loads libraries
|
|
|
850
553
|
trn sign_delegation _:($role_ad -> role_ad_blob: bin, $role_id -> role_id: str)
|
|
851
554
|
{
|
|
852
555
|
current_transaction_info::validate_origin_or_abort (transaction::envelope::origin::user,).
|
|
853
|
-
abort "Only a root identity can sign delegation certificates." when delegation_cert != NIL.
|
|
556
|
+
abort "Only a root identity can sign delegation certificates." when a2a_messaging::delegation_cert != NIL.
|
|
854
557
|
|
|
855
558
|
role_ad = (_read_or_abort role_ad_blob) safe address_document_types::t_address_document.
|
|
856
559
|
role_cid = role_ad $identity $container_id.
|
|
857
560
|
abort "Cannot issue a delegation certificate to myself." when role_cid == _get_container_id().
|
|
858
561
|
|
|
859
|
-
core is delegation_core_t = (
|
|
562
|
+
core is a2a_protocol::delegation_core_t = (
|
|
860
563
|
$version -> 1,
|
|
861
564
|
$role_cid -> role_cid,
|
|
862
565
|
$role_ad_hash -> _value_id role_ad,
|
|
@@ -864,7 +567,7 @@ application actor loads libraries
|
|
|
864
567
|
$root_cid -> _get_container_id(),
|
|
865
568
|
$issued_at -> (current_transaction_info::get_transaction_time())?
|
|
866
569
|
).
|
|
867
|
-
cert is delegation_cert_t = ($c -> core, $s -> key_storage::default_sign (_value_id core)).
|
|
570
|
+
cert is a2a_protocol::delegation_cert_t = ($c -> core, $s -> key_storage::default_sign (_value_id core)).
|
|
868
571
|
return transaction::success [
|
|
869
572
|
_return_data ($cert -> (_write cert))
|
|
870
573
|
].
|
|
@@ -876,17 +579,17 @@ application actor loads libraries
|
|
|
876
579
|
trn export_root_profile _
|
|
877
580
|
{
|
|
878
581
|
current_transaction_info::validate_origin_or_abort (transaction::envelope::origin::user,).
|
|
879
|
-
abort "Only a root identity can export a root profile." when delegation_cert != NIL.
|
|
582
|
+
abort "Only a root identity can export a root profile." when a2a_messaging::delegation_cert != NIL.
|
|
880
583
|
|
|
881
584
|
my_ad = address_document::get_my_address_document().
|
|
882
|
-
core is root_profile_core_t = (
|
|
585
|
+
core is a2a_protocol::root_profile_core_t = (
|
|
883
586
|
$version -> 1,
|
|
884
587
|
$root_cid -> _get_container_id(),
|
|
885
|
-
$name -> my_name,
|
|
886
|
-
$bio -> my_bio,
|
|
588
|
+
$name -> a2a_messaging::my_name,
|
|
589
|
+
$bio -> a2a_messaging::my_bio,
|
|
887
590
|
$keys -> my_ad $identity $key_list
|
|
888
591
|
).
|
|
889
|
-
profile is root_profile_t = ($p -> core, $s -> key_storage::default_sign (_value_id core)).
|
|
592
|
+
profile is a2a_protocol::root_profile_t = ($p -> core, $s -> key_storage::default_sign (_value_id core)).
|
|
890
593
|
return transaction::success [
|
|
891
594
|
_return_data ($profile -> (_write profile))
|
|
892
595
|
].
|
|
@@ -901,9 +604,9 @@ application actor loads libraries
|
|
|
901
604
|
{
|
|
902
605
|
current_transaction_info::validate_origin_or_abort (transaction::envelope::origin::user,).
|
|
903
606
|
|
|
904
|
-
cert = (_read_or_abort cert_blob) safe delegation_cert_t.
|
|
607
|
+
cert = (_read_or_abort cert_blob) safe a2a_protocol::delegation_cert_t.
|
|
905
608
|
new_root_ad = (_read_or_abort root_ad_blob) safe address_document_types::t_address_document.
|
|
906
|
-
rp = (_read_or_abort rp_blob) safe root_profile_t.
|
|
609
|
+
rp = (_read_or_abort rp_blob) safe a2a_protocol::root_profile_t.
|
|
907
610
|
|
|
908
611
|
abort "Unsupported delegation certificate version." when (cert $c $version) != 1.
|
|
909
612
|
abort "This delegation certificate was issued to a different identity." when (cert $c $role_cid) != _get_container_id().
|
|
@@ -916,9 +619,9 @@ application actor loads libraries
|
|
|
916
619
|
abort "The root profile's key list does not match the root's address document." when (_value_id (rp $p $keys)) != (_value_id (new_root_ad $identity $key_list)).
|
|
917
620
|
abort "The root profile signature is invalid." when key_storage::check_signature_new_container (_value_id (rp $p)) (rp $s) (new_root_ad $identity $key_list) != TRUE.
|
|
918
621
|
|
|
919
|
-
delegation_cert -> cert.
|
|
920
|
-
root_ad -> new_root_ad.
|
|
921
|
-
root_profile -> rp.
|
|
622
|
+
a2a_messaging::delegation_cert -> cert.
|
|
623
|
+
a2a_messaging::root_ad -> new_root_ad.
|
|
624
|
+
a2a_messaging::root_profile -> rp.
|
|
922
625
|
|
|
923
626
|
return transaction::success [
|
|
924
627
|
_return_data ($delegated -> TRUE, $root_cid -> (_str (cert $c $root_cid)), $role_id -> cert $c $role_id),
|
|
@@ -928,16 +631,16 @@ application actor loads libraries
|
|
|
928
631
|
|
|
929
632
|
trn readonly describe_identity _
|
|
930
633
|
{
|
|
931
|
-
if delegation_cert == NIL
|
|
634
|
+
if a2a_messaging::delegation_cert == NIL
|
|
932
635
|
{
|
|
933
|
-
return ($name -> my_name, $bio -> my_bio, $has_cert -> FALSE, $role_id -> "", $root_cid -> "", $root_name -> "").
|
|
636
|
+
return ($name -> a2a_messaging::my_name, $bio -> a2a_messaging::my_bio, $has_cert -> FALSE, $role_id -> "", $root_cid -> "", $root_name -> "").
|
|
934
637
|
}
|
|
935
|
-
cert = delegation_cert?.
|
|
638
|
+
cert = a2a_messaging::delegation_cert?.
|
|
936
639
|
rname is str = "".
|
|
937
|
-
if root_profile != NIL { rname -> root_profile? $p $name. }
|
|
640
|
+
if a2a_messaging::root_profile != NIL { rname -> a2a_messaging::root_profile? $p $name. }
|
|
938
641
|
return (
|
|
939
|
-
$name -> my_name,
|
|
940
|
-
$bio -> my_bio,
|
|
642
|
+
$name -> a2a_messaging::my_name,
|
|
643
|
+
$bio -> a2a_messaging::my_bio,
|
|
941
644
|
$has_cert -> TRUE,
|
|
942
645
|
$role_id -> cert $c $role_id,
|
|
943
646
|
$root_cid -> (_str (cert $c $root_cid)),
|
|
@@ -945,11 +648,6 @@ application actor loads libraries
|
|
|
945
648
|
).
|
|
946
649
|
}
|
|
947
650
|
|
|
948
|
-
trn readonly list_contact_roots _
|
|
949
|
-
{
|
|
950
|
-
return contact_roots.
|
|
951
|
-
}
|
|
952
|
-
|
|
953
651
|
// Connect to an intra-root sibling (Ring 1): register it as a contact and
|
|
954
652
|
// introduce myself over the encrypted channel, presenting my delegation
|
|
955
653
|
// cert (NIL when I am the root itself — the channel proves I control the
|
|
@@ -965,22 +663,22 @@ application actor loads libraries
|
|
|
965
663
|
abort "This sibling is your own identity." when target_id == _get_container_id().
|
|
966
664
|
|
|
967
665
|
cert_blob is bin+ = NIL.
|
|
968
|
-
if delegation_cert != NIL { cert_blob -> (_write delegation_cert?). }
|
|
666
|
+
if a2a_messaging::delegation_cert != NIL { cert_blob -> (_write a2a_messaging::delegation_cert?). }
|
|
969
667
|
|
|
970
|
-
contacts target_id -> ($name -> name, $container_id -> target_id).
|
|
971
|
-
peer_ads target_id -> target_ad.
|
|
668
|
+
a2a_messaging::contacts target_id -> ($name -> name, $container_id -> target_id).
|
|
669
|
+
a2a_messaging::peer_ads target_id -> target_ad.
|
|
972
670
|
// Record the target's root linkage: a sibling shares my root by
|
|
973
671
|
// definition (the receiving side verifies the converse independently).
|
|
974
|
-
if delegation_cert != NIL && root_profile != NIL
|
|
672
|
+
if a2a_messaging::delegation_cert != NIL && a2a_messaging::root_profile != NIL
|
|
975
673
|
{
|
|
976
|
-
contact_roots target_id -> ($root_cid -> delegation_cert? $c $root_cid, $root_name -> root_profile? $p $name, $role_id -> name).
|
|
674
|
+
a2a_messaging::contact_roots target_id -> ($root_cid -> a2a_messaging::delegation_cert? $c $root_cid, $root_name -> a2a_messaging::root_profile? $p $name, $role_id -> name).
|
|
977
675
|
}
|
|
978
676
|
else
|
|
979
677
|
{
|
|
980
|
-
contact_roots target_id -> ($root_cid -> _get_container_id(), $root_name -> my_name, $role_id -> name).
|
|
678
|
+
a2a_messaging::contact_roots target_id -> ($root_cid -> _get_container_id(), $root_name -> a2a_messaging::my_name, $role_id -> name).
|
|
981
679
|
}
|
|
982
680
|
|
|
983
|
-
my_self_name = my_name.
|
|
681
|
+
my_self_name = a2a_messaging::my_name.
|
|
984
682
|
my_ad = address_document::get_my_address_document().
|
|
985
683
|
return encrypted_channel::execute_transaction target_id (fn (_) -> transaction::results::type {
|
|
986
684
|
return transaction::success [
|
|
@@ -1002,27 +700,32 @@ application actor loads libraries
|
|
|
1002
700
|
//
|
|
1003
701
|
// The packet-level snapshot is NOT used for upgrades: it is bound to the unit
|
|
1004
702
|
// code hash, so a new .muflo cannot load an old snapshot. This data blob is.
|
|
703
|
+
//
|
|
704
|
+
// The blob stays FLAT with the historical field names — the core fields come
|
|
705
|
+
// from a2a_messaging::export_core_state / import_core_state, the app fields
|
|
706
|
+
// are composed in here — so a PRE-migration export imports unchanged.
|
|
1005
707
|
|
|
1006
708
|
trn readonly export_state _
|
|
1007
709
|
{
|
|
710
|
+
core_state = a2a_messaging::export_core_state NIL.
|
|
1008
711
|
return (
|
|
1009
|
-
$my_name -> my_name,
|
|
1010
|
-
$contacts -> contacts,
|
|
1011
|
-
$pending_invites -> pending_invites,
|
|
712
|
+
$my_name -> core_state $my_name,
|
|
713
|
+
$contacts -> core_state $contacts,
|
|
714
|
+
$pending_invites -> core_state $pending_invites,
|
|
1012
715
|
$inbox -> inbox,
|
|
1013
716
|
$next_msg_seq -> next_msg_seq,
|
|
1014
|
-
$peer_ads -> peer_ads,
|
|
717
|
+
$peer_ads -> core_state $peer_ads,
|
|
1015
718
|
$registrar_ad -> registrar_ad,
|
|
1016
719
|
$local_auto_accept -> local_auto_accept,
|
|
1017
720
|
// Nonces are exported so a restart does not reopen the replay window
|
|
1018
721
|
// for still-fresh credentials; stale ones are purged lazily anyway.
|
|
1019
722
|
$seen_nonces -> seen_nonces,
|
|
1020
723
|
$pending_introductions -> pending_introductions,
|
|
1021
|
-
$my_bio -> my_bio,
|
|
1022
|
-
$delegation_cert -> delegation_cert,
|
|
1023
|
-
$root_ad -> root_ad,
|
|
1024
|
-
$root_profile -> root_profile,
|
|
1025
|
-
$contact_roots -> contact_roots
|
|
724
|
+
$my_bio -> core_state $my_bio,
|
|
725
|
+
$delegation_cert -> core_state $delegation_cert,
|
|
726
|
+
$root_ad -> core_state $root_ad,
|
|
727
|
+
$root_profile -> core_state $root_profile,
|
|
728
|
+
$contact_roots -> core_state $contact_roots
|
|
1026
729
|
).
|
|
1027
730
|
}
|
|
1028
731
|
|
|
@@ -1030,12 +733,11 @@ application actor loads libraries
|
|
|
1030
733
|
{
|
|
1031
734
|
current_transaction_info::validate_origin_or_abort (transaction::envelope::origin::user,).
|
|
1032
735
|
|
|
1033
|
-
//
|
|
1034
|
-
//
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
peer_ads -> (data $peer_ads) safe (global_id ->> address_document_types::t_address_document).
|
|
736
|
+
// Core fields (contacts/profile/hierarchy) — validated and restored by
|
|
737
|
+
// the shared library, which also replays every peer's address document
|
|
738
|
+
// through process_address_document so encrypted channels keep working
|
|
739
|
+
// after the upgrade with no re-handshake.
|
|
740
|
+
a2a_messaging::import_core_state data.
|
|
1039
741
|
|
|
1040
742
|
// The inbox + next_msg_seq are the only parts the message-lifecycle changes
|
|
1041
743
|
// touched. A pre-lifecycle blob has no $next_msg_seq and inbox entries with
|
|
@@ -1106,36 +808,6 @@ application actor loads libraries
|
|
|
1106
808
|
pending_introductions -> (data $pending_introductions) safe (global_id ->> pending_intro_t).
|
|
1107
809
|
}
|
|
1108
810
|
|
|
1109
|
-
// Identity-hierarchy state arrived after the local-contact-book schema —
|
|
1110
|
-
// same pattern: every field is optional, defaults stay when absent.
|
|
1111
|
-
if (data $my_bio) != NIL
|
|
1112
|
-
{
|
|
1113
|
-
my_bio -> (data $my_bio) safe str.
|
|
1114
|
-
}
|
|
1115
|
-
if (data $delegation_cert) != NIL
|
|
1116
|
-
{
|
|
1117
|
-
delegation_cert -> (data $delegation_cert) safe delegation_cert_t.
|
|
1118
|
-
}
|
|
1119
|
-
if (data $root_ad) != NIL
|
|
1120
|
-
{
|
|
1121
|
-
root_ad -> (data $root_ad) safe address_document_types::t_address_document.
|
|
1122
|
-
}
|
|
1123
|
-
if (data $root_profile) != NIL
|
|
1124
|
-
{
|
|
1125
|
-
root_profile -> (data $root_profile) safe root_profile_t.
|
|
1126
|
-
}
|
|
1127
|
-
if (data $contact_roots) != NIL
|
|
1128
|
-
{
|
|
1129
|
-
contact_roots -> (data $contact_roots) safe (global_id ->> contact_root_t).
|
|
1130
|
-
}
|
|
1131
|
-
|
|
1132
|
-
// Re-register every peer's keys so encrypted channels keep working after
|
|
1133
|
-
// the upgrade — no handshake needed (my own keys are unchanged, and the
|
|
1134
|
-
// peers' self-signed address documents re-authorize on this fresh packet).
|
|
1135
|
-
sc peer_ads -- ( -> ad)
|
|
1136
|
-
{
|
|
1137
|
-
address_document::process_address_document ad TRUE.
|
|
1138
|
-
}
|
|
1139
811
|
// Pending introducers' keys too: their channel to me predates approval,
|
|
1140
812
|
// so it must survive an upgrade exactly like an approved contact's.
|
|
1141
813
|
sc pending_introductions -- ( -> p)
|
|
@@ -1144,103 +816,24 @@ application actor loads libraries
|
|
|
1144
816
|
}
|
|
1145
817
|
|
|
1146
818
|
return transaction::success [
|
|
1147
|
-
_return_data ($imported -> TRUE, $contacts -> _count contacts|, $peers -> _count peer_ads|),
|
|
819
|
+
_return_data ($imported -> TRUE, $contacts -> _count a2a_messaging::contacts|, $peers -> _count a2a_messaging::peer_ads|),
|
|
1148
820
|
_save_state NIL
|
|
1149
821
|
].
|
|
1150
822
|
}
|
|
1151
823
|
|
|
1152
824
|
// ---- external (inbound) transactions ------------------------------------
|
|
1153
825
|
|
|
1154
|
-
//
|
|
1155
|
-
//
|
|
826
|
+
// Compat shims (Option A): pre-migration peers address these as ::actor::*,
|
|
827
|
+
// and the core keeps SENDING to the ::actor:: names too. Each delegates to
|
|
828
|
+
// the shared handler — remove only when no old clients remain.
|
|
1156
829
|
trn accept_contact args: any
|
|
1157
830
|
{
|
|
1158
|
-
|
|
1159
|
-
encrypted_channel::check_encrypted_or_abort().
|
|
1160
|
-
|
|
1161
|
-
sender_id = current_transaction_info::get_external_envelope_or_abort() $from.
|
|
1162
|
-
invite_id = (args $invite_id) safe global_id.
|
|
1163
|
-
joiner_ad = (args $joiner_ad) safe address_document_types::t_address_document.
|
|
1164
|
-
|
|
1165
|
-
// Only an invite I generated (and have not yet consumed) authorizes a
|
|
1166
|
-
// contact registration. Without this gate any invite blob would be a
|
|
1167
|
-
// multi-use bearer credential: anyone who ever saw one could register
|
|
1168
|
-
// themselves as my contact with a self-chosen name.
|
|
1169
|
-
assigned_name = pending_invites invite_id.
|
|
1170
|
-
abort "Unknown or already-redeemed invite." when assigned_name == NIL.
|
|
1171
|
-
// An empty assigned name means the invite was generated without one:
|
|
1172
|
-
// the joiner's self-announced name wins (container id as a last resort
|
|
1173
|
-
// when the joiner never set a name either).
|
|
1174
|
-
contact_name is str = assigned_name?.
|
|
1175
|
-
if contact_name == ""
|
|
1176
|
-
{
|
|
1177
|
-
joiner_self = (args $joiner_name) safe str.
|
|
1178
|
-
contact_name -> (joiner_self == "" ?? (_str sender_id) ; joiner_self).
|
|
1179
|
-
}
|
|
1180
|
-
|
|
1181
|
-
// A delegated-role joiner carries its chain so I learn its root linkage
|
|
1182
|
-
// symmetrically; an invalid chain rejects the redemption outright.
|
|
1183
|
-
joiner_root is contact_root_t+ = NIL.
|
|
1184
|
-
if (args $joiner_cert) != NIL
|
|
1185
|
-
{
|
|
1186
|
-
cert = (_read_or_abort ((args $joiner_cert) safe bin)) safe delegation_cert_t.
|
|
1187
|
-
rp = (_read_or_abort ((args $joiner_root_profile) safe bin)) safe root_profile_t.
|
|
1188
|
-
joiner_root -> verify_peer_delegation sender_id (_value_id joiner_ad) cert rp.
|
|
1189
|
-
}
|
|
1190
|
-
|
|
1191
|
-
contacts sender_id -> ($name -> contact_name, $container_id -> sender_id).
|
|
1192
|
-
// Remember the joiner's address document for upgrade-time re-registration.
|
|
1193
|
-
peer_ads sender_id -> joiner_ad.
|
|
1194
|
-
if joiner_root != NIL
|
|
1195
|
-
{
|
|
1196
|
-
contact_roots sender_id -> joiner_root?.
|
|
1197
|
-
}
|
|
1198
|
-
delete pending_invites invite_id.
|
|
1199
|
-
|
|
1200
|
-
return transaction::success [
|
|
1201
|
-
_notify_agent ($event -> $contact_accepted, $name -> contact_name, $container_id -> sender_id),
|
|
1202
|
-
_save_state NIL
|
|
1203
|
-
].
|
|
831
|
+
return a2a_messaging::handle_accept_contact args.
|
|
1204
832
|
}
|
|
1205
833
|
|
|
1206
834
|
trn receive_message _:($text -> text: str)
|
|
1207
835
|
{
|
|
1208
|
-
|
|
1209
|
-
encrypted_channel::check_encrypted_or_abort().
|
|
1210
|
-
|
|
1211
|
-
sender_id = current_transaction_info::get_external_envelope_or_abort() $from.
|
|
1212
|
-
msg_date = (current_transaction_info::get_transaction_time())?.
|
|
1213
|
-
sender = contacts sender_id.
|
|
1214
|
-
|
|
1215
|
-
if sender == NIL
|
|
1216
|
-
{
|
|
1217
|
-
// A verified-but-unapproved local introduction may message me before
|
|
1218
|
-
// approval: queue (bounded) inside its pending entry. Approval
|
|
1219
|
-
// flushes the queue into the inbox in order; anything else from an
|
|
1220
|
-
// unknown sender is rejected as before.
|
|
1221
|
-
p = pending_introductions sender_id.
|
|
1222
|
-
abort "Message from an unknown sender was rejected." when p == NIL.
|
|
1223
|
-
entry = p?.
|
|
1224
|
-
queued = entry $messages.
|
|
1225
|
-
abort "Pending-introduction message queue is full; awaiting approval." when (_count queued|) >= pending_queue_cap.
|
|
1226
|
-
queued (_count queued|) -> ($text -> text, $date -> msg_date).
|
|
1227
|
-
pending_introductions sender_id -> ($name -> entry $name, $ad -> entry $ad, $messages -> queued).
|
|
1228
|
-
return transaction::success [
|
|
1229
|
-
_notify_agent ($event -> $pending_message, $sender_name -> entry $name, $queued -> _count queued|),
|
|
1230
|
-
_save_state NIL
|
|
1231
|
-
].
|
|
1232
|
-
}
|
|
1233
|
-
|
|
1234
|
-
sender_name = sender? $name.
|
|
1235
|
-
mid = deposit_message sender_id sender_name text msg_date.
|
|
1236
|
-
|
|
1237
|
-
// The notification deliberately carries NO message body — only that a
|
|
1238
|
-
// message arrived, from whom, and its id. The body stays in the packet
|
|
1239
|
-
// and only leaves through get_messages.
|
|
1240
|
-
return transaction::success [
|
|
1241
|
-
_notify_agent ($event -> $message_received, $sender_name -> sender_name, $msg_id -> mid, $date -> msg_date),
|
|
1242
|
-
_save_state NIL
|
|
1243
|
-
].
|
|
836
|
+
return a2a_messaging::handle_receive_message text.
|
|
1244
837
|
}
|
|
1245
838
|
|
|
1246
839
|
// A same-host peer connects via the local contact book. The credential must
|
|
@@ -1263,7 +856,7 @@ application actor loads libraries
|
|
|
1263
856
|
sender_id = current_transaction_info::get_external_envelope_or_abort() $from.
|
|
1264
857
|
abort "This identity does not accept local-contact-book introductions." when registrar_ad == NIL.
|
|
1265
858
|
|
|
1266
|
-
signed = (_read_or_abort intro_blob) safe signed_intro_t.
|
|
859
|
+
signed = (_read_or_abort intro_blob) safe a2a_protocol::signed_intro_t.
|
|
1267
860
|
intro = signed $i.
|
|
1268
861
|
abort "Unsupported introduction credential version." when (intro $version) != 1.
|
|
1269
862
|
abort "Introduction credential was not signed by this host's registrar." when key_storage::check_signature_new_container (_value_id intro) (signed $s) (registrar_ad? $identity $key_list) != TRUE.
|
|
@@ -1289,12 +882,12 @@ application actor loads libraries
|
|
|
1289
882
|
abort "Too many concurrent introductions; try again shortly." when (_count seen_nonces|) >= seen_nonce_cap.
|
|
1290
883
|
seen_nonces (intro $nonce) -> now.
|
|
1291
884
|
|
|
1292
|
-
existing = contacts sender_id.
|
|
885
|
+
existing = a2a_messaging::contacts sender_id.
|
|
1293
886
|
if existing != NIL
|
|
1294
887
|
{
|
|
1295
888
|
// Already a contact (idempotent re-introduction): keep my assigned
|
|
1296
889
|
// name, refresh the stored address document, deliver any payload.
|
|
1297
|
-
peer_ads sender_id -> joiner_ad.
|
|
890
|
+
a2a_messaging::peer_ads sender_id -> joiner_ad.
|
|
1298
891
|
if text != NIL
|
|
1299
892
|
{
|
|
1300
893
|
mid = deposit_message sender_id (existing? $name) text? now.
|
|
@@ -1308,8 +901,8 @@ application actor loads libraries
|
|
|
1308
901
|
|
|
1309
902
|
if local_auto_accept
|
|
1310
903
|
{
|
|
1311
|
-
contacts sender_id -> ($name -> joiner_name, $container_id -> sender_id).
|
|
1312
|
-
peer_ads sender_id -> joiner_ad.
|
|
904
|
+
a2a_messaging::contacts sender_id -> ($name -> joiner_name, $container_id -> sender_id).
|
|
905
|
+
a2a_messaging::peer_ads sender_id -> joiner_ad.
|
|
1313
906
|
if text != NIL
|
|
1314
907
|
{
|
|
1315
908
|
mid = deposit_message sender_id joiner_name text? now.
|
|
@@ -1356,30 +949,30 @@ application actor loads libraries
|
|
|
1356
949
|
sender_id = current_transaction_info::get_external_envelope_or_abort() $from.
|
|
1357
950
|
now = (current_transaction_info::get_transaction_time())?.
|
|
1358
951
|
|
|
1359
|
-
link is contact_root_t+ = NIL.
|
|
952
|
+
link is a2a_protocol::contact_root_t+ = NIL.
|
|
1360
953
|
if cert_blob == NIL
|
|
1361
954
|
{
|
|
1362
955
|
// Sender claims to be my root.
|
|
1363
|
-
abort "A certificate-less sibling introduction is only accepted from my root." when delegation_cert == NIL.
|
|
1364
|
-
abort "Sender is not my root." when sender_id != (delegation_cert? $c $root_cid).
|
|
956
|
+
abort "A certificate-less sibling introduction is only accepted from my root." when a2a_messaging::delegation_cert == NIL.
|
|
957
|
+
abort "Sender is not my root." when sender_id != (a2a_messaging::delegation_cert? $c $root_cid).
|
|
1365
958
|
link -> ($root_cid -> sender_id, $root_name -> joiner_name, $role_id -> "").
|
|
1366
959
|
}
|
|
1367
960
|
else
|
|
1368
961
|
{
|
|
1369
|
-
cert = (_read_or_abort cert_blob?) safe delegation_cert_t.
|
|
962
|
+
cert = (_read_or_abort cert_blob?) safe a2a_protocol::delegation_cert_t.
|
|
1370
963
|
abort "Unsupported delegation certificate version." when (cert $c $version) != 1.
|
|
1371
964
|
abort "Sibling certificate was issued for a different sender." when (cert $c $role_cid) != sender_id.
|
|
1372
965
|
abort "Sibling certificate does not match the sender's address document." when (cert $c $role_ad_hash) != (_value_id joiner_ad).
|
|
1373
966
|
|
|
1374
967
|
root_name_known is str = "".
|
|
1375
|
-
if delegation_cert != NIL
|
|
968
|
+
if a2a_messaging::delegation_cert != NIL
|
|
1376
969
|
{
|
|
1377
970
|
// I am a role: the cert must name MY root and verify against the
|
|
1378
971
|
// root key material pinned at delegation time.
|
|
1379
|
-
abort "My root material is missing — cannot verify sibling certificates." when root_ad == NIL.
|
|
1380
|
-
abort "Sibling certificate names a different root." when (cert $c $root_cid) != (delegation_cert? $c $root_cid).
|
|
1381
|
-
abort "Sibling certificate was not signed by my root." when key_storage::check_signature_new_container (_value_id (cert $c)) (cert $s) (root_ad? $identity $key_list) != TRUE.
|
|
1382
|
-
if root_profile != NIL { root_name_known -> root_profile? $p $name. }
|
|
972
|
+
abort "My root material is missing — cannot verify sibling certificates." when a2a_messaging::root_ad == NIL.
|
|
973
|
+
abort "Sibling certificate names a different root." when (cert $c $root_cid) != (a2a_messaging::delegation_cert? $c $root_cid).
|
|
974
|
+
abort "Sibling certificate was not signed by my root." when key_storage::check_signature_new_container (_value_id (cert $c)) (cert $s) (a2a_messaging::root_ad? $identity $key_list) != TRUE.
|
|
975
|
+
if a2a_messaging::root_profile != NIL { root_name_known -> a2a_messaging::root_profile? $p $name. }
|
|
1383
976
|
}
|
|
1384
977
|
else
|
|
1385
978
|
{
|
|
@@ -1388,18 +981,18 @@ application actor loads libraries
|
|
|
1388
981
|
abort "Sibling certificate names a different root." when (cert $c $root_cid) != _get_container_id().
|
|
1389
982
|
my_ad = address_document::get_my_address_document().
|
|
1390
983
|
abort "Sibling certificate was not signed by me." when key_storage::check_signature_new_container (_value_id (cert $c)) (cert $s) (my_ad $identity $key_list) != TRUE.
|
|
1391
|
-
root_name_known -> my_name.
|
|
984
|
+
root_name_known -> a2a_messaging::my_name.
|
|
1392
985
|
}
|
|
1393
986
|
link -> ($root_cid -> cert $c $root_cid, $root_name -> root_name_known, $role_id -> cert $c $role_id).
|
|
1394
987
|
}
|
|
1395
988
|
|
|
1396
|
-
existing = contacts sender_id.
|
|
989
|
+
existing = a2a_messaging::contacts sender_id.
|
|
1397
990
|
if existing != NIL
|
|
1398
991
|
{
|
|
1399
992
|
// Already a contact (idempotent re-introduction): keep my assigned
|
|
1400
993
|
// name, refresh the stored material, deliver any payload.
|
|
1401
|
-
peer_ads sender_id -> joiner_ad.
|
|
1402
|
-
contact_roots sender_id -> link?.
|
|
994
|
+
a2a_messaging::peer_ads sender_id -> joiner_ad.
|
|
995
|
+
a2a_messaging::contact_roots sender_id -> link?.
|
|
1403
996
|
if text != NIL
|
|
1404
997
|
{
|
|
1405
998
|
mid = deposit_message sender_id (existing? $name) text? now.
|
|
@@ -1411,9 +1004,9 @@ application actor loads libraries
|
|
|
1411
1004
|
return transaction::success [ _save_state NIL ].
|
|
1412
1005
|
}
|
|
1413
1006
|
|
|
1414
|
-
contacts sender_id -> ($name -> joiner_name, $container_id -> sender_id).
|
|
1415
|
-
peer_ads sender_id -> joiner_ad.
|
|
1416
|
-
contact_roots sender_id -> link?.
|
|
1007
|
+
a2a_messaging::contacts sender_id -> ($name -> joiner_name, $container_id -> sender_id).
|
|
1008
|
+
a2a_messaging::peer_ads sender_id -> joiner_ad.
|
|
1009
|
+
a2a_messaging::contact_roots sender_id -> link?.
|
|
1417
1010
|
if text != NIL
|
|
1418
1011
|
{
|
|
1419
1012
|
mid = deposit_message sender_id joiner_name text? now.
|
|
@@ -1,20 +1,25 @@
|
|
|
1
1
|
// a2adapt messenger packet — compile configuration.
|
|
2
2
|
//
|
|
3
|
-
// Pulls in the full ADAPT standard library
|
|
4
|
-
// the
|
|
5
|
-
//
|
|
6
|
-
//
|
|
3
|
+
// Pulls in the full ADAPT standard library plus the shared a2adapt mufl core
|
|
4
|
+
// (the a2adapt-mufl-core repo, checked out as the core/ subfolder) so
|
|
5
|
+
// `actor.mu` can `loads libraries` the crypto / identity / transport modules
|
|
6
|
+
// and the shared protocol libraries (`a2a_protocol`, `version`) by name.
|
|
7
7
|
//
|
|
8
|
-
// Compile:
|
|
9
|
-
//
|
|
10
|
-
// mufl-compile -mp <adapt-toolkit>/meta -mp <adapt-toolkit>/transactions -d-c actor.mu
|
|
11
|
-
// -> emits <content-hash>.muflo in the cwd.
|
|
8
|
+
// Compile: scripts/compile-mufl.sh (copies actor.mu, this file, and core/
|
|
9
|
+
// into a temp dir and runs mufl-compile there).
|
|
12
10
|
|
|
13
11
|
config script
|
|
14
12
|
{
|
|
13
|
+
stdlib_config = (config_load #$MUFL_STDLIB_PATH).
|
|
14
|
+
core_config = (config_load #"core").
|
|
15
|
+
|
|
15
16
|
(
|
|
16
|
-
$imports ->
|
|
17
|
-
|
|
17
|
+
$imports ->
|
|
18
|
+
(
|
|
19
|
+
$libraries -> (stdlib_config $exports $libraries)'(core_config $exports $libraries),
|
|
20
|
+
),
|
|
21
|
+
$exports ->
|
|
22
|
+
(
|
|
18
23
|
$libraries -> (,),
|
|
19
24
|
$applications -> (,)
|
|
20
25
|
)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adapt-toolkit/a2adapt",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.4",
|
|
4
4
|
"description": "MCP server daemon for a2adapt — one native ADAPT wrapper hosting N self-sovereign identities, exposing secure agent-to-agent messaging tools over HTTP (Streamable HTTP). Run `a2adapt-mcp start`.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|