Remove P2P

This commit is contained in:
Maxim Shishmarev 2020-01-28 14:19:39 +11:00
parent 215f6631a4
commit 02320334f0
17 changed files with 17 additions and 1020 deletions

View File

@ -258,13 +258,6 @@
}
// are there limits on tracking, is this unneeded?
// window.mixpanel.track("Desktop boot");
window.lokiP2pAPI = new window.LokiP2pAPI(ourKey);
window.lokiP2pAPI.on('pingContact', pubKey => {
const isPing = true;
libloki.api.sendOnlineBroadcastMessage(pubKey, isPing);
});
window.lokiP2pAPI.on('online', ConversationController._handleOnline);
window.lokiP2pAPI.on('offline', ConversationController._handleOffline);
window.initialisedAPI = true;
if (storage.get('isSecondaryDevice')) {
@ -286,14 +279,6 @@
}
}
function startLocalLokiServer() {
if (window.localLokiServer) {
return;
}
const pems = window.getSelfSignedCert();
window.localLokiServer = new window.LocalLokiServer(pems);
}
// We need this 'first' check because we don't want to start the app up any other time
// than the first time. And storage.fetch() will cause onready() to fire.
let first = true;
@ -391,8 +376,6 @@
},
shutdown: async () => {
await window.localLokiServer.close();
// Stop background processing
window.Signal.AttachmentDownloads.stop();
if (idleDetector) {
@ -1262,15 +1245,6 @@
}
});
Whisper.events.on('p2pMessageSent', ({ pubKey, timestamp }) => {
try {
const conversation = ConversationController.get(pubKey);
conversation.onP2pMessageSent(pubKey, timestamp);
} catch (e) {
window.log.error('Error setting p2p on message');
}
});
Whisper.events.on(
'publicMessageSent',
({ pubKey, timestamp, serverId }) => {
@ -1418,7 +1392,6 @@
window.lokiFileServerAPI = await window.lokiFileServerAPIFactory.establishHomeConnection(
window.getDefaultFileServer()
);
window.localLokiServer = null;
window.lokiPublicChatAPI = null;
window.feeds = [];
messageReceiver = new textsecure.MessageReceiver(
@ -1436,8 +1409,6 @@
return;
}
// initialize the socket and start listening for messages
startLocalLokiServer();
await initAPIs();
await initSpecialConversations();
messageReceiver = new textsecure.MessageReceiver(
@ -2054,7 +2025,6 @@
unidentifiedDeliveryReceived: data.unidentifiedDeliveryReceived,
type: 'incoming',
unread: 1,
isP2p: data.isP2p,
isPublic: data.isPublic,
isRss: data.isRss,
};

View File

@ -12,7 +12,6 @@
profileImages,
clipboard,
BlockedNumberController,
lokiP2pAPI,
lokiPublicChatAPI,
JobQueue
*/
@ -182,13 +181,6 @@
if (this.id === this.ourNumber) {
this.set({ friendRequestStatus: FriendRequestStatusEnum.friends });
} else if (typeof lokiP2pAPI !== 'undefined') {
// Online status handling, only for contacts that aren't us
this.set({ isOnline: lokiP2pAPI.isOnline(this.id) });
} else {
window.log.warn(
'lokiP2pAPI not initialised when spawning conversation!'
);
}
this.messageSendQueue = new JobQueue();
@ -484,11 +476,6 @@
await Promise.all(messages.map(m => m.setCalculatingPoW()));
},
async onP2pMessageSent(pubKey, timestamp) {
const messages = this._getMessagesWithTimestamp(pubKey, timestamp);
await Promise.all(messages.map(m => m.setIsP2p(true)));
},
async onPublicMessageSent(pubKey, timestamp, serverId) {
const messages = this._getMessagesWithTimestamp(pubKey, timestamp);
await Promise.all(

View File

@ -694,7 +694,6 @@
expirationTimestamp,
selected: this.selected,
multiSelectMode: conversation && conversation.selectedMessages.size > 0,
isP2p: !!this.get('isP2p'),
isPublic: !!this.get('isPublic'),
isRss: !!this.get('isRss'),
senderIsModerator:
@ -1360,19 +1359,6 @@
Message: Whisper.Message,
});
},
async setIsP2p(isP2p) {
if (_.isEqual(this.get('isP2p'), isP2p)) {
return;
}
this.set({
isP2p: !!isP2p,
});
await window.Signal.Data.saveMessage(this.attributes, {
Message: Whisper.Message,
});
},
getServerId() {
return this.get('serverId');
},

