@rine-network/cli 0.3.0 → 0.4.0
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/dist/main.js +82 -32
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -1700,6 +1700,31 @@ async function getOrCreateSenderKey(client, senderAgentId, groupHandle, extraHea
|
|
|
1700
1700
|
groupId
|
|
1701
1701
|
};
|
|
1702
1702
|
}
|
|
1703
|
+
/**
|
|
1704
|
+
* Fetch pending sender key distributions from the inbox and ingest them.
|
|
1705
|
+
* Used by `read` and `stream` to auto-recover when a sender key is missing.
|
|
1706
|
+
*
|
|
1707
|
+
* Optionally short-circuits once `targetSenderKeyId` is ingested.
|
|
1708
|
+
* Returns the number of newly ingested keys.
|
|
1709
|
+
*/
|
|
1710
|
+
async function fetchAndIngestPendingSKDistributions(client, agentId, targetSenderKeyId) {
|
|
1711
|
+
const inbox = await client.get(`/agents/${agentId}/messages`, {
|
|
1712
|
+
type: "rine.v1.sender_key_distribution",
|
|
1713
|
+
limit: 100
|
|
1714
|
+
});
|
|
1715
|
+
let ingested = 0;
|
|
1716
|
+
for (const msg of inbox.items) try {
|
|
1717
|
+
const full = await client.get(`/messages/${msg.id}`);
|
|
1718
|
+
const result = await decryptMessage(agentId, full.encrypted_payload, client);
|
|
1719
|
+
if (ingestSenderKeyDistribution(agentId, full.type, result)) {
|
|
1720
|
+
ingested++;
|
|
1721
|
+
if (targetSenderKeyId) {
|
|
1722
|
+
if (JSON.parse(result.plaintext).sender_key_id === targetSenderKeyId) break;
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1725
|
+
} catch {}
|
|
1726
|
+
return ingested;
|
|
1727
|
+
}
|
|
1703
1728
|
//#endregion
|
|
1704
1729
|
//#region src/commands/messages.ts
|
|
1705
1730
|
function msgFrom(m) {
|
|
@@ -1775,32 +1800,48 @@ function addMessageCommands(parent, program) {
|
|
|
1775
1800
|
parent.command("read").description("Read and decrypt a message by ID").argument("<message-id>", "Message ID").option("--agent <id>", "Agent ID (for decryption key)").action(withClient(program, async ({ client, gOpts }, messageId, opts) => {
|
|
1776
1801
|
const data = await client.get(`/messages/${messageId}`);
|
|
1777
1802
|
const agentId = await resolveAgent(client, opts.agent, gOpts.as);
|
|
1778
|
-
if ((data.encryption_version === "hpke-v1" || data.encryption_version === "sender-key-v1") && agentKeysExist(agentId))
|
|
1803
|
+
if ((data.encryption_version === "hpke-v1" || data.encryption_version === "sender-key-v1") && agentKeysExist(agentId)) {
|
|
1779
1804
|
let result;
|
|
1780
|
-
if (data.encryption_version === "sender-key-v1" && data.group_id)
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1805
|
+
if (data.encryption_version === "sender-key-v1" && data.group_id) try {
|
|
1806
|
+
result = await decryptGroupMessage(agentId, data.group_id, data.encrypted_payload, client);
|
|
1807
|
+
} catch (err) {
|
|
1808
|
+
const match = err instanceof Error && err.message.match(/^unknown sender key id: (.+)$/);
|
|
1809
|
+
if (match) {
|
|
1810
|
+
if (await fetchAndIngestPendingSKDistributions(client, agentId, match[1]) > 0) try {
|
|
1811
|
+
result = await decryptGroupMessage(agentId, data.group_id, data.encrypted_payload, client);
|
|
1812
|
+
} catch (retryErr) {
|
|
1813
|
+
if (!gOpts.json) printError(`Decryption failed after auto-ingest: ${retryErr instanceof Error ? retryErr.message : String(retryErr)}`);
|
|
1814
|
+
}
|
|
1815
|
+
else if (!gOpts.json) printError(`Decryption failed: ${err.message}`);
|
|
1816
|
+
} else if (!gOpts.json) printError(`Decryption failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1817
|
+
}
|
|
1818
|
+
else try {
|
|
1819
|
+
result = await decryptMessage(agentId, data.encrypted_payload, client);
|
|
1820
|
+
} catch (err) {
|
|
1821
|
+
if (!gOpts.json) printError(`Decryption failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1822
|
+
}
|
|
1823
|
+
if (result) {
|
|
1824
|
+
if (ingestSenderKeyDistribution(agentId, data.type, result)) printText("Sender key ingested");
|
|
1825
|
+
if (gOpts.json) printJson({
|
|
1826
|
+
...data,
|
|
1827
|
+
decrypted_payload: JSON.parse(result.plaintext),
|
|
1828
|
+
signature_verified: result.verified,
|
|
1829
|
+
verification_status: result.verificationStatus,
|
|
1830
|
+
sender_kid: result.senderKid
|
|
1831
|
+
});
|
|
1832
|
+
else printTable([{
|
|
1833
|
+
ID: data.id,
|
|
1834
|
+
"Conversation ID": data.conversation_id,
|
|
1835
|
+
From: msgFrom(data),
|
|
1836
|
+
To: msgTo(data),
|
|
1837
|
+
Group: msgGroup(data),
|
|
1838
|
+
Type: data.type,
|
|
1839
|
+
Verified: result.verificationStatus === "verified" ? "✓" : result.verificationStatus === "invalid" ? "✗ INVALID" : "?",
|
|
1840
|
+
Payload: result.plaintext.slice(0, 200),
|
|
1841
|
+
Created: data.created_at
|
|
1842
|
+
}]);
|
|
1843
|
+
return;
|
|
1844
|
+
}
|
|
1804
1845
|
}
|
|
1805
1846
|
if (gOpts.json) printJson(data);
|
|
1806
1847
|
else printTable([{
|
|
@@ -2004,16 +2045,25 @@ async function formatMessageLine(dataStr, agentId, client) {
|
|
|
2004
2045
|
const msgType = data.type ?? "?";
|
|
2005
2046
|
const target = data.group_handle ? `${data.group_handle} (${msgType})` : msgType;
|
|
2006
2047
|
let preview = "[encrypted]";
|
|
2007
|
-
if (data.encrypted_payload && agentKeysExist(agentId))
|
|
2048
|
+
if (data.encrypted_payload && agentKeysExist(agentId)) {
|
|
2008
2049
|
let result;
|
|
2009
|
-
if (data.encryption_version === "sender-key-v1" && data.group_id)
|
|
2010
|
-
|
|
2050
|
+
if (data.encryption_version === "sender-key-v1" && data.group_id) try {
|
|
2051
|
+
result = await decryptGroupMessage(agentId, data.group_id, data.encrypted_payload, client);
|
|
2052
|
+
} catch (err) {
|
|
2053
|
+
const match = err instanceof Error && err.message.match(/^unknown sender key id: (.+)$/);
|
|
2054
|
+
if (match) {
|
|
2055
|
+
if (await fetchAndIngestPendingSKDistributions(client, agentId, match[1]) > 0) try {
|
|
2056
|
+
result = await decryptGroupMessage(agentId, data.group_id, data.encrypted_payload, client);
|
|
2057
|
+
} catch {}
|
|
2058
|
+
}
|
|
2059
|
+
}
|
|
2060
|
+
else if (data.encryption_version === "hpke-v1") try {
|
|
2011
2061
|
result = await decryptMessage(agentId, data.encrypted_payload, client);
|
|
2062
|
+
} catch {}
|
|
2063
|
+
if (result) {
|
|
2012
2064
|
ingestSenderKeyDistribution(agentId, data.type ?? "", result);
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
} catch {
|
|
2016
|
-
preview = "[decrypt failed]";
|
|
2065
|
+
preview = `[${result.verified ? "✓" : "?"}] ${result.plaintext.slice(0, 60)}`;
|
|
2066
|
+
} else if (data.encryption_version === "hpke-v1" || data.encryption_version === "sender-key-v1") preview = "[decrypt failed]";
|
|
2017
2067
|
}
|
|
2018
2068
|
return `[${ts}] ${sender} \u2192 ${target}: ${preview}`;
|
|
2019
2069
|
} catch {
|