Merge branch 'clearnet' of https://github.com/loki-project/loki-messenger into clearnet
commit
4f881ab9a3
@ -1,122 +0,0 @@
|
|||||||
/* global setTimeout, clearTimeout */
|
|
||||||
|
|
||||||
const EventEmitter = require('events');
|
|
||||||
const { isEmpty } = require('lodash');
|
|
||||||
|
|
||||||
const offlinePingTime = 2 * 60 * 1000; // 2 minutes
|
|
||||||
|
|
||||||
class LokiP2pAPI extends EventEmitter {
|
|
||||||
constructor(ourKey) {
|
|
||||||
super();
|
|
||||||
this.contactP2pDetails = {};
|
|
||||||
this.ourKey = ourKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
reset() {
|
|
||||||
Object.keys(this.contactP2pDetails).forEach(key => {
|
|
||||||
clearTimeout(this.contactP2pDetails[key].pingTimer);
|
|
||||||
delete this.contactP2pDetails[key];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
updateContactP2pDetails(pubKey, address, port, isP2PMessage = false) {
|
|
||||||
// Stagger the timers so the friends don't ping each other at the same time
|
|
||||||
const timerDuration =
|
|
||||||
pubKey < this.ourKey
|
|
||||||
? 60 * 1000 // 1 minute
|
|
||||||
: 2 * 60 * 1000; // 2 minutes
|
|
||||||
|
|
||||||
// Get the current contact details
|
|
||||||
// This will be empty if we don't have them
|
|
||||||
const baseDetails = { ...(this.contactP2pDetails[pubKey] || {}) };
|
|
||||||
|
|
||||||
// Always set the new contact details
|
|
||||||
this.contactP2pDetails[pubKey] = {
|
|
||||||
address,
|
|
||||||
port,
|
|
||||||
timerDuration,
|
|
||||||
pingTimer: null,
|
|
||||||
isOnline: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
const contactExists = !isEmpty(baseDetails);
|
|
||||||
const { isOnline } = baseDetails;
|
|
||||||
const detailsChanged =
|
|
||||||
baseDetails.address !== address || baseDetails.port !== port;
|
|
||||||
|
|
||||||
// If we had the contact details
|
|
||||||
// And we got a P2P message
|
|
||||||
// And the contact was online
|
|
||||||
// And the new details that we got matched the old
|
|
||||||
// Then we don't need to bother pinging
|
|
||||||
if (contactExists && isP2PMessage && isOnline && !detailsChanged) {
|
|
||||||
// We also need to set the current contact details to show online
|
|
||||||
// because they get reset to `false` above
|
|
||||||
this.setContactOnline(pubKey);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Ping the contact.
|
|
||||||
This happens in the following scenarios:
|
|
||||||
1. We didn't have the contact, we need to ping them to let them know our details.
|
|
||||||
2. isP2PMessage = false, so we assume the contact doesn't have our details.
|
|
||||||
3. We had the contact marked as offline,
|
|
||||||
we need to make sure that we can reach their server.
|
|
||||||
4. The other contact details have changed,
|
|
||||||
we need to make sure that we can reach their new server.
|
|
||||||
*/
|
|
||||||
this.pingContact(pubKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
getContactP2pDetails(pubKey) {
|
|
||||||
if (!this.contactP2pDetails[pubKey]) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return { ...this.contactP2pDetails[pubKey] };
|
|
||||||
}
|
|
||||||
|
|
||||||
setContactOffline(pubKey) {
|
|
||||||
this.emit('offline', pubKey);
|
|
||||||
if (!this.contactP2pDetails[pubKey]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
clearTimeout(this.contactP2pDetails[pubKey].pingTimer);
|
|
||||||
this.contactP2pDetails[pubKey].pingTimer = setTimeout(
|
|
||||||
this.pingContact.bind(this),
|
|
||||||
offlinePingTime,
|
|
||||||
pubKey
|
|
||||||
);
|
|
||||||
this.contactP2pDetails[pubKey].isOnline = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
setContactOnline(pubKey) {
|
|
||||||
if (!this.contactP2pDetails[pubKey]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.emit('online', pubKey);
|
|
||||||
clearTimeout(this.contactP2pDetails[pubKey].pingTimer);
|
|
||||||
this.contactP2pDetails[pubKey].isOnline = true;
|
|
||||||
this.contactP2pDetails[pubKey].pingTimer = setTimeout(
|
|
||||||
this.pingContact.bind(this),
|
|
||||||
this.contactP2pDetails[pubKey].timerDuration,
|
|
||||||
pubKey
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
isOnline(pubKey) {
|
|
||||||
return !!(
|
|
||||||
this.contactP2pDetails[pubKey] && this.contactP2pDetails[pubKey].isOnline
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pingContact(pubKey) {
|
|
||||||
if (!this.contactP2pDetails[pubKey]) {
|
|
||||||
// Don't ping if we don't have their details
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.emit('pingContact', pubKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = LokiP2pAPI;
|
|
@ -1,219 +0,0 @@
|
|||||||
/* global textsecure */
|
|
||||||
const https = require('https');
|
|
||||||
const EventEmitter = require('events');
|
|
||||||
const natUpnp = require('nat-upnp');
|
|
||||||
|
|
||||||
const STATUS = {
|
|
||||||
OK: 200,
|
|
||||||
BAD_REQUEST: 400,
|
|
||||||
NOT_FOUND: 404,
|
|
||||||
METHOD_NOT_ALLOWED: 405,
|
|
||||||
INTERNAL_SERVER_ERROR: 500,
|
|
||||||
};
|
|
||||||
|
|
||||||
class LocalLokiServer extends EventEmitter {
|
|
||||||
/**
|
|
||||||
* Creates an instance of LocalLokiServer.
|
|
||||||
* Sends out a `message` event when a new message is received.
|
|
||||||
*/
|
|
||||||
constructor(pems, options = {}) {
|
|
||||||
super();
|
|
||||||
const httpsOptions = {
|
|
||||||
key: pems.private,
|
|
||||||
cert: pems.cert,
|
|
||||||
};
|
|
||||||
if (!options.skipUpnp) {
|
|
||||||
this.upnpClient = natUpnp.createClient();
|
|
||||||
}
|
|
||||||
this.server = https.createServer(httpsOptions, (req, res) => {
|
|
||||||
let body = [];
|
|
||||||
|
|
||||||
const sendResponse = (statusCode, message = null) => {
|
|
||||||
const headers = message && {
|
|
||||||
'Content-Type': 'text/plain',
|
|
||||||
};
|
|
||||||
res.writeHead(statusCode, headers);
|
|
||||||
res.end(message);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (req.method !== 'POST') {
|
|
||||||
sendResponse(STATUS.METHOD_NOT_ALLOWED);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check endpoints
|
|
||||||
req
|
|
||||||
.on('error', () => {
|
|
||||||
// Internal server error
|
|
||||||
sendResponse(STATUS.INTERNAL_SERVER_ERROR);
|
|
||||||
})
|
|
||||||
.on('data', chunk => {
|
|
||||||
body.push(chunk);
|
|
||||||
})
|
|
||||||
.on('end', () => {
|
|
||||||
try {
|
|
||||||
body = Buffer.concat(body).toString();
|
|
||||||
} catch (e) {
|
|
||||||
// Internal server error: failed to convert body to string
|
|
||||||
sendResponse(STATUS.INTERNAL_SERVER_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check endpoints here
|
|
||||||
if (req.url === '/storage_rpc/v1') {
|
|
||||||
try {
|
|
||||||
const bodyObject = JSON.parse(body);
|
|
||||||
if (bodyObject.method !== 'store') {
|
|
||||||
sendResponse(STATUS.NOT_FOUND, 'Invalid endpoint!');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.emit('message', {
|
|
||||||
message: bodyObject.params.data,
|
|
||||||
onSuccess: () => sendResponse(STATUS.OK),
|
|
||||||
onFailure: () => sendResponse(STATUS.NOT_FOUND),
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
// Bad Request: Failed to decode json
|
|
||||||
sendResponse(STATUS.BAD_REQUEST, 'Failed to decode JSON');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sendResponse(STATUS.NOT_FOUND, 'Invalid endpoint!');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async start(port, ip) {
|
|
||||||
// Close the old server
|
|
||||||
await this.close();
|
|
||||||
|
|
||||||
// Start a listening on new server
|
|
||||||
return new Promise((res, rej) => {
|
|
||||||
this.server.listen(port, ip, async err => {
|
|
||||||
if (err) {
|
|
||||||
rej(err);
|
|
||||||
} else if (this.upnpClient) {
|
|
||||||
try {
|
|
||||||
const publicPort = await this.punchHole();
|
|
||||||
res(publicPort);
|
|
||||||
} catch (e) {
|
|
||||||
if (e instanceof textsecure.HolePunchingError) {
|
|
||||||
await this.close();
|
|
||||||
}
|
|
||||||
rej(e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
res(port);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async punchHole() {
|
|
||||||
const privatePort = this.server.address().port;
|
|
||||||
const portStart = 22100;
|
|
||||||
const portEnd = 22200;
|
|
||||||
const ttl = 60 * 15; // renew upnp every 15 minutes
|
|
||||||
const publicPortsInUse = await new Promise((resolve, reject) => {
|
|
||||||
this.upnpClient.getMappings({ local: true }, (err, results) => {
|
|
||||||
if (err) {
|
|
||||||
// We assume an error here means upnp not enabled
|
|
||||||
reject(
|
|
||||||
new textsecure.HolePunchingError(
|
|
||||||
'Could not get mapping from upnp. Upnp not available?',
|
|
||||||
err
|
|
||||||
)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// remove the current private port from the current mapping
|
|
||||||
// to allow reusing that port.
|
|
||||||
resolve(
|
|
||||||
results
|
|
||||||
.filter(entry => entry.private.port !== privatePort)
|
|
||||||
.map(entry => entry.public.port)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
for (let publicPort = portStart; publicPort <= portEnd; publicPort += 1) {
|
|
||||||
if (publicPortsInUse.includes(publicPort)) {
|
|
||||||
// eslint-disable-next-line no-continue
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const p = new Promise((resolve, reject) => {
|
|
||||||
this.upnpClient.portMapping(
|
|
||||||
{
|
|
||||||
public: publicPort,
|
|
||||||
private: privatePort,
|
|
||||||
ttl,
|
|
||||||
},
|
|
||||||
err => {
|
|
||||||
if (err) {
|
|
||||||
reject(err);
|
|
||||||
} else {
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
try {
|
|
||||||
// eslint-disable-next-line no-await-in-loop
|
|
||||||
await p;
|
|
||||||
this.publicPort = publicPort;
|
|
||||||
this.timerHandler = setTimeout(async () => {
|
|
||||||
try {
|
|
||||||
this.publicPort = await this.punchHole();
|
|
||||||
} catch (e) {
|
|
||||||
this.close();
|
|
||||||
}
|
|
||||||
}, ttl * 1000);
|
|
||||||
return publicPort;
|
|
||||||
} catch (e) {
|
|
||||||
throw new textsecure.HolePunchingError(
|
|
||||||
'Could not punch hole. Disabled upnp?',
|
|
||||||
e
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const e = new Error();
|
|
||||||
throw new textsecure.HolePunchingError(
|
|
||||||
`Could not punch hole: no available port. Public ports: ${portStart}-${portEnd}`,
|
|
||||||
e
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// Async wrapper for http server close
|
|
||||||
close() {
|
|
||||||
clearInterval(this.timerHandler);
|
|
||||||
if (this.upnpClient) {
|
|
||||||
this.upnpClient.portUnmapping({
|
|
||||||
public: this.publicPort,
|
|
||||||
});
|
|
||||||
this.publicPort = null;
|
|
||||||
}
|
|
||||||
if (this.server) {
|
|
||||||
return new Promise(res => {
|
|
||||||
this.server.close(() => res());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
getPort() {
|
|
||||||
if (this.server.listening) {
|
|
||||||
return this.server.address().port;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
getPublicPort() {
|
|
||||||
return this.publicPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
isListening() {
|
|
||||||
return this.server.listening;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = LocalLokiServer;
|
|
@ -1,111 +0,0 @@
|
|||||||
const axios = require('axios');
|
|
||||||
const { assert } = require('chai');
|
|
||||||
const LocalLokiServer = require('../../modules/local_loki_server');
|
|
||||||
const selfsigned = require('selfsigned');
|
|
||||||
const https = require('https');
|
|
||||||
|
|
||||||
class HolePunchingError extends Error {
|
|
||||||
constructor(message, err) {
|
|
||||||
super(message);
|
|
||||||
this.name = 'HolePunchingError';
|
|
||||||
this.error = err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('LocalLokiServer', () => {
|
|
||||||
before(async () => {
|
|
||||||
const attrs = [{ name: 'commonName', value: 'mypubkey' }];
|
|
||||||
const pems = selfsigned.generate(attrs, { days: 365 * 10 });
|
|
||||||
global.textsecure = {};
|
|
||||||
global.textsecure.HolePunchingError = HolePunchingError;
|
|
||||||
this.server = new LocalLokiServer(pems, { skipUpnp: true });
|
|
||||||
await this.server.start(8000);
|
|
||||||
this.axiosClient = axios.create({
|
|
||||||
httpsAgent: new https.Agent({
|
|
||||||
rejectUnauthorized: false,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
after(async () => {
|
|
||||||
await this.server.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return 405 if not a POST request', async () => {
|
|
||||||
try {
|
|
||||||
await this.axiosClient.get('https://localhost:8000');
|
|
||||||
assert.fail('Got a successful response');
|
|
||||||
} catch (error) {
|
|
||||||
if (error.response) {
|
|
||||||
assert.equal(405, error.response.status);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
assert.isNotOk(error, 'Another error was receieved');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return 404 if no endpoint provided', async () => {
|
|
||||||
try {
|
|
||||||
await this.axiosClient.post('https://localhost:8000', { name: 'Test' });
|
|
||||||
assert.fail('Got a successful response');
|
|
||||||
} catch (error) {
|
|
||||||
if (error.response) {
|
|
||||||
assert.equal(404, error.response.status);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
assert.isNotOk(error, 'Another error was receieved');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return 404 and a string if invalid enpoint is provided', async () => {
|
|
||||||
try {
|
|
||||||
await this.axiosClient.post('https://localhost:8000/invalid', {
|
|
||||||
name: 'Test',
|
|
||||||
});
|
|
||||||
assert.fail('Got a successful response');
|
|
||||||
} catch (error) {
|
|
||||||
if (error.response) {
|
|
||||||
assert.equal(404, error.response.status);
|
|
||||||
assert.equal('Invalid endpoint!', error.response.data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
assert.isNotOk(error, 'Another error was receieved');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('/store', async () => {
|
|
||||||
it('should pass the POSTed data to the callback', async () => {
|
|
||||||
const attrs = [{ name: 'commonName', value: 'mypubkey' }];
|
|
||||||
const pems = selfsigned.generate(attrs, { days: 365 * 10 });
|
|
||||||
const server = new LocalLokiServer(pems, { skipUpnp: true });
|
|
||||||
await server.start(8001);
|
|
||||||
const messageData = {
|
|
||||||
method: 'store',
|
|
||||||
params: {
|
|
||||||
data: 'This is data',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const promise = new Promise(res => {
|
|
||||||
server.on('message', eventData => {
|
|
||||||
const { message, onSuccess } = eventData;
|
|
||||||
assert.equal(message, 'This is data');
|
|
||||||
onSuccess();
|
|
||||||
server.close();
|
|
||||||
res();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
|
||||||
await this.axiosClient.post(
|
|
||||||
'https://localhost:8001/storage_rpc/v1',
|
|
||||||
messageData
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
assert.isNotOk(error, 'Error occured');
|
|
||||||
}
|
|
||||||
|
|
||||||
return promise;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,193 +0,0 @@
|
|||||||
const { assert } = require('chai');
|
|
||||||
const LokiP2pAPI = require('../../../js/modules/loki_p2p_api');
|
|
||||||
|
|
||||||
describe('LokiP2pAPI', () => {
|
|
||||||
const usedKey = 'aPubKey';
|
|
||||||
const usedAddress = 'anAddress';
|
|
||||||
const usedPort = 'aPort';
|
|
||||||
|
|
||||||
const usedDetails = {
|
|
||||||
address: usedAddress,
|
|
||||||
port: usedPort,
|
|
||||||
timerDuration: 100,
|
|
||||||
pingTimer: null,
|
|
||||||
isOnline: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
this.lokiP2pAPI = new LokiP2pAPI();
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
this.lokiP2pAPI.removeAllListeners();
|
|
||||||
this.lokiP2pAPI.reset();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getContactP2pDetails', () => {
|
|
||||||
it('Should return null if no contact details exist', () => {
|
|
||||||
const details = this.lokiP2pAPI.getContactP2pDetails(usedKey);
|
|
||||||
assert.isNull(details);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should return the exact same object if contact details exist', () => {
|
|
||||||
this.lokiP2pAPI.contactP2pDetails[usedKey] = usedDetails;
|
|
||||||
const details = this.lokiP2pAPI.getContactP2pDetails(usedKey);
|
|
||||||
assert.deepEqual(details, usedDetails);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('pingContact', () => {
|
|
||||||
it("Should not emit a pingContact event if that contact doesn't exits", () => {
|
|
||||||
this.lokiP2pAPI.on('pingContact', () => {
|
|
||||||
assert.fail();
|
|
||||||
});
|
|
||||||
this.lokiP2pAPI.pingContact('not stored');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('updateContactP2pDetails', () => {
|
|
||||||
it("Shouldn't ping a contact if contact exists, p2p message was sent, contact was online and details didn't change", () => {
|
|
||||||
this.lokiP2pAPI.on('pingContact', () => {
|
|
||||||
assert.fail();
|
|
||||||
});
|
|
||||||
|
|
||||||
// contact exists
|
|
||||||
const details = { ...usedDetails };
|
|
||||||
// P2p message
|
|
||||||
const isP2P = true;
|
|
||||||
// Contact was online
|
|
||||||
details.isOnline = true;
|
|
||||||
// details were the same
|
|
||||||
const { address, port } = details;
|
|
||||||
|
|
||||||
this.lokiP2pAPI.contactP2pDetails[usedKey] = details;
|
|
||||||
this.lokiP2pAPI.updateContactP2pDetails(usedKey, address, port, isP2P);
|
|
||||||
|
|
||||||
// They should also be marked as online
|
|
||||||
assert.isTrue(this.lokiP2pAPI.isOnline(usedKey));
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should ping a contact if we don't have details for it", done => {
|
|
||||||
this.lokiP2pAPI.on('pingContact', pubKey => {
|
|
||||||
assert.strictEqual(pubKey, usedKey);
|
|
||||||
assert.isFalse(this.lokiP2pAPI.isOnline(usedKey));
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
this.lokiP2pAPI.updateContactP2pDetails(
|
|
||||||
usedKey,
|
|
||||||
usedAddress,
|
|
||||||
usedPort,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should ping a contact if a P2P message wasn't received", done => {
|
|
||||||
// The precondition for this is that we had the contact stored
|
|
||||||
this.lokiP2pAPI.contactP2pDetails[usedKey] = { ...usedDetails };
|
|
||||||
|
|
||||||
this.lokiP2pAPI.on('pingContact', pubKey => {
|
|
||||||
assert.strictEqual(pubKey, usedKey);
|
|
||||||
assert.isFalse(this.lokiP2pAPI.isOnline(usedKey));
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
this.lokiP2pAPI.updateContactP2pDetails(
|
|
||||||
usedKey,
|
|
||||||
usedAddress,
|
|
||||||
usedPort,
|
|
||||||
false // We didn't get a p2p message
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should ping a contact if they were marked as offline', done => {
|
|
||||||
// The precondition for this is that we had the contact stored
|
|
||||||
// And that p2p message was true
|
|
||||||
this.lokiP2pAPI.contactP2pDetails[usedKey] = { ...usedDetails };
|
|
||||||
|
|
||||||
this.lokiP2pAPI.on('pingContact', pubKey => {
|
|
||||||
assert.strictEqual(pubKey, usedKey);
|
|
||||||
assert.isFalse(this.lokiP2pAPI.isOnline(usedKey));
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
this.lokiP2pAPI.updateContactP2pDetails(
|
|
||||||
usedKey,
|
|
||||||
usedAddress,
|
|
||||||
usedPort,
|
|
||||||
true // We got a p2p message
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should ping a contact if the address was different', done => {
|
|
||||||
// The precondition for this is that we had the contact stored
|
|
||||||
// And that p2p message was true
|
|
||||||
// And that the user was online
|
|
||||||
this.lokiP2pAPI.contactP2pDetails[usedKey] = { ...usedDetails };
|
|
||||||
this.lokiP2pAPI.contactP2pDetails[usedKey].isOnline = true;
|
|
||||||
|
|
||||||
this.lokiP2pAPI.on('pingContact', pubKey => {
|
|
||||||
assert.strictEqual(pubKey, usedKey);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
this.lokiP2pAPI.updateContactP2pDetails(
|
|
||||||
usedKey,
|
|
||||||
'different address',
|
|
||||||
usedPort,
|
|
||||||
true // We got a p2p message
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should ping a contact if the port was different', done => {
|
|
||||||
// The precondition for this is that we had the contact stored
|
|
||||||
// And that p2p message was true
|
|
||||||
// And that the user was online
|
|
||||||
this.lokiP2pAPI.contactP2pDetails[usedKey] = { ...usedDetails };
|
|
||||||
this.lokiP2pAPI.contactP2pDetails[usedKey].isOnline = true;
|
|
||||||
|
|
||||||
this.lokiP2pAPI.on('pingContact', pubKey => {
|
|
||||||
assert.strictEqual(pubKey, usedKey);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
this.lokiP2pAPI.updateContactP2pDetails(
|
|
||||||
usedKey,
|
|
||||||
usedAddress,
|
|
||||||
'different port',
|
|
||||||
true // We got a p2p message
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should emit an online event if the contact is online', done => {
|
|
||||||
this.lokiP2pAPI.on('online', pubKey => {
|
|
||||||
assert.strictEqual(pubKey, usedKey);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
this.lokiP2pAPI.contactP2pDetails[usedKey] = { ...usedDetails };
|
|
||||||
this.lokiP2pAPI.setContactOnline(usedKey);
|
|
||||||
}).timeout(1000);
|
|
||||||
|
|
||||||
it('Should store a contacts p2p details', () => {
|
|
||||||
this.lokiP2pAPI.updateContactP2pDetails(
|
|
||||||
usedKey,
|
|
||||||
usedAddress,
|
|
||||||
usedPort,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
const p2pDetails = this.lokiP2pAPI.getContactP2pDetails(usedKey);
|
|
||||||
assert.strictEqual(usedAddress, p2pDetails.address);
|
|
||||||
assert.strictEqual(usedPort, p2pDetails.port);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should set a contact as offline and online', () => {
|
|
||||||
this.lokiP2pAPI.contactP2pDetails[usedKey] = { ...usedDetails };
|
|
||||||
let p2pDetails = this.lokiP2pAPI.getContactP2pDetails(usedKey);
|
|
||||||
assert.isNotNull(p2pDetails);
|
|
||||||
assert.isFalse(p2pDetails.isOnline);
|
|
||||||
this.lokiP2pAPI.setContactOnline(usedKey);
|
|
||||||
|
|
||||||
p2pDetails = this.lokiP2pAPI.getContactP2pDetails(usedKey);
|
|
||||||
assert.isTrue(p2pDetails.isOnline);
|
|
||||||
this.lokiP2pAPI.setContactOffline(usedKey);
|
|
||||||
|
|
||||||
p2pDetails = this.lokiP2pAPI.getContactP2pDetails(usedKey);
|
|
||||||
assert.isFalse(p2pDetails.isOnline);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
Loading…
Reference in New Issue