Merge pull request #9 from status-im/move_index_to_ts

move remaining code to typescript
This commit is contained in:
Iuri Matias 2018-12-01 17:37:02 -05:00 committed by GitHub
commit 2fd2fa5579
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 147 additions and 194 deletions

76
poc.js
View File

@ -1,76 +0,0 @@
const Web3 = require('web3');
const { utils: { asciiToHex, hexToAscii, sha3 } } = Web3;
const POW_TIME = 1;
const TTL = 10;
const POW_TARGET = 0.002;
const CHANNEL_NAME ="mytest"
const CHANNEL = Web3.utils.sha3(CHANNEL_NAME).slice(0, 10);
function createStatusPayload() {
let tag = '~#c4';
let content = 'Hello everyone, it\s status js';
let messageType = '~:public-group-user-message';
let clockValue = (new Date().getTime()) * 100;
let contentType = 'text/plain';
let timestamp = new Date().getTime();
return asciiToHex(
JSON.stringify([
tag,
[
content,
contentType,
messageType,
clockValue,
timestamp,
],
]),
);
}
(async () => {
let web3 = new Web3();
web3.setProvider(new Web3.providers.WebsocketProvider('ws://localhost:8546', {headers: {Origin: "statusjs"}}));
await web3.shh.setMinPoW(POW_TARGET);
let keys = {};
// keys.symKeyID = await web3.shh.newSymKey();
// keys.sig = await web3.shh.newKeyPair();
keys.symKeyID = await web3.shh.generateSymKeyFromPassword(CHANNEL_NAME);
keys.sig = await web3.shh.newKeyPair();
console.dir("keys generated");
console.dir(keys);
subscription = web3.shh.subscribe("messages", {
minPow: POW_TARGET,
symKeyID: keys.symKeyID,
topics: [CHANNEL]
}).on('data', (data) => {
console.dir("message received!");
console.dir(data);
console.dir(JSON.parse(hexToAscii(data.payload)));
}).on('error', () => {
console.dir("error receiving message");
});
web3.shh.post({
symKeyID: keys.symKeyID, // encrypts using the sym key ID
sig: keys.sig, // signs the message using the keyPair ID
ttl: TTL,
topic: CHANNEL,
payload: createStatusPayload(),
powTime: POW_TIME,
powTarget: POW_TARGET
}).then(() => {
console.dir('message sent!');
}).catch((e) => {
console.dir("error sending message");
console.dir(e);
});
})()

View File

