mirror of
https://github.com/Skylar-Tech/node-red-contrib-matrix-chat.git
synced 2026-05-25 00:23:39 -06:00
Upgrade to matrix-js-sdk 41.5.0; add device verification
Upgrades matrix-js-sdk from 34.13.0 to 41.5.0. This crosses the v37 removal of the legacy libolm crypto stack, so E2EE is migrated to the Rust crypto implementation. Also adds device verification, cross-signing setup, and authenticated media support. Dependencies - Bump matrix-js-sdk ^34.13.0 -> ^41.5.0; require Node.js >= 22. - Drop the `olm` dependency (legacy crypto only); add `fake-indexeddb`. Rust crypto - Replace initCrypto() with initRustCrypto(); the legacy crypto stack was removed upstream in v37. - Add src/matrix-crypto-store.js: the Rust crypto store requires IndexedDB, absent in Node.js, so it is backed by fake-indexeddb and snapshotted to disk (rust-crypto-store.v8) to survive restarts. - Migrate existing libolm crypto state into the Rust store on first run, and discard the stored crypto state when the device ID changes. Homeserver discovery - Resolve the homeserver via .well-known, so a delegating domain (e.g. example.org) works as the configured server URL. Cross-signing & secure backup - Add a secured /matrix-chat/secure-backup admin endpoint and a modal dialog on the server config node: check status, unlock an existing secure backup with its recovery key, or reset and create a new one. Device verification (new nodes) - matrix-verification: event source emitting verification requests and phase changes, with on-node filters (phase, initiated by, type, self-verification, user allowlist, room). - matrix-verification-action: request, accept, start SAS, confirm, mismatch, or cancel an in-flight verification. Authenticated media - matrix-receive and matrix-crypt-file use the authenticated media endpoints, send a bearer token via msg.headers, and fall back between the v3 and v1 media endpoints on a 404. Fixes - Surface connection/auth errors in the log; node.error() calls were passed an empty msg object, which routed the error and suppressed console logging. - matrix-get-user: await getProfileInfo()/getPresence(). - matrix-invite-room: pass the reason as the third invite() argument (the removed callback parameter was shifting it out). - Guard the verification handlers so a throwing SDK getter cannot crash Node-RED. Docs - Add the device-verification example flow; update the READMEs and node help, correcting stale claims that device verification, secure backup, and encrypted file uploads were unsupported.
This commit is contained in:
@@ -32,7 +32,9 @@ module.exports = function(RED) {
|
||||
}
|
||||
|
||||
try{
|
||||
let buffer = await got(msg.url).buffer();
|
||||
const requestOptions = getRequestOptions(msg);
|
||||
|
||||
let buffer = await downloadBufferWithFallback(got, msg.url, requestOptions);
|
||||
msg.payload = Buffer.from(await decryptAttachment(buffer, msg.content.file));
|
||||
|
||||
// handle thumbnail decryption if necessary
|
||||
@@ -41,13 +43,14 @@ module.exports = function(RED) {
|
||||
&& msg.thumbnail_url
|
||||
&& msg.content.info.thumbnail_file
|
||||
) {
|
||||
let thumb_buffer = await got(msg.thumbnail_url).buffer();
|
||||
let thumb_buffer = await downloadBufferWithFallback(got, msg.thumbnail_url, requestOptions);
|
||||
msg.thumbnail_payload = Buffer.from(await decryptAttachment(thumb_buffer, msg.content.info.thumbnail_file));
|
||||
}
|
||||
} catch(error){
|
||||
node.error(error);
|
||||
msg.error = error;
|
||||
node.send([null, msg]);
|
||||
return;
|
||||
}
|
||||
|
||||
msg.filename = msg.content.filename || msg.content.body;
|
||||
@@ -57,6 +60,52 @@ module.exports = function(RED) {
|
||||
}
|
||||
RED.nodes.registerType("matrix-decrypt-file", MatrixDecryptFile);
|
||||
|
||||
function getRequestOptions(msg) {
|
||||
const headers = { ...(msg.headers || {}) };
|
||||
if (!headers.Authorization && msg.access_token) {
|
||||
headers.Authorization = `Bearer ${msg.access_token}`;
|
||||
}
|
||||
|
||||
return Object.keys(headers).length ? { headers } : {};
|
||||
}
|
||||
|
||||
function getMediaEndpointFallbackUrl(url) {
|
||||
if (typeof url !== "string") {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (url.includes("/_matrix/media/v3/download/")) {
|
||||
return url.replace("/_matrix/media/v3/download/", "/_matrix/client/v1/media/download/");
|
||||
}
|
||||
|
||||
if (url.includes("/_matrix/client/v1/media/download/")) {
|
||||
return url.replace("/_matrix/client/v1/media/download/", "/_matrix/media/v3/download/");
|
||||
}
|
||||
|
||||
if (url.includes("/_matrix/media/v3/thumbnail/")) {
|
||||
return url.replace("/_matrix/media/v3/thumbnail/", "/_matrix/client/v1/media/thumbnail/");
|
||||
}
|
||||
|
||||
if (url.includes("/_matrix/client/v1/media/thumbnail/")) {
|
||||
return url.replace("/_matrix/client/v1/media/thumbnail/", "/_matrix/media/v3/thumbnail/");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
async function downloadBufferWithFallback(got, url, requestOptions) {
|
||||
try {
|
||||
return await got(url, requestOptions).buffer();
|
||||
} catch (error) {
|
||||
const fallbackUrl = getMediaEndpointFallbackUrl(url);
|
||||
if (error?.response?.statusCode === 404 && fallbackUrl && fallbackUrl !== url) {
|
||||
return await got(fallbackUrl, requestOptions).buffer();
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
function atob(a) {
|
||||
return Buffer.from(a, 'base64').toString('binary');
|
||||
}
|
||||
@@ -200,4 +249,4 @@ module.exports = function(RED) {
|
||||
}
|
||||
return uint8Array;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user