mirror of
https://github.com/Skylar-Tech/node-red-contrib-matrix-chat.git
synced 2026-05-14 11:13:37 -06:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| db14bd96a7 | |||
| 512b7320d5 |
Generated
+5031
-16691
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -3,18 +3,18 @@
|
|||||||
"version": "0.8.0",
|
"version": "0.8.0",
|
||||||
"description": "Matrix chat server client for Node-RED",
|
"description": "Matrix chat server client for Node-RED",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@matrix-org/matrix-sdk-crypto-nodejs": "^0.2.0-beta.1",
|
||||||
"abort-controller": "^3.0.0",
|
"abort-controller": "^3.0.0",
|
||||||
"fluent-ffmpeg": "^2.1.2",
|
"fluent-ffmpeg": "^2.1.2",
|
||||||
"fs-extra": "^11.1.0",
|
"fs-extra": "^11.1.0",
|
||||||
"got": "^12.0.2",
|
"got": "^12.0.2",
|
||||||
"image-size": "^1.0.2",
|
"image-size": "^1.0.2",
|
||||||
"isomorphic-webcrypto": "^2.3.8",
|
"isomorphic-webcrypto": "^2.3.8",
|
||||||
"matrix-js-sdk": "^28.0.0",
|
"matrix-js-sdk": "^34.5.0",
|
||||||
"mime": "^3.0.0",
|
"mime": "^3.0.0",
|
||||||
"node-fetch": "^3.3.0",
|
"node-fetch": "^3.3.0",
|
||||||
"node-localstorage": "^2.2.1",
|
"node-localstorage": "^2.2.1",
|
||||||
"olm": "https://gitlab.matrix.org/matrix-org/olm/-/package_files/2572/download",
|
"olm": "https://gitlab.matrix.org/matrix-org/olm/-/package_files/2572/download",
|
||||||
"request": "^2.88.2",
|
|
||||||
"sharp": "^0.33.4",
|
"sharp": "^0.33.4",
|
||||||
"tmp": "^0.2.1",
|
"tmp": "^0.2.1",
|
||||||
"utf8": "^3.0.0"
|
"utf8": "^3.0.0"
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
const {RelationType, EventType, Direction} = require("matrix-js-sdk");
|
|
||||||
|
|
||||||
module.exports = function(RED) {
|
module.exports = function(RED) {
|
||||||
function MatrixFetchRelations(n) {
|
function MatrixFetchRelations(n) {
|
||||||
RED.nodes.createNode(this, n);
|
RED.nodes.createNode(this, n);
|
||||||
@@ -43,6 +41,8 @@ module.exports = function(RED) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
node.on("input", async function(msg) {
|
node.on("input", async function(msg) {
|
||||||
|
const {Direction} = await import("matrix-js-sdk");
|
||||||
|
|
||||||
if (!node.server || !node.server.matrixClient) {
|
if (!node.server || !node.server.matrixClient) {
|
||||||
node.error("No matrix server selected", msg);
|
node.error("No matrix server selected", msg);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
const {TimelineWindow, RelationType, Filter} = require("matrix-js-sdk");
|
|
||||||
const crypto = require('crypto');
|
|
||||||
module.exports = function(RED) {
|
module.exports = function(RED) {
|
||||||
function MatrixReceiveMessage(n) {
|
function MatrixReceiveMessage(n) {
|
||||||
RED.nodes.createNode(this, n);
|
RED.nodes.createNode(this, n);
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
const {TimelineWindow, RelationType, Filter} = require("matrix-js-sdk");
|
|
||||||
const crypto = require('crypto');
|
|
||||||
module.exports = function(RED) {
|
module.exports = function(RED) {
|
||||||
function MatrixReceiveMessage(n) {
|
function MatrixReceiveMessage(n) {
|
||||||
RED.nodes.createNode(this, n);
|
RED.nodes.createNode(this, n);
|
||||||
@@ -34,6 +32,9 @@ module.exports = function(RED) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
node.on("input", async function (msg) {
|
node.on("input", async function (msg) {
|
||||||
|
const {TimelineWindow, RelationType, Filter} = await import("matrix-js-sdk");
|
||||||
|
const crypto = await import('crypto');
|
||||||
|
|
||||||
if (! node.server || ! node.server.matrixClient) {
|
if (! node.server || ! node.server.matrixClient) {
|
||||||
node.error("No matrix server selected", msg);
|
node.error("No matrix server selected", msg);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
const {RelationType} = require("matrix-js-sdk");
|
|
||||||
module.exports = function(RED) {
|
module.exports = function(RED) {
|
||||||
function MatrixReceiveMessage(n) {
|
function MatrixReceiveMessage(n) {
|
||||||
RED.nodes.createNode(this, n);
|
RED.nodes.createNode(this, n);
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
const {RelationType} = require("matrix-js-sdk");
|
|
||||||
|
|
||||||
module.exports = function(RED) {
|
module.exports = function(RED) {
|
||||||
function MatrixSendImage(n) {
|
function MatrixSendImage(n) {
|
||||||
RED.nodes.createNode(this, n);
|
RED.nodes.createNode(this, n);
|
||||||
@@ -68,7 +66,8 @@ module.exports = function(RED) {
|
|||||||
node.status({ fill: "green", shape: "ring", text: "connected" });
|
node.status({ fill: "green", shape: "ring", text: "connected" });
|
||||||
});
|
});
|
||||||
|
|
||||||
node.on("input", function (msg) {
|
node.on("input", async function (msg) {
|
||||||
|
const {RelationType} = await import("matrix-js-sdk");
|
||||||
function getToValue(msg, type, property) {
|
function getToValue(msg, type, property) {
|
||||||
let value = property;
|
let value = property;
|
||||||
if (type === "msg") {
|
if (type === "msg") {
|
||||||
|
|||||||
+50
-60
@@ -1,14 +1,10 @@
|
|||||||
const {RelationType, TimelineWindow} = require("matrix-js-sdk");
|
|
||||||
|
|
||||||
global.Olm = require('olm');
|
global.Olm = require('olm');
|
||||||
const fs = require("fs-extra");
|
const fs = require("fs-extra");
|
||||||
const sdk = require("matrix-js-sdk");
|
|
||||||
const { resolve } = require('path');
|
const { resolve } = require('path');
|
||||||
const { LocalStorage } = require('node-localstorage');
|
const { LocalStorage } = require('node-localstorage');
|
||||||
const { LocalStorageCryptoStore } = require('matrix-js-sdk/lib/crypto/store/localStorage-crypto-store');
|
globalThis.crypto = require('crypto');
|
||||||
const {RoomEvent, RoomMemberEvent, HttpApiEvent, ClientEvent, MemoryStore} = require("matrix-js-sdk");
|
|
||||||
const request = require("request");
|
|
||||||
require("abort-controller/polyfill"); // polyfill abort-controller if we don't have it
|
require("abort-controller/polyfill"); // polyfill abort-controller if we don't have it
|
||||||
|
|
||||||
if (!globalThis.fetch) {
|
if (!globalThis.fetch) {
|
||||||
// polyfill fetch if we don't have it
|
// polyfill fetch if we don't have it
|
||||||
if (!globalThis.fetch) {
|
if (!globalThis.fetch) {
|
||||||
@@ -19,16 +15,22 @@ if (!globalThis.fetch) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
module.exports = function(RED) {
|
module.exports = function(RED) {
|
||||||
|
// Prepare dynamic imports
|
||||||
|
const sdkPromise = import("matrix-js-sdk");
|
||||||
|
const LocalStorageCryptoStorePromise = import('matrix-js-sdk/lib/crypto/store/localStorage-crypto-store.js');
|
||||||
|
const loggerPromise = import('matrix-js-sdk/lib/logger.js');
|
||||||
|
|
||||||
// disable logging if set to "off"
|
// disable logging if set to "off"
|
||||||
let loggingSettings = RED.settings.get('logging');
|
// let loggingSettings = RED.settings.get('logging');
|
||||||
if(
|
// if(
|
||||||
typeof loggingSettings.console !== 'undefined' &&
|
// typeof loggingSettings.console !== 'undefined' &&
|
||||||
typeof loggingSettings.console.level !== 'undefined' &&
|
// typeof loggingSettings.console.level !== 'undefined' &&
|
||||||
['info','debug','trace'].indexOf(loggingSettings.console.level.toLowerCase()) >= 0
|
// ['info','debug','trace'].indexOf(loggingSettings.console.level.toLowerCase()) >= 0
|
||||||
) {
|
// ) {
|
||||||
const { logger } = require('matrix-js-sdk/lib/logger');
|
// loggerPromise.then(({ logger }) => {
|
||||||
logger.disableAll();
|
// logger.disableAll();
|
||||||
}
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
function MatrixFolderNameFromUserId(name) {
|
function MatrixFolderNameFromUserId(name) {
|
||||||
return name.replace(/[^a-z0-9]/gi, '_').toLowerCase();
|
return name.replace(/[^a-z0-9]/gi, '_').toLowerCase();
|
||||||
@@ -83,7 +85,7 @@ module.exports = function(RED) {
|
|||||||
} else if(!this.url) {
|
} else if(!this.url) {
|
||||||
node.error("Matrix connection failed: missing server URL in configuration.", {});
|
node.error("Matrix connection failed: missing server URL in configuration.", {});
|
||||||
} else {
|
} else {
|
||||||
node.setConnected = async function(connected, cb) {
|
node.setConnected = function(connected, cb) {
|
||||||
if (node.connected !== connected) {
|
if (node.connected !== connected) {
|
||||||
node.connected = connected;
|
node.connected = connected;
|
||||||
if(typeof cb === 'function') {
|
if(typeof cb === 'function') {
|
||||||
@@ -145,16 +147,21 @@ module.exports = function(RED) {
|
|||||||
|
|
||||||
fs.ensureDirSync(storageDir); // create storage directory if it doesn't exist
|
fs.ensureDirSync(storageDir); // create storage directory if it doesn't exist
|
||||||
upgradeDirectoryIfNecessary(node, storageDir);
|
upgradeDirectoryIfNecessary(node, storageDir);
|
||||||
|
|
||||||
|
// Wait for the dynamic imports to resolve
|
||||||
|
Promise.all([sdkPromise, LocalStorageCryptoStorePromise]).then(([sdkModule, LocalStorageCryptoStoreModule]) => {
|
||||||
|
const sdk = sdkModule.default || sdkModule;
|
||||||
|
const { LocalStorageCryptoStore } = LocalStorageCryptoStoreModule;
|
||||||
|
|
||||||
node.matrixClient = sdk.createClient({
|
node.matrixClient = sdk.createClient({
|
||||||
baseUrl: this.url,
|
baseUrl: this.url,
|
||||||
accessToken: this.credentials.accessToken,
|
accessToken: this.credentials.accessToken,
|
||||||
cryptoStore: new LocalStorageCryptoStore(localStorage),
|
cryptoStore: new LocalStorageCryptoStore(localStorage),
|
||||||
store: new MemoryStore({
|
store: new sdk.MemoryStore({
|
||||||
localStorage: localStorage,
|
localStorage: localStorage,
|
||||||
}),
|
}),
|
||||||
userId: this.userId,
|
userId: this.userId,
|
||||||
deviceId: (this.deviceId || getStoredDeviceId(localStorage)) || undefined,
|
deviceId: (this.deviceId || getStoredDeviceId(localStorage)) || undefined
|
||||||
request
|
|
||||||
// verificationMethods: ["m.sas.v1"]
|
// verificationMethods: ["m.sas.v1"]
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -192,6 +199,8 @@ module.exports = function(RED) {
|
|||||||
return node.connected;
|
return node.connected;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const { RelationType, RoomEvent, RoomMemberEvent, HttpApiEvent, ClientEvent } = sdk;
|
||||||
|
|
||||||
node.matrixClient.on(RoomEvent.Timeline, async function(event, room, toStartOfTimeline, removed, data) {
|
node.matrixClient.on(RoomEvent.Timeline, async function(event, room, toStartOfTimeline, removed, data) {
|
||||||
if (toStartOfTimeline) {
|
if (toStartOfTimeline) {
|
||||||
node.log("Ignoring" + (event.isEncrypted() ? ' encrypted' : '') +" timeline event [" + (event.getContent()['msgtype'] || event.getType()) + "]: (" + room.name + ") " + event.getId() + " for reason: paginated result");
|
node.log("Ignoring" + (event.isEncrypted() ? ' encrypted' : '') +" timeline event [" + (event.getContent()['msgtype'] || event.getType()) + "]: (" + room.name + ") " + event.getId() + " for reason: paginated result");
|
||||||
@@ -245,42 +254,18 @@ module.exports = function(RED) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// remove keys from user property that start with an underscore
|
// remove keys from user property that start with an underscore
|
||||||
|
if (msg.user) {
|
||||||
Object.keys(msg.user).forEach(function (key) {
|
Object.keys(msg.user).forEach(function (key) {
|
||||||
if (/^_/.test(key)) {
|
if (/^_/.test(key)) {
|
||||||
delete msg.user[key];
|
delete msg.user[key];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
node.log(`Received ${msg.encrypted ? 'encrypted ' : ''}timeline event [${msg.type}]: (${room.name}) ${event.getSender()} :: ${msg.content.body} ${toStartOfTimeline ? ' [PAGINATED]' : ''}`);
|
node.log(`Received ${msg.encrypted ? 'encrypted ' : ''}timeline event [${msg.type}]: (${room.name}) ${event.getSender()} :: ${msg.content.body} ${toStartOfTimeline ? ' [PAGINATED]' : ''}`);
|
||||||
node.emit("Room.timeline", event, room, toStartOfTimeline, removed, data, msg);
|
node.emit("Room.timeline", event, room, toStartOfTimeline, removed, data, msg);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* Fires when we want to suggest to the user that they restore their megolm keys
|
|
||||||
* from backup or by cross-signing the device.
|
|
||||||
*
|
|
||||||
* @event module:client~MatrixClient#"crypto.suggestKeyRestore"
|
|
||||||
*/
|
|
||||||
// node.matrixClient.on("crypto.suggestKeyRestore", function(){
|
|
||||||
//
|
|
||||||
// });
|
|
||||||
|
|
||||||
// node.matrixClient.on("RoomMember.typing", async function(event, member) {
|
|
||||||
// let isTyping = member.typing;
|
|
||||||
// let roomId = member.roomId;
|
|
||||||
// });
|
|
||||||
|
|
||||||
// node.matrixClient.on("RoomMember.powerLevel", async function(event, member) {
|
|
||||||
// let newPowerLevel = member.powerLevel;
|
|
||||||
// let newNormPowerLevel = member.powerLevelNorm;
|
|
||||||
// let roomId = member.roomId;
|
|
||||||
// });
|
|
||||||
|
|
||||||
// node.matrixClient.on("RoomMember.name", async function(event, member) {
|
|
||||||
// let newName = member.name;
|
|
||||||
// let roomId = member.roomId;
|
|
||||||
// });
|
|
||||||
|
|
||||||
// handle auto-joining rooms
|
// handle auto-joining rooms
|
||||||
|
|
||||||
node.matrixClient.on(RoomMemberEvent.Membership, async function(event, member) {
|
node.matrixClient.on(RoomMemberEvent.Membership, async function(event, member) {
|
||||||
@@ -380,17 +365,6 @@ module.exports = function(RED) {
|
|||||||
|
|
||||||
|
|
||||||
node.matrixClient.on(HttpApiEvent.SessionLoggedOut, async function(errorObj){
|
node.matrixClient.on(HttpApiEvent.SessionLoggedOut, async function(errorObj){
|
||||||
// Example if user auth token incorrect:
|
|
||||||
// {
|
|
||||||
// errcode: 'M_UNKNOWN_TOKEN',
|
|
||||||
// data: {
|
|
||||||
// errcode: 'M_UNKNOWN_TOKEN',
|
|
||||||
// error: 'Invalid macaroon passed.',
|
|
||||||
// soft_logout: false
|
|
||||||
// },
|
|
||||||
// httpStatus: 401
|
|
||||||
// }
|
|
||||||
|
|
||||||
node.error("Authentication failure: " + errorObj, {});
|
node.error("Authentication failure: " + errorObj, {});
|
||||||
stopClient();
|
stopClient();
|
||||||
});
|
});
|
||||||
@@ -398,8 +372,13 @@ module.exports = function(RED) {
|
|||||||
async function run() {
|
async function run() {
|
||||||
try {
|
try {
|
||||||
if(node.e2ee){
|
if(node.e2ee){
|
||||||
node.log("Initializing crypto...");
|
node.matrixClient.on("crypto.legacyCryptoStoreMigrationProgress", function(progress, total){
|
||||||
await node.matrixClient.initCrypto();
|
node.log(`Migrating from legacy crypto to rust crypto. ${progress}/${total}`);
|
||||||
|
});
|
||||||
|
await node.matrixClient.initRustCrypto({
|
||||||
|
useIndexedDB: false
|
||||||
|
});
|
||||||
|
console.log(`CRYPTO VERSION: ${node.matrixClient.getCrypto()?.getVersion()}`);
|
||||||
node.matrixClient.getCrypto().globalBlacklistUnverifiedDevices = false; // prevent errors from unverified devices
|
node.matrixClient.getCrypto().globalBlacklistUnverifiedDevices = false; // prevent errors from unverified devices
|
||||||
}
|
}
|
||||||
node.log("Connecting to Matrix server...");
|
node.log("Connecting to Matrix server...");
|
||||||
@@ -407,6 +386,7 @@ module.exports = function(RED) {
|
|||||||
initialSyncLimit: node.initialSyncLimit
|
initialSyncLimit: node.initialSyncLimit
|
||||||
});
|
});
|
||||||
} catch(error) {
|
} catch(error) {
|
||||||
|
node.error(error);
|
||||||
node.error(error, {});
|
node.error(error, {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -452,6 +432,9 @@ module.exports = function(RED) {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
})();
|
})();
|
||||||
|
}).catch((error) => {
|
||||||
|
node.error("Failed to load Matrix SDK modules: " + error, {});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -475,6 +458,9 @@ module.exports = function(RED) {
|
|||||||
deviceId = req.body.deviceId || undefined,
|
deviceId = req.body.deviceId || undefined,
|
||||||
displayName = req.body.displayName || undefined;
|
displayName = req.body.displayName || undefined;
|
||||||
|
|
||||||
|
sdkPromise.then((sdkModule) => {
|
||||||
|
const sdk = sdkModule.default || sdk;
|
||||||
|
|
||||||
const matrixClient = sdk.createClient({
|
const matrixClient = sdk.createClient({
|
||||||
baseUrl: baseUrl,
|
baseUrl: baseUrl,
|
||||||
deviceId: deviceId,
|
deviceId: deviceId,
|
||||||
@@ -483,8 +469,6 @@ module.exports = function(RED) {
|
|||||||
request
|
request
|
||||||
});
|
});
|
||||||
|
|
||||||
new TimelineWindow()
|
|
||||||
|
|
||||||
matrixClient.timelineSupport = true;
|
matrixClient.timelineSupport = true;
|
||||||
|
|
||||||
matrixClient.login(
|
matrixClient.login(
|
||||||
@@ -512,6 +496,12 @@ module.exports = function(RED) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
}).catch((error) => {
|
||||||
|
res.json({
|
||||||
|
'result': 'error',
|
||||||
|
'message': "Failed to load Matrix SDK: " + error
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function upgradeDirectoryIfNecessary(node, storageDir) {
|
function upgradeDirectoryIfNecessary(node, storageDir) {
|
||||||
|
|||||||
Reference in New Issue
Block a user