Compare commits
4 Commits
dev
...
e2ee-key-s
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5119bc42d4 | ||
|
|
2993dea974 | ||
|
|
678702e9c6 | ||
|
|
36c8208b01 |
@@ -32,7 +32,9 @@
|
|||||||
"matrix-synapse-deactivate-user": "src/matrix-synapse-deactivate-user.js",
|
"matrix-synapse-deactivate-user": "src/matrix-synapse-deactivate-user.js",
|
||||||
"matrix-synapse-join-room": "src/matrix-synapse-join-room.js",
|
"matrix-synapse-join-room": "src/matrix-synapse-join-room.js",
|
||||||
"matrix-whois-user": "src/matrix-whois-user.js",
|
"matrix-whois-user": "src/matrix-whois-user.js",
|
||||||
"matrix-room-users": "src/matrix-room-users.js"
|
"matrix-room-users": "src/matrix-room-users.js",
|
||||||
|
"matrix-device-verify": "src/matrix-device-verify.js",
|
||||||
|
"matrix-secret-storage": "src/matrix-secret-storage.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|||||||
308
src/matrix-device-verify.html
Normal file
308
src/matrix-device-verify.html
Normal file
@@ -0,0 +1,308 @@
|
|||||||
|
<script type="text/javascript">
|
||||||
|
RED.nodes.registerType('matrix-device-verify-request', {
|
||||||
|
category: 'matrix',
|
||||||
|
color: '#00b7ca',
|
||||||
|
icon: "matrix.png",
|
||||||
|
inputs: 0,
|
||||||
|
outputs: 1,
|
||||||
|
defaults: {
|
||||||
|
name: { value: null },
|
||||||
|
server: { value: "", type: "matrix-server-config" }
|
||||||
|
},
|
||||||
|
label: function() {
|
||||||
|
return this.name || "Device Verify Request";
|
||||||
|
},
|
||||||
|
paletteLabel: 'Device Verify Request'
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/html" data-template-name="matrix-device-verify-request">
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-input-name"><i class="icon-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>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/html" data-help-name="matrix-device-verify-request">
|
||||||
|
<h3>Details</h3>
|
||||||
|
<p>
|
||||||
|
This API invites a user to participate in a particular room. They do not start participating in the room until they actually join the room.
|
||||||
|
</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>
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dt>msg.topic
|
||||||
|
<span class="property-type">string</span>
|
||||||
|
</dt>
|
||||||
|
<dd> The room identifier to invite to: for example, <code>!h8zld9j31:example.com. If configured on the node it overrides this input and is no longer required.</code>.</dd>
|
||||||
|
|
||||||
|
<dt>msg.userId
|
||||||
|
<span class="property-type">string</span>
|
||||||
|
</dt>
|
||||||
|
<dd> User's ID that will be invited to the room.</dd>
|
||||||
|
|
||||||
|
<dt class="optional">msg.reason
|
||||||
|
<span class="property-type">string</span>
|
||||||
|
</dt>
|
||||||
|
<dd> Reason for the membership change.</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<h3>Outputs</h3>
|
||||||
|
<ol class="node-ports">
|
||||||
|
<li>Success
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dt>msg.payload <span class="property-type">object</span></dt>
|
||||||
|
<dd>Currently this endpoint returns an empty object</dd>
|
||||||
|
</dl>
|
||||||
|
</li>
|
||||||
|
<li>Error
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dt>msg.error <span class="property-type">string</span></dt>
|
||||||
|
<dd>the error that occurred.</dd>
|
||||||
|
</dl>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
RED.nodes.registerType('matrix-device-verify-start', {
|
||||||
|
category: 'matrix',
|
||||||
|
color: '#00b7ca',
|
||||||
|
icon: "matrix.png",
|
||||||
|
inputs: 1,
|
||||||
|
outputs: 1,
|
||||||
|
defaults: {
|
||||||
|
name: { value: null },
|
||||||
|
server: { value: "", type: "matrix-server-config" }
|
||||||
|
},
|
||||||
|
label: function() {
|
||||||
|
return this.name || "Device Verify Start";
|
||||||
|
},
|
||||||
|
paletteLabel: 'Device Verify Start'
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/html" data-template-name="matrix-device-verify-start">
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-input-name"><i class="icon-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>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/html" data-help-name="matrix-device-verify-start">
|
||||||
|
<h3>Details</h3>
|
||||||
|
<p>
|
||||||
|
This API invites a user to participate in a particular room. They do not start participating in the room until they actually join the room.
|
||||||
|
</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>
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dt>msg.topic
|
||||||
|
<span class="property-type">string</span>
|
||||||
|
</dt>
|
||||||
|
<dd> The room identifier to invite to: for example, <code>!h8zld9j31:example.com. If configured on the node it overrides this input and is no longer required.</code>.</dd>
|
||||||
|
|
||||||
|
<dt>msg.userId
|
||||||
|
<span class="property-type">string</span>
|
||||||
|
</dt>
|
||||||
|
<dd> User's ID that will be invited to the room.</dd>
|
||||||
|
|
||||||
|
<dt class="optional">msg.reason
|
||||||
|
<span class="property-type">string</span>
|
||||||
|
</dt>
|
||||||
|
<dd> Reason for the membership change.</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<h3>Outputs</h3>
|
||||||
|
<ol class="node-ports">
|
||||||
|
<li>Success
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dt>msg.payload <span class="property-type">object</span></dt>
|
||||||
|
<dd>Currently this endpoint returns an empty object</dd>
|
||||||
|
</dl>
|
||||||
|
</li>
|
||||||
|
<li>Error
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dt>msg.error <span class="property-type">string</span></dt>
|
||||||
|
<dd>the error that occurred.</dd>
|
||||||
|
</dl>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
RED.nodes.registerType('matrix-device-verify-cancel', {
|
||||||
|
category: 'matrix',
|
||||||
|
color: '#00b7ca',
|
||||||
|
icon: "matrix.png",
|
||||||
|
inputs: 1,
|
||||||
|
outputs: 1,
|
||||||
|
defaults: {
|
||||||
|
name: { value: null },
|
||||||
|
server: { value: "", type: "matrix-server-config" }
|
||||||
|
},
|
||||||
|
label: function() {
|
||||||
|
return this.name || "Device Verify Cancel";
|
||||||
|
},
|
||||||
|
paletteLabel: 'Device Verify Cancel'
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/html" data-template-name="matrix-device-verify-cancel">
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-input-name"><i class="icon-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>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/html" data-help-name="matrix-device-verify-cancel">
|
||||||
|
<h3>Details</h3>
|
||||||
|
<p>
|
||||||
|
This API invites a user to participate in a particular room. They do not start participating in the room until they actually join the room.
|
||||||
|
</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>
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dt>msg.topic
|
||||||
|
<span class="property-type">string</span>
|
||||||
|
</dt>
|
||||||
|
<dd> The room identifier to invite to: for example, <code>!h8zld9j31:example.com. If configured on the node it overrides this input and is no longer required.</code>.</dd>
|
||||||
|
|
||||||
|
<dt>msg.userId
|
||||||
|
<span class="property-type">string</span>
|
||||||
|
</dt>
|
||||||
|
<dd> User's ID that will be invited to the room.</dd>
|
||||||
|
|
||||||
|
<dt class="optional">msg.reason
|
||||||
|
<span class="property-type">string</span>
|
||||||
|
</dt>
|
||||||
|
<dd> Reason for the membership change.</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<h3>Outputs</h3>
|
||||||
|
<ol class="node-ports">
|
||||||
|
<li>Success
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dt>msg.payload <span class="property-type">object</span></dt>
|
||||||
|
<dd>Currently this endpoint returns an empty object</dd>
|
||||||
|
</dl>
|
||||||
|
</li>
|
||||||
|
<li>Error
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dt>msg.error <span class="property-type">string</span></dt>
|
||||||
|
<dd>the error that occurred.</dd>
|
||||||
|
</dl>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
RED.nodes.registerType('matrix-device-verify-accept', {
|
||||||
|
category: 'matrix',
|
||||||
|
color: '#00b7ca',
|
||||||
|
icon: "matrix.png",
|
||||||
|
inputs: 1,
|
||||||
|
outputs: 1,
|
||||||
|
defaults: {
|
||||||
|
name: { value: null },
|
||||||
|
server: { value: "", type: "matrix-server-config" }
|
||||||
|
},
|
||||||
|
label: function() {
|
||||||
|
return this.name || "Device Verify Accept";
|
||||||
|
},
|
||||||
|
paletteLabel: 'Device Verify Accept'
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/html" data-template-name="matrix-device-verify-accept">
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-input-name"><i class="icon-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>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/html" data-help-name="matrix-device-verify-accept">
|
||||||
|
<h3>Details</h3>
|
||||||
|
<p>
|
||||||
|
This API invites a user to participate in a particular room. They do not start participating in the room until they actually join the room.
|
||||||
|
</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>
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dt>msg.topic
|
||||||
|
<span class="property-type">string</span>
|
||||||
|
</dt>
|
||||||
|
<dd> The room identifier to invite to: for example, <code>!h8zld9j31:example.com. If configured on the node it overrides this input and is no longer required.</code>.</dd>
|
||||||
|
|
||||||
|
<dt>msg.userId
|
||||||
|
<span class="property-type">string</span>
|
||||||
|
</dt>
|
||||||
|
<dd> User's ID that will be invited to the room.</dd>
|
||||||
|
|
||||||
|
<dt class="optional">msg.reason
|
||||||
|
<span class="property-type">string</span>
|
||||||
|
</dt>
|
||||||
|
<dd> Reason for the membership change.</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<h3>Outputs</h3>
|
||||||
|
<ol class="node-ports">
|
||||||
|
<li>Success
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dt>msg.payload <span class="property-type">object</span></dt>
|
||||||
|
<dd>Currently this endpoint returns an empty object</dd>
|
||||||
|
</dl>
|
||||||
|
</li>
|
||||||
|
<li>Error
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dt>msg.error <span class="property-type">string</span></dt>
|
||||||
|
<dd>the error that occurred.</dd>
|
||||||
|
</dl>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
</script>
|
||||||
271
src/matrix-device-verify.js
Normal file
271
src/matrix-device-verify.js
Normal file
@@ -0,0 +1,271 @@
|
|||||||
|
module.exports = function(RED) {
|
||||||
|
const verificationRequests = new Map();
|
||||||
|
|
||||||
|
function MatrixDeviceVerifyRequest(n) {
|
||||||
|
RED.nodes.createNode(this, n);
|
||||||
|
|
||||||
|
var node = this;
|
||||||
|
|
||||||
|
this.name = n.name;
|
||||||
|
this.server = RED.nodes.getNode(n.server);
|
||||||
|
|
||||||
|
if (!node.server) {
|
||||||
|
node.warn("No configuration node");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
node.status({ fill: "red", shape: "ring", text: "disconnected" });
|
||||||
|
|
||||||
|
node.server.on("disconnected", function(){
|
||||||
|
node.status({ fill: "red", shape: "ring", text: "disconnected" });
|
||||||
|
});
|
||||||
|
|
||||||
|
node.server.on("connected", function() {
|
||||||
|
node.status({ fill: "green", shape: "ring", text: "connected" });
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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("crypto.verification.request", async function(data){
|
||||||
|
console.log("[######### crypto.verification.request #########]", data.phase, data);
|
||||||
|
|
||||||
|
if(data.phase === 5 || data.phase === 6) {
|
||||||
|
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,
|
||||||
|
type: 'crypto.verification.request',
|
||||||
|
selfVerification: data.isSelfVerification
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
RED.nodes.registerType("matrix-device-verify-request", MatrixDeviceVerifyRequest);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function MatrixDeviceVerifyStart(n) {
|
||||||
|
RED.nodes.createNode(this, n);
|
||||||
|
|
||||||
|
var node = this;
|
||||||
|
|
||||||
|
this.name = n.name;
|
||||||
|
this.server = RED.nodes.getNode(n.server);
|
||||||
|
|
||||||
|
if (!node.server) {
|
||||||
|
node.warn("No configuration node");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
node.status({ fill: "red", shape: "ring", text: "disconnected" });
|
||||||
|
|
||||||
|
node.server.on("disconnected", function(){
|
||||||
|
node.status({ fill: "red", shape: "ring", text: "disconnected" });
|
||||||
|
});
|
||||||
|
|
||||||
|
node.server.on("connected", function() {
|
||||||
|
node.status({ fill: "green", shape: "ring", text: "connected" });
|
||||||
|
});
|
||||||
|
|
||||||
|
node.on('close', function(done) {
|
||||||
|
verificationRequests.clear();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
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("Invaid verification request: " + (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;
|
||||||
|
console.log("[##### VERIFICATION PHASE CHANGE #######]", this.phase);
|
||||||
|
if(this.phase === 4) {
|
||||||
|
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 verificaiton 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){
|
||||||
|
console.log("!!!!!!!!!!! VERIFY THEN", 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
RED.nodes.registerType("matrix-device-verify-start", MatrixDeviceVerifyStart);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function MatrixDeviceVerifyCancel(n) {
|
||||||
|
RED.nodes.createNode(this, n);
|
||||||
|
|
||||||
|
var node = this;
|
||||||
|
|
||||||
|
this.name = n.name;
|
||||||
|
this.server = RED.nodes.getNode(n.server);
|
||||||
|
|
||||||
|
if (!node.server) {
|
||||||
|
node.warn("No configuration node");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
node.status({ fill: "red", shape: "ring", text: "disconnected" });
|
||||||
|
|
||||||
|
node.server.on("disconnected", function(){
|
||||||
|
node.status({ fill: "red", shape: "ring", text: "disconnected" });
|
||||||
|
});
|
||||||
|
|
||||||
|
node.server.on("connected", function() {
|
||||||
|
node.status({ fill: "green", shape: "ring", text: "connected" });
|
||||||
|
});
|
||||||
|
|
||||||
|
node.on('close', function(done) {
|
||||||
|
verificationRequests.clear();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
node.on('input', async function(msg){
|
||||||
|
if(!msg.verifyRequestId || !verificationRequests.has(msg.verifyRequestId)) {
|
||||||
|
node.error("Invaid verification request: " + (msg.verifyRequestId || null));
|
||||||
|
}
|
||||||
|
|
||||||
|
var data = verificationRequests.get(msg.verifyRequestId);
|
||||||
|
if(data) {
|
||||||
|
data.cancel();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
RED.nodes.registerType("matrix-device-verify-cancel", MatrixDeviceVerifyCancel);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function MatrixDeviceVerifyAccept(n) {
|
||||||
|
RED.nodes.createNode(this, n);
|
||||||
|
|
||||||
|
var node = this;
|
||||||
|
|
||||||
|
this.name = n.name;
|
||||||
|
this.server = RED.nodes.getNode(n.server);
|
||||||
|
|
||||||
|
if (!node.server) {
|
||||||
|
node.warn("No configuration node");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
node.status({ fill: "red", shape: "ring", text: "disconnected" });
|
||||||
|
|
||||||
|
node.server.on("disconnected", function(){
|
||||||
|
node.status({ fill: "red", shape: "ring", text: "disconnected" });
|
||||||
|
});
|
||||||
|
|
||||||
|
node.server.on("connected", function() {
|
||||||
|
node.status({ fill: "green", shape: "ring", text: "connected" });
|
||||||
|
});
|
||||||
|
|
||||||
|
node.on('close', function(done) {
|
||||||
|
verificationRequests.clear();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
node.on('input', async function(msg){
|
||||||
|
if(!msg.verifyRequestId || !verificationRequests.has(msg.verifyRequestId)) {
|
||||||
|
node.error("Invaid verification request: " + (msg.verifyRequestId || null));
|
||||||
|
}
|
||||||
|
|
||||||
|
var data = verificationRequests.get(msg.verifyRequestId);
|
||||||
|
if(data._verifier && data._verifier.sasEvent) {
|
||||||
|
data._verifier.sasEvent.confirm()
|
||||||
|
.then(function(e){
|
||||||
|
console.log("!!!!!!!! CONFIRMED VERIFY", e);
|
||||||
|
})
|
||||||
|
.catch(function(e) {
|
||||||
|
console.log("!!!!!!!! CONFIRMED VERIFY FAILED", e);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.log("Verification must be started", data);
|
||||||
|
node.error("Verification must be started");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
RED.nodes.registerType("matrix-device-verify-accept", MatrixDeviceVerifyAccept);
|
||||||
|
}
|
||||||
71
src/matrix-secret-storage.html
Normal file
71
src/matrix-secret-storage.html
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
<script type="text/javascript">
|
||||||
|
RED.nodes.registerType('matrix-secret-storage', {
|
||||||
|
category: 'matrix',
|
||||||
|
color: '#00b7ca',
|
||||||
|
icon: "matrix.png",
|
||||||
|
inputs: 1,
|
||||||
|
outputs: 1,
|
||||||
|
defaults: {
|
||||||
|
name: { value: null },
|
||||||
|
server: { value: "", type: "matrix-server-config" }
|
||||||
|
},
|
||||||
|
label: function() {
|
||||||
|
return this.name || "Secret Storage";
|
||||||
|
},
|
||||||
|
paletteLabel: 'Secret Storage'
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/html" data-template-name="matrix-secret-storage">
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-input-name"><i class="icon-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>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/html" data-help-name="matrix-secret-storage">
|
||||||
|
<h3>Details</h3>
|
||||||
|
<p>
|
||||||
|
Secure backup node. Use this to setup security key backup to the remote server. You can also use this node to import an existing secure backup.
|
||||||
|
</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>
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dt>msg.topic
|
||||||
|
<span class="property-type">string</span>
|
||||||
|
</dt>
|
||||||
|
<dd> The room identifier to invite to: for example, <code>!h8zld9j31:example.com. If configured on the node it overrides this input and is no longer required.</code>.</dd>
|
||||||
|
|
||||||
|
<dt>msg.userId
|
||||||
|
<span class="property-type">string</span>
|
||||||
|
</dt>
|
||||||
|
<dd> User's ID that will be invited to the room.</dd>
|
||||||
|
|
||||||
|
<dt class="optional">msg.reason
|
||||||
|
<span class="property-type">string</span>
|
||||||
|
</dt>
|
||||||
|
<dd> Reason for the membership change.</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<h3>Outputs</h3>
|
||||||
|
<ol class="node-ports">
|
||||||
|
<li>Success
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dt>msg.payload <span class="property-type">object</span></dt>
|
||||||
|
<dd>Currently this endpoint returns an empty object</dd>
|
||||||
|
</dl>
|
||||||
|
</li>
|
||||||
|
<li>Error
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dt>msg.error <span class="property-type">string</span></dt>
|
||||||
|
<dd>the error that occurred.</dd>
|
||||||
|
</dl>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</script>
|
||||||
92
src/matrix-secret-storage.js
Normal file
92
src/matrix-secret-storage.js
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
module.exports = function(RED) {
|
||||||
|
const verificationRequests = new Map();
|
||||||
|
|
||||||
|
function MatrixSecretStorage(n) {
|
||||||
|
RED.nodes.createNode(this, n);
|
||||||
|
|
||||||
|
var node = this;
|
||||||
|
|
||||||
|
this.name = n.name;
|
||||||
|
this.server = RED.nodes.getNode(n.server);
|
||||||
|
|
||||||
|
if (!node.server) {
|
||||||
|
node.warn("No configuration node");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
node.status({ fill: "red", shape: "ring", text: "disconnected" });
|
||||||
|
|
||||||
|
node.server.on("disconnected", function(){
|
||||||
|
node.status({ fill: "red", shape: "ring", text: "disconnected" });
|
||||||
|
});
|
||||||
|
|
||||||
|
node.server.on("connected", function() {
|
||||||
|
node.status({ fill: "green", shape: "ring", text: "connected" });
|
||||||
|
});
|
||||||
|
|
||||||
|
node.on('input', async function(msg){
|
||||||
|
try {
|
||||||
|
msg.hasSecretStorage = await node.server.matrixClient.hasSecretStorageKey();
|
||||||
|
} catch(e) {
|
||||||
|
console.log("ERROR", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(msg.action) {
|
||||||
|
if(msg.action === 'create') {
|
||||||
|
if(msg.hasSecretStorage && !msg.forceReset) {
|
||||||
|
node.error("Secret storage already setup. Pass msg.forceReset to bypass and regenerate.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// copying this from https://github.com/matrix-org/matrix-react-sdk/blob/e78a1adb6f1af2ea425b0bae9034fb7344a4b2e8/src/SecurityManager.ts#L294
|
||||||
|
const recoveryKey = await node.server.matrixClient.createRecoveryKeyFromPassphrase(msg.key || undefined);
|
||||||
|
if(msg.forceReset) {
|
||||||
|
await node.server.matrixClient.bootstrapSecretStorage({
|
||||||
|
createSecretStorageKey: async () => recoveryKey,
|
||||||
|
setupNewKeyBackup: true,
|
||||||
|
setupNewSecretStorage: true,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// For password authentication users after 2020-09, this cross-signing
|
||||||
|
// step will be a no-op since it is now setup during registration or login
|
||||||
|
// when needed. We should keep this here to cover other cases such as:
|
||||||
|
// * Users with existing sessions prior to 2020-09 changes
|
||||||
|
// * SSO authentication users which require interactive auth to upload
|
||||||
|
// keys (and also happen to skip all post-authentication flows at the
|
||||||
|
// moment via token login)
|
||||||
|
await node.server.matrixClient.bootstrapCrossSigning({
|
||||||
|
// maybe we can skip this?
|
||||||
|
// authUploadDeviceSigningKeys: this._doBootstrapUIAuth,
|
||||||
|
});
|
||||||
|
const backupInfo = await node.server.matrixClient.getKeyBackupVersion();
|
||||||
|
await node.server.matrixClient.bootstrapSecretStorage({
|
||||||
|
createSecretStorageKey: async () => this._recoveryKey,
|
||||||
|
keyBackupInfo: backupInfo,
|
||||||
|
setupNewKeyBackup: !backupInfo,
|
||||||
|
getKeyBackupPassphrase: () => {
|
||||||
|
// We may already have the backup key if we earlier went
|
||||||
|
// through the restore backup path, so pass it along
|
||||||
|
// rather than prompting again.
|
||||||
|
if (this._backupKey) {
|
||||||
|
return this._backupKey;
|
||||||
|
}
|
||||||
|
return promptForBackupPassphrase();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(msg.action === 'download') {
|
||||||
|
if(!msg.hasSecretStorage) {
|
||||||
|
node.error("Secret storage not setup so cannot download.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
node.send(msg);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
RED.nodes.registerType("matrix-secret-storage", MatrixSecretStorage);
|
||||||
|
}
|
||||||
@@ -29,7 +29,8 @@
|
|||||||
userId: { type: "text", required: true },
|
userId: { type: "text", required: true },
|
||||||
deviceLabel: { type: "text", required: false },
|
deviceLabel: { type: "text", required: false },
|
||||||
accessToken: { type: "password", required: true },
|
accessToken: { type: "password", required: true },
|
||||||
deviceId: { type: "text", required: false },
|
deviceId: { type: "text", required: true },
|
||||||
|
secureStoragePassphrase: { type: "text", required: false },
|
||||||
url: { type: "text", required: true }
|
url: { type: "text", required: true }
|
||||||
},
|
},
|
||||||
defaults: {
|
defaults: {
|
||||||
@@ -95,6 +96,14 @@
|
|||||||
WARNING: If you change this after the client has already initialized you will break encryption. Your Device ID is tied to your encryption keys.
|
WARNING: If you change this after the client has already initialized you will break encryption. Your Device ID is tied to your encryption keys.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-config-input-secureStoragePassphrase"><i class="fa fa-key"></i> Secure Storage Passphrase</label>
|
||||||
|
<input type="text" id="node-config-input-secureStoragePassphrase">
|
||||||
|
</div>
|
||||||
|
<div class="form-tips" style="margin-bottom: 12px;">
|
||||||
|
If set secure storage will be setup with this passphrase. If secure storage already exists on the account it will attempt to decrypt it. Leave blank to skip.
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@@ -198,6 +207,12 @@
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$(function(){
|
||||||
|
$("#node-config-input-enableE2ee").on('change', function(e){
|
||||||
|
$("#node-config-input-secureStoragePassphrase").attr('disabled', !$(this).is(':checked'));
|
||||||
|
}).change();
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ const sdk = require("matrix-js-sdk");
|
|||||||
const { resolve } = require('path');
|
const { resolve } = require('path');
|
||||||
const { LocalStorage } = require('node-localstorage');
|
const { LocalStorage } = require('node-localstorage');
|
||||||
const { LocalStorageCryptoStore } = require('matrix-js-sdk/lib/crypto/store/localStorage-crypto-store');
|
const { LocalStorageCryptoStore } = require('matrix-js-sdk/lib/crypto/store/localStorage-crypto-store');
|
||||||
|
const {deriveKey} = require("matrix-js-sdk/lib/crypto/key_passphrase");
|
||||||
|
|
||||||
module.exports = function(RED) {
|
module.exports = function(RED) {
|
||||||
function MatrixFolderNameFromUserId(name) {
|
function MatrixFolderNameFromUserId(name) {
|
||||||
@@ -27,6 +28,7 @@ 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.secureStoragePassphrase = this.credentials.secureStoragePassphrase || null;
|
||||||
this.url = this.credentials.url;
|
this.url = this.credentials.url;
|
||||||
this.autoAcceptRoomInvites = n.autoAcceptRoomInvites;
|
this.autoAcceptRoomInvites = n.autoAcceptRoomInvites;
|
||||||
this.enableE2ee = n.enableE2ee || false;
|
this.enableE2ee = n.enableE2ee || false;
|
||||||
@@ -50,7 +52,7 @@ module.exports = function(RED) {
|
|||||||
} else if(!this.url) {
|
} else if(!this.url) {
|
||||||
node.error("Matrix connection failed: missing server URL in configuration.");
|
node.error("Matrix connection failed: missing server URL in configuration.");
|
||||||
} else {
|
} else {
|
||||||
node.setConnected = function(connected, cb) {
|
node.setConnected = async function(connected, cb) {
|
||||||
if (node.connected !== connected) {
|
if (node.connected !== connected) {
|
||||||
node.connected = connected;
|
node.connected = connected;
|
||||||
if(typeof cb === 'function') {
|
if(typeof cb === 'function') {
|
||||||
@@ -92,6 +94,13 @@ module.exports = function(RED) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await accessSecretStorage(function(){});
|
||||||
|
} catch(e) {
|
||||||
|
node.error("secret storage bootstrap failure: " + e);
|
||||||
|
console.log("secret storage bootstrap failure: ", e);
|
||||||
|
}
|
||||||
|
|
||||||
initialSetup = true;
|
initialSetup = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -107,13 +116,70 @@ 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);
|
||||||
|
|
||||||
node.matrixClient = sdk.createClient({
|
node.matrixClient = sdk.createClient({
|
||||||
baseUrl: this.url,
|
baseUrl: this.url,
|
||||||
accessToken: this.credentials.accessToken,
|
accessToken: this.credentials.accessToken,
|
||||||
sessionStore: new sdk.WebStorageSessionStore(localStorage),
|
sessionStore: new sdk.WebStorageSessionStore(localStorage),
|
||||||
cryptoStore: new LocalStorageCryptoStore(localStorage),
|
cryptoStore: new LocalStorageCryptoStore(localStorage),
|
||||||
userId: this.userId,
|
userId: this.userId,
|
||||||
deviceId: (this.deviceId || getStoredDeviceId(localStorage)) || undefined
|
deviceId: (this.deviceId || getStoredDeviceId(localStorage)) || undefined,
|
||||||
|
verificationMethods: ["m.sas.v1"],
|
||||||
|
// cryptoCallbacks: {
|
||||||
|
// getSecretStorageKey: async function(
|
||||||
|
// { keys: keyInfos },
|
||||||
|
// ssssItemName,
|
||||||
|
// ){
|
||||||
|
// const cli = node.matrixClient;
|
||||||
|
// let keyId = await cli.getDefaultSecretStorageKeyId();
|
||||||
|
// // console.log("DEFAULT SECRET STORAGE KEY ID: " + keyId, keyInfos);
|
||||||
|
// //
|
||||||
|
// // let decodeBase64 = function(base64) {
|
||||||
|
// // return Buffer.from(base64, "base64");
|
||||||
|
// // }
|
||||||
|
// // return await this.crypto.getSecretStorageKey(keyId);
|
||||||
|
// let keyInfo;
|
||||||
|
// if (keyId) {
|
||||||
|
// // use the default SSSS key if set
|
||||||
|
// keyInfo = keyInfos[keyId];
|
||||||
|
// if (!keyInfo) {
|
||||||
|
// // if the default key is not available, pretend the default key
|
||||||
|
// // isn't set
|
||||||
|
// keyId = undefined;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if (!keyId) {
|
||||||
|
// // if no default SSSS key is set, fall back to a heuristic of using the
|
||||||
|
// // only available key, if only one key is set
|
||||||
|
// const keyInfoEntries = Object.entries(keyInfos);
|
||||||
|
// if (keyInfoEntries.length > 1) {
|
||||||
|
// throw new Error("Multiple storage key requests not implemented");
|
||||||
|
// }
|
||||||
|
// [keyId, keyInfo] = keyInfoEntries[0];
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // Check the in-memory cache
|
||||||
|
// // if (isCachingAllowed() && secretStorageKeys[keyId]) {
|
||||||
|
// // return [keyId, secretStorageKeys[keyId]];
|
||||||
|
// // }
|
||||||
|
//
|
||||||
|
// // if (dehydrationCache.key) {
|
||||||
|
// // if (await MatrixClientPeg.get().checkSecretStorageKey(dehydrationCache.key, keyInfo)) {
|
||||||
|
// // cacheSecretStorageKey(keyId, keyInfo, dehydrationCache.key);
|
||||||
|
// // return [keyId, dehydrationCache.key];
|
||||||
|
// // }
|
||||||
|
// // }
|
||||||
|
//
|
||||||
|
// // const backupInfo = await node.matrixClient.getKeyBackupVersion();
|
||||||
|
// const backupInfo = await node.matrixClient.getAccountDataFromServer(
|
||||||
|
// "m.secret_storage.key." + keyId
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// // if(await cli.checkSecretStorageKey(key, keyInfo)) {
|
||||||
|
// // }
|
||||||
|
// return [keyId, await node.matrixClient.keyBackupKeyFromPassword(node.secureStoragePassphrase, backupInfo)] ;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
});
|
});
|
||||||
|
|
||||||
// set globally if configured to do so
|
// set globally if configured to do so
|
||||||
@@ -303,13 +369,88 @@ module.exports = function(RED) {
|
|||||||
stopClient();
|
stopClient();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This helper should be used whenever you need to access secret storage. It
|
||||||
|
* ensures that secret storage (and also cross-signing since they each depend on
|
||||||
|
* each other in a cycle of sorts) have been bootstrapped before running the
|
||||||
|
* provided function.
|
||||||
|
*
|
||||||
|
* Bootstrapping secret storage may take one of these paths:
|
||||||
|
* 1. Create secret storage from a passphrase and store cross-signing keys
|
||||||
|
* in secret storage.
|
||||||
|
* 2. Access existing secret storage by requesting passphrase and accessing
|
||||||
|
* cross-signing keys as needed.
|
||||||
|
* 3. All keys are loaded and there's nothing to do.
|
||||||
|
*
|
||||||
|
* @param {Function} [func] An operation to perform once secret storage has been
|
||||||
|
* bootstrapped. Optional.
|
||||||
|
* @param {boolean} [forceReset] Reset secret storage even if it's already set up
|
||||||
|
*/
|
||||||
|
let accessSecretStorage = async function(func = async () => { }, forceReset = false) {
|
||||||
|
// only do this if we have a secure storage password
|
||||||
|
if(!node.secureStoragePassphrase) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const recoveryKey = await node.matrixClient.createRecoveryKeyFromPassphrase(node.secureStoragePassphrase);
|
||||||
|
const cli = node.matrixClient;
|
||||||
|
try {
|
||||||
|
if (!(await cli.hasSecretStorageKey()) || forceReset) {
|
||||||
|
// For password authentication users after 2020-09, this cross-signing
|
||||||
|
// step will be a no-op since it is now setup during registration or login
|
||||||
|
// when needed. We should keep this here to cover other cases such as:
|
||||||
|
// * Users with existing sessions prior to 2020-09 changes
|
||||||
|
// * SSO authentication users which require interactive auth to upload
|
||||||
|
// keys (and also happen to skip all post-authentication flows at the
|
||||||
|
// moment via token login)
|
||||||
|
if(!await node.matrixClient.isCrossSigningReady()) {
|
||||||
|
await node.matrixClient.bootstrapCrossSigning({
|
||||||
|
// maybe we can skip this?
|
||||||
|
authUploadDeviceSigningKeys: () => {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const backupInfo = await node.matrixClient.getKeyBackupVersion();
|
||||||
|
await node.matrixClient.bootstrapSecretStorage({
|
||||||
|
createSecretStorageKey: async () => recoveryKey,
|
||||||
|
keyBackupInfo: backupInfo,
|
||||||
|
setupNewKeyBackup: !backupInfo,
|
||||||
|
getKeyBackupPassphrase: () => {
|
||||||
|
return recoveryKey;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await node.matrixClient.bootstrapSecretStorage({
|
||||||
|
getKeyBackupPassphrase: async () => recoveryKey,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// `return await` needed here to ensure `finally` block runs after the
|
||||||
|
// inner operation completes.
|
||||||
|
return await func();
|
||||||
|
} catch (e) {
|
||||||
|
node.error("Secret storage init failure: " + e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
async function run() {
|
async function run() {
|
||||||
try {
|
try {
|
||||||
if(node.e2ee){
|
if(node.e2ee && node.matrixClient.initCrypto){
|
||||||
node.log("Initializing crypto...");
|
node.log("Initializing crypto...");
|
||||||
|
try {
|
||||||
await node.matrixClient.initCrypto();
|
await node.matrixClient.initCrypto();
|
||||||
node.matrixClient.setGlobalErrorOnUnknownDevices(false);
|
node.matrixClient.setGlobalErrorOnUnknownDevices(false);
|
||||||
|
node.matrixClient.setCryptoTrustCrossSignedDevices(true); // false = manually verify sessions
|
||||||
|
// await tryToUnlockSecretStorageWithDehydrationKey(this.matrixClient);
|
||||||
|
} catch (e) {
|
||||||
|
node.error("Failed to initialize crypto: " + e);
|
||||||
|
console.log(e);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
node.log("Connecting to Matrix server...");
|
node.log("Connecting to Matrix server...");
|
||||||
await node.matrixClient.startClient({
|
await node.matrixClient.startClient({
|
||||||
initialSyncLimit: 8
|
initialSyncLimit: 8
|
||||||
@@ -349,6 +490,7 @@ module.exports = function(RED) {
|
|||||||
userId: { type: "text", required: true },
|
userId: { type: "text", required: true },
|
||||||
accessToken: { type: "text", required: true },
|
accessToken: { type: "text", required: true },
|
||||||
deviceId: { type: "text", required: false },
|
deviceId: { type: "text", required: false },
|
||||||
|
secureStoragePassphrase: { type: "text", required: false },
|
||||||
url: { type: "text", required: true }
|
url: { type: "text", required: true }
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user