mirror of
https://github.com/Skylar-Tech/node-red-contrib-matrix-chat.git
synced 2026-05-18 05:03:37 -06:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b49cb5b12f |
Generated
+16523
-5063
File diff suppressed because it is too large
Load Diff
+1
-2
@@ -52,8 +52,7 @@
|
|||||||
"matrix-whois-user": "src/matrix-whois-user.js",
|
"matrix-whois-user": "src/matrix-whois-user.js",
|
||||||
"matrix-paginate-room": "src/matrix-paginate-room.js",
|
"matrix-paginate-room": "src/matrix-paginate-room.js",
|
||||||
"matrix-get-event": "src/matrix-get-event.js",
|
"matrix-get-event": "src/matrix-get-event.js",
|
||||||
"matrix-event-relations": "src/matrix-event-relations.js",
|
"matrix-event-relations": "src/matrix-event-relations.js"
|
||||||
"matrix-device-verification": "src/matrix-device-verification.js"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|||||||
@@ -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,267 +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.requestDeviceVerification(msg.userId, msg.devices || undefined)
|
|
||||||
.then(function(e) {
|
|
||||||
node.log("Successfully requested verification", e);
|
|
||||||
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.VerificationRequestReceived, 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)) {
|
|
||||||
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() {
|
|
||||||
// VerificationPhase {
|
|
||||||
// /** Initial state: no event yet exchanged */
|
|
||||||
// Unsent = 1,
|
|
||||||
//
|
|
||||||
// /** An `m.key.verification.request` event has been sent or received */
|
|
||||||
// Requested = 2,
|
|
||||||
//
|
|
||||||
// /** An `m.key.verification.ready` event has been sent or received, indicating the verification request is accepted. */
|
|
||||||
// Ready = 3,
|
|
||||||
//
|
|
||||||
// /** An `m.key.verification.start` event has been sent or received, choosing a verification method */
|
|
||||||
// Started = 4,
|
|
||||||
//
|
|
||||||
// /** An `m.key.verification.cancel` event has been sent or received at any time before the `done` event, cancelling the verification request */
|
|
||||||
// Cancelled = 5,
|
|
||||||
//
|
|
||||||
// /** An `m.key.verification.done` event has been **sent**, completing the verification request. */
|
|
||||||
// Done = 6,
|
|
||||||
// }
|
|
||||||
console.log("[Verification Start] VERIFIER EVENT CHANGE", this.phase);
|
|
||||||
var that = this;
|
|
||||||
if(this.phase === Phase.Started) {
|
|
||||||
console.log("[Verification Start] VERIFIER EVENT 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);
|
|
||||||
console.log(JSON.stringify(e.value));
|
|
||||||
verifierCancel();
|
|
||||||
});
|
|
||||||
const sasEventPromise = new Promise(resolve =>
|
|
||||||
data.verifier.once("show_sas", resolve)
|
|
||||||
);
|
|
||||||
console.log("[Verification Start] Starting verification");
|
|
||||||
data.verifier.verify()
|
|
||||||
.then(function() {
|
|
||||||
console.log("[Verification Start] verify() success");
|
|
||||||
}).catch(function(e) {
|
|
||||||
console.log("[Verification Start] verify() error", e);
|
|
||||||
msg.error = e;
|
|
||||||
node.send([null, msg]);
|
|
||||||
});
|
|
||||||
console.log("[Verification Start] WAITING FOR SHOW SAS EVENT");
|
|
||||||
const sasEvent = await sasEventPromise;
|
|
||||||
|
|
||||||
console.log("SHOW SAS", sasEvent);
|
|
||||||
// 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 = sasEvent.sas;
|
|
||||||
msg.emojis = sasEvent.sas.emoji.map(function(emoji, i) {
|
|
||||||
return emoji[0];
|
|
||||||
});
|
|
||||||
msg.emojis_text = sasEvent.sas.emoji.map(function(emoji, i) {
|
|
||||||
return emoji[1];
|
|
||||||
});
|
|
||||||
node.send(msg);
|
|
||||||
|
|
||||||
// sasEvent.mismatch();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log("[Verification Start] Starting verification");
|
|
||||||
try {
|
|
||||||
console.log("[Verification Start] Accepting..");
|
|
||||||
await data.accept();
|
|
||||||
console.log(`[Verification] beginKeyVerification (methods=${data.methods[0]}, targetDevice=${data.targetDevice})`);
|
|
||||||
await data.beginKeyVerification(
|
|
||||||
data.methods[0],
|
|
||||||
data.targetDevice
|
|
||||||
);
|
|
||||||
} catch(e) {
|
|
||||||
console.log("[Verification Start] VERIFICATION ERROR", e);
|
|
||||||
}
|
|
||||||
} 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) {
|
|
||||||
try {
|
|
||||||
await data.verifier.sasEvent.confirm();
|
|
||||||
node.send([msg, null]);
|
|
||||||
} catch(e) {
|
|
||||||
|
|
||||||
msg.error = e;
|
|
||||||
node.send([null, msg]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
node.error("Verification must be started");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RED.nodes.registerType("matrix-device-verification", MatrixDeviceVerification);
|
|
||||||
}
|
|
||||||
+3
-113
@@ -52,7 +52,6 @@ module.exports = function(RED) {
|
|||||||
this.userId = this.credentials.userId;
|
this.userId = this.credentials.userId;
|
||||||
this.deviceLabel = this.credentials.deviceLabel || null;
|
this.deviceLabel = this.credentials.deviceLabel || null;
|
||||||
this.deviceId = this.credentials.deviceId || null;
|
this.deviceId = this.credentials.deviceId || null;
|
||||||
this.secretStoragePassphrase = null;
|
|
||||||
this.url = this.credentials.url;
|
this.url = this.credentials.url;
|
||||||
this.autoAcceptRoomInvites = n.autoAcceptRoomInvites;
|
this.autoAcceptRoomInvites = n.autoAcceptRoomInvites;
|
||||||
this.e2ee = n.enableE2ee || false;
|
this.e2ee = n.enableE2ee || false;
|
||||||
@@ -73,33 +72,6 @@ module.exports = function(RED) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let cryptoCallbacks = undefined;
|
|
||||||
if(node.e2ee) {
|
|
||||||
cryptoCallbacks = {
|
|
||||||
getSecretStorageKey: async ({ keys }) => {
|
|
||||||
return null; // we don't do secret storage right now
|
|
||||||
const backupPassphrase = node.secretStoragePassphrase;
|
|
||||||
if (!backupPassphrase) {
|
|
||||||
node.WARN("Missing secret storage key");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
let keyId = await node.matrixClient.getDefaultSecretStorageKeyId();
|
|
||||||
if (keyId && !keys[keyId]) {
|
|
||||||
keyId = undefined;
|
|
||||||
}
|
|
||||||
if (!keyId) {
|
|
||||||
keyId = keys[0][0];
|
|
||||||
}
|
|
||||||
const backupInfo = await node.matrixClient.getKeyBackupVersion();
|
|
||||||
const key = await node.matrixClient.keyBackupKeyFromPassword(
|
|
||||||
backupPassphrase,
|
|
||||||
backupInfo
|
|
||||||
);
|
|
||||||
return [keyId, key];
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let localStorageDir = storageDir + '/' + MatrixFolderNameFromUserId(this.userId),
|
let localStorageDir = storageDir + '/' + MatrixFolderNameFromUserId(this.userId),
|
||||||
localStorage = new LocalStorage(localStorageDir),
|
localStorage = new LocalStorage(localStorageDir),
|
||||||
initialSetup = false;
|
initialSetup = false;
|
||||||
@@ -111,61 +83,6 @@ 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 {
|
||||||
/**
|
|
||||||
* Ensures secret storage and cross signing are ready for use. Does not
|
|
||||||
* support initial setup of secret storage. If the backup passphrase is not
|
|
||||||
* set, this is a no-op, else it is cleared once the operation is complete.
|
|
||||||
*
|
|
||||||
* @returns {Promise<void>}
|
|
||||||
*/
|
|
||||||
async function bootstrapSSSS() {
|
|
||||||
if (!node.matrixClient) {
|
|
||||||
// client startup will do bootstrapping
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const password = "testphrase";
|
|
||||||
if (!password) {
|
|
||||||
// We do not support setting up secret storage, so we need a passphrase
|
|
||||||
// to bootstrap.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const backupInfo = await node.matrixClient.getKeyBackupVersion();
|
|
||||||
await node.matrixClient.getCrypto().bootstrapSecretStorage({
|
|
||||||
setupNewKeyBackup: false,
|
|
||||||
async getKeyBackupPassphrase() {
|
|
||||||
const key = await node.matrixClient.keyBackupKeyFromPassword(
|
|
||||||
password,
|
|
||||||
backupInfo
|
|
||||||
);
|
|
||||||
return key;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
await node.matrixClient.getCrypto().bootstrapCrossSigning({
|
|
||||||
authUploadDeviceSigningKeys(makeRequest) {
|
|
||||||
console.log("authUploadDeviceSigningKeys");
|
|
||||||
makeRequest({
|
|
||||||
"type": "m.login.password",
|
|
||||||
"identifier": {
|
|
||||||
"type": "m.id.user",
|
|
||||||
"user": node.matrixClient.getUserId()
|
|
||||||
},
|
|
||||||
"password": "examplepass",
|
|
||||||
"session": node.matrixClient.getSessionId()
|
|
||||||
});
|
|
||||||
return Promise.resolve();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
await node.matrixClient.checkOwnCrossSigningTrust();
|
|
||||||
if (backupInfo) {
|
|
||||||
await node.matrixClient.restoreKeyBackupWithSecretStorage(backupInfo);
|
|
||||||
}
|
|
||||||
// Clear passphrase once bootstrap was successful
|
|
||||||
// this.imAccount.setString("backupPassphrase", "");
|
|
||||||
// this.imAccount.save();
|
|
||||||
// this._encryptionError = "";
|
|
||||||
// await this.updateEncryptionStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
node.setConnected = async function(connected, cb) {
|
node.setConnected = async function(connected, cb) {
|
||||||
if (node.connected !== connected) {
|
if (node.connected !== connected) {
|
||||||
node.connected = connected;
|
node.connected = connected;
|
||||||
@@ -177,19 +94,11 @@ module.exports = function(RED) {
|
|||||||
node.log("Matrix server connection ready.");
|
node.log("Matrix server connection ready.");
|
||||||
node.emit("connected");
|
node.emit("connected");
|
||||||
if(!initialSetup) {
|
if(!initialSetup) {
|
||||||
console.log("INITIAL SETUP", await node.matrixClient.getCrypto().getCrossSigningStatus());
|
|
||||||
if(node.e2ee && !await node.matrixClient.getCrypto().isCrossSigningReady()) {
|
|
||||||
// bootstrap cross-signing
|
|
||||||
await bootstrapSSSS();
|
|
||||||
let crossSigningStatus = node.matrixClient.getCrypto().getCrossSigningStatus();
|
|
||||||
console.log("crossSigningStatus", crossSigningStatus);
|
|
||||||
}
|
|
||||||
|
|
||||||
// store Device ID internally
|
// store Device ID internally
|
||||||
let stored_device_id = getStoredDeviceId(localStorage),
|
let stored_device_id = getStoredDeviceId(localStorage),
|
||||||
device_id = this.matrixClient.getDeviceId();
|
device_id = this.matrixClient.getDeviceId();
|
||||||
|
|
||||||
if(!device_id && node.e2ee) {
|
if(!device_id && node.enableE2ee) {
|
||||||
node.error("Failed to auto detect deviceId for this auth token. You will need to manually specify one. You may need to login to create a new deviceId.", {})
|
node.error("Failed to auto detect deviceId for this auth token. You will need to manually specify one. You may need to login to create a new deviceId.", {})
|
||||||
} else {
|
} else {
|
||||||
if(!stored_device_id || stored_device_id !== device_id) {
|
if(!stored_device_id || stored_device_id !== device_id) {
|
||||||
@@ -236,17 +145,6 @@ module.exports = function(RED) {
|
|||||||
|
|
||||||
fs.ensureDirSync(storageDir); // create storage directory if it doesn't exist
|
fs.ensureDirSync(storageDir); // create storage directory if it doesn't exist
|
||||||
upgradeDirectoryIfNecessary(node, storageDir);
|
upgradeDirectoryIfNecessary(node, storageDir);
|
||||||
|
|
||||||
// taken from https://github.com/matrix-org/matrix-react-sdk/blob/d9d0ab3d98dea8f260bd7037482c3c8cf288ae82/cypress/support/bot.ts
|
|
||||||
// these next lines are to fix "Device verification cancelled Error: No getCrossSigningKey callback supplied" error
|
|
||||||
const privateKeys = {};
|
|
||||||
const getCrossSigningKey = (type) => {
|
|
||||||
return privateKeys[type];
|
|
||||||
};
|
|
||||||
const saveCrossSigningKeys = (k) => {
|
|
||||||
Object.assign(privateKeys, k);
|
|
||||||
};
|
|
||||||
|
|
||||||
node.matrixClient = sdk.createClient({
|
node.matrixClient = sdk.createClient({
|
||||||
baseUrl: this.url,
|
baseUrl: this.url,
|
||||||
accessToken: this.credentials.accessToken,
|
accessToken: this.credentials.accessToken,
|
||||||
@@ -256,14 +154,8 @@ module.exports = function(RED) {
|
|||||||
}),
|
}),
|
||||||
userId: this.userId,
|
userId: this.userId,
|
||||||
deviceId: (this.deviceId || getStoredDeviceId(localStorage)) || undefined,
|
deviceId: (this.deviceId || getStoredDeviceId(localStorage)) || undefined,
|
||||||
request,
|
request
|
||||||
verificationMethods: ["m.sas.v1"],
|
// verificationMethods: ["m.sas.v1"]
|
||||||
cryptoCallbacks: { getCrossSigningKey, saveCrossSigningKeys },
|
|
||||||
});
|
|
||||||
|
|
||||||
node.matrixClient.on("crypto.keyBackupStatus", function() {
|
|
||||||
console.log("crypto.keyBackupStatus");
|
|
||||||
bootstrapSSSS();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
node.debug(`hasLazyLoadMembersEnabled=${node.matrixClient.hasLazyLoadMembersEnabled()}`);
|
node.debug(`hasLazyLoadMembersEnabled=${node.matrixClient.hasLazyLoadMembersEnabled()}`);
|
||||||
@@ -508,8 +400,6 @@ module.exports = function(RED) {
|
|||||||
if(node.e2ee){
|
if(node.e2ee){
|
||||||
node.log("Initializing crypto...");
|
node.log("Initializing crypto...");
|
||||||
await node.matrixClient.initCrypto();
|
await node.matrixClient.initCrypto();
|
||||||
node.log("Bootstrapping SSSS...");
|
|
||||||
await bootstrapSSSS();
|
|
||||||
node.matrixClient.getCrypto().globalBlacklistUnverifiedDevices = false; // prevent errors from unverified devices
|
node.matrixClient.getCrypto().globalBlacklistUnverifiedDevices = false; // prevent errors from unverified devices
|
||||||
}
|
}
|
||||||
node.log("Connecting to Matrix server...");
|
node.log("Connecting to Matrix server...");
|
||||||
|
|||||||
Reference in New Issue
Block a user