mirror of
https://github.com/Skylar-Tech/node-red-contrib-matrix-chat.git
synced 2025-07-09 04:01:11 -06:00
Compare commits
No commits in common. "2ce80e2906e7b2395f8f19107ef8cb934a33faa0" and "d304cb95f6c4736991032927e71b97b675f65834" have entirely different histories.
2ce80e2906
...
d304cb95f6
Binary file not shown.
@ -48,9 +48,7 @@ You are not limited by just the nodes we have created. If you turn on global acc
|
|||||||
View an example [here](https://github.com/Skylar-Tech/node-red-contrib-matrix-chat/tree/master/examples#use-function-node-to-run-any-command)
|
View an example [here](https://github.com/Skylar-Tech/node-red-contrib-matrix-chat/tree/master/examples#use-function-node-to-run-any-command)
|
||||||
|
|
||||||
### End-to-End Encryption Notes
|
### End-to-End Encryption Notes
|
||||||
It is recommended you use the bot exclusively with Node-RED after it's creation if using e2ee. Failure to do so will lead to your bot being unable to receive messages from e2ee rooms it joined from another client. Shared secret registration makes this super easy since it returns a token and device ID.
|
Currently, this module has no way of getting encryption keys from other devices on the same account. Therefore it is recommended you use the bot exclusively with Node-RED after it's creation. Failure to do so will lead to your bot being unable to receive messages from e2ee rooms it joined from another client. Shared secret registration makes this super easy since it returns a token and device ID.
|
||||||
|
|
||||||
We now have a device verification node that will help in sharing keys (check the [examples](https://github.com/Skylar-Tech/node-red-contrib-matrix-chat/tree/master/examples#readme) for more info). This node is currently in beta and is still experimental.
|
|
||||||
|
|
||||||
This module stores a folder in your Node-RED directory called `matrix-client-storage` and is it vital that you periodically back this up if you are using e2ee. This is where the client stores all the keys necessary to decrypt messages and if lost you will lose access to e2e rooms. If you move your client to another NR install make sure to migrate this folder as well (and do not let both the old and new client run at same time).
|
This module stores a folder in your Node-RED directory called `matrix-client-storage` and is it vital that you periodically back this up if you are using e2ee. This is where the client stores all the keys necessary to decrypt messages and if lost you will lose access to e2e rooms. If you move your client to another NR install make sure to migrate this folder as well (and do not let both the old and new client run at same time).
|
||||||
|
|
||||||
|
@ -10,14 +10,11 @@ Build something cool with these nodes? Feel free to submit a pull request to sha
|
|||||||
- [Create User with Shared Secret Registration](#create-user-with-shared-secret-registration)
|
- [Create User with Shared Secret Registration](#create-user-with-shared-secret-registration)
|
||||||
- [Create/Edit Synapse User](#createedit-synapse-user)
|
- [Create/Edit Synapse User](#createedit-synapse-user)
|
||||||
- [Use function node to run any command](#use-function-node-to-run-any-command)
|
- [Use function node to run any command](#use-function-node-to-run-any-command)
|
||||||
- [Start and accept device verification from specific user](#start-and-accept-device-verification-from-specific-user)
|
|
||||||
- [Request device verification & immediately accept](#request-device-verification--immediately-accept)
|
|
||||||
- [Respond to "ping" with "pong"](#respond-to-ping-with-pong)
|
- [Respond to "ping" with "pong"](#respond-to-ping-with-pong)
|
||||||
- [Respond to "html" with an HTML message](#respond-to-html-with-an-html-message)
|
- [Respond to "html" with an HTML message](#respond-to-html-with-an-html-message)
|
||||||
- [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)
|
||||||
@ -55,7 +52,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 you can do this manually with a function node. We now have a node for removing events but this is still a good example.
|
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.
|
||||||
|
|
||||||
**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.
|
||||||
|
|
||||||
@ -63,26 +60,6 @@ To view what sort of functions you have access to check out the `client.ts` file
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
### Request device verification & immediately accept
|
|
||||||
|
|
||||||
[View JSON](request-device-verification.json)
|
|
||||||
|
|
||||||
Edit the inject node to match the details of a user & device you would like to request verification from.
|
|
||||||
After the end user starts verification the bot automatically accepts the result (note: you should be validating the result and not just blindly accepting them, this is just an example)
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
### Start and accept device verification from specific user
|
|
||||||
|
|
||||||
[View JSON](start-accept-verification-from-user.json)
|
|
||||||
|
|
||||||
Edit the switch node labeled "is from me" to match whatever user ID you would like to accept verification requests from.
|
|
||||||
After verification starts the bot automatically accepts the result (note: you should be validating the result and not just blindly accepting them, this is just an example)
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### Respond to "ping" with "pong"
|
### Respond to "ping" with "pong"
|
||||||
|
|
||||||
[View JSON](respond-ping-pong.json)
|
[View JSON](respond-ping-pong.json)
|
||||||
@ -133,16 +110,6 @@ 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 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)
|
||||||
|
@ -1,73 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"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.
Before Width: | Height: | Size: 11 KiB |
@ -1,92 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"id": "9345e8c42e327dba",
|
|
||||||
"type": "matrix-device-verification",
|
|
||||||
"z": "f025a8b9fbd1b054",
|
|
||||||
"name": "",
|
|
||||||
"server": null,
|
|
||||||
"mode": "request",
|
|
||||||
"inputs": 1,
|
|
||||||
"outputs": 2,
|
|
||||||
"x": 480,
|
|
||||||
"y": 1660,
|
|
||||||
"wires": [
|
|
||||||
[
|
|
||||||
"b676082d56430aec"
|
|
||||||
],
|
|
||||||
[]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "b676082d56430aec",
|
|
||||||
"type": "matrix-device-verification",
|
|
||||||
"z": "f025a8b9fbd1b054",
|
|
||||||
"name": "",
|
|
||||||
"server": null,
|
|
||||||
"mode": "start",
|
|
||||||
"inputs": 1,
|
|
||||||
"outputs": 1,
|
|
||||||
"x": 740,
|
|
||||||
"y": 1660,
|
|
||||||
"wires": [
|
|
||||||
[
|
|
||||||
"23a0225f2f2615a3"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "23a0225f2f2615a3",
|
|
||||||
"type": "matrix-device-verification",
|
|
||||||
"z": "f025a8b9fbd1b054",
|
|
||||||
"name": "",
|
|
||||||
"server": null,
|
|
||||||
"mode": "accept",
|
|
||||||
"inputs": 1,
|
|
||||||
"outputs": 1,
|
|
||||||
"x": 970,
|
|
||||||
"y": 1660,
|
|
||||||
"wires": [
|
|
||||||
[]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "3eced60b58c999eb",
|
|
||||||
"type": "inject",
|
|
||||||
"z": "f025a8b9fbd1b054",
|
|
||||||
"name": "",
|
|
||||||
"props": [
|
|
||||||
{
|
|
||||||
"p": "userId",
|
|
||||||
"v": "@bot:example.com",
|
|
||||||
"vt": "str"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"p": "devices",
|
|
||||||
"v": "[\"ZRRJKASJDUK\"]",
|
|
||||||
"vt": "json"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"repeat": "",
|
|
||||||
"crontab": "",
|
|
||||||
"once": false,
|
|
||||||
"onceDelay": 0.1,
|
|
||||||
"topic": "",
|
|
||||||
"x": 290,
|
|
||||||
"y": 1660,
|
|
||||||
"wires": [
|
|
||||||
[
|
|
||||||
"9345e8c42e327dba"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "f58ceba2a8819c09",
|
|
||||||
"type": "comment",
|
|
||||||
"z": "f025a8b9fbd1b054",
|
|
||||||
"name": "Request verification from a specific userId and device",
|
|
||||||
"info": "",
|
|
||||||
"x": 440,
|
|
||||||
"y": 1620,
|
|
||||||
"wires": []
|
|
||||||
}
|
|
||||||
]
|
|
Binary file not shown.
Before Width: | Height: | Size: 17 KiB |
@ -1,86 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"id": "5073ca88b21abfb4",
|
|
||||||
"type": "matrix-device-verification",
|
|
||||||
"z": "f025a8b9fbd1b054",
|
|
||||||
"name": "",
|
|
||||||
"server": null,
|
|
||||||
"mode": "receive",
|
|
||||||
"inputs": 0,
|
|
||||||
"outputs": 1,
|
|
||||||
"x": 350,
|
|
||||||
"y": 1540,
|
|
||||||
"wires": [
|
|
||||||
[
|
|
||||||
"b76c1d185c2793a0"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "05947740ced04e2c",
|
|
||||||
"type": "matrix-device-verification",
|
|
||||||
"z": "f025a8b9fbd1b054",
|
|
||||||
"name": "",
|
|
||||||
"server": null,
|
|
||||||
"mode": "start",
|
|
||||||
"inputs": 1,
|
|
||||||
"outputs": 1,
|
|
||||||
"x": 740,
|
|
||||||
"y": 1540,
|
|
||||||
"wires": [
|
|
||||||
[
|
|
||||||
"b3158c0779b72b41"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "b76c1d185c2793a0",
|
|
||||||
"type": "switch",
|
|
||||||
"z": "f025a8b9fbd1b054",
|
|
||||||
"name": "is from me",
|
|
||||||
"property": "userId",
|
|
||||||
"propertyType": "msg",
|
|
||||||
"rules": [
|
|
||||||
{
|
|
||||||
"t": "eq",
|
|
||||||
"v": "@skylord123:skylar.tech",
|
|
||||||
"vt": "str"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"checkall": "true",
|
|
||||||
"repair": false,
|
|
||||||
"outputs": 1,
|
|
||||||
"x": 550,
|
|
||||||
"y": 1540,
|
|
||||||
"wires": [
|
|
||||||
[
|
|
||||||
"05947740ced04e2c"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "b3158c0779b72b41",
|
|
||||||
"type": "matrix-device-verification",
|
|
||||||
"z": "f025a8b9fbd1b054",
|
|
||||||
"name": "",
|
|
||||||
"server": null,
|
|
||||||
"mode": "accept",
|
|
||||||
"inputs": 1,
|
|
||||||
"outputs": 1,
|
|
||||||
"x": 970,
|
|
||||||
"y": 1540,
|
|
||||||
"wires": [
|
|
||||||
[]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "eb8ba0741df1b365",
|
|
||||||
"type": "comment",
|
|
||||||
"z": "f025a8b9fbd1b054",
|
|
||||||
"name": "Accept all device validation from a user",
|
|
||||||
"info": "",
|
|
||||||
"x": 390,
|
|
||||||
"y": 1500,
|
|
||||||
"wires": []
|
|
||||||
}
|
|
||||||
]
|
|
Binary file not shown.
Before Width: | Height: | Size: 15 KiB |
924
package-lock.json
generated
924
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
11
package.json
11
package.json
@ -1,14 +1,14 @@
|
|||||||
{
|
{
|
||||||
"name": "node-red-contrib-matrix-chat",
|
"name": "node-red-contrib-matrix-chat",
|
||||||
"version": "0.5.5",
|
"version": "0.4.6",
|
||||||
"description": "Matrix chat server client for Node-RED",
|
"description": "Matrix chat server client for Node-RED",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fs-extra": "^10.0.1",
|
"fs-extra": "^10.0.0",
|
||||||
"got": "^12.0.2",
|
"got": "^12.0.1",
|
||||||
"isomorphic-webcrypto": "^2.3.8",
|
"isomorphic-webcrypto": "^2.3.8",
|
||||||
"matrix-js-sdk": "^16.0.0",
|
"matrix-js-sdk": "^15.5.0",
|
||||||
"node-localstorage": "^2.2.1",
|
"node-localstorage": "^2.2.1",
|
||||||
"olm": "https://gitlab.matrix.org/matrix-org/olm/-/package_files/271/download",
|
"olm": "https://packages.matrix.org/npm/olm/olm-3.2.1.tgz",
|
||||||
"utf8": "^3.0.0"
|
"utf8": "^3.0.0"
|
||||||
},
|
},
|
||||||
"node-red": {
|
"node-red": {
|
||||||
@ -27,7 +27,6 @@
|
|||||||
"matrix-crypt-file": "src/matrix-crypt-file.js",
|
"matrix-crypt-file": "src/matrix-crypt-file.js",
|
||||||
"matrix-room-kick": "src/matrix-room-kick.js",
|
"matrix-room-kick": "src/matrix-room-kick.js",
|
||||||
"matrix-room-ban": "src/matrix-room-ban.js",
|
"matrix-room-ban": "src/matrix-room-ban.js",
|
||||||
"matrix-device-verification": "src/matrix-device-verification.js",
|
|
||||||
"matrix-synapse-users": "src/matrix-synapse-users.js",
|
"matrix-synapse-users": "src/matrix-synapse-users.js",
|
||||||
"matrix-synapse-register": "src/matrix-synapse-register.js",
|
"matrix-synapse-register": "src/matrix-synapse-register.js",
|
||||||
"matrix-synapse-create-edit-user": "src/matrix-synapse-create-edit-user.js",
|
"matrix-synapse-create-edit-user": "src/matrix-synapse-create-edit-user.js",
|
||||||
|
@ -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="fa fa-tag"></i> Name</label>
|
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||||
<input type="text" id="node-input-name" placeholder="Name">
|
<input type="text" id="node-input-name" placeholder="Name">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -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="fa fa-tag"></i> Name</label>
|
<label for="node-input-name"><i class="icon-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 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 encrypt/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">
|
||||||
|
@ -7,10 +7,10 @@
|
|||||||
inputs:1,
|
inputs:1,
|
||||||
outputs:2,
|
outputs:2,
|
||||||
defaults: {
|
defaults: {
|
||||||
name: { value: null },
|
name: {value:""},
|
||||||
server: { value: "", type: "matrix-server-config" },
|
server: { value: "", type: "matrix-server-config" },
|
||||||
roomId: { value: null },
|
roomId: { value: null },
|
||||||
reason: { value: "" },
|
reason: {value:""},
|
||||||
},
|
},
|
||||||
label: function() {
|
label: function() {
|
||||||
return this.name||"Delete Event";
|
return this.name||"Delete Event";
|
||||||
@ -29,21 +29,8 @@
|
|||||||
<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-comments"></i> Room ID</label>
|
<label for="node-input-roomId"><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>
|
|
||||||
<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>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-reason"><i class="fa fa-sticky-note"></i> Reason</label>
|
<label for="node-input-reason"><i class="fa fa-sticky-note"></i> Reason</label>
|
||||||
|
@ -55,7 +55,7 @@ module.exports = function(RED) {
|
|||||||
msg.reason = '';
|
msg.reason = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
node.server.matrixClient.redactEvent(msg.topic, msg.eventId, undefined,{
|
node.server.matrixClient.redactEvent(msg.topic,msg.eventId,undefined ,{
|
||||||
reason: msg.reason
|
reason: msg.reason
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1,240 +0,0 @@
|
|||||||
<script type="text/javascript">
|
|
||||||
let computeInputAndOutputCounts = function(node){
|
|
||||||
switch($("#node-input-mode").val()) {
|
|
||||||
default:
|
|
||||||
node.outputs = node.inputs = 0;
|
|
||||||
break;
|
|
||||||
case 'receive':
|
|
||||||
node.outputs = 1;
|
|
||||||
node.inputs = 0;
|
|
||||||
break;
|
|
||||||
case 'request':
|
|
||||||
case 'start':
|
|
||||||
case 'accept':
|
|
||||||
case 'cancel':
|
|
||||||
node.outputs = 2;
|
|
||||||
node.inputs = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
RED.nodes.registerType('matrix-device-verification', {
|
|
||||||
category: 'matrix',
|
|
||||||
color: '#00b7ca',
|
|
||||||
icon: "matrix.png",
|
|
||||||
inputs: 0,
|
|
||||||
outputs: 0,
|
|
||||||
outputLabels: ["success", "error"],
|
|
||||||
defaults: {
|
|
||||||
name: { value: null },
|
|
||||||
server: { value: "", type: "matrix-server-config" },
|
|
||||||
mode: { value: null, type: "text", required: true },
|
|
||||||
inputs: { value: 0 },
|
|
||||||
outputs: { value: 0 }
|
|
||||||
},
|
|
||||||
oneditprepare: function () {
|
|
||||||
computeInputAndOutputCounts(this);
|
|
||||||
},
|
|
||||||
oneditsave: function () {
|
|
||||||
computeInputAndOutputCounts(this);
|
|
||||||
},
|
|
||||||
label: function() {
|
|
||||||
if(this.name) {
|
|
||||||
return this.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(this.mode) {
|
|
||||||
default:
|
|
||||||
return 'Device Verification';
|
|
||||||
case 'receive':
|
|
||||||
return 'Receive Device Verification';
|
|
||||||
case 'request':
|
|
||||||
return 'Request Device Verification';
|
|
||||||
case 'start':
|
|
||||||
return 'Start Device Verification';
|
|
||||||
case 'accept':
|
|
||||||
return 'Accept Device Verification';
|
|
||||||
case 'cancel':
|
|
||||||
return 'Cancel Device Verification';
|
|
||||||
}
|
|
||||||
return this.name || "Device Verify Request";
|
|
||||||
},
|
|
||||||
paletteLabel: function(){
|
|
||||||
return "Device Verification";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script type="text/html" data-template-name="matrix-device-verification">
|
|
||||||
<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-mode"><i class="fa fa-user"></i> Mode</label>
|
|
||||||
<select id="node-input-mode" style="width:70%;">
|
|
||||||
<option value="">Unconfigured</option>
|
|
||||||
<option value="receive">Receive Verification Request</option>
|
|
||||||
<option value="request">Request Verification</option>
|
|
||||||
<option value="start">Verification Start</option>
|
|
||||||
<option value="accept">Verification Accept</option>
|
|
||||||
<option value="cancel">Verification Cancel</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script type="text/html" data-help-name="matrix-device-verification">
|
|
||||||
<h3>Details</h3>
|
|
||||||
<p>
|
|
||||||
Handle device verification. Check out the <a href="https://github.com/Skylar-Tech/node-red-contrib-matrix-chat/tree/master/examples#readme" target="_blank">examples</a> page for a good understanding of how this works.
|
|
||||||
<br />
|
|
||||||
General flow:
|
|
||||||
<ol>
|
|
||||||
<li>Request/Receive device verification</li>
|
|
||||||
<li>Start Verification</li>
|
|
||||||
<li>Compare Emojis</li>
|
|
||||||
<li>Accept/Cancel Verification</li>
|
|
||||||
</ol>
|
|
||||||
<br />
|
|
||||||
THIS NODE IS IN BETA. There is a good chance that we will change how this node works later down the road. Make sure to read the release notes before upgrading.
|
|
||||||
</p>
|
|
||||||
<a href="https://matrix-org.github.io/synapse/develop/admin_api/room_membership.html#edit-room-membership-api" target="_blank">Synapse API Endpoint Information</a>
|
|
||||||
|
|
||||||
<h3>Inputs</h3>
|
|
||||||
<ul class="node-inputs">
|
|
||||||
<li><code>mode</code> set to '<strong>Receive Verification Request</strong>'
|
|
||||||
<div class="form-tips" style="margin-bottom: 12px;">
|
|
||||||
Doesn't take an input
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li><code>mode</code> set to '<strong>Request Verification</strong>'
|
|
||||||
<dl class="message-properties">
|
|
||||||
<dt>msg.userId <span class="property-type">string</span></dt>
|
|
||||||
<dd>
|
|
||||||
ID of the user to request device verification from
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
<dl class="message-properties">
|
|
||||||
<dt>msg.devices <span class="property-type">array[string]|null</span></dt>
|
|
||||||
<dd> list of <code>msg.userId</code>'s devices IDs to request verification from. If empty it will request from all known devices.</dd>
|
|
||||||
</dl>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li><code>mode</code> set to '<strong>Verification Start</strong>'
|
|
||||||
<dl class="message-properties">
|
|
||||||
<dt>msg.verifyRequestId <span class="property-type">string</span></dt>
|
|
||||||
<dd>
|
|
||||||
Internal ID to reference the verification request throughout the flows
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
<dl class="message-properties">
|
|
||||||
<dt>msg.cancel <span class="property-type">bool</span></dt>
|
|
||||||
<dd>
|
|
||||||
If set and is true the verification request will be cancelled
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li><code>mode</code> set to '<strong>Verification Accept</strong>'
|
|
||||||
<dl class="message-properties">
|
|
||||||
<dt>msg.verifyRequestId <span class="property-type">string</span></dt>
|
|
||||||
<dd>
|
|
||||||
Internal ID to reference the verification request throughout the flows
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li><code>mode</code> set to '<strong>Verification Cancel</strong>'
|
|
||||||
<dl class="message-properties">
|
|
||||||
<dt>msg.verifyRequestId <span class="property-type">string</span></dt>
|
|
||||||
<dd>
|
|
||||||
Internal ID to reference the verification request throughout the flows
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h3>Outputs</h3>
|
|
||||||
<ul class="node-outputs">
|
|
||||||
<li><code>mode</code> set to '<strong>Receive Verification Request</strong>' or '<strong>Request Verification</strong>'
|
|
||||||
<dl class="message-properties">
|
|
||||||
<dt>msg.verifyRequestId <span class="property-type">string</span></dt>
|
|
||||||
<dd>
|
|
||||||
Internal ID to reference the verification request throughout the flows
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
<dl class="message-properties">
|
|
||||||
<dt>msg.verifyMethods <span class="property-type">string</span></dt>
|
|
||||||
<dd>
|
|
||||||
Common verification methods supported by both sides
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
<dl class="message-properties">
|
|
||||||
<dt>msg.userId <span class="property-type">string</span></dt>
|
|
||||||
<dd>
|
|
||||||
ID of the user to request device verification from
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
<dl class="message-properties">
|
|
||||||
<dt>msg.deviceIds <span class="property-type">array[string]</span></dt>
|
|
||||||
<dd>
|
|
||||||
List of devices we are verifying
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
<dl class="message-properties">
|
|
||||||
<dt>msg.selfVerification <span class="property-type">bool</span></dt>
|
|
||||||
<dd>
|
|
||||||
true if we are verifying one of our own devices
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
<dl class="message-properties">
|
|
||||||
<dt>msg.phase <span class="property-type">string</span></dt>
|
|
||||||
<dd>
|
|
||||||
what phase of verification we are in
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li><code>mode</code> set to '<strong>Verification Start</strong>'
|
|
||||||
<dl class="message-properties">
|
|
||||||
<dt>msg.payload <span class="property-type">string</span></dt>
|
|
||||||
<dd>
|
|
||||||
sas verification payload
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
<dl class="message-properties">
|
|
||||||
<dt>msg.emojis <span class="property-type">array[string]</span></dt>
|
|
||||||
<dd>
|
|
||||||
array of emojis for verification request
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
<dl class="message-properties">
|
|
||||||
<dt>msg.emojis_text <span class="property-type">array[string]</span></dt>
|
|
||||||
<dd>
|
|
||||||
array of emojis in text form for verification request
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li><code>mode</code> set to '<strong>Verification Accept</strong>' or '<strong>Verification Cancel</strong>'
|
|
||||||
<div class="form-tips" style="margin-bottom: 12px;">
|
|
||||||
Passes input straight to output on success. If an error occurs it goes to the second output.
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
</script>
|
|
@ -1,234 +0,0 @@
|
|||||||
const {Phase} = require("matrix-js-sdk/lib/crypto/verification/request/VerificationRequest");
|
|
||||||
const {CryptoEvent} = require("matrix-js-sdk/lib/crypto");
|
|
||||||
|
|
||||||
module.exports = function(RED) {
|
|
||||||
const verificationRequests = new Map();
|
|
||||||
|
|
||||||
function MatrixDeviceVerification(n) {
|
|
||||||
RED.nodes.createNode(this, n);
|
|
||||||
|
|
||||||
var node = this;
|
|
||||||
|
|
||||||
this.name = n.name;
|
|
||||||
this.server = RED.nodes.getNode(n.server);
|
|
||||||
this.mode = n.mode;
|
|
||||||
|
|
||||||
if (!node.server) {
|
|
||||||
node.warn("No configuration node");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!node.server.e2ee) {
|
|
||||||
node.error("End-to-end encryption needs to be enabled to use this.");
|
|
||||||
}
|
|
||||||
|
|
||||||
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" });
|
|
||||||
});
|
|
||||||
|
|
||||||
function getKeyByValue(object, value) {
|
|
||||||
return Object.keys(object).find(key => object[key] === value);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(node.mode) {
|
|
||||||
default:
|
|
||||||
node.error("Node not configured with a mode");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'request':
|
|
||||||
node.on('input', async function(msg){
|
|
||||||
if(!msg.userId) {
|
|
||||||
node.error("msg.userId is required for start verification mode");
|
|
||||||
}
|
|
||||||
|
|
||||||
node.server.matrixClient.requestVerification(msg.userId, msg.devices || null)
|
|
||||||
.then(function(e) {
|
|
||||||
node.log("Successfully requested verification");
|
|
||||||
let verifyRequestId = msg.userId + ':' + e.channel.deviceId;
|
|
||||||
verificationRequests.set(verifyRequestId, e);
|
|
||||||
node.send({
|
|
||||||
verifyRequestId: verifyRequestId, // internally used to reference between nodes
|
|
||||||
verifyMethods: e.methods,
|
|
||||||
userId: msg.userId,
|
|
||||||
deviceIds: e.channel.devices,
|
|
||||||
selfVerification: e.isSelfVerification,
|
|
||||||
phase: getKeyByValue(Phase, e.phase)
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(function(e){
|
|
||||||
node.warn("Error requesting device verification: " + e);
|
|
||||||
msg.error = e;
|
|
||||||
node.send([null, msg]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'receive':
|
|
||||||
/**
|
|
||||||
* Fires when a key verification is requested.
|
|
||||||
* @event module:client~MatrixClient#"crypto.verification.request"
|
|
||||||
* @param {object} data
|
|
||||||
* @param {MatrixEvent} data.event the original verification request message
|
|
||||||
* @param {Array} data.methods the verification methods that can be used
|
|
||||||
* @param {Number} data.timeout the amount of milliseconds that should be waited
|
|
||||||
* before cancelling the request automatically.
|
|
||||||
* @param {Function} data.beginKeyVerification a function to call if a key
|
|
||||||
* verification should be performed. The function takes one argument: the
|
|
||||||
* name of the key verification method (taken from data.methods) to use.
|
|
||||||
* @param {Function} data.cancel a function to call if the key verification is
|
|
||||||
* rejected.
|
|
||||||
*/
|
|
||||||
node.server.matrixClient.on(CryptoEvent.VerificationRequest, async function(data){
|
|
||||||
if(data.phase === Phase.Cancelled || data.phase === Phase.Done) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(data.requested || true) {
|
|
||||||
let verifyRequestId = data.targetDevice.userId + ':' + data.targetDevice.deviceId;
|
|
||||||
verificationRequests.set(verifyRequestId, data);
|
|
||||||
node.send({
|
|
||||||
verifyRequestId: verifyRequestId, // internally used to reference between nodes
|
|
||||||
verifyMethods: data.methods,
|
|
||||||
userId: data.targetDevice.userId,
|
|
||||||
deviceId: data.targetDevice.deviceId,
|
|
||||||
selfVerification: data.isSelfVerification,
|
|
||||||
phase: getKeyByValue(Phase, data.phase)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
node.on('close', function(done) {
|
|
||||||
// clear verification requests
|
|
||||||
verificationRequests.clear();
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'start':
|
|
||||||
node.on('input', async function(msg){
|
|
||||||
if(!msg.verifyRequestId || !verificationRequests.has(msg.verifyRequestId)) {
|
|
||||||
// if(msg.userId && msg.deviceId) {
|
|
||||||
// node.server.beginKeyVerification("m.sas.v1", msg.userId, msg.deviceId);
|
|
||||||
// }
|
|
||||||
|
|
||||||
node.error("invalid verification request (invalid msg.verifyRequestId): " + (msg.verifyRequestId || null));
|
|
||||||
}
|
|
||||||
|
|
||||||
var data = verificationRequests.get(msg.verifyRequestId);
|
|
||||||
if(msg.cancel) {
|
|
||||||
await data._verifier.cancel();
|
|
||||||
verificationRequests.delete(msg.verifyRequestId);
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
data.on('change', async function() {
|
|
||||||
var that = this;
|
|
||||||
if(this.phase === Phase.Started) {
|
|
||||||
let verifierCancel = function(){
|
|
||||||
let verifyRequestId = that.targetDevice.userId + ':' + that.targetDevice.deviceId;
|
|
||||||
if(verificationRequests.has(verifyRequestId)) {
|
|
||||||
verificationRequests.delete(verifyRequestId);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
data._verifier.on('cancel', function(e){
|
|
||||||
node.warn("Device verification cancelled " + e);
|
|
||||||
verifierCancel();
|
|
||||||
});
|
|
||||||
|
|
||||||
let show_sas = function(e) {
|
|
||||||
// e = {
|
|
||||||
// sas: {
|
|
||||||
// decimal: [ 8641, 3153, 2357 ],
|
|
||||||
// emoji: [
|
|
||||||
// [Array], [Array],
|
|
||||||
// [Array], [Array],
|
|
||||||
// [Array], [Array],
|
|
||||||
// [Array]
|
|
||||||
// ]
|
|
||||||
// },
|
|
||||||
// confirm: [AsyncFunction: confirm],
|
|
||||||
// cancel: [Function: cancel],
|
|
||||||
// mismatch: [Function: mismatch]
|
|
||||||
// }
|
|
||||||
msg.payload = e.sas;
|
|
||||||
msg.emojis = e.sas.emoji.map(function(emoji, i) {
|
|
||||||
return emoji[0];
|
|
||||||
});
|
|
||||||
msg.emojis_text = e.sas.emoji.map(function(emoji, i) {
|
|
||||||
return emoji[1];
|
|
||||||
});
|
|
||||||
node.send(msg);
|
|
||||||
};
|
|
||||||
data._verifier.on('show_sas', show_sas);
|
|
||||||
data._verifier.verify()
|
|
||||||
.then(function(e){
|
|
||||||
data._verifier.off('show_sas', show_sas);
|
|
||||||
data._verifier.done();
|
|
||||||
}, function(e) {
|
|
||||||
verifierCancel();
|
|
||||||
node.warn(e);
|
|
||||||
// @todo return over second output
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
data.emit("change");
|
|
||||||
await data.accept();
|
|
||||||
} catch(e) {
|
|
||||||
console.log("ERROR", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'cancel':
|
|
||||||
node.on('input', async function(msg){
|
|
||||||
if(!msg.verifyRequestId || !verificationRequests.has(msg.verifyRequestId)) {
|
|
||||||
node.error("Invalid verification request: " + (msg.verifyRequestId || null));
|
|
||||||
}
|
|
||||||
|
|
||||||
var data = verificationRequests.get(msg.verifyRequestId);
|
|
||||||
if(data) {
|
|
||||||
data.cancel()
|
|
||||||
.then(function(e){
|
|
||||||
node.send([msg, null]);
|
|
||||||
})
|
|
||||||
.catch(function(e) {
|
|
||||||
msg.error = e;
|
|
||||||
node.send([null, msg]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'accept':
|
|
||||||
node.on('input', async function(msg){
|
|
||||||
if(!msg.verifyRequestId || !verificationRequests.has(msg.verifyRequestId)) {
|
|
||||||
node.error("Invalid verification request: " + (msg.verifyRequestId || null));
|
|
||||||
}
|
|
||||||
|
|
||||||
var data = verificationRequests.get(msg.verifyRequestId);
|
|
||||||
if(data._verifier && data._verifier.sasEvent) {
|
|
||||||
data._verifier.sasEvent.confirm()
|
|
||||||
.then(function(e){
|
|
||||||
node.send([msg, null]);
|
|
||||||
})
|
|
||||||
.catch(function(e) {
|
|
||||||
msg.error = e;
|
|
||||||
node.send([null, msg]);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
node.error("Verification must be started");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RED.nodes.registerType("matrix-device-verification", MatrixDeviceVerification);
|
|
||||||
}
|
|
@ -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="fa fa-tag"></i> Name</label>
|
<label for="node-input-name"><i class="icon-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,21 +30,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-roomId"><i class="fa fa-comments"></i> Room ID</label>
|
<label for="node-input-roomId"><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>
|
|
||||||
<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>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -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="fa fa-tag"></i> Name</label>
|
<label for="node-input-name"><i class="icon-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">
|
||||||
|
@ -9,8 +9,7 @@
|
|||||||
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";
|
||||||
@ -21,7 +20,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="fa fa-tag"></i> Name</label>
|
<label for="node-input-name"><i class="icon-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,25 +28,8 @@
|
|||||||
<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-comments"></i> Room ID</label>
|
<label for="node-input-roomId"><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>
|
|
||||||
<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>
|
|
||||||
</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>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -60,7 +42,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. If configured on the node this is ignored otherwise it required. </dd>
|
<dd> Usually an emoji but can also be text. </dd>
|
||||||
|
|
||||||
<dt>msg.topic
|
<dt>msg.topic
|
||||||
<span class="property-type">string | null</span>
|
<span class="property-type">string | null</span>
|
||||||
|
@ -7,7 +7,6 @@ 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");
|
||||||
@ -41,9 +40,8 @@ module.exports = function(RED) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let payload = n.reaction || msg.payload;
|
if(!msg.payload) {
|
||||||
if(!payload) {
|
node.error('msg.payload is required');
|
||||||
node.error('msg.payload must be defined or the reaction configured on the node.');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +59,7 @@ module.exports = function(RED) {
|
|||||||
{
|
{
|
||||||
"m.relates_to": {
|
"m.relates_to": {
|
||||||
event_id: eventId,
|
event_id: eventId,
|
||||||
key: payload,
|
key: msg.payload,
|
||||||
rel_type: "m.annotation"
|
rel_type: "m.annotation"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,20 +34,8 @@
|
|||||||
<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-comments"></i> Room ID</label>
|
<label for="node-input-roomId"><i class="fa fa-user"></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>
|
|
||||||
<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>
|
|
||||||
</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;">
|
||||||
@ -128,11 +116,6 @@
|
|||||||
</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>
|
||||||
|
@ -9,8 +9,7 @@
|
|||||||
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";
|
||||||
@ -21,7 +20,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="fa fa-tag"></i> Name</label>
|
<label for="node-input-name"><i class="icon-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,25 +28,8 @@
|
|||||||
<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-comments"></i> Room ID</label>
|
<label for="node-input-roomId"><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>
|
|
||||||
<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>
|
|
||||||
</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>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -70,7 +52,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. If configured on the node it will overwrite this input</dd>
|
<dd> Reason for banning the user.</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<h3>Outputs</h3>
|
<h3>Outputs</h3>
|
||||||
|
@ -7,7 +7,6 @@ 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");
|
||||||
@ -46,7 +45,7 @@ module.exports = function(RED) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
node.server.matrixClient.ban(msg.topic, msg.userId, n.reason || msg.reason || undefined)
|
node.server.matrixClient.ban(msg.topic, msg.userId, 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;
|
||||||
|
@ -9,8 +9,7 @@
|
|||||||
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";
|
||||||
@ -21,7 +20,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="fa fa-tag"></i> Name</label>
|
<label for="node-input-name"><i class="icon-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,25 +28,8 @@
|
|||||||
<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-comments"></i> Room ID</label>
|
<label for="node-input-roomId"><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>
|
|
||||||
<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>
|
|
||||||
</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>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -70,7 +52,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. If configured on the node it will overwrite this input</dd>
|
<dd> Reason for kicking the user.</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<h3>Outputs</h3>
|
<h3>Outputs</h3>
|
||||||
|
@ -7,7 +7,6 @@ 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");
|
||||||
@ -46,7 +45,7 @@ module.exports = function(RED) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
node.server.matrixClient.kick(msg.topic, msg.userId, n.reason || msg.reason || undefined)
|
node.server.matrixClient.kick(msg.topic, msg.userId, 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;
|
||||||
|
@ -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="fa fa-tag"></i> Name</label>
|
<label for="node-input-name"><i class="icon-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,20 +28,8 @@
|
|||||||
<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-server"><i class="fa fa-user"></i> Room Id</label> <input type="text" id="node-input-roomId" placeholder="msg.topic">
|
<label for="node-input-server"><i class="fa fa-user"></i> Room Id</label>
|
||||||
<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>
|
<input type="text" id="node-input-roomId" placeholder="msg.topic">
|
||||||
<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>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -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="fa fa-tag"></i> Name</label>
|
<label for="node-input-name"><i class="icon-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,21 +29,8 @@
|
|||||||
<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-comments"></i> Room ID</label>
|
<label for="node-input-roomId"><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>
|
|
||||||
<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>
|
|
||||||
</div>
|
|
||||||
</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>
|
||||||
|
@ -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="fa fa-tag"></i> Name</label>
|
<label for="node-input-name"><i class="icon-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,21 +29,8 @@
|
|||||||
<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-comments"></i> Room ID</label>
|
<label for="node-input-roomId"><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>
|
|
||||||
<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>
|
|
||||||
</div>
|
|
||||||
</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>
|
||||||
|
@ -10,10 +10,8 @@
|
|||||||
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";
|
||||||
@ -24,7 +22,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="fa fa-tag"></i> Name</label>
|
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||||
<input type="text" id="node-input-name" placeholder="Name">
|
<input type="text" id="node-input-name" placeholder="Name">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -34,37 +32,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-roomId"><i class="fa fa-comments"></i> Room ID</label>
|
<label for="node-input-roomId"><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>
|
|
||||||
<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>
|
|
||||||
</div>
|
|
||||||
</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">
|
||||||
@ -107,17 +76,12 @@
|
|||||||
<dt>msg.payload
|
<dt>msg.payload
|
||||||
<span class="property-type">string</span>
|
<span class="property-type">string</span>
|
||||||
</dt>
|
</dt>
|
||||||
<dd> the message text. If configured on the node this is ignored otherwise it required. </dd>
|
<dd> the message text. </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 <code>msg.payload</code> if not defined). This only affects HTML messages.</dd>
|
<dd> the formatted HTML message (uses msg.payload 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>
|
||||||
|
@ -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);
|
||||||
@ -11,8 +9,6 @@ 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 = [
|
||||||
@ -102,15 +98,14 @@ module.exports = function(RED) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let payload = n.message || msg.payload;
|
if(!msg.payload) {
|
||||||
if(!payload) {
|
node.error('msg.payload is required');
|
||||||
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: payload.toString()
|
body: msg.payload.toString()
|
||||||
};
|
};
|
||||||
|
|
||||||
if(msgFormat === 'html') {
|
if(msgFormat === 'html') {
|
||||||
@ -118,31 +113,12 @@ 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()
|
||||||
: payload.toString();
|
: msg.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: " + payload);
|
node.log("Message sent: " + msg.payload);
|
||||||
msg.eventId = e.event_id;
|
msg.eventId = e.event_id;
|
||||||
node.send([msg, null]);
|
node.send([msg, null]);
|
||||||
})
|
})
|
||||||
|
@ -4,7 +4,6 @@ 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) {
|
||||||
@ -147,7 +146,7 @@ module.exports = function(RED) {
|
|||||||
return node.connected;
|
return node.connected;
|
||||||
};
|
};
|
||||||
|
|
||||||
node.matrixClient.on(RoomEvent.Timeline, async function(event, room, toStartOfTimeline, removed, data) {
|
node.matrixClient.on("Room.timeline", async function(event, room, toStartOfTimeline, removed, data) {
|
||||||
if (toStartOfTimeline) {
|
if (toStartOfTimeline) {
|
||||||
return; // ignore paginated results
|
return; // ignore paginated results
|
||||||
}
|
}
|
||||||
@ -168,32 +167,16 @@ 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]' : ''));
|
||||||
@ -206,9 +189,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;
|
||||||
@ -227,8 +210,7 @@ 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() {
|
||||||
@ -242,7 +224,7 @@ module.exports = function(RED) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
node.matrixClient.on(ClientEvent.Sync, async function(state, prevState, data) {
|
node.matrixClient.on("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.
|
||||||
@ -310,8 +292,7 @@ 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',
|
||||||
|
@ -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="fa fa-tag"></i> Name</label>
|
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||||
<input type="text" id="node-input-name" placeholder="Name">
|
<input type="text" id="node-input-name" placeholder="Name">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -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="fa fa-tag"></i> Name</label>
|
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||||
<input type="text" id="node-input-name" placeholder="Name">
|
<input type="text" id="node-input-name" placeholder="Name">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -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="fa fa-tag"></i> Name</label>
|
<label for="node-input-name"><i class="icon-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,21 +30,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-roomId"><i class="fa fa-comments"></i> Room ID</label>
|
<label for="node-input-roomId"><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>
|
|
||||||
<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>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-tips" style="margin-bottom: 12px;">
|
<div class="form-tips" style="margin-bottom: 12px;">
|
||||||
|
@ -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="fa fa-tag"></i> Name</label>
|
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||||
<input type="text" id="node-input-name" placeholder="Name">
|
<input type="text" id="node-input-name" placeholder="Name">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -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="fa fa-tag"></i> Name</label>
|
<label for="node-input-name"><i class="icon-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">
|
||||||
|
@ -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="fa fa-tag"></i> Name</label>
|
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||||
<input type="text" id="node-input-name" placeholder="Name">
|
<input type="text" id="node-input-name" placeholder="Name">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user