First commit
This commit is contained in:
commit
56d6ee6897
|
@ -0,0 +1 @@
|
||||||
|
node_modules/**
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"extends": "airbnb",
|
||||||
|
"globals": {
|
||||||
|
"artifacts": false,
|
||||||
|
"document": false,
|
||||||
|
"window": false
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
"arrow-body-style": [2, "as-needed"],
|
||||||
|
"arrow-parens": [2, "as-needed"],
|
||||||
|
"import/prefer-default-export": [2, "never"],
|
||||||
|
"space-before-function-paren": [2, "never"]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
node_modules
|
||||||
|
.idea
|
||||||
|
dist
|
||||||
|
.env
|
|
@ -0,0 +1,47 @@
|
||||||
|
## matrix-whisper-bridge
|
||||||
|
|
||||||
|
A two-way bridge between the matrix protocol and the whisper protocol
|
||||||
|
|
||||||
|
### Development
|
||||||
|
|
||||||
|
1. Clone repository and enter project folder
|
||||||
|
|
||||||
|
```
|
||||||
|
git clone ...
|
||||||
|
cd matrix-whisper-bridge
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Install dependencies
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Install geth
|
||||||
|
|
||||||
|
4. Launch lightweight testnet with proper whisper settings for Status chat protocol
|
||||||
|
|
||||||
|
```
|
||||||
|
geth --testnet --light --shh.pow=0.002
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
5. You need to add Status peers so you can join the network.
|
||||||
|
|
||||||
|
First connect to the running geth instance
|
||||||
|
|
||||||
|
```
|
||||||
|
geth --testnet attach
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Then add the peers from this list: https://github.com/status-im/status-go/blob/develop/geth/params/cluster.go
|
||||||
|
|
||||||
|
```
|
||||||
|
var peers = ['enode://436cc6f674928fdc9a9f7990f2944002b685d1c37f025c1be425185b5b1f0900feaf1ccc2a6130268f9901be4a7d252f37302c8335a2c1a62736e9232691cc3a@174.138.105.243:30404','enode://5395aab7833f1ecb671b59bf0521cf20224fe8162fc3d2675de4ee4d5636a75ec32d13268fc184df8d1ddfa803943906882da62a4df42d4fccf6d17808156a87@206.189.243.57:30404','enode://7427dfe38bd4cf7c58bb96417806fab25782ec3e6046a8053370022cbaa281536e8d64ecd1b02e1f8f72768e295d06258ba43d88304db068e6f2417ae8bcb9a6@104.154.88.123:30404','enode://ebefab39b69bbbe64d8cd86be765b3be356d8c4b24660f65d493143a0c44f38c85a257300178f7845592a1b0332811542e9a58281c835babdd7535babb64efc1@35.202.99.224:30404','enode://a6a2a9b3a7cbb0a15da74301537ebba549c990e3325ae78e1272a19a3ace150d03c184b8ac86cc33f1f2f63691e467d49308f02d613277754c4dccd6773b95e8@206.189.108.68:30304','enode://207e53d9bf66be7441e3daba36f53bfbda0b6099dba9a865afc6260a2d253fb8a56a72a48598a4f7ba271792c2e4a8e1a43aaef7f34857f520c8c820f63b44c8@35.224.15.65:30304','enode://436cc6f674928fdc9a9f7990f2944002b685d1c37f025c1be425185b5b1f0900feaf1ccc2a6130268f9901be4a7d252f37302c8335a2c1a62736e9232691cc3a@174.138.105.243:30404','enode://5395aab7833f1ecb671b59bf0521cf20224fe8162fc3d2675de4ee4d5636a75ec32d13268fc184df8d1ddfa803943906882da62a4df42d4fccf6d17808156a87@206.189.243.57:30404','enode://7427dfe38bd4cf7c58bb96417806fab25782ec3e6046a8053370022cbaa281536e8d64ecd1b02e1f8f72768e295d06258ba43d88304db068e6f2417ae8bcb9a6@104.154.88.123:30404','enode://ebefab39b69bbbe64d8cd86be765b3be356d8c4b24660f65d493143a0c44f38c85a257300178f7845592a1b0332811542e9a58281c835babdd7535babb64efc1@35.202.99.224:30404','enode://a6a2a9b3a7cbb0a15da74301537ebba549c990e3325ae78e1272a19a3ace150d03c184b8ac86cc33f1f2f63691e467d49308f02d613277754c4dccd6773b95e8@206.189.108.68:30304','enode://207e53d9bf66be7441e3daba36f53bfbda0b6099dba9a865afc6260a2d253fb8a56a72a48598a4f7ba271792c2e4a8e1a43aaef7f34857f520c8c820f63b44c8@35.224.15.65:30304'];
|
||||||
|
peers.forEach(function addPeer(peer) { admin.addPeer(peer); });
|
||||||
|
exit
|
||||||
|
|
||||||
|
```
|
|
@ -0,0 +1,22 @@
|
||||||
|
const WhisperUtils = require('../utils/whisperUtils');
|
||||||
|
|
||||||
|
class MatrixRiotBridge {
|
||||||
|
init() {
|
||||||
|
return Promise.all([
|
||||||
|
this.connectToWhisper(),
|
||||||
|
this.connectToMatrix(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
connectToWhisper() {
|
||||||
|
this.whisperUtils = new WhisperUtils();
|
||||||
|
return this.whisperUtils.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
connectToMatrix() {
|
||||||
|
this.matrixUtils = {};
|
||||||
|
return this.matrixUtils;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = MatrixRiotBridge;
|
|
@ -0,0 +1,37 @@
|
||||||
|
//const transit = require('transit-js');
|
||||||
|
|
||||||
|
const MatrixRiotBridge = require('./app/MatrixRiotBridge');
|
||||||
|
const { decodeStatusPayload } = require('./utils/statusUtils');
|
||||||
|
|
||||||
|
const CHANNEL = 'noman-test';
|
||||||
|
|
||||||
|
const bridge = new MatrixRiotBridge();
|
||||||
|
|
||||||
|
bridge.init().then(([whisperUtils]) => {
|
||||||
|
whisperUtils.getPublicKey().then(publicKey => {
|
||||||
|
function isMe(sig) {
|
||||||
|
return publicKey === sig;
|
||||||
|
}
|
||||||
|
|
||||||
|
whisperUtils.send(CHANNEL, 'Bot is alive');
|
||||||
|
|
||||||
|
whisperUtils.listen(CHANNEL).then(
|
||||||
|
subscription => {
|
||||||
|
subscription.on('data', ({ payload, sig, timestamp, topic }) => {
|
||||||
|
const [, [message]] = decodeStatusPayload(payload);
|
||||||
|
const me = isMe(sig);
|
||||||
|
const name = me ? 'Bot' : sig.slice(0, 10);
|
||||||
|
|
||||||
|
console.log('From:', name, 'at', timestamp);
|
||||||
|
console.log('Topic:', topic);
|
||||||
|
console.log('Message:', message, '\n');
|
||||||
|
|
||||||
|
if (!me) {
|
||||||
|
whisperUtils.send(CHANNEL, `${message} back`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
error => console.error(error));
|
||||||
|
});
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
"name": "matrix-whisper-bridge",
|
||||||
|
"private": true,
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "A two-way bridge between the matrix protocol and the whisper protocol",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node index.js",
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "Noman <noman@noman.land>",
|
||||||
|
"license": "MIT",
|
||||||
|
"devDependencies": {
|
||||||
|
"babel-cli": "^6.26.0",
|
||||||
|
"babel-preset-env": "^1.7.0",
|
||||||
|
"eslint": "^5.2.0",
|
||||||
|
"eslint-config-airbnb": "^17.0.0",
|
||||||
|
"eslint-plugin-import": "^2.13.0",
|
||||||
|
"eslint-plugin-jsx-a11y": "^6.1.1",
|
||||||
|
"eslint-plugin-react": "^7.10.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"npm": "^6.4.1",
|
||||||
|
"prompt": "^1.0.0",
|
||||||
|
"transit-js": "^0.8.861",
|
||||||
|
"web3": "^1.0.0-beta.35",
|
||||||
|
"ws": "^6.0.0"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
const Web3 = require('web3');
|
||||||
|
|
||||||
|
const web3 = new Web3();
|
||||||
|
|
||||||
|
const { utils: { asciiToHex, hexToAscii, sha3 } } = web3;
|
||||||
|
|
||||||
|
function createStatusPayload(
|
||||||
|
{
|
||||||
|
tag = '~#c4',
|
||||||
|
content = 'This is a whisper/slack test!',
|
||||||
|
messageType = '~:public-group-user-message',
|
||||||
|
clockValue = (new Date().getTime()) * 100,
|
||||||
|
contentType = 'text/plain',
|
||||||
|
timestamp = new Date().getTime(),
|
||||||
|
} = {},
|
||||||
|
) {
|
||||||
|
return asciiToHex(
|
||||||
|
JSON.stringify([
|
||||||
|
tag,
|
||||||
|
[
|
||||||
|
content,
|
||||||
|
contentType,
|
||||||
|
messageType,
|
||||||
|
clockValue,
|
||||||
|
timestamp,
|
||||||
|
],
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeStatusPayload(payload) {
|
||||||
|
return JSON.parse(hexToAscii(payload));
|
||||||
|
}
|
||||||
|
|
||||||
|
function topicFromChannelName(channelName) {
|
||||||
|
return sha3(channelName).slice(0, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
createStatusPayload,
|
||||||
|
decodeStatusPayload,
|
||||||
|
topicFromChannelName,
|
||||||
|
};
|
|
@ -0,0 +1,71 @@
|
||||||
|
const net = require('net');
|
||||||
|
const Web3 = require('web3');
|
||||||
|
|
||||||
|
const {
|
||||||
|
createStatusPayload,
|
||||||
|
topicFromChannelName,
|
||||||
|
} = require('./statusUtils');
|
||||||
|
|
||||||
|
const CHANNEL = 'noman-test';
|
||||||
|
|
||||||
|
class WhisperUtils {
|
||||||
|
init() {
|
||||||
|
this.web3 = new Web3(new Web3.providers.IpcProvider(
|
||||||
|
process.env.GETH_IPC_PATH,
|
||||||
|
net,
|
||||||
|
));
|
||||||
|
|
||||||
|
this.shh = this.web3.shh;
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.createWhisperIdentity().then(
|
||||||
|
sig => {
|
||||||
|
this.sig = sig;
|
||||||
|
resolve(this);
|
||||||
|
},
|
||||||
|
error => reject(error),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
createWhisperIdentity() {
|
||||||
|
return this.shh.newKeyPair();
|
||||||
|
}
|
||||||
|
|
||||||
|
getPublicKey() {
|
||||||
|
return this.shh.getPublicKey(this.sig);
|
||||||
|
}
|
||||||
|
|
||||||
|
listen(channel) {
|
||||||
|
const topic = topicFromChannelName(channel);
|
||||||
|
|
||||||
|
return new Promise(resolve => {
|
||||||
|
this.shh.generateSymKeyFromPassword(channel)
|
||||||
|
.then(symKeyID => {
|
||||||
|
const subscription = this.shh.subscribe('messages', {
|
||||||
|
minPow: 0.002,
|
||||||
|
symKeyID,
|
||||||
|
topics: [topic],
|
||||||
|
});
|
||||||
|
resolve(subscription);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
send(channel, message) {
|
||||||
|
const payload = createStatusPayload({ content: message });
|
||||||
|
|
||||||
|
return this.shh.generateSymKeyFromPassword(channel)
|
||||||
|
.then(symKeyID => this.shh.post({
|
||||||
|
payload,
|
||||||
|
powTarget: 0.002,
|
||||||
|
powTime: 1,
|
||||||
|
sig: this.sig,
|
||||||
|
symKeyID,
|
||||||
|
topic: topicFromChannelName(channel),
|
||||||
|
ttl: 10,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = WhisperUtils;
|
Loading…
Reference in New Issue