Merge branch 'development' into clearnet

pull/300/head
Beaudan 6 years ago
commit 52c191fc94

@ -5,6 +5,7 @@
"contentProxyUrl": "random.snode", "contentProxyUrl": "random.snode",
"localServerPort": "8081", "localServerPort": "8081",
"snodeServerPort": "8080", "snodeServerPort": "8080",
"defaultPoWDifficulty": "100",
"disableAutoUpdate": false, "disableAutoUpdate": false,
"updatesUrl": "https://updates2.signal.org/desktop", "updatesUrl": "https://updates2.signal.org/desktop",
"updatesPublicKey": "updatesPublicKey":

@ -233,6 +233,11 @@
window.libloki.api.sendOnlineBroadcastMessage(pubKey, isPing); window.libloki.api.sendOnlineBroadcastMessage(pubKey, isPing);
}); });
const currentPoWDifficulty = storage.get('PoWDifficulty', null);
if (!currentPoWDifficulty) {
storage.put('PoWDifficulty', window.getDefaultPoWDifficulty());
}
// These make key operations available to IPC handlers created in preload.js // These make key operations available to IPC handlers created in preload.js
window.Events = { window.Events = {
getDeviceName: () => textsecure.storage.user.getDeviceName(), getDeviceName: () => textsecure.storage.user.getDeviceName(),

@ -31,10 +31,10 @@ const filterIncomingMessages = async messages => {
}; };
const calcNonce = (messageEventData, pubKey, data64, timestamp, ttl) => { const calcNonce = (messageEventData, pubKey, data64, timestamp, ttl) => {
const difficulty = window.storage.get('PoWDifficulty', null);
// Nonce is returned as a base64 string to include in header // Nonce is returned as a base64 string to include in header
window.Whisper.events.trigger('calculatingPoW', messageEventData); window.Whisper.events.trigger('calculatingPoW', messageEventData);
const development = window.getEnvironment() !== 'production'; return callWorker('calcPoW', timestamp, ttl, pubKey, data64, difficulty);
return callWorker('calcPoW', timestamp, ttl, pubKey, data64, development);
}; };
const trySendP2p = async (pubKey, data64, isPing, messageEventData) => { const trySendP2p = async (pubKey, data64, isPing, messageEventData) => {
@ -124,7 +124,17 @@ class LokiMessageAPI {
promises.push(this.openSendConnection(params)); promises.push(this.openSendConnection(params));
} }
const results = await Promise.all(promises); let results;
try {
results = await Promise.all(promises);
} catch (e) {
if (e instanceof textsecure.WrongDifficultyError) {
// Force nonce recalculation
this.sendMessage(pubKey, data, messageTimeStamp, ttl, options);
return;
}
throw e;
}
delete this.sendingSwarmNodes[timestamp]; delete this.sendingSwarmNodes[timestamp];
if (results.every(value => value === false)) { if (results.every(value => value === false)) {
throw new window.textsecure.EmptySwarmError( throw new window.textsecure.EmptySwarmError(
@ -155,7 +165,19 @@ class LokiMessageAPI {
while (successiveFailures < 3) { while (successiveFailures < 3) {
await sleepFor(successiveFailures * 500); await sleepFor(successiveFailures * 500);
try { try {
await rpc(`https://${url}`, this.snodeServerPort, 'store', params); const result = await rpc(
`https://${url}`,
this.snodeServerPort,
'store',
params
);
// Make sure we aren't doing too much PoW
const currentDifficulty = window.storage.get('PoWDifficulty', null);
const newDifficulty = result.difficulty;
if (newDifficulty != null && newDifficulty !== currentDifficulty) {
window.storage.put('PoWDifficulty', newDifficulty);
}
return true; return true;
} catch (e) { } catch (e) {
log.warn('Loki send message:', e); log.warn('Loki send message:', e);
@ -164,6 +186,12 @@ class LokiMessageAPI {
await lokiSnodeAPI.updateSwarmNodes(params.pubKey, newSwarm); await lokiSnodeAPI.updateSwarmNodes(params.pubKey, newSwarm);
this.sendingSwarmNodes[params.timestamp] = newSwarm; this.sendingSwarmNodes[params.timestamp] = newSwarm;
return false; return false;
} else if (e instanceof textsecure.WrongDifficultyError) {
const { newDifficulty } = e;
if (!Number.isNaN(newDifficulty)) {
window.storage.put('PoWDifficulty', newDifficulty);
}
throw e;
} else if (e instanceof textsecure.NotFoundError) { } else if (e instanceof textsecure.NotFoundError) {
// TODO: Handle resolution error // TODO: Handle resolution error
successiveFailures += 1; successiveFailures += 1;

@ -6,6 +6,21 @@ const { parse } = require('url');
const LOKI_EPHEMKEY_HEADER = 'X-Loki-EphemKey'; const LOKI_EPHEMKEY_HEADER = 'X-Loki-EphemKey';
const endpointBase = '/v1/storage_rpc'; const endpointBase = '/v1/storage_rpc';
const decryptResponse = async (response, address) => {
try {
const ciphertext = await response.text();
const plaintext = await libloki.crypto.snodeCipher.decrypt(
address,
ciphertext
);
const result = plaintext === '' ? {} : JSON.parse(plaintext);
return result;
} catch (e) {
log.warn(`Could not decrypt response from ${address}`, e);
}
return {};
};
// A small wrapper around node-fetch which deserializes response // A small wrapper around node-fetch which deserializes response
const fetch = async (url, options = {}) => { const fetch = async (url, options = {}) => {
const timeout = options.timeout || 10000; const timeout = options.timeout || 10000;
@ -39,49 +54,41 @@ const fetch = async (url, options = {}) => {
method, method,
}); });
let result;
// Wrong swarm
if (response.status === 421) { if (response.status === 421) {
let newSwarm = await response.text();
if (doEncryptChannel) { if (doEncryptChannel) {
try { result = decryptResponse(response, address);
newSwarm = await libloki.crypto.snodeCipher.decrypt( } else {
address, result = await response.json();
newSwarm
);
} catch (e) {
log.warn(`Could not decrypt response from ${address}`, e);
}
try {
newSwarm = newSwarm === '' ? {} : JSON.parse(newSwarm);
} catch (e) {
log.warn(`Could not parse string to json ${newSwarm}`, e);
}
} }
const newSwarm = result.snodes ? result.snodes : [];
throw new textsecure.WrongSwarmError(newSwarm); throw new textsecure.WrongSwarmError(newSwarm);
} }
// Wrong PoW difficulty
if (response.status === 432) {
if (doEncryptChannel) {
result = decryptResponse(response, address);
} else {
result = await response.json();
}
const { difficulty } = result;
throw new textsecure.WrongDifficultyError(difficulty);
}
if (!response.ok) { if (!response.ok) {
throw new textsecure.HTTPError('Loki_rpc error', response); throw new textsecure.HTTPError('Loki_rpc error', response);
} }
let result;
if (response.headers.get('Content-Type') === 'application/json') { if (response.headers.get('Content-Type') === 'application/json') {
result = await response.json(); result = await response.json();
} else if (options.responseType === 'arraybuffer') { } else if (options.responseType === 'arraybuffer') {
result = await response.buffer(); result = await response.buffer();
} else if (doEncryptChannel) {
result = decryptResponse(response, address);
} else { } else {
result = await response.text(); result = await response.text();
if (doEncryptChannel) {
try {
result = await libloki.crypto.snodeCipher.decrypt(address, result);
} catch (e) {
log.warn(`Could not decrypt response from ${address}`, e);
}
try {
result = result === '' ? {} : JSON.parse(result);
} catch (e) {
log.warn(`Could not parse string to json ${result}`, e);
}
}
} }
return result; return result;

@ -47,7 +47,7 @@ function calcPoW(
pubKey, pubKey,
data, data,
development, development,
nonceTrials = undefined, difficulty = undefined,
increment = 1, increment = 1,
startNonce = 0 startNonce = 0
) { ) {
@ -57,7 +57,7 @@ function calcPoW(
pubKey, pubKey,
data, data,
development, development,
nonceTrials, difficulty,
increment, increment,
startNonce startNonce
); );

@ -1,8 +1,7 @@
/* global dcodeIO, crypto, JSBI */ /* global dcodeIO, crypto, JSBI */
const NONCE_LEN = 8; const NONCE_LEN = 8;
// Modify this value for difficulty scaling // Modify this value for difficulty scaling
const DEV_NONCE_TRIALS = 10; const FALLBACK_DIFFICULTY = 10;
const PROD_NONCE_TRIALS = 100;
const pow = { const pow = {
// Increment Uint8Array nonce by '_increment' with carrying // Increment Uint8Array nonce by '_increment' with carrying
@ -62,8 +61,7 @@ const pow = {
ttl, ttl,
pubKey, pubKey,
data, data,
development = false, _difficulty = null,
_nonceTrials = null,
increment = 1, increment = 1,
startNonce = 0 startNonce = 0
) { ) {
@ -74,9 +72,8 @@ const pow = {
).toArrayBuffer() ).toArrayBuffer()
); );
const nonceTrials = const difficulty = _difficulty || FALLBACK_DIFFICULTY;
_nonceTrials || (development ? DEV_NONCE_TRIALS : PROD_NONCE_TRIALS); const target = pow.calcTarget(ttl, payload.length, difficulty);
const target = pow.calcTarget(ttl, payload.length, nonceTrials);
let nonce = new Uint8Array(NONCE_LEN); let nonce = new Uint8Array(NONCE_LEN);
nonce = pow.incrementNonce(nonce, startNonce); // initial value nonce = pow.incrementNonce(nonce, startNonce); // initial value
@ -103,7 +100,7 @@ const pow = {
return pow.bufferToBase64(nonce); return pow.bufferToBase64(nonce);
}, },
calcTarget(ttl, payloadLen, nonceTrials = PROD_NONCE_TRIALS) { calcTarget(ttl, payloadLen, difficulty = FALLBACK_DIFFICULTY) {
// payloadLength + NONCE_LEN // payloadLength + NONCE_LEN
const totalLen = JSBI.add(JSBI.BigInt(payloadLen), JSBI.BigInt(NONCE_LEN)); const totalLen = JSBI.add(JSBI.BigInt(payloadLen), JSBI.BigInt(NONCE_LEN));
// ttl converted to seconds // ttl converted to seconds
@ -119,9 +116,9 @@ const pow = {
const innerFrac = JSBI.divide(ttlMult, two16); const innerFrac = JSBI.divide(ttlMult, two16);
// totalLen + innerFrac // totalLen + innerFrac
const lenPlusInnerFrac = JSBI.add(totalLen, innerFrac); const lenPlusInnerFrac = JSBI.add(totalLen, innerFrac);
// nonceTrials * lenPlusInnerFrac // difficulty * lenPlusInnerFrac
const denominator = JSBI.multiply( const denominator = JSBI.multiply(
JSBI.BigInt(nonceTrials), JSBI.BigInt(difficulty),
lenPlusInnerFrac lenPlusInnerFrac
); );
// 2^64 - 1 // 2^64 - 1

@ -3,7 +3,7 @@ let jobId = 0;
let currentTrace = 0; let currentTrace = 0;
let plotlyDiv; let plotlyDiv;
const workers = []; const workers = [];
async function run(messageLength, numWorkers = 1, nonceTrials = 100, ttl = 72) { async function run(messageLength, numWorkers = 1, difficulty = 100, ttl = 72) {
const timestamp = Math.floor(Date.now() / 1000); const timestamp = Math.floor(Date.now() / 1000);
const pubKey = const pubKey =
'05ec8635a07a13743516c7c9b3412f3e8252efb7fcaf67eb1615ffba62bebc6802'; '05ec8635a07a13743516c7c9b3412f3e8252efb7fcaf67eb1615ffba62bebc6802';
@ -29,7 +29,7 @@ async function run(messageLength, numWorkers = 1, nonceTrials = 100, ttl = 72) {
pubKey, pubKey,
data, data,
false, false,
nonceTrials, difficulty,
increment, increment,
index, index,
]); ]);
@ -50,12 +50,12 @@ async function run(messageLength, numWorkers = 1, nonceTrials = 100, ttl = 72) {
async function runPoW({ async function runPoW({
iteration, iteration,
nonceTrials, difficulty,
numWorkers, numWorkers,
messageLength = 50, messageLength = 50,
ttl = 72, ttl = 72,
}) { }) {
const name = `W:${numWorkers} - NT: ${nonceTrials} - L:${messageLength} - TTL:${ttl}`; const name = `W:${numWorkers} - NT: ${difficulty} - L:${messageLength} - TTL:${ttl}`;
Plotly.addTraces(plotlyDiv, { Plotly.addTraces(plotlyDiv, {
y: [], y: [],
type: 'box', type: 'box',
@ -64,7 +64,7 @@ async function runPoW({
}); });
for (let i = 0; i < iteration; i += 1) { for (let i = 0; i < iteration; i += 1) {
// eslint-disable-next-line no-await-in-loop // eslint-disable-next-line no-await-in-loop
await run(messageLength, numWorkers, nonceTrials, ttl); await run(messageLength, numWorkers, difficulty, ttl);
} }
currentTrace += 1; currentTrace += 1;
@ -86,9 +86,7 @@ function addPoint(duration) {
} }
async function startMessageLengthRun() { async function startMessageLengthRun() {
const iteration0 = parseFloat(document.getElementById('iteration0').value); const iteration0 = parseFloat(document.getElementById('iteration0').value);
const nonceTrials0 = parseFloat( const difficulty0 = parseFloat(document.getElementById('difficulty0').value);
document.getElementById('nonceTrials0').value
);
const numWorkers0 = parseFloat(document.getElementById('numWorkers0').value); const numWorkers0 = parseFloat(document.getElementById('numWorkers0').value);
const messageLengthStart0 = parseFloat( const messageLengthStart0 = parseFloat(
document.getElementById('messageLengthStart0').value document.getElementById('messageLengthStart0').value
@ -108,7 +106,7 @@ async function startMessageLengthRun() {
// eslint-disable-next-line no-await-in-loop // eslint-disable-next-line no-await-in-loop
await runPoW({ await runPoW({
iteration: iteration0, iteration: iteration0,
nonceTrials: nonceTrials0, difficulty: difficulty0,
numWorkers: numWorkers0, numWorkers: numWorkers0,
messageLength: l, messageLength: l,
ttl: TTL0, ttl: TTL0,
@ -117,9 +115,7 @@ async function startMessageLengthRun() {
} }
async function startNumWorkerRun() { async function startNumWorkerRun() {
const iteration1 = parseFloat(document.getElementById('iteration1').value); const iteration1 = parseFloat(document.getElementById('iteration1').value);
const nonceTrials1 = parseFloat( const difficulty1 = parseFloat(document.getElementById('difficulty1').value);
document.getElementById('nonceTrials1').value
);
const numWorkersStart1 = parseFloat( const numWorkersStart1 = parseFloat(
document.getElementById('numWorkersStart1').value document.getElementById('numWorkersStart1').value
); );
@ -138,34 +134,34 @@ async function startNumWorkerRun() {
// eslint-disable-next-line no-await-in-loop // eslint-disable-next-line no-await-in-loop
await runPoW({ await runPoW({
iteration: iteration1, iteration: iteration1,
nonceTrials: nonceTrials1, difficulty: difficulty1,
numWorkers, numWorkers,
messageLength: messageLength1, messageLength: messageLength1,
ttl: TTL1, ttl: TTL1,
}); });
} }
} }
async function startNonceTrialsRun() { async function startDifficultyRun() {
const iteration2 = parseFloat(document.getElementById('iteration2').value); const iteration2 = parseFloat(document.getElementById('iteration2').value);
const messageLength2 = parseFloat( const messageLength2 = parseFloat(
document.getElementById('messageLength2').value document.getElementById('messageLength2').value
); );
const numWorkers2 = parseFloat(document.getElementById('numWorkers2').value); const numWorkers2 = parseFloat(document.getElementById('numWorkers2').value);
const nonceTrialsStart2 = parseFloat( const difficultyStart2 = parseFloat(
document.getElementById('nonceTrialsStart2').value document.getElementById('difficultyStart2').value
); );
const nonceTrialsStop2 = parseFloat( const difficultyStop2 = parseFloat(
document.getElementById('nonceTrialsStop2').value document.getElementById('difficultyStop2').value
); );
const nonceTrialsStep2 = parseFloat( const difficultyStep2 = parseFloat(
document.getElementById('nonceTrialsStep2').value document.getElementById('difficultyStep2').value
); );
const TTL2 = parseFloat(document.getElementById('TTL2').value); const TTL2 = parseFloat(document.getElementById('TTL2').value);
for (let n = nonceTrialsStart2; n < nonceTrialsStop2; n += nonceTrialsStep2) { for (let n = difficultyStart2; n < difficultyStop2; n += difficultyStep2) {
// eslint-disable-next-line no-await-in-loop // eslint-disable-next-line no-await-in-loop
await runPoW({ await runPoW({
iteration: iteration2, iteration: iteration2,
nonceTrials: n, difficulty: n,
numWorkers: numWorkers2, numWorkers: numWorkers2,
messageLength: messageLength2, messageLength: messageLength2,
ttl: TTL2, ttl: TTL2,
@ -174,9 +170,7 @@ async function startNonceTrialsRun() {
} }
async function starTTLRun() { async function starTTLRun() {
const iteration3 = parseFloat(document.getElementById('iteration3').value); const iteration3 = parseFloat(document.getElementById('iteration3').value);
const nonceTrials3 = parseFloat( const difficulty3 = parseFloat(document.getElementById('difficulty3').value);
document.getElementById('nonceTrials3').value
);
const messageLength3 = parseFloat( const messageLength3 = parseFloat(
document.getElementById('messageLength3').value document.getElementById('messageLength3').value
); );
@ -188,7 +182,7 @@ async function starTTLRun() {
// eslint-disable-next-line no-await-in-loop // eslint-disable-next-line no-await-in-loop
await runPoW({ await runPoW({
iteration: iteration3, iteration: iteration3,
nonceTrials: nonceTrials3, difficulty: difficulty3,
numWorkers: numWorkers3, numWorkers: numWorkers3,
messageLength: messageLength3, messageLength: messageLength3,
ttl, ttl,
@ -216,7 +210,7 @@ async function start(index) {
await startNumWorkerRun(); await startNumWorkerRun();
break; break;
case 2: case 2:
await startNonceTrialsRun(); await startDifficultyRun();
break; break;
case 3: case 3:
await starTTLRun(); await starTTLRun();

@ -222,6 +222,19 @@
} }
} }
function WrongDifficultyError(newDifficulty) {
this.name = 'WrongDifficultyError';
this.newDifficulty = newDifficulty;
Error.call(this, this.name);
// 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);
}
}
window.textsecure.UnregisteredUserError = UnregisteredUserError; window.textsecure.UnregisteredUserError = UnregisteredUserError;
window.textsecure.SendMessageNetworkError = SendMessageNetworkError; window.textsecure.SendMessageNetworkError = SendMessageNetworkError;
window.textsecure.IncomingIdentityKeyError = IncomingIdentityKeyError; window.textsecure.IncomingIdentityKeyError = IncomingIdentityKeyError;
@ -237,4 +250,5 @@
window.textsecure.HTTPError = HTTPError; window.textsecure.HTTPError = HTTPError;
window.textsecure.NotFoundError = NotFoundError; window.textsecure.NotFoundError = NotFoundError;
window.textsecure.WrongSwarmError = WrongSwarmError; window.textsecure.WrongSwarmError = WrongSwarmError;
window.textsecure.WrongDifficultyError = WrongDifficultyError;
})(); })();

@ -156,6 +156,7 @@ function prepareURL(pathSegments, moreKeys) {
cdnUrl: config.get('cdnUrl'), cdnUrl: config.get('cdnUrl'),
snodeServerPort: config.get('snodeServerPort'), snodeServerPort: config.get('snodeServerPort'),
localServerPort: config.get('localServerPort'), localServerPort: config.get('localServerPort'),
defaultPoWDifficulty: config.get('defaultPoWDifficulty'),
certificateAuthority: config.get('certificateAuthority'), certificateAuthority: config.get('certificateAuthority'),
environment: config.environment, environment: config.environment,
node_version: process.versions.node, node_version: process.versions.node,

@ -22,6 +22,7 @@ if (config.appInstance) {
} }
window.platform = process.platform; window.platform = process.platform;
window.getDefaultPoWDifficulty = () => config.defaultPoWDifficulty;
window.getTitle = () => title; window.getTitle = () => title;
window.getEnvironment = () => config.environment; window.getEnvironment = () => config.environment;
window.getAppInstance = () => config.appInstance; window.getAppInstance = () => config.appInstance;

Loading…
Cancel
Save