@ -1,30 +1,38 @@
const Web3 = require('web3'); const Web3 = require("web3");
import utils from './utils.js'; import utils from "./utils.js";
import mailservers from './mailservers.js'; import mailservers from "./mailservers.js";
const constants = require('./constants'); const constants = require("./constants");
const { utils: { asciiToHex, hexToAscii } } = Web3; const { utils: { asciiToHex, hexToAscii } } = Web3;
function createStatusPayload(content, messageType, clockValue, isJson) { function createStatusPayload(content: string, messageType: string, clockValue: number, isJson = false) {
const tag = constants.messageTags.message; const tag: string = constants.messageTags.message;
const oneMonthInMs = 60 * 60 * 24 * 31 * 1000; const oneMonthInMs: number = 60 * 60 * 24 * 31 * 1000;
if(clockValue < (new Date().getTime())){ if (clockValue < (new Date().getTime())) {
clockValue = (new Date().getTime() + oneMonthInMs) * 100; clockValue = (new Date().getTime() + oneMonthInMs) * 100;
} }
const contentType = (isJson ? 'content/json' : 'text/plain'); const contentType = (isJson ? "content/json" : "text/plain");
const timestamp = new Date().getTime(); const timestamp = new Date().getTime();
return asciiToHex( return asciiToHex(
JSON.stringify([ JSON.stringify([
tag, tag,
[content, contentType, messageType, clockValue, timestamp, ["^ ","~:text", content]], [content, contentType, messageType, clockValue, timestamp, ["^ ", "~:text", content]],
]), ]),
); );
} }
const _sig = new WeakMap(); const sig = new WeakMap();
class StatusJS { class StatusJS {
private channels: any;
private contacts: any;
private userMessagesSubscription: any;
private mailservers: any;
private isHttpProvider: boolean;
private shh: any;
private chatRequestCb: any;
constructor() { constructor() {
this.channels = {}; this.channels = {};
@ -34,16 +42,16 @@ class StatusJS {
this.isHttpProvider = false; this.isHttpProvider = false;
} }
async connect(url, privateKey) { public async connect(url: string, privateKey?: string) {
let web3 = new Web3(); const web3: any = new Web3();
if(url.startsWith("ws://")){ if (url.startsWith("ws://")) {
web3.setProvider(new Web3.providers.WebsocketProvider(url, {headers: {Origin: "statusjs"}})); web3.setProvider(new Web3.providers.WebsocketProvider(url, {headers: {Origin: "statusjs"}}));
} else if(url.startsWith("http://") || url.startsWith("https://")) { } else if (url.startsWith("http://") || url.startsWith("https://")) {
// Deprecated but required for statusd // Deprecated but required for statusd
web3.setProvider(new Web3.providers.HttpProvider(url)); web3.setProvider(new Web3.providers.HttpProvider(url));
this.isHttpProvider = true; this.isHttpProvider = true;
} else { } else {
const net = require('net'); const net = require("net");
web3.setProvider(new Web3.providers.IpcProvider(url, net)); web3.setProvider(new Web3.providers.IpcProvider(url, net));
} }
@ -51,59 +59,63 @@ class StatusJS {
this.mailservers = new mailservers(web3); this.mailservers = new mailservers(web3);
await web3.shh.setMinPoW(constants.post.POW_TARGET); await web3.shh.setMinPoW(constants.post.POW_TARGET);
_sig.set( sig.set(
this, this,
privateKey ? await this.generateWhisperKeyFromWallet(privateKey) : await web3.shh.newKeyPair() privateKey ? await this.generateWhisperKeyFromWallet(privateKey) : await web3.shh.newKeyPair(),
); );
} }
isConnected() { public isConnected() {
return this.shh.isListening(); return this.shh.isListening();
} }
async generateWhisperKeyFromWallet(key){ private async generateWhisperKeyFromWallet(key: string) {
await this.shh.addPrivateKey(key); const keyId = await this.shh.addPrivateKey(key);
return; return keyId;
} }
async getPublicKey(){ public async getPublicKey() {
const pubKey = await this.shh.getPublicKey(_sig.get(this)); const pubKey = await this.shh.getPublicKey(sig.get(this));
return pubKey; return pubKey;
} }
async getUserName(pubKey){ public async getUserName(pubKey?: any) {
if(!pubKey) { if (!pubKey) {
pubKey = await this.getPublicKey(); pubKey = await this.getPublicKey();
} }
return utils.generateUsernameFromSeed(pubKey); return utils.generateUsernameFromSeed(pubKey);
} }
async joinChat(channelName, cb) { public async joinChat(channelName: string, cb?: any) {
let channelKey = await this.shh.generateSymKeyFromPassword(channelName); const channelKey = await this.shh.generateSymKeyFromPassword(channelName);
this.channels[channelName] = { this.channels[channelName] = {
channelName, channelCode: Web3.utils.sha3(channelName).slice(0, 10),
channelKey, channelKey,
channelName,
lastClockValue: 0, lastClockValue: 0,
channelCode: Web3.utils.sha3(channelName).slice(0, 10)
}; };
if (cb) cb(); if (cb) {
cb();
}
} }
async addContact(contactCode, cb) { public async addContact(contactCode: string, cb?: any) {
this.contacts[contactCode] = { this.contacts[contactCode] = {
lastClockValue: 0,
username: utils.generateUsernameFromSeed(contactCode), username: utils.generateUsernameFromSeed(contactCode),
lastClockValue: 0
}; };
if (cb) cb(); if (cb) {
cb();
}
} }
leaveChat(channelName) { public leaveChat(channelName: string) {
if(!this.isHttpProvider) { if (!this.isHttpProvider) {
this.channels[channelName].subscription.unsubscribe(); this.channels[channelName].subscription.unsubscribe();
} else { } else {
// TODO: fix me // TODO: fix me
//web3.shh.deleteMessageFilter(this.channels[channelName].filterId) // web3.shh.deleteMessageFilter(this.channels[channelName].filterId)
// .then(result => { // .then(result => {
// clearInterval(this.channels[channelName].interval); // clearInterval(this.channels[channelName].interval);
// }); // });
@ -111,217 +123,233 @@ class StatusJS {
delete this.channels[channelName]; delete this.channels[channelName];
} }
async removeContact(contactCode, _cb) { public async removeContact(contactCode: string) {
delete this.contacts[contactCode]; delete this.contacts[contactCode];
} }
isSubscribedTo(channelName) { public isSubscribedTo(channelName: string) {
return !!this.channels[channelName]; return !!this.channels[channelName];
} }
onMessage(par1, par2) { public onMessage(par1: any, par2: any) {
if(typeof par1 === "function"){ if (typeof par1 === "function") {
this.onUserMessage(par1); this.onUserMessage(par1);
} else { } else {
this.onChannelMessage(par1, par2); this.onChannelMessage(par1, par2);
} }
} }
onChatRequest(cb){ public onChatRequest(cb: any) {
this.chatRequestCb = cb; this.chatRequestCb = cb;
} }
onChannelMessage(channelName, cb) { public onChannelMessage(channelName: string, cb: any) {
if (!this.channels[channelName]) { if (!this.channels[channelName]) {
return cb("unknown channel: " + channelName); return cb("unknown channel: " + channelName);
} }
const filters = { const filters = {
allowP2P: true,
symKeyID: this.channels[channelName].channelKey, symKeyID: this.channels[channelName].channelKey,
topics: [this.channels[channelName].channelCode], topics: [this.channels[channelName].channelCode],
allowP2P: true
}; };
const messageHandler = (data) => { const messageHandler = (data: any) => {
let username = utils.generateUsernameFromSeed(data.sig); const username = utils.generateUsernameFromSeed(data.sig);
const payloadArray = JSON.parse(hexToAscii(data.payload)); const payloadArray = JSON.parse(hexToAscii(data.payload));
if(this.channels[channelName].lastClockValue < payloadArray[1][3]){ if (this.channels[channelName].lastClockValue < payloadArray[1][3]) {
this.channels[channelName].lastClockValue = payloadArray[1][3]; this.channels[channelName].lastClockValue = payloadArray[1][3];
} }
cb(null, {payload: hexToAscii(data.payload), data: data, username: username}); cb(null, {payload: hexToAscii(data.payload), data, username});
}; };
if(this.isHttpProvider){ if (this.isHttpProvider) {
this.shh.newMessageFilter(filters) this.shh.newMessageFilter(filters)
.then(filterId => { .then((filterId: any) => {
this.channels[channelName].filterId = filterId; this.channels[channelName].filterId = filterId;
this.channels[channelName].interval = setInterval(() => { this.channels[channelName].interval = setInterval(() => {
this.shh.getFilterMessages(filterId) this.shh.getFilterMessages(filterId)
.then(data => { .then((data: any) => {
data.map(d => { data.map((d: any) => {
messageHandler(d); messageHandler(d);
}); });
}) })
.catch((err) => { cb(err); }); .catch((err: any) => { cb(err); });
}, 250); }, 250);
}); });
} else { } else {
this.channels[channelName].subscription = this.shh.subscribe("messages", filters) this.channels[channelName].subscription = this.shh.subscribe("messages", filters)
.on('data', messageHandler) .on("data", messageHandler)
.on('error', (err) => { cb(err); }); .on("error", (err: any) => { cb(err); });
} }
} }
onUserMessage(cb) { public onUserMessage(cb: any) {
const filters = { const filters = {
allowP2P: true,
minPow: constants.post.POW_TARGET, minPow: constants.post.POW_TARGET,
privateKeyID: _sig.get(this), privateKeyID: sig.get(this),
topics: [constants.topics.CONTACT_DISCOVERY_TOPIC], topics: [constants.topics.CONTACT_DISCOVERY_TOPIC],
allowP2P: true
}; };
const messageHandler = (data) => { const messageHandler = (data: any) => {
if(!this.contacts[data.sig]){ if (!this.contacts[data.sig]) {
this.addContact(data.sig); this.addContact(data.sig);
} }
const payloadArray = JSON.parse(hexToAscii(data.payload)); const payloadArray = JSON.parse(hexToAscii(data.payload));
if(this.contacts[data.sig].lastClockValue < payloadArray[1][3]){ if (this.contacts[data.sig].lastClockValue < payloadArray[1][3]) {
this.contacts[data.sig].lastClockValue = payloadArray[1][3]; this.contacts[data.sig].lastClockValue = payloadArray[1][3];
} }
if(payloadArray[0] === constants.messageTags.message){ if (payloadArray[0] === constants.messageTags.message) {
cb(null, {payload: hexToAscii(data.payload), data: data, username: this.contacts[data.sig].username}); cb(null, {payload: hexToAscii(data.payload), data, username: this.contacts[data.sig].username});
} else if(payloadArray[0] === constants.messageTags.chatRequest) { } else if (payloadArray[0] === constants.messageTags.chatRequest) {
this.contacts[data.sig].displayName = payloadArray[1][0]; this.contacts[data.sig].displayName = payloadArray[1][0];
this.contacts[data.sig].profilePic = payloadArray[1][1]; this.contacts[data.sig].profilePic = payloadArray[1][1];
if(this.chatRequestCb){ if (this.chatRequestCb) {
this.chatRequestCb(null, { this.chatRequestCb(null, {
'username': this.contacts[data.sig].username, displayName: this.contacts[data.sig].displayName,
'displayName': this.contacts[data.sig].displayName, profilePic: this.contacts[data.sig].profilePic,
'profilePic': this.contacts[data.sig].profilePic, username: this.contacts[data.sig].username,
}); });
} }
} }
}; };
if (this.isHttpProvider) {
if(this.isHttpProvider){
this.shh.newMessageFilter(filters) this.shh.newMessageFilter(filters)
.then(filterId => { .then((filterId: any) => {
this.userMessagesSubscription = {}; this.userMessagesSubscription = {};
this.userMessagesSubscription.filterId = filterId; this.userMessagesSubscription.filterId = filterId;
this.userMessagesSubscription.interval = setInterval(() => { this.userMessagesSubscription.interval = setInterval(() => {
this.shh.getFilterMessages(filterId) this.shh.getFilterMessages(filterId)
.then(data => { .then((data: any) => {
data.map(d => { data.map((d: any) => {
messageHandler(d); messageHandler(d);
}); });
}) })
.catch((err) => { cb(err); }); .catch((err: any) => { cb(err); });
}, 250); }, 250);
}); });
} else { } else {
this.userMessagesSubscription = this.shh.subscribe("messages", filters) this.userMessagesSubscription = this.shh.subscribe("messages", filters)
.on('data', (data) => { messageHandler(data); }) .on("data", (data: any) => { messageHandler(data); })
.on('error', (err) => { cb(err); }); .on("error", (err: any) => { cb(err); });
} }
} }
sendUserMessage(contactCode, msg, cb) { public sendUserMessage(contactCode: string, msg: string, cb?: any) {
if(!this.contacts[contactCode]){ if (!this.contacts[contactCode]) {
this.addContact(contactCode); this.addContact(contactCode);
} }
this.contacts[contactCode].lastClockValue++; this.contacts[contactCode].lastClockValue++;
this.shh.post({ this.shh.post({
pubKey: contactCode,
sig: _sig.get(this),
ttl: constants.post.TTL,
topic: constants.topics.CONTACT_DISCOVERY_TOPIC,
payload: createStatusPayload(msg, constants.messageTypes.USER_MESSAGE, this.contacts[contactCode].lastClockValue), payload: createStatusPayload(msg, constants.messageTypes.USER_MESSAGE, this.contacts[contactCode].lastClockValue),
powTarget: constants.post.POW_TARGET,
powTime: constants.post.POW_TIME, powTime: constants.post.POW_TIME,
powTarget: constants.post.POW_TARGET pubKey: contactCode,
sig: sig.get(this),
topic: constants.topics.CONTACT_DISCOVERY_TOPIC,
ttl: constants.post.TTL,
}).then(() => { }).then(() => {
if (!cb) return; if (!cb) {
return;
}
cb(null, true); cb(null, true);
}).catch((e) => { }).catch((e: any) => {
if (!cb) return; if (!cb) {
return;
}
cb(e, false); cb(e, false);
}); });
} }
sendGroupMessage(channelName, msg, cb) { public sendGroupMessage(channelName: string, msg: string, cb?: any) {
if (!this.channels[channelName]) { if (!this.channels[channelName]) {
if(!cb) return; if (!cb) {
return;
}
return cb("unknown channel: " + channelName); return cb("unknown channel: " + channelName);
} }
this.channels[channelName].lastClockValue++; this.channels[channelName].lastClockValue++;
this.shh.post({ this.shh.post({
symKeyID: this.channels[channelName].channelKey,
sig: _sig.get(this),
ttl: constants.post.TTL,
topic: this.channels[channelName].channelCode,
payload: createStatusPayload(msg, constants.messageTypes.GROUP_MESSAGE, this.channels[channelName].lastClockValue), payload: createStatusPayload(msg, constants.messageTypes.GROUP_MESSAGE, this.channels[channelName].lastClockValue),
powTarget: constants.post.POW_TARGET,
powTime: constants.post.POW_TIME, powTime: constants.post.POW_TIME,
powTarget: constants.post.POW_TARGET sig: sig.get(this),
symKeyID: this.channels[channelName].channelKey,
topic: this.channels[channelName].channelCode,
ttl: constants.post.TTL,
}).then(() => { }).then(() => {
if (!cb) return; if (!cb) {
return;
}
cb(null, true); cb(null, true);
}).catch((e) => { }).catch((e: any) => {
if (!cb) return; if (!cb) {
return;
}
cb(e, false); cb(e, false);
}); });
} }
sendJsonMessage(destination, msg, cb) { public sendJsonMessage(destination: string, msg: string, cb?: any) {
if (constants.regExp.CONTACT_CODE_REGEXP.test(destination)) { if (constants.regExp.CONTACT_CODE_REGEXP.test(destination)) {
if(!this.contacts[destination]){ if (!this.contacts[destination]) {
this.addContact(destination); this.addContact(destination);
} }
this.contacts[destination].lastClockValue++; this.contacts[destination].lastClockValue++;
this.shh.post({ this.shh.post({
pubKey: destination,
sig: _sig.get(this),
ttl: constants.post.TTL,
topic: constants.topics.CONTACT_DISCOVERY_TOPIC,
payload: createStatusPayload(msg, constants.messageTypes.USER_MESSAGE, this.contacts[destination].lastClockValue, true), payload: createStatusPayload(msg, constants.messageTypes.USER_MESSAGE, this.contacts[destination].lastClockValue, true),
powTarget: constants.post.POW_TARGET,
powTime: constants.post.POW_TIME, powTime: constants.post.POW_TIME,
powTarget: constants.post.POW_TARGET pubKey: destination,
sig: sig.get(this),
topic: constants.topics.CONTACT_DISCOVERY_TOPIC,
ttl: constants.post.TTL,
}).then(() => { }).then(() => {
if (!cb) return; if (!cb) {
return;
}
cb(null, true); cb(null, true);
}).catch((e) => { }).catch((e: any) => {
if (!cb) return; if (!cb) {
return;
}
cb(e, false); cb(e, false);
}); });
} else { } else {
this.channels[destination].lastClockValue++; this.channels[destination].lastClockValue++;
this.shh.post({ this.shh.post({
symKeyID: this.channels[destination].channelKey,
sig: _sig.get(this),
ttl: constants.post.TTL,
topic: this.channels[destination].channelCode,
payload: createStatusPayload(JSON.stringify(msg), constants.messageTypes.GROUP_MESSAGE, this.channels[destination].lastClockValue, true), payload: createStatusPayload(JSON.stringify(msg), constants.messageTypes.GROUP_MESSAGE, this.channels[destination].lastClockValue, true),
powTarget: constants.post.POW_TARGET,
powTime: constants.post.POW_TIME, powTime: constants.post.POW_TIME,
powTarget: constants.post.POW_TARGET sig: sig.get(this),
symKeyID: this.channels[destination].channelKey,
topic: this.channels[destination].channelCode,
ttl: constants.post.TTL,
}).then(() => { }).then(() => {
if (!cb) return; if (!cb) {
return;
}
cb(null, true); cb(null, true);
}).catch((e) => { }).catch((e: any) => {
if (!cb) return; if (!cb) {
return;
}
cb(e, false); cb(e, false);
}); });
} }
} }
sendMessage(destination, msg, cb){ public sendMessage(destination: string, msg: string, cb?: any) {
if (constants.regExp.CONTACT_CODE_REGEXP.test(destination)) { if (constants.regExp.CONTACT_CODE_REGEXP.test(destination)) {
this.sendUserMessage(destination, msg, cb); this.sendUserMessage(destination, msg, cb);
} else { } else {

View File

@ -9,7 +9,7 @@ class MailServers {
this.web3 = web3; this.web3 = web3;
} }
public async useMailserver(mailserver: string, cb?: Function) { public async useMailserver(mailserver: string, cb?: any) {
const enode: string = mailserverList[mailserver]; const enode: string = mailserverList[mailserver];
if (!enode) { if (!enode) {

2
src/types.d.ts vendored
View File

@ -1 +1 @@
declare module 'chance' declare module "chance";

View File

@ -9,6 +9,7 @@
"interface-name": [true, "never-prefix"], "interface-name": [true, "never-prefix"],
"member-ordering": [false], "member-ordering": [false],
"no-var-requires": false, "no-var-requires": false,
"ordered-imports": false,
"no-empty": false, "no-empty": false,
"no-console": false "no-console": false
}, },