Compare commits

..

30 Commits

Author SHA1 Message Date
skylord123 4c17a21008 Merge pull request #63 from Skylar-Tech/dev
Version 0.6.1
2022-04-19 13:03:47 -06:00
skylord123 bd4f6ea486 Update version to 0.6.1
- Fix: Error thrown in folder migration if new and old path are same
2022-04-19 13:01:00 -06:00
skylord123 5ef0b6a11f Fix: Error thrown in folder migration if new and old path are same 2022-04-19 12:58:52 -06:00
skylord123 97f27e61c6 Merge pull request #62 from Skylar-Tech/61-audio-messages
61 audio messages
2022-03-28 00:45:22 -06:00
skylord123 7bdadc0fe9 Closes #209
- Can now receive audio files
- Can now receive locations
- Readme updated
2022-03-28 00:42:52 -06:00
skylord123 5f129560aa Couple of little changes:
- Fix matrix-receive message types displaying in uppercase when it should be lowercase
- Readme updated with some extra things that are now possible since last release
- Link to matrix.org project in our README.md
2022-03-28 00:42:19 -06:00
skylord123 00bc14e1c7 Merge pull request #59 from Skylar-Tech/dev
Version 0.5.8
2022-03-18 13:50:28 -06:00
skylord123 9f41b67174 Version 0.5.8 2022-03-18 13:49:38 -06:00
skylord123 4e93b7253e Revert examples 2022-03-18 13:37:24 -06:00
skylord123 ecb4427217 - Revert device verification/e2ee stuff. It's not ready. 2022-03-18 13:34:46 -06:00
skylord123 3e70369cae WIP 2022-03-18 00:23:28 -06:00
skylord123 2ce80e2906 Update version to 0.5.5
- `fs-extra` and `got` dependencies updates
2022-03-17 21:06:15 -06:00
skylord123 0c657caf5f Update version to 0.5.0 2022-03-17 20:05:06 -06:00
skylord123 848fd0ec9d Merge pull request #58 from Skylar-Tech/48-key-sharing
48 key sharing
2022-03-17 20:03:56 -06:00
skylord123 fef40f4ea9 - Update matrix-device-verification node description with super basic info on how to use it 2022-03-17 20:03:48 -06:00
skylord123 595fbca3df - Update main readme with new verification notes 2022-03-17 19:58:25 -06:00
skylord123 487f17a439 Update examples to move function example above verification ones. 2022-03-17 19:54:13 -06:00
skylord123 68cb5a026e Update examples to include one for receiving and requesting device verification 2022-03-17 19:51:14 -06:00
skylord123 d01733c647 closes #48
- Device verification can now be requested or received
2022-03-17 19:38:29 -06:00
skylord123 ed146e98d8 Closes #56 Closes #50
- can now specify message in node's configuration for matrix-send-message
- can now specify reaction in node's configuration for matrix-react
- reason can now be configured on both matrix-room-kick and matrix-room-ban
- icons updated for various nodes
- fix tag for name configuration field for various nodes
- roomId input is now validated to ensure it starts with ! and if not shows an error
2022-03-17 17:21:44 -06:00
skylord123 3dc6363a88 Closes #56
- can now specify message in node's configuration for matrix-send-message
- can now specify reaction in node's configuration for matrix-react
- reason can now be configured on both matrix-room-kick and matrix-room-ban
- icons updated for various nodes
2022-03-17 16:01:27 -06:00
skylord123 380e548425 Closes #54
- New option for matrix-send-message node that allows replacing existing message if enabled and `msg.eventId` is passed in.
2022-03-17 15:37:10 -06:00
skylord123 27dd4d81a2 name should default to null 2022-03-17 14:47:01 -06:00
skylord123 de3c58044f Add example for delete-event node 2022-03-17 14:40:53 -06:00
skylord123 db1901ed1e Closes #29
- msg.isDM is now returned on received messages to help determine if it originated from a direct message room
2022-03-17 14:30:10 -06:00
skylord123 ac68060825 - matrix-crypt-file documentation updated (it cannot encrypt, only decrypts)
- matrix-js-sdk update from 15.5.0 to 16.0.0
- Fixed matrix-js-sdk breaking changes
- @matrix-org_olm-3.2.8.tgz added to package since there is no npm release for this. It fixes some errors so we need it.
2022-03-17 14:23:22 -06:00
skylord123 d304cb95f6 Merge pull request #55 from Skylar-Tech/51-device_id-fix
- We now use /whoami to validate the auth token since it gives us the…
2022-03-17 13:29:48 -06:00
skylord123 85764c08d3 Merge pull request #52 from aikitori/feature/delete-message
Add Delete Message Node
2022-03-17 12:26:40 -06:00
aikitori 050be29d64 rename node 2022-03-13 10:58:17 +01:00
aikitori d826c58b51 Add Delete Message Node 2022-03-12 16:48:52 +01:00
34 changed files with 1107 additions and 524 deletions
Binary file not shown.
+4 -2
View File
@@ -1,5 +1,5 @@
# node-red-contrib-matrix-chat # node-red-contrib-matrix-chat
Matrix chat server client for [Node-RED](https://nodered.org/) [Matrix](https://matrix.org/) chat server client for [Node-RED](https://nodered.org/)
***Currently we are in beta. We ask that you open any issues you have on our repository to help us reach a stable well tested version. Things may change & break before our first release so check changelog before updating.*** ***Currently we are in beta. We ask that you open any issues you have on our repository to help us reach a stable well tested version. Things may change & break before our first release so check changelog before updating.***
@@ -11,8 +11,10 @@ The following is supported from this package:
- End-to-end encryption - End-to-end encryption
- [Currently a WIP](#end-to-end-encryption-notes) - [Currently a WIP](#end-to-end-encryption-notes)
- Receive events from a room (messages, reactions, images, and files) whether encrypted or not - Receive events from a room (messages, reactions, images, audio, locations, and files) whether encrypted or not
- Send Images/Files (sending files to e2ee room doesn't currently encrypt them yet) - Send Images/Files (sending files to e2ee room doesn't currently encrypt them yet)
- Edit messages
- Delete events (messages, reactions, etc)
- Decrypt files in e2ee rooms - Decrypt files in e2ee rooms
- Send HTML/Plain Text Message/Notice - Send HTML/Plain Text Message/Notice
- React to messages - React to messages
+14 -1
View File
@@ -15,6 +15,7 @@ Build something cool with these nodes? Feel free to submit a pull request to sha
- [Respond to "image" with an uploaded image](#respond-to-image-with-an-uploaded-image) - [Respond to "image" with an uploaded image](#respond-to-image-with-an-uploaded-image)
- [Respond to "file" with an uploaded file](#respond-to-file-with-an-uploaded-file) - [Respond to "file" with an uploaded file](#respond-to-file-with-an-uploaded-file)
- [Respond to "react" with a reaction](#respond-to-react-with-a-reaction) - [Respond to "react" with a reaction](#respond-to-react-with-a-reaction)
- [Remove messages containing "delete"](#remove-messages-containing-delete)
- [Respond to "users" with full list of server users](#respond-to-users-with-full-list-of-server-users) - [Respond to "users" with full list of server users](#respond-to-users-with-full-list-of-server-users)
- [Respond to "newroom" by creating new room and inviting user](#respond-to-newroom-by-creating-new-room-and-inviting-user) - [Respond to "newroom" by creating new room and inviting user](#respond-to-newroom-by-creating-new-room-and-inviting-user)
- [Respond to "joinroom <room_id_or_alias>" by joining mentioned room](#respond-to-joinroom-room_id_or_alias-by-joining-mentioned-room) - [Respond to "joinroom <room_id_or_alias>" by joining mentioned room](#respond-to-joinroom-room_id_or_alias-by-joining-mentioned-room)
@@ -52,7 +53,7 @@ Allows an administrator to create or modify a user account with a specified `msg
[View JSON](custom-redact-function-node.json) [View JSON](custom-redact-function-node.json)
If we do not have a node for something you want to do (such as redacting events/messages) you can do this manually with a function node. If we do not have a node for something you want to do you can do this manually with a function node. We now have a node for removing events but this is still a good example.
**Note:** You should make sure to catch any errors in your function node otherwise you could cause Node-RED to crash. **Note:** You should make sure to catch any errors in your function node otherwise you could cause Node-RED to crash.
@@ -60,6 +61,8 @@ To view what sort of functions you have access to check out the `client.ts` file
![custom-redact-function-node.png](custom-redact-function-node.png) ![custom-redact-function-node.png](custom-redact-function-node.png)
### Respond to "ping" with "pong" ### Respond to "ping" with "pong"
[View JSON](respond-ping-pong.json) [View JSON](respond-ping-pong.json)
@@ -110,6 +113,16 @@ Give a 👍 reaction when someone says "react"
### Remove messages containing "delete"
[View JSON](delete-event.json)
Any messages containing "delete" will try to be removed by the client.
![respond-react-with-reaction.png](delete-event.png)
### Respond to "users" with full list of server users ### Respond to "users" with full list of server users
[View JSON](respond-users-list.json) [View JSON](respond-users-list.json)
+73
View File
@@ -0,0 +1,73 @@
[
{
"id": "fed9197df27197a4",
"type": "matrix-receive",
"z": "f025a8b9fbd1b054",
"name": "",
"server": null,
"roomId": "",
"acceptText": true,
"acceptEmotes": true,
"acceptStickers": true,
"acceptReactions": true,
"acceptFiles": true,
"acceptImages": true,
"x": 340,
"y": 1560,
"wires": [
[
"b289bb4fed9fa166"
]
]
},
{
"id": "b289bb4fed9fa166",
"type": "switch",
"z": "f025a8b9fbd1b054",
"name": "",
"property": "payload",
"propertyType": "msg",
"rules": [
{
"t": "cont",
"v": "delete",
"vt": "str"
}
],
"checkall": "true",
"repair": false,
"outputs": 1,
"x": 490,
"y": 1560,
"wires": [
[
"48766b632ab2e6a1"
]
]
},
{
"id": "48766b632ab2e6a1",
"type": "matrix-delete-event",
"z": "f025a8b9fbd1b054",
"name": "",
"server": null,
"roomId": "",
"reason": "Requested deletion",
"x": 630,
"y": 1560,
"wires": [
[],
[]
]
},
{
"id": "11f9cbbed7b95c83",
"type": "comment",
"z": "f025a8b9fbd1b054",
"name": "Delete messages containing \"delete\"",
"info": "",
"x": 480,
"y": 1520,
"wires": []
}
]
Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

+473 -451
View File
File diff suppressed because it is too large Load Diff
+6 -5
View File
@@ -1,14 +1,14 @@
{ {
"name": "node-red-contrib-matrix-chat", "name": "node-red-contrib-matrix-chat",
"version": "0.4.6", "version": "0.6.1",
"description": "Matrix chat server client for Node-RED", "description": "Matrix chat server client for Node-RED",
"dependencies": { "dependencies": {
"fs-extra": "^10.0.0", "fs-extra": "^10.0.1",
"got": "^12.0.1", "got": "^12.0.2",
"isomorphic-webcrypto": "^2.3.8", "isomorphic-webcrypto": "^2.3.8",
"matrix-js-sdk": "^15.5.0", "matrix-js-sdk": "^16.0.0",
"node-localstorage": "^2.2.1", "node-localstorage": "^2.2.1",
"olm": "https://packages.matrix.org/npm/olm/olm-3.2.1.tgz", "olm": "https://gitlab.matrix.org/matrix-org/olm/-/package_files/271/download",
"utf8": "^3.0.0" "utf8": "^3.0.0"
}, },
"node-red": { "node-red": {
@@ -17,6 +17,7 @@
"matrix-server-config": "src/matrix-server-config.js", "matrix-server-config": "src/matrix-server-config.js",
"matrix-receive": "src/matrix-receive.js", "matrix-receive": "src/matrix-receive.js",
"matrix-send-message": "src/matrix-send-message.js", "matrix-send-message": "src/matrix-send-message.js",
"matrix-delete-event": "src/matrix-delete-event.js",
"matrix-send-file": "src/matrix-send-file.js", "matrix-send-file": "src/matrix-send-file.js",
"matrix-send-image": "src/matrix-send-image.js", "matrix-send-image": "src/matrix-send-image.js",
"matrix-react": "src/matrix-react.js", "matrix-react": "src/matrix-react.js",
+1 -1
View File
@@ -19,7 +19,7 @@
<script type="text/html" data-template-name="matrix-create-room"> <script type="text/html" data-template-name="matrix-create-room">
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label> <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name"> <input type="text" id="node-input-name" placeholder="Name">
</div> </div>
+2 -2
View File
@@ -18,14 +18,14 @@
<script type="text/html" data-template-name="matrix-decrypt-file"> <script type="text/html" data-template-name="matrix-decrypt-file">
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label> <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name"> <input type="text" id="node-input-name" placeholder="Name">
</div> </div>
</script> </script>
<script type="text/html" data-help-name="matrix-decrypt-file"> <script type="text/html" data-help-name="matrix-decrypt-file">
<h3>Details</h3> <h3>Details</h3>
<p>Files sent in an encrypted room are themselves encrypted. Use this node to encrypt/decrypt files. Note: This node will download the encrypted file so be cautious of large downloads.</p> <p>Files sent in an encrypted room are themselves encrypted. Use this node to decrypt files. Note: This node will download the encrypted file so be cautious of large downloads.</p>
<h3>Inputs</h3> <h3>Inputs</h3>
<dl class="message-properties"> <dl class="message-properties">
+96
View File
@@ -0,0 +1,96 @@
<script type="text/javascript">
RED.nodes.registerType('matrix-delete-event',{
category: 'matrix',
color: '#00b7ca',
icon: "matrix.png",
outputLabels: ["success", "error"],
inputs:1,
outputs:2,
defaults: {
name: { value: null },
server: { value: "", type: "matrix-server-config" },
roomId: { value: null },
reason: { value: "" },
},
label: function() {
return this.name||"Delete Event";
},
paletteLabel: 'Delete Event'
});
</script>
<script type="text/html" data-template-name="matrix-delete-event">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
<div class="form-row">
<label for="node-input-server"><i class="fa fa-user"></i> Matrix Server Config</label>
<input type="text" id="node-input-server">
</div>
<div class="form-row">
<label for="node-input-roomId"><i class="fa fa-comments"></i> Room ID</label>
<input type="text" id="node-input-roomId" placeholder="msg.topic">
<pre class="form-tips" id="node-input-roomId-error" style="color: #721c24;background-color: #f8d7da;border-color: #f5c6cb;margin-bottom: 12px;margin-top: 12px;display:none;"></pre>
</div>
<div class="form-row">
<label for="node-input-reason"><i class="fa fa-sticky-note"></i> Reason</label>
<input type="text" id="node-input-reason" placeholder="msg.reason">
</div>
<script type="text/javascript">
$(function(){
$("#node-input-roomId").on("keyup", function() {
if($(this).val() && !$(this).val().startsWith("!")) {
$("#node-input-roomId-error").html(`Room IDs start with exclamation point "!"<br />Example: !OGEhHVWSdvArJzumhm:matrix.org`).show();
} else {
$("#node-input-roomId-error").hide();
}
}).trigger('keyup');
});
</script>
</script>
<script type="text/html" data-help-name="matrix-delete-event">
<h3>Details</h3>
<p>Delete an event in a room</p>
<dl class="message-properties">
<dt>msg.topic
<span class="property-type">string</span>
</dt>
<dd> Room ID from where the event should be deleted from. Optional if configured on the node. If configured on the node this input will be overridden.</dd>
<dt>msg.eventId
<span class="property-type">string</span>
</dt>
<dd>Event ID of the Event which should be deleted.</dd>
<dt>msg.reason
<span class="property-type">string</span>
</dt>
<dd>Reason why the event is deleted. Default an empty string</dd>
</dl>
<h3>Outputs</h3>
<ol class="node-ports">
<li>Success
<dl class="message-properties">
<dt>msg.eventId <span class="property-type">string</span></dt>
<dd>the eventId from the deleted event.</dd>
</dl>
<dl class="message-properties">
<dt>msg.deleted <span class="property-type">boolean</span></dt>
<dd>True, if the event is deleted</dd>
</dl>
</li>
<li>Error
<dl class="message-properties">
<dt>msg.error <span class="property-type">string</span></dt>
<dd>the error that occurred.</dd>
<dl class="message-properties">
<dt>msg.deleted <span class="property-type">boolean</span></dt>
<dd>False, if the event is not deleted</dd>
</dl>
</dl>
</li>
</ol>
</script>
+75
View File
@@ -0,0 +1,75 @@
module.exports = function(RED) {
function MatrixDeleteEvent(n) {
RED.nodes.createNode(this,n);
var node = this;
this.name = n.name;
this.server = RED.nodes.getNode(n.server);
this.roomId = n.roomId;
this.reason = n.reason
if (!node.server) {
node.warn("No configuration node");
return;
}
node.status({ fill: "red", shape: "ring", text: "disconnected" });
node.server.on("disconnected", function(){
node.status({ fill: "red", shape: "ring", text: "disconnected" });
});
node.server.on("connected", function() {
node.status({ fill: "green", shape: "ring", text: "connected" });
});
node.on('input', function(msg) {
if(!msg.eventId) {
node.error("eventId is missing");
node.send([null, msg])
return;
}
if (!node.server || !node.server.matrixClient) {
node.warn("No matrix server selected");
return;
}
if(!node.server.isConnected()) {
node.error("Matrix server connection is currently closed");
node.send([null, msg]);
return;
}
msg.topic = node.roomId || msg.topic;
if(!msg.topic) {
node.warn("Room must be specified in msg.topic or in configuration");
return;
}
msg.reason = node.reason || msg.reason;
if(!msg.reason) {
msg.reason = '';
}
node.server.matrixClient.redactEvent(msg.topic, msg.eventId, undefined,{
reason: msg.reason
})
.then(function(e) {
msg.deleted = true
node.send([msg, null]);
})
.catch(function(e){
node.warn("Error deleting event " + e);
msg.error = e;
msg.deleted = false
node.send([null, msg]);
});
});
}
RED.nodes.registerType("matrix-delete-event",MatrixDeleteEvent);
}
+14 -2
View File
@@ -20,7 +20,7 @@
<script type="text/html" data-template-name="matrix-invite-room"> <script type="text/html" data-template-name="matrix-invite-room">
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label> <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name"> <input type="text" id="node-input-name" placeholder="Name">
</div> </div>
@@ -30,9 +30,21 @@
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-roomId"><i class="fa fa-user"></i> Room ID</label> <label for="node-input-roomId"><i class="fa fa-comments"></i> Room ID</label>
<input type="text" id="node-input-roomId" placeholder="msg.topic"> <input type="text" id="node-input-roomId" placeholder="msg.topic">
<pre class="form-tips" id="node-input-roomId-error" style="color: #721c24;background-color: #f8d7da;border-color: #f5c6cb;margin-bottom: 12px;margin-top: 12px;display:none;"></pre>
</div> </div>
<script type="text/javascript">
$(function(){
$("#node-input-roomId").on("keyup", function() {
if($(this).val() && !$(this).val().startsWith("!")) {
$("#node-input-roomId-error").html(`Room IDs start with exclamation point "!"<br />Example: !OGEhHVWSdvArJzumhm:matrix.org`).show();
} else {
$("#node-input-roomId-error").hide();
}
}).trigger('keyup');
});
</script>
</script> </script>
<script type="text/html" data-help-name="matrix-invite-room"> <script type="text/html" data-help-name="matrix-invite-room">
+1 -1
View File
@@ -19,7 +19,7 @@
<script type="text/html" data-template-name="matrix-join-room"> <script type="text/html" data-template-name="matrix-join-room">
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label> <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name"> <input type="text" id="node-input-name" placeholder="Name">
</div> </div>
<div class="form-row"> <div class="form-row">
+21 -4
View File
@@ -9,7 +9,8 @@
defaults: { defaults: {
name: { value: null }, name: { value: null },
server: { value: "", type: "matrix-server-config" }, server: { value: "", type: "matrix-server-config" },
roomId: { value: null } roomId: { value: null },
reaction: { value: null }
}, },
label: function() { label: function() {
return this.name || "React"; return this.name || "React";
@@ -20,7 +21,7 @@
<script type="text/html" data-template-name="matrix-react"> <script type="text/html" data-template-name="matrix-react">
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label> <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name"> <input type="text" id="node-input-name" placeholder="Name">
</div> </div>
<div class="form-row"> <div class="form-row">
@@ -28,9 +29,25 @@
<input type="text" id="node-input-server"> <input type="text" id="node-input-server">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-roomId"><i class="fa fa-user"></i> Room ID</label> <label for="node-input-roomId"><i class="fa fa-comments"></i> Room ID</label>
<input type="text" id="node-input-roomId" placeholder="msg.topic"> <input type="text" id="node-input-roomId" placeholder="msg.topic">
<pre class="form-tips" id="node-input-roomId-error" style="color: #721c24;background-color: #f8d7da;border-color: #f5c6cb;margin-bottom: 12px;margin-top: 12px;display:none;"></pre>
</div> </div>
<div class="form-row">
<label for="node-input-reaction"><i class="fa fa-thumbs-up"></i> Reaction</label>
<input type="text" id="node-input-reaction" placeholder="msg.payload">
</div>
<script type="text/javascript">
$(function(){
$("#node-input-roomId").on("keyup", function() {
if($(this).val() && !$(this).val().startsWith("!")) {
$("#node-input-roomId-error").html(`Room IDs start with exclamation point "!"<br />Example: !OGEhHVWSdvArJzumhm:matrix.org`).show();
} else {
$("#node-input-roomId-error").hide();
}
}).trigger('keyup');
});
</script>
</script> </script>
<script type="text/html" data-help-name="matrix-react"> <script type="text/html" data-help-name="matrix-react">
@@ -42,7 +59,7 @@
<dt>msg.payload <dt>msg.payload
<span class="property-type">string</span> <span class="property-type">string</span>
</dt> </dt>
<dd> Usually an emoji but can also be text. </dd> <dd> Usually an emoji but can also be text. If configured on the node this is ignored otherwise it required. </dd>
<dt>msg.topic <dt>msg.topic
<span class="property-type">string | null</span> <span class="property-type">string | null</span>
+5 -3
View File
@@ -7,6 +7,7 @@ module.exports = function(RED) {
this.name = n.name; this.name = n.name;
this.server = RED.nodes.getNode(n.server); this.server = RED.nodes.getNode(n.server);
this.roomId = n.roomId; this.roomId = n.roomId;
this.reaction = n.reaction;
if (!node.server) { if (!node.server) {
node.warn("No configuration node"); node.warn("No configuration node");
@@ -40,8 +41,9 @@ module.exports = function(RED) {
return; return;
} }
if(!msg.payload) { let payload = n.reaction || msg.payload;
node.error('msg.payload is required'); if(!payload) {
node.error('msg.payload must be defined or the reaction configured on the node.');
return; return;
} }
@@ -59,7 +61,7 @@ module.exports = function(RED) {
{ {
"m.relates_to": { "m.relates_to": {
event_id: eventId, event_id: eventId,
key: msg.payload, key: payload,
rel_type: "m.annotation" rel_type: "m.annotation"
} }
} }
+85 -7
View File
@@ -15,7 +15,9 @@
acceptStickers: {"value": true}, acceptStickers: {"value": true},
acceptReactions: {"value": true}, acceptReactions: {"value": true},
acceptFiles: {"value": true}, acceptFiles: {"value": true},
acceptAudio: {"value": true},
acceptImages: {"value": true}, acceptImages: {"value": true},
acceptLocations: {"value": true},
}, },
label: function() { label: function() {
return this.name || "Matrix Receive"; return this.name || "Matrix Receive";
@@ -34,8 +36,9 @@
<input type="text" id="node-input-server"> <input type="text" id="node-input-server">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-roomId"><i class="fa fa-user"></i> Room ID</label> <label for="node-input-roomId"><i class="fa fa-comments"></i> Room ID</label>
<input type="text" id="node-input-roomId"> <input type="text" id="node-input-roomId">
<pre class="form-tips" id="node-input-roomId-error" style="color: #721c24;background-color: #f8d7da;border-color: #f5c6cb;margin-bottom: 12px;margin-top: 12px;display:none;"></pre>
</div> </div>
<div class="form-tips">Enter a single room, comma separated list of rooms, or leave blank to get from all</div> <div class="form-tips">Enter a single room, comma separated list of rooms, or leave blank to get from all</div>
<div class="form-row" style="margin-left: 100px;margin-top:10px;font-weight:bold;"> <div class="form-row" style="margin-left: 100px;margin-top:10px;font-weight:bold;">
@@ -48,7 +51,7 @@
style="width: auto; margin-left: 125px; vertical-align: top" style="width: auto; margin-left: 125px; vertical-align: top"
/> />
<label for="node-input-acceptText" style="width: auto"> <label for="node-input-acceptText" style="width: auto">
Accept text <code>m.text</code> Accept text <code style="text-transform: none;">m.text</code>
</label> </label>
</div> </div>
<div class="form-row"> <div class="form-row">
@@ -58,7 +61,7 @@
style="width: auto; margin-left: 125px; vertical-align: top" style="width: auto; margin-left: 125px; vertical-align: top"
/> />
<label for="node-input-acceptEmotes" style="width: auto"> <label for="node-input-acceptEmotes" style="width: auto">
Accept emotes <code>m.emote</code> Accept emotes <code style="text-transform: none;">m.emote</code>
</label> </label>
</div> </div>
<div class="form-row"> <div class="form-row">
@@ -68,7 +71,7 @@
style="width: auto; margin-left: 125px; vertical-align: top" style="width: auto; margin-left: 125px; vertical-align: top"
/> />
<label for="node-input-acceptStickers" style="width: auto"> <label for="node-input-acceptStickers" style="width: auto">
Accept stickers <code>m.sticker</code> Accept stickers <code style="text-transform: none;">m.sticker</code>
</label> </label>
</div> </div>
<div class="form-row"> <div class="form-row">
@@ -78,7 +81,7 @@
style="width: auto; margin-left: 125px; vertical-align: top" style="width: auto; margin-left: 125px; vertical-align: top"
/> />
<label for="node-input-acceptReactions" style="width: auto"> <label for="node-input-acceptReactions" style="width: auto">
Accept reactions <code>m.reaction</code> Accept reactions <code style="text-transform: none;">m.reaction</code>
</label> </label>
</div> </div>
<div class="form-row"> <div class="form-row">
@@ -88,7 +91,17 @@
style="width: auto; margin-left: 125px; vertical-align: top" style="width: auto; margin-left: 125px; vertical-align: top"
/> />
<label for="node-input-acceptFiles" style="width: auto"> <label for="node-input-acceptFiles" style="width: auto">
Accept files <code>m.file</code> Accept files <code style="text-transform: none;">m.file</code>
</label>
</div>
<div class="form-row">
<input
type="checkbox"
id="node-input-acceptAudio"
style="width: auto; margin-left: 125px; vertical-align: top"
/>
<label for="node-input-acceptAudio" style="width: auto">
Accept files <code style="text-transform: none;">m.audio</code>
</label> </label>
</div> </div>
<div class="form-row"> <div class="form-row">
@@ -98,9 +111,30 @@
style="width: auto; margin-left: 125px; vertical-align: top" style="width: auto; margin-left: 125px; vertical-align: top"
/> />
<label for="node-input-acceptImages" style="width: auto"> <label for="node-input-acceptImages" style="width: auto">
Accept images <code>m.image</code> Accept images <code style="text-transform: none;">m.image</code>
</label> </label>
</div> </div>
<div class="form-row">
<input
type="checkbox"
id="node-input-acceptLocations"
style="width: auto; margin-left: 125px; vertical-align: top"
/>
<label for="node-input-acceptLocations" style="width: auto">
Accept locations <code style="text-transform: none;">m.location</code>
</label>
</div>
<script type="text/javascript">
$(function(){
$("#node-input-roomId").on("keyup", function() {
if($(this).val() && !$(this).val().startsWith("!")) {
$("#node-input-roomId-error").html(`Room IDs start with exclamation point "!"<br />Example: !OGEhHVWSdvArJzumhm:matrix.org`).show();
} else {
$("#node-input-roomId-error").hide();
}
}).trigger('keyup');
});
</script>
</script> </script>
<script type="text/html" data-help-name="matrix-receive"> <script type="text/html" data-help-name="matrix-receive">
@@ -116,6 +150,11 @@
</dd> </dd>
</dl> </dl>
<dl class="message-properties">
<dt>msg.isDM <span class="property-type">bool</span></dt>
<dd> returns true if message is from a direct message room.</dd>
</dl>
<dl class="message-properties"> <dl class="message-properties">
<dt>msg.encrypted <span class="property-type">bool</span></dt> <dt>msg.encrypted <span class="property-type">bool</span></dt>
<dd> returns true if message was encrypted (e2ee).</dd> <dd> returns true if message was encrypted (e2ee).</dd>
@@ -220,6 +259,38 @@
</dl> </dl>
</li> </li>
<li><code>msg.type</code> == '<strong>m.audio</strong>'
<dl class="message-properties">
<dt>msg.filename <span class="property-type">string</span></dt>
<dd>the image's parsed filename</dd>
</dl>
<dl class="message-properties">
<dt>msg.mimetype <span class="property-type">string</span></dt>
<dd>audio file mimetype (ex: audio/ogg)</dd>
</dl>
<dl class="message-properties">
<dt>msg.url <span class="property-type">string</span></dt>
<dd>the file's URL</dd>
</dl>
<dl class="message-properties">
<dt>msg.mxc_url <span class="property-type">string</span></dt>
<dd>the file's Matrix URL</dd>
</dl>
<dl class="message-properties">
<dt>msg.duration <span class="property-type">integer</span></dt>
<dd>duration of audio file in milliseconds</dd>
</dl>
<dl class="message-properties">
<dt>msg.waveform <span class="property-type">array[int]</span></dt>
<dd>waveform of the audio clip</dd>
</dl>
</li>
<li><code>msg.type</code> == '<strong>m.image</strong>' <li><code>msg.type</code> == '<strong>m.image</strong>'
<dl class="message-properties"> <dl class="message-properties">
<dt>msg.filename <span class="property-type">string</span></dt> <dt>msg.filename <span class="property-type">string</span></dt>
@@ -246,5 +317,12 @@
<dd>the image's thumbnail Matrix URL</dd> <dd>the image's thumbnail Matrix URL</dd>
</dl> </dl>
</li> </li>
<li><code>msg.type</code> == '<strong>m.location</strong>'
<dl class="message-properties">
<dt>msg.geo_uri <span class="property-type">string</span></dt>
<dd>URI format of the geolocation</dd>
</dl>
</li>
</ul> </ul>
</script> </script>
+29
View File
@@ -11,7 +11,9 @@ module.exports = function(RED) {
this.acceptStickers = n.acceptStickers; this.acceptStickers = n.acceptStickers;
this.acceptReactions = n.acceptReactions; this.acceptReactions = n.acceptReactions;
this.acceptFiles = n.acceptFiles; this.acceptFiles = n.acceptFiles;
this.acceptAudio = n.acceptAudio;
this.acceptImages = n.acceptImages; this.acceptImages = n.acceptImages;
this.acceptLocations = n.acceptLocations;
this.roomId = n.roomId; this.roomId = n.roomId;
this.roomIds = this.roomId ? this.roomId.split(',') : []; this.roomIds = this.roomId ? this.roomId.split(',') : [];
@@ -72,6 +74,27 @@ module.exports = function(RED) {
} }
break; break;
case 'm.audio':
if(!node.acceptAudio) return;
if(msg.encrypted) {
msg.url = node.server.matrixClient.mxcUrlToHttp(msg.content.file.url);
msg.mxc_url = msg.content.file.url;
} else {
msg.url = node.server.matrixClient.mxcUrlToHttp(msg.content.url);
msg.mxc_url = msg.content.url;
}
if('org.matrix.msc1767.file' in msg.content) {
msg.filename = msg.content['org.matrix.msc1767.file'].name;
msg.mimetype = msg.content['org.matrix.msc1767.file'].mimetype;
}
if('org.matrix.msc1767.audio' in msg.content) {
msg.duration = msg.content['org.matrix.msc1767.audio'].duration;
msg.waveform = msg.content['org.matrix.msc1767.audio'].waveform;
}
break;
case 'm.image': case 'm.image':
if(!node.acceptImages) return; if(!node.acceptImages) return;
msg.filename = msg.content.filename || msg.content.body; msg.filename = msg.content.filename || msg.content.body;
@@ -88,6 +111,12 @@ module.exports = function(RED) {
} }
break; break;
case 'm.location':
if(!node.acceptLocations) return;
msg.geo_uri = msg.content.geo_uri;
msg.payload = msg.content.body;
break;
case 'm.reaction': case 'm.reaction':
if(!node.acceptReactions) return; if(!node.acceptReactions) return;
msg.info = msg.content["m.relates_to"].info; msg.info = msg.content["m.relates_to"].info;
+21 -4
View File
@@ -9,7 +9,8 @@
defaults: { defaults: {
name: { value: null }, name: { value: null },
server: { value: "", type: "matrix-server-config" }, server: { value: "", type: "matrix-server-config" },
roomId: { value: null } roomId: { value: null },
reason: { value: null }
}, },
label: function() { label: function() {
return this.name || "Room Ban"; return this.name || "Room Ban";
@@ -20,7 +21,7 @@
<script type="text/html" data-template-name="matrix-room-ban"> <script type="text/html" data-template-name="matrix-room-ban">
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label> <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name"> <input type="text" id="node-input-name" placeholder="Name">
</div> </div>
<div class="form-row"> <div class="form-row">
@@ -28,9 +29,25 @@
<input type="text" id="node-input-server"> <input type="text" id="node-input-server">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-roomId"><i class="fa fa-user"></i> Room ID</label> <label for="node-input-roomId"><i class="fa fa-comments"></i> Room ID</label>
<input type="text" id="node-input-roomId" placeholder="msg.topic"> <input type="text" id="node-input-roomId" placeholder="msg.topic">
<pre class="form-tips" id="node-input-roomId-error" style="color: #721c24;background-color: #f8d7da;border-color: #f5c6cb;margin-bottom: 12px;margin-top: 12px;display:none;"></pre>
</div> </div>
<div class="form-row">
<label for="node-input-reason"><i class="fa fa-comment"></i> Reason</label>
<input type="text" id="node-input-reason" placeholder="msg.topic">
</div>
<script type="text/javascript">
$(function(){
$("#node-input-roomId").on("keyup", function() {
if($(this).val() && !$(this).val().startsWith("!")) {
$("#node-input-roomId-error").html(`Room IDs start with exclamation point "!"<br />Example: !OGEhHVWSdvArJzumhm:matrix.org`).show();
} else {
$("#node-input-roomId-error").hide();
}
}).trigger('keyup');
});
</script>
</script> </script>
<script type="text/html" data-help-name="matrix-room-ban"> <script type="text/html" data-help-name="matrix-room-ban">
@@ -52,7 +69,7 @@
<dt class="optional">msg.reason <dt class="optional">msg.reason
<span class="property-type">string</span> <span class="property-type">string</span>
</dt> </dt>
<dd> Reason for banning the user.</dd> <dd> Reason for banning the user. If configured on the node it will overwrite this input</dd>
</dl> </dl>
<h3>Outputs</h3> <h3>Outputs</h3>
+2 -1
View File
@@ -7,6 +7,7 @@ module.exports = function(RED) {
this.name = n.name; this.name = n.name;
this.server = RED.nodes.getNode(n.server); this.server = RED.nodes.getNode(n.server);
this.roomId = n.roomId; this.roomId = n.roomId;
this.reason = n.reason;
if (!node.server) { if (!node.server) {
node.warn("No configuration node"); node.warn("No configuration node");
@@ -45,7 +46,7 @@ module.exports = function(RED) {
return; return;
} }
node.server.matrixClient.ban(msg.topic, msg.userId, msg.reason || undefined) node.server.matrixClient.ban(msg.topic, msg.userId, n.reason || msg.reason || undefined)
.then(function(e) { .then(function(e) {
node.log("Successfully banned " + msg.userId + " from " + msg.topic); node.log("Successfully banned " + msg.userId + " from " + msg.topic);
msg.eventId = e.event_id; msg.eventId = e.event_id;
+21 -4
View File
@@ -9,7 +9,8 @@
defaults: { defaults: {
name: { value: null }, name: { value: null },
server: { value: "", type: "matrix-server-config" }, server: { value: "", type: "matrix-server-config" },
roomId: { value: null } roomId: { value: null },
reason: { value: null }
}, },
label: function() { label: function() {
return this.name || "Room Kick"; return this.name || "Room Kick";
@@ -20,7 +21,7 @@
<script type="text/html" data-template-name="matrix-room-kick"> <script type="text/html" data-template-name="matrix-room-kick">
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label> <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name"> <input type="text" id="node-input-name" placeholder="Name">
</div> </div>
<div class="form-row"> <div class="form-row">
@@ -28,9 +29,25 @@
<input type="text" id="node-input-server"> <input type="text" id="node-input-server">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-roomId"><i class="fa fa-user"></i> Room ID</label> <label for="node-input-roomId"><i class="fa fa-comments"></i> Room ID</label>
<input type="text" id="node-input-roomId" placeholder="msg.topic"> <input type="text" id="node-input-roomId" placeholder="msg.topic">
<pre class="form-tips" id="node-input-roomId-error" style="color: #721c24;background-color: #f8d7da;border-color: #f5c6cb;margin-bottom: 12px;margin-top: 12px;display:none;"></pre>
</div> </div>
<div class="form-row">
<label for="node-input-reason"><i class="fa fa-comment"></i> Reason</label>
<input type="text" id="node-input-reason" placeholder="msg.topic">
</div>
<script type="text/javascript">
$(function(){
$("#node-input-roomId").on("keyup", function() {
if($(this).val() && !$(this).val().startsWith("!")) {
$("#node-input-roomId-error").html(`Room IDs start with exclamation point "!"<br />Example: !OGEhHVWSdvArJzumhm:matrix.org`).show();
} else {
$("#node-input-roomId-error").hide();
}
}).trigger('keyup');
});
</script>
</script> </script>
<script type="text/html" data-help-name="matrix-room-kick"> <script type="text/html" data-help-name="matrix-room-kick">
@@ -52,7 +69,7 @@
<dt class="optional">msg.reason <dt class="optional">msg.reason
<span class="property-type">string</span> <span class="property-type">string</span>
</dt> </dt>
<dd> Reason for kicking the user.</dd> <dd> Reason for kicking the user. If configured on the node it will overwrite this input</dd>
</dl> </dl>
<h3>Outputs</h3> <h3>Outputs</h3>
+2 -1
View File
@@ -7,6 +7,7 @@ module.exports = function(RED) {
this.name = n.name; this.name = n.name;
this.server = RED.nodes.getNode(n.server); this.server = RED.nodes.getNode(n.server);
this.roomId = n.roomId; this.roomId = n.roomId;
this.reason = n.reason;
if (!node.server) { if (!node.server) {
node.warn("No configuration node"); node.warn("No configuration node");
@@ -45,7 +46,7 @@ module.exports = function(RED) {
return; return;
} }
node.server.matrixClient.kick(msg.topic, msg.userId, msg.reason || undefined) node.server.matrixClient.kick(msg.topic, msg.userId, n.reason || msg.reason || undefined)
.then(function(e) { .then(function(e) {
node.log("Successfully kicked " + msg.userId + " from " + msg.topic); node.log("Successfully kicked " + msg.userId + " from " + msg.topic);
msg.eventId = e.event_id; msg.eventId = e.event_id;
+13 -1
View File
@@ -20,7 +20,7 @@
<script type="text/html" data-template-name="matrix-room-users"> <script type="text/html" data-template-name="matrix-room-users">
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label> <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name"> <input type="text" id="node-input-name" placeholder="Name">
</div> </div>
<div class="form-row"> <div class="form-row">
@@ -30,7 +30,19 @@
<div class="form-row"> <div class="form-row">
<label for="node-input-server"><i class="fa fa-user"></i> Room Id</label> <label for="node-input-server"><i class="fa fa-user"></i> Room Id</label>
<input type="text" id="node-input-roomId" placeholder="msg.topic"> <input type="text" id="node-input-roomId" placeholder="msg.topic">
<pre class="form-tips" id="node-input-roomId-error" style="color: #721c24;background-color: #f8d7da;border-color: #f5c6cb;margin-bottom: 12px;margin-top: 12px;display:none;"></pre>
</div> </div>
<script type="text/javascript">
$(function(){
$("#node-input-roomId").on("keyup", function() {
if($(this).val() && !$(this).val().startsWith("!")) {
$("#node-input-roomId-error").html(`Room IDs start with exclamation point "!"<br />Example: !OGEhHVWSdvArJzumhm:matrix.org`).show();
} else {
$("#node-input-roomId-error").hide();
}
}).trigger('keyup');
});
</script>
</script> </script>
<script type="text/html" data-help-name="matrix-room-users"> <script type="text/html" data-help-name="matrix-room-users">
+14 -2
View File
@@ -21,7 +21,7 @@
<script type="text/html" data-template-name="matrix-send-file"> <script type="text/html" data-template-name="matrix-send-file">
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label> <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name"> <input type="text" id="node-input-name" placeholder="Name">
</div> </div>
<div class="form-row"> <div class="form-row">
@@ -29,8 +29,9 @@
<input type="text" id="node-input-server"> <input type="text" id="node-input-server">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-roomId"><i class="fa fa-user"></i> Room ID</label> <label for="node-input-roomId"><i class="fa fa-comments"></i> Room ID</label>
<input type="text" id="node-input-roomId" placeholder="msg.topic"> <input type="text" id="node-input-roomId" placeholder="msg.topic">
<pre class="form-tips" id="node-input-roomId-error" style="color: #721c24;background-color: #f8d7da;border-color: #f5c6cb;margin-bottom: 12px;margin-top: 12px;display:none;"></pre>
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-contentType"><i class="fa fa-user"></i> Content-Type</label> <label for="node-input-contentType"><i class="fa fa-user"></i> Content-Type</label>
@@ -39,6 +40,17 @@
<div class="form-tips"> <div class="form-tips">
Must be a valid <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types" target="_blank">MIME Type</a> (ex: application/pdf) or left empty Must be a valid <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types" target="_blank">MIME Type</a> (ex: application/pdf) or left empty
</div> </div>
<script type="text/javascript">
$(function(){
$("#node-input-roomId").on("keyup", function() {
if($(this).val() && !$(this).val().startsWith("!")) {
$("#node-input-roomId-error").html(`Room IDs start with exclamation point "!"<br />Example: !OGEhHVWSdvArJzumhm:matrix.org`).show();
} else {
$("#node-input-roomId-error").hide();
}
}).trigger('keyup');
});
</script>
</script> </script>
<script type="text/html" data-help-name="matrix-send-file"> <script type="text/html" data-help-name="matrix-send-file">
+14 -2
View File
@@ -21,7 +21,7 @@
<script type="text/html" data-template-name="matrix-send-image"> <script type="text/html" data-template-name="matrix-send-image">
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label> <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name"> <input type="text" id="node-input-name" placeholder="Name">
</div> </div>
<div class="form-row"> <div class="form-row">
@@ -29,8 +29,9 @@
<input type="text" id="node-input-server"> <input type="text" id="node-input-server">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-roomId"><i class="fa fa-user"></i> Room ID</label> <label for="node-input-roomId"><i class="fa fa-comments"></i> Room ID</label>
<input type="text" id="node-input-roomId" placeholder="msg.topic"> <input type="text" id="node-input-roomId" placeholder="msg.topic">
<pre class="form-tips" id="node-input-roomId-error" style="color: #721c24;background-color: #f8d7da;border-color: #f5c6cb;margin-bottom: 12px;margin-top: 12px;display:none;"></pre>
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-contentType"><i class="fa fa-user"></i> Content-Type</label> <label for="node-input-contentType"><i class="fa fa-user"></i> Content-Type</label>
@@ -39,6 +40,17 @@
<div class="form-tips"> <div class="form-tips">
Must be a valid <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types" target="_blank">MIME Type</a> (ex: image/png) or left empty Must be a valid <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types" target="_blank">MIME Type</a> (ex: image/png) or left empty
</div> </div>
<script type="text/javascript">
$(function(){
$("#node-input-roomId").on("keyup", function() {
if($(this).val() && !$(this).val().startsWith("!")) {
$("#node-input-roomId-error").html(`Room IDs start with exclamation point "!"<br />Example: !OGEhHVWSdvArJzumhm:matrix.org`).show();
} else {
$("#node-input-roomId-error").hide();
}
}).trigger('keyup');
});
</script>
</script> </script>
<script type="text/html" data-help-name="matrix-send-image"> <script type="text/html" data-help-name="matrix-send-image">
+39 -4
View File
@@ -10,8 +10,10 @@
name: { value: null }, name: { value: null },
server: { value: "", type: "matrix-server-config" }, server: { value: "", type: "matrix-server-config" },
roomId: { value: null }, roomId: { value: null },
message: { value: null },
messageType: { value: 'm.text' }, messageType: { value: 'm.text' },
messageFormat: { value: '' }, messageFormat: { value: '' },
replaceMessage : { value: false }
}, },
label: function() { label: function() {
return this.name || "Send Message"; return this.name || "Send Message";
@@ -22,7 +24,7 @@
<script type="text/html" data-template-name="matrix-send-message"> <script type="text/html" data-template-name="matrix-send-message">
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label> <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name"> <input type="text" id="node-input-name" placeholder="Name">
</div> </div>
@@ -32,8 +34,25 @@
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-roomId"><i class="fa fa-user"></i> Room ID</label> <label for="node-input-roomId"><i class="fa fa-comments"></i> Room ID</label>
<input type="text" id="node-input-roomId" placeholder="msg.topic"> <input type="text" id="node-input-roomId" placeholder="msg.topic">
<pre class="form-tips" id="node-input-roomId-error" style="color: #721c24;background-color: #f8d7da;border-color: #f5c6cb;margin-bottom: 12px;margin-top: 12px;display:none;"></pre>
</div>
<div class="form-row">
<label for="node-input-message"><i class="fa fa-comment"></i> Message</label>
<textarea id="node-input-message" placeholder="msg.payload" style="width: 70%;"></textarea>
</div>
<div class="form-row">
<input
type="checkbox"
id="node-input-replaceMessage"
style="width: auto; margin-left: 105px; vertical-align: top"
/>
<label for="node-input-replaceMessage" style="width: auto;max-width:50%;">
Update existing message if <code>msg.eventId</code> is set
</label>
</div> </div>
<div class="form-row"> <div class="form-row">
@@ -60,6 +79,17 @@
<option value="msg.format">msg.format input</option> <option value="msg.format">msg.format input</option>
</select> </select>
</div> </div>
<script type="text/javascript">
$(function(){
$("#node-input-roomId").on("keyup", function() {
if($(this).val() && !$(this).val().startsWith("!")) {
$("#node-input-roomId-error").html(`Room IDs start with exclamation point "!"<br />Example: !OGEhHVWSdvArJzumhm:matrix.org`).show();
} else {
$("#node-input-roomId-error").hide();
}
}).trigger('keyup');
});
</script>
</script> </script>
<script type="text/html" data-help-name="matrix-send-message"> <script type="text/html" data-help-name="matrix-send-message">
@@ -76,12 +106,17 @@
<dt>msg.payload <dt>msg.payload
<span class="property-type">string</span> <span class="property-type">string</span>
</dt> </dt>
<dd> the message text. </dd> <dd> the message text. If configured on the node this is ignored otherwise it required. </dd>
<dt>msg.replace
<span class="property-type">bool</span>
</dt>
<dd> If true and <code>msg.eventId</code> is present it will update an existing message. Posts a new message if false or <code>msg.eventId</code> is missing. </dd>
<dt class="optional">msg.formatted_payload <dt class="optional">msg.formatted_payload
<span class="property-type">string</span> <span class="property-type">string</span>
</dt> </dt>
<dd> the formatted HTML message (uses msg.payload if not defined). This only affects HTML messages.</dd> <dd> the formatted HTML message (uses <code>msg.payload</code> if not defined). This only affects HTML messages.</dd>
<dt class="optional">msg.type <dt class="optional">msg.type
<span class="property-type">string | null</span> <span class="property-type">string | null</span>
+29 -5
View File
@@ -1,3 +1,5 @@
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);
@@ -9,6 +11,8 @@ module.exports = function(RED) {
this.roomId = n.roomId; this.roomId = n.roomId;
this.messageType = n.messageType; this.messageType = n.messageType;
this.messageFormat = n.messageFormat; this.messageFormat = n.messageFormat;
this.replaceMessage = n.replaceMessage;
this.message = n.message;
// taken from https://github.com/matrix-org/synapse/blob/master/synapse/push/mailer.py // taken from https://github.com/matrix-org/synapse/blob/master/synapse/push/mailer.py
this.allowedTags = [ this.allowedTags = [
@@ -98,14 +102,15 @@ module.exports = function(RED) {
return; return;
} }
if(!msg.payload) { let payload = n.message || msg.payload;
node.error('msg.payload is required'); if(!payload) {
node.error('msg.payload must be defined or the message configured on the node.');
return; return;
} }
let content = { let content = {
msgtype: msgType, msgtype: msgType,
body: msg.payload.toString() body: payload.toString()
}; };
if(msgFormat === 'html') { if(msgFormat === 'html') {
@@ -113,12 +118,31 @@ module.exports = function(RED) {
content.formatted_body = content.formatted_body =
(typeof msg.formatted_payload !== 'undefined' && msg.formatted_payload) (typeof msg.formatted_payload !== 'undefined' && msg.formatted_payload)
? msg.formatted_payload.toString() ? msg.formatted_payload.toString()
: msg.payload.toString(); : payload.toString();
}
if((node.replaceMessage || msg.replace) && msg.eventId) {
content['m.new_content'] = {
msgtype: content.msgtype,
body: content.body
};
if('format' in content) {
content['m.new_content']['format'] = content['format'];
}
if('formatted_body' in content) {
content['m.new_content']['formatted_body'] = content['formatted_body'];
}
content['m.relates_to'] = {
rel_type: RelationType.Replace,
event_id: msg.eventId
};
content['body'] = ' * ' + content['body'];
} }
node.server.matrixClient.sendMessage(msg.topic, content) node.server.matrixClient.sendMessage(msg.topic, content)
.then(function(e) { .then(function(e) {
node.log("Message sent: " + msg.payload); node.log("Message sent: " + payload);
msg.eventId = e.event_id; msg.eventId = e.event_id;
node.send([msg, null]); node.send([msg, null]);
}) })
+1 -1
View File
@@ -30,7 +30,7 @@
deviceLabel: { type: "text", required: false }, deviceLabel: { type: "text", required: false },
accessToken: { type: "password", required: true }, accessToken: { type: "password", required: true },
deviceId: { type: "text", required: false }, deviceId: { type: "text", required: false },
url: { type: "text", required: true } url: { type: "text", required: true },
}, },
defaults: { defaults: {
name: { value: null }, name: { value: null },
+33 -13
View File
@@ -4,6 +4,7 @@ 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'); const { LocalStorageCryptoStore } = require('matrix-js-sdk/lib/crypto/store/localStorage-crypto-store');
const {RoomEvent, RoomMemberEvent, HttpApiEvent, ClientEvent} = require("matrix-js-sdk");
module.exports = function(RED) { module.exports = function(RED) {
function MatrixFolderNameFromUserId(name) { function MatrixFolderNameFromUserId(name) {
@@ -29,8 +30,8 @@ module.exports = function(RED) {
this.deviceId = this.credentials.deviceId || null; this.deviceId = this.credentials.deviceId || null;
this.url = this.credentials.url; this.url = this.credentials.url;
this.autoAcceptRoomInvites = n.autoAcceptRoomInvites; this.autoAcceptRoomInvites = n.autoAcceptRoomInvites;
this.enableE2ee = n.enableE2ee || false; this.e2ee = n.enableE2ee || false;
this.e2ee = (this.enableE2ee && this.deviceId);
this.globalAccess = n.global; this.globalAccess = n.global;
this.initializedAt = new Date(); this.initializedAt = new Date();
@@ -50,7 +51,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 = function(connected, cb) { node.setConnected = async 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') {
@@ -118,7 +119,8 @@ module.exports = function(RED) {
sessionStore: new sdk.WebStorageSessionStore(localStorage), sessionStore: new sdk.WebStorageSessionStore(localStorage),
cryptoStore: new LocalStorageCryptoStore(localStorage), cryptoStore: new LocalStorageCryptoStore(localStorage),
userId: this.userId, userId: this.userId,
deviceId: (this.deviceId || getStoredDeviceId(localStorage)) || undefined deviceId: (this.deviceId || getStoredDeviceId(localStorage)) || undefined,
// verificationMethods: ["m.sas.v1"]
}); });
// set globally if configured to do so // set globally if configured to do so
@@ -146,7 +148,7 @@ module.exports = function(RED) {
return node.connected; return node.connected;
}; };
node.matrixClient.on("Room.timeline", async function(event, room, toStartOfTimeline, removed, data) { node.matrixClient.on(RoomEvent.Timeline, async function(event, room, toStartOfTimeline, removed, data) {
if (toStartOfTimeline) { if (toStartOfTimeline) {
return; // ignore paginated results return; // ignore paginated results
} }
@@ -167,16 +169,32 @@ module.exports = function(RED) {
return; return;
} }
const isDmRoom = (room) => {
// Find out if this is a direct message room.
let isDM = !!room.getDMInviter();
const allMembers = room.currentState.getMembers();
if (!isDM && allMembers.length <= 2) {
// if not a DM, but there are 2 users only
// double check DM (needed because getDMInviter works only if you were invited, not if you invite)
// hence why we check for each member
if (allMembers.some((m) => m.getDMInviter())) {
return true;
}
}
return allMembers.length <= 2 && isDM;
};
let msg = { let msg = {
encrypted : event.isEncrypted(), encrypted : event.isEncrypted(),
redacted : event.isRedacted(), redacted : event.isRedacted(),
content : event.getContent(), content : event.getContent(),
type : (event.getContent()['msgtype'] || event.getType()) || null, type : (event.getContent()['msgtype'] || event.getType()) || null,
payload : (event.getContent()['body'] || event.getContent()) || null, payload : (event.getContent()['body'] || event.getContent()) || null,
isDM : isDmRoom(room),
userId : event.getSender(), userId : event.getSender(),
topic : event.getRoomId(), topic : event.getRoomId(),
eventId : event.getId(), eventId : event.getId(),
event : event, event : event
}; };
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]' : ''));
@@ -189,9 +207,9 @@ module.exports = function(RED) {
* *
* @event module:client~MatrixClient#"crypto.suggestKeyRestore" * @event module:client~MatrixClient#"crypto.suggestKeyRestore"
*/ */
node.matrixClient.on("crypto.suggestKeyRestore", function(){ // node.matrixClient.on("crypto.suggestKeyRestore", function(){
//
}); // });
// node.matrixClient.on("RoomMember.typing", async function(event, member) { // node.matrixClient.on("RoomMember.typing", async function(event, member) {
// let isTyping = member.typing; // let isTyping = member.typing;
@@ -210,7 +228,8 @@ module.exports = function(RED) {
// }); // });
// handle auto-joining rooms // handle auto-joining rooms
node.matrixClient.on("RoomMember.membership", async function(event, member) {
node.matrixClient.on(RoomMemberEvent.Membership, async function(event, member) {
if (member.membership === "invite" && member.userId === node.userId) { if (member.membership === "invite" && member.userId === node.userId) {
if(node.autoAcceptRoomInvites) { if(node.autoAcceptRoomInvites) {
node.matrixClient.joinRoom(member.roomId).then(function() { node.matrixClient.joinRoom(member.roomId).then(function() {
@@ -224,7 +243,7 @@ module.exports = function(RED) {
} }
}); });
node.matrixClient.on("sync", async function(state, prevState, data) { node.matrixClient.on(ClientEvent.Sync, async function(state, prevState, data) {
node.debug("SYNC [STATE=" + state + "] [PREVSTATE=" + prevState + "]"); node.debug("SYNC [STATE=" + state + "] [PREVSTATE=" + prevState + "]");
if(prevState === null && state === "PREPARED" ) { if(prevState === null && state === "PREPARED" ) {
// Occurs when the initial sync is completed first time. // Occurs when the initial sync is completed first time.
@@ -292,7 +311,8 @@ module.exports = function(RED) {
} }
}); });
node.matrixClient.on("Session.logged_out", async function(errorObj){
node.matrixClient.on(HttpApiEvent.SessionLoggedOut, async function(errorObj){
// Example if user auth token incorrect: // Example if user auth token incorrect:
// { // {
// errcode: 'M_UNKNOWN_TOKEN', // errcode: 'M_UNKNOWN_TOKEN',
@@ -444,7 +464,7 @@ module.exports = function(RED) {
fs.renameSync(oldStorageDir, oldStorageDir + "-backup"); fs.renameSync(oldStorageDir, oldStorageDir + "-backup");
} }
if(RED.settings.userDir !== resolve('./')) { if(RED.settings.userDir !== resolve('./') && resolve(oldStorageDir2) !== resolve(storageDir)) {
// user directory does not match running directory // user directory does not match running directory
// check if we stored stuff in wrong directory and move it // check if we stored stuff in wrong directory and move it
if(fs.pathExistsSync(oldStorageDir2)){ if(fs.pathExistsSync(oldStorageDir2)){
+1 -1
View File
@@ -19,7 +19,7 @@
<script type="text/html" data-template-name="matrix-synapse-create-edit-user"> <script type="text/html" data-template-name="matrix-synapse-create-edit-user">
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label> <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name"> <input type="text" id="node-input-name" placeholder="Name">
</div> </div>
+1 -1
View File
@@ -19,7 +19,7 @@
<script type="text/html" data-template-name="matrix-synapse-deactivate-user"> <script type="text/html" data-template-name="matrix-synapse-deactivate-user">
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label> <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name"> <input type="text" id="node-input-name" placeholder="Name">
</div> </div>
+14 -2
View File
@@ -20,7 +20,7 @@
<script type="text/html" data-template-name="matrix-synapse-join-room"> <script type="text/html" data-template-name="matrix-synapse-join-room">
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label> <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name"> <input type="text" id="node-input-name" placeholder="Name">
</div> </div>
@@ -30,13 +30,25 @@
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-roomId"><i class="fa fa-user"></i> Room ID</label> <label for="node-input-roomId"><i class="fa fa-comments"></i> Room ID</label>
<input type="text" id="node-input-roomId" placeholder="msg.topic"> <input type="text" id="node-input-roomId" placeholder="msg.topic">
<pre class="form-tips" id="node-input-roomId-error" style="color: #721c24;background-color: #f8d7da;border-color: #f5c6cb;margin-bottom: 12px;margin-top: 12px;display:none;"></pre>
</div> </div>
<div class="form-tips" style="margin-bottom: 12px;"> <div class="form-tips" style="margin-bottom: 12px;">
User must be an admin to use this endpoint. User must be an admin to use this endpoint.
</div> </div>
<script type="text/javascript">
$(function(){
$("#node-input-roomId").on("keyup", function() {
if($(this).val() && !$(this).val().startsWith("!")) {
$("#node-input-roomId-error").html(`Room IDs start with exclamation point "!"<br />Example: !OGEhHVWSdvArJzumhm:matrix.org`).show();
} else {
$("#node-input-roomId-error").hide();
}
}).trigger('keyup');
});
</script>
</script> </script>
<script type="text/html" data-help-name="matrix-synapse-join-room"> <script type="text/html" data-help-name="matrix-synapse-join-room">
+1 -1
View File
@@ -22,7 +22,7 @@
<script type="text/html" data-template-name="matrix-synapse-register"> <script type="text/html" data-template-name="matrix-synapse-register">
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label> <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name"> <input type="text" id="node-input-name" placeholder="Name">
</div> </div>
+1 -1
View File
@@ -19,7 +19,7 @@
<script type="text/html" data-template-name="matrix-synapse-users"> <script type="text/html" data-template-name="matrix-synapse-users">
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label> <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name"> <input type="text" id="node-input-name" placeholder="Name">
</div> </div>
<div class="form-row"> <div class="form-row">
+1 -1
View File
@@ -19,7 +19,7 @@
<script type="text/html" data-template-name="matrix-whois-user"> <script type="text/html" data-template-name="matrix-whois-user">
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label> <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name"> <input type="text" id="node-input-name" placeholder="Name">
</div> </div>