View File

@ -1,6 +1,6 @@
/* eslint-disable no-await-in-loop */
/* eslint-disable no-loop-func */
/* global log, dcodeIO, window, callWorker, lokiP2pAPI, lokiSnodeAPI, textsecure */
/* global log, dcodeIO, window, callWorker, lokiSnodeAPI, textsecure */
const _ = require('lodash');
const { lokiRpc } = require('./loki_rpc');
@ -38,38 +38,6 @@ const calcNonce = (messageEventData, pubKey, data64, timestamp, ttl) => {
return callWorker('calcPoW', timestamp, ttl, pubKey, data64, difficulty);
};
const trySendP2p = async (pubKey, data64, isPing, messageEventData) => {
if (typeof lokiP2pAPI === 'undefined') {
return false;
}
const p2pDetails = lokiP2pAPI.getContactP2pDetails(pubKey);
if (!p2pDetails || (!isPing && !p2pDetails.isOnline)) {
return false;
}
try {
await lokiRpc(p2pDetails.address, p2pDetails.port, 'store', {
data: data64,
});
lokiP2pAPI.setContactOnline(pubKey);
window.Whisper.events.trigger('p2pMessageSent', messageEventData);
if (isPing) {
log.info(`Successfully pinged ${pubKey}`);
} else {
log.info(`Successful p2p message to ${pubKey}`);
}
return true;
} catch (e) {
lokiP2pAPI.setContactOffline(pubKey);
if (isPing) {
// If this was just a ping, we don't bother sending to storage server
log.warn('Ping failed, contact marked offline', e);
return true;
}
log.warn('Failed to send P2P message, falling back to storage', e);
return false;
}
};
class LokiMessageAPI {
constructor(ourKey) {
this.jobQueue = new window.JobQueue();
@ -79,7 +47,6 @@ class LokiMessageAPI {
async sendMessage(pubKey, data, messageTimeStamp, ttl, options = {}) {
const {
isPing = false,
isPublic = false,
numConnections = DEFAULT_CONNECTIONS,
publicSendData = null,
@ -108,15 +75,6 @@ class LokiMessageAPI {
}
const data64 = dcodeIO.ByteBuffer.wrap(data).toString('base64');
const p2pSuccess = await trySendP2p(
pubKey,
data64,
isPing,
messageEventData
);
if (p2pSuccess) {
return;
}
const timestamp = Date.now();
const nonce = await calcNonce(

View File

@ -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;

View File

@ -2,32 +2,7 @@
/* global window, ConversationController, _, log */
const is = require('@sindresorhus/is');
const dns = require('dns');
const process = require('process');
const { lokiRpc } = require('./loki_rpc');
const natUpnp = require('nat-upnp');
const resolve4 = url =>
new Promise((resolve, reject) => {
dns.resolve4(url, (err, ip) => {
if (err) {
reject(err);
} else {
resolve(ip);
}
});
});
const resolveCname = url =>
new Promise((resolve, reject) => {
dns.resolveCname(url, (err, address) => {
if (err) {
reject(err);
} else {
resolve(address[0]);
}
});
});
class LokiSnodeAPI {
constructor({ serverUrl, localUrl }) {
@ -38,40 +13,6 @@ class LokiSnodeAPI {
this.localUrl = localUrl;
this.randomSnodePool = [];
this.swarmsPendingReplenish = {};
// When we package lokinet with messenger we can ensure this ip is correct
if (process.platform === 'win32') {
dns.setServers(['127.0.0.1']);
}
}
async getMyClearIp() {
const upnpClient = natUpnp.createClient();
return new Promise((resolve, reject) => {
upnpClient.externalIp((err, ip) => {
if (err) {
reject(err);
} else {
resolve(ip);
}
});
});
}
async getMyLokiIp() {
try {
const address = await resolveCname(this.localUrl);
return resolve4(address);
} catch (e) {
throw new window.textsecure.LokiIpError(
'Failed to resolve localhost.loki',
e
);
}
}
getMyLokiAddress() {
/* resolve our local loki address */
return resolveCname(this.localUrl);
}
async getRandomSnodeAddress() {

View File

@ -1,4 +1,4 @@
/* global window, textsecure, log, Whisper, dcodeIO, StringView, ConversationController */
/* global window, textsecure, Whisper, dcodeIO, StringView, ConversationController */
// eslint-disable-next-line func-names
(function() {
@ -8,24 +8,6 @@
return sendOnlineBroadcastMessage(pubKey);
}
async function broadcastOnlineStatus() {
const friendKeys = await window.Signal.Data.getPubKeysWithFriendStatus(
window.friends.friendRequestStatusEnum.friends
);
await Promise.all(
friendKeys.map(async pubKey => {
if (pubKey === textsecure.storage.user.getNumber()) {
return;
}
try {
await sendOnlineBroadcastMessage(pubKey);
} catch (e) {
log.warn(`Failed to send online broadcast message to ${pubKey}`);
}
})
);
}
async function sendOnlineBroadcastMessage(pubKey, isPing = false) {
const authorisation = await window.libloki.storage.getGrantAuthorisationForSecondaryPubKey(
pubKey
@ -34,27 +16,10 @@
sendOnlineBroadcastMessage(authorisation.primaryDevicePubKey);
return;
}
let p2pAddress = null;
let p2pPort = null;
let type;
let myIp;
if (window.localLokiServer && window.localLokiServer.isListening()) {
try {
// clearnet change: getMyLokiAddress -> getMyClearIP
// const myLokiAddress = await window.lokiSnodeAPI.getMyLokiAddress();
myIp = await window.lokiSnodeAPI.getMyClearIp();
} catch (e) {
log.warn(`Failed to get clear IP for local server ${e}`);
}
}
if (myIp) {
p2pAddress = `https://${myIp}`;
p2pPort = window.localLokiServer.getPublicPort();
type = textsecure.protobuf.LokiAddressMessage.Type.HOST_REACHABLE;
} else {
type = textsecure.protobuf.LokiAddressMessage.Type.HOST_UNREACHABLE;
}
const p2pAddress = null;
const p2pPort = null;
// We result loki address message for sending "background" messages
const type = textsecure.protobuf.LokiAddressMessage.Type.HOST_UNREACHABLE;
const lokiAddressMessage = new textsecure.protobuf.LokiAddressMessage({
p2pAddress,
@ -252,7 +217,6 @@
window.libloki.api = {
sendBackgroundMessage,
sendOnlineBroadcastMessage,
broadcastOnlineStatus,
sendPairingAuthorisation,
createPairingAuthorisationProtoMessage,
sendUnpairingMessageToSecondary,

View File

@ -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;

View File

@ -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;
});
});
});

View File

@ -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);
});
});
});

View File

@ -163,38 +163,6 @@
}
inherit(ReplayableError, DNSResolutionError);
function HolePunchingError(message, error) {
this.name = 'HolePunchingError';
this.message = message;
this.error = error;
Error.call(this, message);
// Maintains proper stack trace, where our error was thrown (only available on V8)
// via https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
}
appendStack(this, error);
}
function LokiIpError(message, resolutionError) {
this.name = 'LokiIpError';
this.message = message;
this.error = resolutionError;
Error.call(this, message);
// Maintains proper stack trace, where our error was thrown (only available on V8)
// via https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
}
appendStack(this, resolutionError);
}
function NotFoundError(message, error) {
this.name = 'NotFoundError';
this.message = message;
@ -307,8 +275,6 @@
window.textsecure.EmptySwarmError = EmptySwarmError;
window.textsecure.SeedNodeError = SeedNodeError;
window.textsecure.DNSResolutionError = DNSResolutionError;
window.textsecure.LokiIpError = LokiIpError;
window.textsecure.HolePunchingError = HolePunchingError;
window.textsecure.HTTPError = HTTPError;
window.textsecure.NotFoundError = NotFoundError;
window.textsecure.WrongSwarmError = WrongSwarmError;

View File

@ -12,11 +12,8 @@
/* global ContactBuffer: false */
/* global GroupBuffer: false */
/* global WebSocketResource: false */
/* global localLokiServer: false */
/* global lokiPublicChatAPI: false */
/* global localServerPort: false */
/* global lokiMessageAPI: false */
/* global lokiP2pAPI: false */
/* global feeds: false */
/* global Whisper: false */
/* global lokiFileServerAPI: false */
@ -82,9 +79,6 @@ MessageReceiver.prototype.extend({
handleRequest: this.handleRequest.bind(this),
});
this.httpPollingResource.pollServer();
if (localLokiServer) {
localLokiServer.on('message', this.handleP2pMessage.bind(this));
}
if (lokiPublicChatAPI) {
lokiPublicChatAPI.on(
'publicMessage',
@ -95,7 +89,6 @@ MessageReceiver.prototype.extend({
feeds.forEach(feed => {
feed.on('rssMessage', this.handleUnencryptedMessage.bind(this));
});
this.startLocalServer();
// TODO: Rework this socket stuff to work with online messaging
const useWebSocket = false;
@ -126,45 +119,6 @@ MessageReceiver.prototype.extend({
// all cached envelopes are processed.
this.incoming = [this.pending];
},
async startLocalServer() {
if (!localLokiServer) {
return;
}
try {
// clearnet change: getMyLokiIp -> getMyClearIp
// const myLokiIp = await window.lokiSnodeAPI.getMyLokiIp();
const myLokiIp = '0.0.0.0';
const myServerPort = await localLokiServer.start(
localServerPort,
myLokiIp
);
window.log.info(`Local Server started at ${myLokiIp}:${myServerPort}`);
libloki.api.broadcastOnlineStatus();
} catch (e) {
if (e instanceof textsecure.HolePunchingError) {
window.log.warn(e.message);
window.log.warn('Abdandoning starting p2p server.');
return;
} else if (e instanceof textsecure.LokiIpError) {
window.log.warn(
'Failed to get my loki address to bind server to, will retry in 30 seconds'
);
} else {
window.log.warn(
'Failed to start local loki server, will retry in 30 seconds'
);
}
setTimeout(this.startLocalServer.bind(this), 30 * 1000);
}
},
handleP2pMessage({ message, onSuccess, onFailure }) {
const options = {
isP2p: true,
onSuccess,
onFailure,
};
this.httpPollingResource.handleMessage(message, options);
},
async handleUnencryptedMessage({ message }) {
const isMe = message.source === textsecure.storage.user.getNumber();
if (!isMe && message.message.profile) {
@ -201,13 +155,6 @@ MessageReceiver.prototype.extend({
this.wsr.removeEventListener('close', this._onClose);
this.wsr = null;
}
if (localLokiServer) {
localLokiServer.removeListener(
'message',
this.handleP2pMessage.bind(this)
);
}
},
async close() {
window.log.info('MessageReceiver.close()');
@ -219,10 +166,6 @@ MessageReceiver.prototype.extend({
this.wsr.close(3000, 'called close');
}
if (localLokiServer) {
localLokiServer.close();
}
if (lokiPublicChatAPI) {
await lokiPublicChatAPI.close();
}
@ -279,7 +222,7 @@ MessageReceiver.prototype.extend({
// });
},
handleRequest(request, options) {
const { isP2p, onSuccess, onFailure } = options;
const { onSuccess, onFailure } = options;
this.incoming = this.incoming || [];
const lastPromise = _.last(this.incoming);
@ -299,9 +242,6 @@ MessageReceiver.prototype.extend({
const promise = Promise.resolve(request.body.toArrayBuffer()) // textsecure.crypto
.then(plaintext => {
const envelope = textsecure.protobuf.Envelope.decode(plaintext);
if (isP2p) {
lokiP2pAPI.setContactOnline(envelope.source);
}
// After this point, decoding errors are not the server's
// fault, and we should handle them gracefully and tell the
// user they received an invalid message
@ -311,7 +251,6 @@ MessageReceiver.prototype.extend({
}
envelope.id = envelope.serverGuid || window.getGuid();
envelope.isP2p = isP2p;
envelope.serverTimestamp = envelope.serverTimestamp
? envelope.serverTimestamp.toNumber()
: null;
@ -1089,16 +1028,8 @@ MessageReceiver.prototype.extend({
})
);
},
async handleLokiAddressMessage(envelope, lokiAddressMessage) {
const { p2pAddress, p2pPort, type } = lokiAddressMessage;
if (type === textsecure.protobuf.LokiAddressMessage.Type.HOST_REACHABLE) {
lokiP2pAPI.updateContactP2pDetails(
envelope.source,
p2pAddress,
p2pPort,
envelope.isP2p
);
}
async handleLokiAddressMessage(envelope) {
window.log.warn('Ignoring a Loki address message');
return this.removeFromCache(envelope);
},
async handlePairingRequest(envelope, pairingRequest) {
@ -1319,14 +1250,6 @@ MessageReceiver.prototype.extend({
await conversation.setLokiProfile(newProfile);
},
handleDataMessage(envelope, msg) {
if (!envelope.isP2p) {
const timestamp = envelope.timestamp.toNumber();
const now = Date.now();
const ageInSeconds = (now - timestamp) / 1000;
if (ageInSeconds <= 120) {
lokiP2pAPI.pingContact(envelope.source);
}
}
window.log.info('data message from', this.getEnvelopeId(envelope));
let p = Promise.resolve();
// eslint-disable-next-line no-bitwise
@ -1465,7 +1388,6 @@ MessageReceiver.prototype.extend({
timestamp: envelope.timestamp.toNumber(),
receivedAt: envelope.receivedAt,
unidentifiedDeliveryReceived: envelope.unidentifiedDeliveryReceived,
isP2p: envelope.isP2p,
message,
};
return this.dispatchAndWait(ev);

View File

@ -98,7 +98,6 @@
"mkdirp": "0.5.1",
"moment": "2.21.0",
"mustache": "2.3.0",
"nat-upnp": "^1.1.1",
"node-fetch": "2.3.0",
"node-gyp": "3.8.0",
"node-sass": "4.9.3",
@ -120,7 +119,6 @@
"redux-promise-middleware": "6.1.0",
"reselect": "4.0.0",
"rimraf": "2.6.2",
"selfsigned": "^1.10.4",
"semver": "5.4.1",
"spellchecker": "3.5.1",
"tar": "4.4.8",
@ -160,7 +158,6 @@
"@types/uuid": "3.4.4",
"arraybuffer-loader": "1.0.3",
"asar": "0.14.0",
"axios": "0.18.0",
"bower": "1.8.2",
"chai": "4.1.2",
"dashdash": "1.14.1",

View File

@ -3,7 +3,6 @@
const path = require('path');
const electron = require('electron');
const semver = require('semver');
const selfsigned = require('selfsigned');
const { deferredToPromise } = require('./js/modules/deferred_to_promise');
const { JobQueue } = require('./js/modules/job_queue');
@ -74,19 +73,6 @@ window.versionInfo = {
// temporary clearnet fix
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
window.getSelfSignedCert = () => {
let pems = window.storage.get('self-signed-certificate', null);
if (!pems) {
const pubKey = window.storage.get('number_id');
const attrs = [{ name: 'commonName', value: pubKey }];
pems = selfsigned.generate(attrs, { days: 365 * 10 });
window.storage.put('self-signed-certificate', pems);
window.log.info(`Created PEM for p2p:\n${pems}`);
} else {
window.log.info(`Found existing PEM for p2p:\n${pems}`);
}
return pems;
};
window.wrapDeferred = deferredToPromise;
@ -377,8 +363,6 @@ window.lokiSnodeAPI = new LokiSnodeAPI({
localUrl: config.localUrl,
});
window.LokiP2pAPI = require('./js/modules/loki_p2p_api');
window.LokiMessageAPI = require('./js/modules/loki_message_api');
window.LokiPublicChatAPI = require('./js/modules/loki_public_chat_api');
@ -391,8 +375,6 @@ const LokiMixpanelAPI = require('./js/modules/loki_mixpanel.js');
window.mixpanel = new LokiMixpanelAPI();
window.LocalLokiServer = require('./libloki/modules/local_loki_server');
window.localServerPort = config.localServerPort;
window.mnemonic = require('./libloki/modules/mnemonic');

View File

@ -82,6 +82,5 @@ window.clearDatabase = async () => {
await window.storage.fetch();
};
window.lokiP2pAPI = new window.LokiP2pAPI('ourKey');
window.Whisper = window.Whisper || {};
window.Whisper.events = _.clone(Backbone.Events);

View File

@ -97,7 +97,6 @@ export interface Props {
expirationLength?: number;
expirationTimestamp?: number;
convoId: string;
isP2p?: boolean;
isPublic?: boolean;
isRss?: boolean;
selected: boolean;
@ -214,13 +213,9 @@ export class Message extends React.PureComponent<Props, State> {
}
public renderMetadataBadges() {
const { direction, isP2p, isPublic, senderIsModerator } = this.props;
const { direction, isPublic, senderIsModerator } = this.props;
const badges = [
isPublic && 'Public',
isP2p && 'P2p',
senderIsModerator && 'Mod',
];
const badges = [isPublic && 'Public', senderIsModerator && 'Mod'];
return badges
.map(badgeText => {

View File

@ -907,7 +907,7 @@ async@^1.5.0, async@~1.5.2:
resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=
async@^2.0.0, async@^2.1.4, async@^2.1.5, async@^2.6.2:
async@^2.0.0, async@^2.1.4, async@^2.6.2:
version "2.6.3"
resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff"
integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==
@ -951,14 +951,6 @@ aws4@^1.6.0, aws4@^1.8.0:
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.1.tgz#7e33d8f7d449b3f673cd72deb9abdc552dbe528e"
integrity sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==
axios@0.18.0:
version "0.18.0"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.18.0.tgz#32d53e4851efdc0a11993b6cd000789d70c05102"
integrity sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=
dependencies:
follow-redirects "^1.3.0"
is-buffer "^1.1.5"
babel-code-frame@6.26.0, babel-code-frame@^6.22.0, babel-code-frame@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
@ -3792,7 +3784,7 @@ flush-write-stream@^1.0.0:
inherits "^2.0.3"
readable-stream "^2.3.6"
follow-redirects@^1.0.0, follow-redirects@^1.3.0:
follow-redirects@^1.0.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.9.0.tgz#8d5bcdc65b7108fe1508649c79c12d732dcedb4f"
integrity sha512-CRcPzsSIbXyVDl0QI01muNDu69S8trU4jArW9LpOt2WtC6LyUJetcIrmfHsRBx7/Jb6GHJUiuqyYxPooFfNt6A==
@ -4989,7 +4981,7 @@ ip-regex@^1.0.1:
resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-1.0.3.tgz#dc589076f659f419c222039a33316f1c7387effd"
integrity sha1-3FiQdvZZ9BnCIgOaMzFvHHOH7/0=
ip@1.1.5, ip@^1.1.0, ip@^1.1.4, ip@^1.1.5:
ip@1.1.5, ip@^1.1.0, ip@^1.1.5:
version "1.1.5"
resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a"
integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=
@ -6575,16 +6567,6 @@ nanomatch@^1.2.9:
snapdragon "^0.8.1"
to-regex "^3.0.1"
nat-upnp@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/nat-upnp/-/nat-upnp-1.1.1.tgz#b18365e4faf44652549bb593c69e6b690df22043"
integrity sha512-b1Q+sf9fHGCXhlWErNgTTEto8A02MnNysw3vx3kD1657+/Ae23vPEAB6QBh+9RqLL4+xw/LmjVTiLy6A7Cx0xw==
dependencies:
async "^2.1.5"
ip "^1.1.4"
request "^2.79.0"
xml2js "~0.1.14"
native-or-lie@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/native-or-lie/-/native-or-lie-1.0.2.tgz#c870ee0ba0bf0ff11350595d216cfea68a6d8086"
@ -8867,7 +8849,7 @@ request@2.87.0:
tunnel-agent "^0.6.0"
uuid "^3.1.0"
request@2.x, request@^2.45.0, request@^2.65.0, request@^2.79.0, request@^2.81.0, request@^2.83.0, request@^2.87.0:
request@2.x, request@^2.45.0, request@^2.65.0, request@^2.81.0, request@^2.83.0, request@^2.87.0:
version "2.88.0"
resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==
@ -9114,7 +9096,7 @@ sass-graph@^2.2.4:
scss-tokenizer "^0.2.3"
yargs "^7.0.0"
sax@>=0.1.1, sax@>=0.6.0, sax@^1.2.4, sax@~1.2.1:
sax@>=0.6.0, sax@^1.2.4, sax@~1.2.1:
version "1.2.4"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
@ -9148,7 +9130,7 @@ select-hose@^2.0.0:
resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=
selfsigned@^1.10.4, selfsigned@^1.9.1:
selfsigned@^1.9.1:
version "1.10.7"
resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.7.tgz#da5819fd049d5574f28e88a9bcc6dbc6e6f3906b"
integrity sha512-8M3wBCzeWIJnQfl43IKwOmC4H/RAp50S8DF60znzjW5GVqTcSe2vWclt7hmYVPkKPlHWOu5EaWOMZ2Y6W8ZXTA==
@ -11104,13 +11086,6 @@ xml2js@^0.4.5:
sax ">=0.6.0"
xmlbuilder "~11.0.0"
xml2js@~0.1.14:
version "0.1.14"
resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.1.14.tgz#5274e67f5a64c5f92974cd85139e0332adc6b90c"
integrity sha1-UnTmf1pkxfkpdM2FE54DMq3GuQw=
dependencies:
sax ">=0.1.1"
xmlbuilder@~11.0.0:
version "11.0.1"
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3"