fix testnet

pull/2290/head
Audric Ackermann 3 years ago
parent d948045e6a
commit 9bd8b73a0c
No known key found for this signature in database
GPG Key ID: 999F434D76324AD4

@ -212,15 +212,9 @@ window.ReactDOM = require('react-dom');
window.clipboard = clipboard; window.clipboard = clipboard;
window.getSeedNodeList = () => [ window.getSeedNodeList = () => [
{ 'https://storage.seed1.loki.network:4433/',
url: 'https://storage.seed1.loki.network:4433/', 'https://storage.seed3.loki.network:4433/',
}, 'https://public.loki.foundation:4433/',
{
url: 'https://storage.seed3.loki.network:4433/',
},
{
url: 'https://public.loki.foundation:4433/',
},
]; ];
const { locale: localFromEnv } = config; const { locale: localFromEnv } = config;

@ -1250,7 +1250,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
public async setIsApproved(value: boolean, shouldCommit: boolean = true) { public async setIsApproved(value: boolean, shouldCommit: boolean = true) {
if (value !== this.isApproved()) { if (value !== this.isApproved()) {
window?.log?.info(`Setting ${this.attributes.profileName} isApproved to:: ${value}`); window?.log?.info(`Setting ${ed25519Str(this.attributes.id)} isApproved to: ${value}`);
this.set({ this.set({
isApproved: value, isApproved: value,
}); });
@ -1263,7 +1263,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
public async setDidApproveMe(value: boolean, shouldCommit: boolean = true) { public async setDidApproveMe(value: boolean, shouldCommit: boolean = true) {
if (value !== this.didApproveMe()) { if (value !== this.didApproveMe()) {
window?.log?.info(`Setting ${this.attributes.profileName} didApproveMe to:: ${value}`); window?.log?.info(`Setting ${ed25519Str(this.attributes.id)} didApproveMe to: ${value}`);
this.set({ this.set({
didApproveMe: value, didApproveMe: value,
}); });
@ -1751,7 +1751,7 @@ const trotthledAllConversationsDispatch = _.debounce(
updatesToDispatch.clear(); updatesToDispatch.clear();
}, },
2000, 2000,
{ maxWait: 5000, trailing: true } { maxWait: 2000, trailing: true, leading: true }
); );
const updatesToDispatch: Map<string, ReduxConversationType> = new Map(); const updatesToDispatch: Map<string, ReduxConversationType> = new Map();

@ -1181,6 +1181,7 @@ function updateToLokiSchemaVersion17(currentVersion: number, db: BetterSqlite3.D
} }
function dropFtsAndTriggers(db: BetterSqlite3.Database) { function dropFtsAndTriggers(db: BetterSqlite3.Database) {
console.info('dropping fts5 table');
db.exec(` db.exec(`
DROP TRIGGER IF EXISTS messages_on_insert; DROP TRIGGER IF EXISTS messages_on_insert;
DROP TRIGGER IF EXISTS messages_on_delete; DROP TRIGGER IF EXISTS messages_on_delete;
@ -1190,6 +1191,7 @@ function dropFtsAndTriggers(db: BetterSqlite3.Database) {
} }
function rebuildFtsTable(db: BetterSqlite3.Database) { function rebuildFtsTable(db: BetterSqlite3.Database) {
console.info('rebuildFtsTable');
db.exec(` db.exec(`
-- Then we create our full-text search table and populate it -- Then we create our full-text search table and populate it
CREATE VIRTUAL TABLE ${MESSAGES_FTS_TABLE} CREATE VIRTUAL TABLE ${MESSAGES_FTS_TABLE}
@ -1220,6 +1222,7 @@ function rebuildFtsTable(db: BetterSqlite3.Database) {
); );
END; END;
`); `);
console.info('rebuildFtsTable built');
} }
function updateToLokiSchemaVersion18(currentVersion: number, db: BetterSqlite3.Database) { function updateToLokiSchemaVersion18(currentVersion: number, db: BetterSqlite3.Database) {
@ -1380,10 +1383,7 @@ function updateToLokiSchemaVersion23(currentVersion: number, db: BetterSqlite3.D
expiresAt INTEGER, expiresAt INTEGER,
namespace INTEGER NOT NULL DEFAULT 0, namespace INTEGER NOT NULL DEFAULT 0,
PRIMARY KEY (id, snode, namespace) PRIMARY KEY (id, snode, namespace)
); );`
`
); );
db.exec( db.exec(
@ -2891,7 +2891,6 @@ function removeAllAttachmentDownloadJobs() {
function removeAll() { function removeAll() {
assertGlobalInstance().exec(` assertGlobalInstance().exec(`
DELETE FROM ${IDENTITY_KEYS_TABLE}; DELETE FROM ${IDENTITY_KEYS_TABLE};
DELETE FROM ${ITEMS_TABLE}; DELETE FROM ${ITEMS_TABLE};
DELETE FROM unprocessed; DELETE FROM unprocessed;
DELETE FROM ${LAST_HASHES_TABLE}; DELETE FROM ${LAST_HASHES_TABLE};
@ -3417,89 +3416,93 @@ function cleanUpOldOpengroups() {
// first remove very old messages for each opengroups // first remove very old messages for each opengroups
dropFtsAndTriggers(assertGlobalInstance()); assertGlobalInstance().transaction(() => {
v2Convos.forEach(convo => { dropFtsAndTriggers(assertGlobalInstance());
const convoId = convo.id; v2Convos.forEach(convo => {
const messagesInConvoBefore = getMessagesCountByConversation(convoId); const convoId = convo.id;
const messagesInConvoBefore = getMessagesCountByConversation(convoId);
if (messagesInConvoBefore >= maxMessagePerOpengroupConvo) {
const minute = 1000 * 60; if (messagesInConvoBefore >= maxMessagePerOpengroupConvo) {
const sixMonths = minute * 60 * 24 * 30 * 6; const minute = 1000 * 60;
const messagesTimestampToRemove = Date.now() - sixMonths; const sixMonths = minute * 60 * 24 * 30 * 6;
const countToRemove = assertGlobalInstance() const messagesTimestampToRemove = Date.now() - sixMonths;
.prepare( const countToRemove = assertGlobalInstance()
`SELECT count(*) from ${MESSAGES_TABLE} WHERE serverTimestamp <= $serverTimestamp AND conversationId = $conversationId;` .prepare(
) `SELECT count(*) from ${MESSAGES_TABLE} WHERE serverTimestamp <= $serverTimestamp AND conversationId = $conversationId;`
.get({ conversationId: convoId, serverTimestamp: Date.now() - sixMonths })['count(*)']; )
const start = Date.now(); .get({ conversationId: convoId, serverTimestamp: Date.now() - sixMonths })['count(*)'];
const start = Date.now();
assertGlobalInstance()
.prepare( assertGlobalInstance()
` .prepare(
`
DELETE FROM ${MESSAGES_TABLE} WHERE serverTimestamp <= $serverTimestamp AND conversationId = $conversationId` DELETE FROM ${MESSAGES_TABLE} WHERE serverTimestamp <= $serverTimestamp AND conversationId = $conversationId`
) )
.run({ conversationId: convoId, serverTimestamp: messagesTimestampToRemove }); // delete messages older than sixMonths .run({ conversationId: convoId, serverTimestamp: messagesTimestampToRemove }); // delete messages older than sixMonths
const messagesInConvoAfter = getMessagesCountByConversation(convoId); const messagesInConvoAfter = getMessagesCountByConversation(convoId);
console.info( console.info(
`Cleaning ${countToRemove} messages older than 6 months in public convo: ${convoId} took ${Date.now() - `Cleaning ${countToRemove} messages older than 6 months in public convo: ${convoId} took ${Date.now() -
start}ms. Old message count: ${messagesInConvoBefore}, new message count: ${messagesInConvoAfter}` start}ms. Old message count: ${messagesInConvoBefore}, new message count: ${messagesInConvoAfter}`
); );
const unreadCount = getUnreadCountByConversation(convoId); const unreadCount = getUnreadCountByConversation(convoId);
const convoProps = getConversationById(convoId); const convoProps = getConversationById(convoId);
if (convoProps) { if (convoProps) {
convoProps.unreadCount = unreadCount; convoProps.unreadCount = unreadCount;
updateConversation(convoProps); updateConversation(convoProps);
}
} }
} });
});
// now, we might have a bunch of private conversation, without any interaction and no messages // now, we might have a bunch of private conversation, without any interaction and no messages
// those are the conversation of the old members in the opengroups we just cleaned. // those are the conversation of the old members in the opengroups we just cleaned.
const allInactiveConvos = assertGlobalInstance() const allInactiveConvos = assertGlobalInstance()
.prepare( .prepare(
` `
SELECT id FROM ${CONVERSATIONS_TABLE} WHERE type = 'private' AND (active_at IS NULL OR active_at = 0)` SELECT id FROM ${CONVERSATIONS_TABLE} WHERE type = 'private' AND (active_at IS NULL OR active_at = 0)`
) )
.all(); .all();
const ourNumber = getItemById('number_id');
if (!ourNumber || !ourNumber.value) {
return;
}
const ourPubkey = ourNumber.value.split('.')[0];
const allInactiveAndWithoutMessagesConvo = allInactiveConvos const ourNumber = getItemById('number_id');
.map(c => c.id as string) if (!ourNumber || !ourNumber.value) {
.filter(convoId => { return;
return convoId !== ourPubkey && getMessagesCountBySender({ source: convoId }) === 0 }
? true const ourPubkey = ourNumber.value.split('.')[0];
: false;
}); const allInactiveAndWithoutMessagesConvo = allInactiveConvos
if (allInactiveAndWithoutMessagesConvo.length) { .map(c => c.id as string)
console.info( .filter(convoId => {
`Removing ${allInactiveAndWithoutMessagesConvo.length} completely inactive convos` return convoId !== ourPubkey && getMessagesCountBySender({ source: convoId }) === 0
); ? true
const start = Date.now(); : false;
});
if (allInactiveAndWithoutMessagesConvo.length) {
console.info(
`Removing ${allInactiveAndWithoutMessagesConvo.length} completely inactive convos`
);
const start = Date.now();
const chunks = chunk(allInactiveAndWithoutMessagesConvo, 500); const chunks = chunk(allInactiveAndWithoutMessagesConvo, 500);
chunks.forEach(ch => { chunks.forEach(ch => {
assertGlobalInstance() assertGlobalInstance()
.prepare(`DELETE FROM ${CONVERSATIONS_TABLE} WHERE id IN (${ch.map(() => '?').join(',')});`) .prepare(
.run(ch); `DELETE FROM ${CONVERSATIONS_TABLE} WHERE id IN (${ch.map(() => '?').join(',')});`
}); )
.run(ch);
});
console.info( console.info(
`Removing of ${ `Removing of ${
allInactiveAndWithoutMessagesConvo.length allInactiveAndWithoutMessagesConvo.length
} completely inactive convos done in ${Date.now() - start}ms` } completely inactive convos done in ${Date.now() - start}ms`
); );
} }
cleanUpMessagesJson(); cleanUpMessagesJson();
rebuildFtsTable(assertGlobalInstance()); rebuildFtsTable(assertGlobalInstance());
});
} }
// tslint:disable: binary-expression-operand-order insecure-random // tslint:disable: binary-expression-operand-order insecure-random

@ -14,17 +14,13 @@ import { ipcRenderer } from 'electron';
// tslint:disable: function-name // tslint:disable: function-name
export type SeedNode = {
url: string;
};
/** /**
* Fetch all snodes from seed nodes. * Fetch all snodes from seed nodes.
* Exported only for tests. This is not to be used by the app directly * Exported only for tests. This is not to be used by the app directly
* @param seedNodes the seednodes to use to fetch snodes details * @param seedNodes the seednodes to use to fetch snodes details
*/ */
export async function fetchSnodePoolFromSeedNodeWithRetries( export async function fetchSnodePoolFromSeedNodeWithRetries(
seedNodes: Array<SeedNode> seedNodes: Array<string>
): Promise<Array<Data.Snode>> { ): Promise<Array<Data.Snode>> {
try { try {
window?.log?.info(`fetchSnodePoolFromSeedNode with seedNodes.length ${seedNodes.length}`); window?.log?.info(`fetchSnodePoolFromSeedNode with seedNodes.length ${seedNodes.length}`);
@ -148,7 +144,7 @@ export interface SnodeFromSeed {
* If all attempts fails, this function will throw the last error. * If all attempts fails, this function will throw the last error.
* The returned list is not shuffled when returned. * The returned list is not shuffled when returned.
*/ */
async function getSnodeListFromSeednode(seedNodes: Array<SeedNode>): Promise<Array<SnodeFromSeed>> { async function getSnodeListFromSeednode(seedNodes: Array<string>): Promise<Array<SnodeFromSeed>> {
const SEED_NODE_RETRIES = 4; const SEED_NODE_RETRIES = 4;
return pRetry( return pRetry(
@ -185,7 +181,7 @@ export function getMinTimeout() {
* This function is to be used with a pRetry caller * This function is to be used with a pRetry caller
*/ */
export async function TEST_fetchSnodePoolFromSeedNodeRetryable( export async function TEST_fetchSnodePoolFromSeedNodeRetryable(
seedNodes: Array<SeedNode> seedNodes: Array<string>
): Promise<Array<SnodeFromSeed>> { ): Promise<Array<SnodeFromSeed>> {
window?.log?.info('fetchSnodePoolFromSeedNodeRetryable starting...'); window?.log?.info('fetchSnodePoolFromSeedNodeRetryable starting...');
@ -194,8 +190,8 @@ export async function TEST_fetchSnodePoolFromSeedNodeRetryable(
throw new Error('fetchSnodePoolFromSeedNodeRetryable: Seed nodes are empty'); throw new Error('fetchSnodePoolFromSeedNodeRetryable: Seed nodes are empty');
} }
const seedNode = _.sample(seedNodes); const seedNodeUrl = _.sample(seedNodes);
if (!seedNode) { if (!seedNodeUrl) {
window?.log?.warn( window?.log?.warn(
'loki_snode_api::fetchSnodePoolFromSeedNodeRetryable - Could not select random snodes from', 'loki_snode_api::fetchSnodePoolFromSeedNodeRetryable - Could not select random snodes from',
seedNodes seedNodes
@ -203,14 +199,14 @@ export async function TEST_fetchSnodePoolFromSeedNodeRetryable(
throw new Error('fetchSnodePoolFromSeedNodeRetryable: Seed nodes are empty #2'); throw new Error('fetchSnodePoolFromSeedNodeRetryable: Seed nodes are empty #2');
} }
const tryUrl = new URL(seedNode.url); const tryUrl = new URL(seedNodeUrl);
const snodes = await getSnodesFromSeedUrl(tryUrl); const snodes = await getSnodesFromSeedUrl(tryUrl);
if (snodes.length === 0) { if (snodes.length === 0) {
window?.log?.warn( window?.log?.warn(
`loki_snode_api::fetchSnodePoolFromSeedNodeRetryable - ${seedNode.url} did not return any snodes` `loki_snode_api::fetchSnodePoolFromSeedNodeRetryable - ${seedNodeUrl} did not return any snodes`
); );
throw new Error(`Failed to contact seed node: ${seedNode.url}`); throw new Error(`Failed to contact seed node: ${seedNodeUrl}`);
} }
return snodes; return snodes;

@ -66,6 +66,7 @@ export type SendParams = {
data: string; data: string;
isSyncMessage?: boolean; isSyncMessage?: boolean;
messageId?: string; messageId?: string;
namespace: number;
}; };
/** /**
@ -438,6 +439,7 @@ export async function storeOnNode(
try { try {
const parsed = JSON.parse(result.body); const parsed = JSON.parse(result.body);
handleTimestampOffset('store', parsed.t); handleTimestampOffset('store', parsed.t);
await handleHardforkResult(parsed);
const messageHash = parsed.hash; const messageHash = parsed.hash;
if (messageHash) { if (messageHash) {
@ -505,12 +507,12 @@ export async function retrieveNextMessages(
targetNode: Snode, targetNode: Snode,
lastHash: string, lastHash: string,
associatedWith: string, associatedWith: string,
namespace: number namespace?: number
): Promise<Array<any>> { ): Promise<Array<any>> {
const params: RetrieveRequestParams = { const params: RetrieveRequestParams = {
pubKey: associatedWith, pubKey: associatedWith,
lastHash: lastHash || '', lastHash: lastHash || '',
namespace: namespace || 0, namespace,
}; };
const signatureParams = (await getRetrieveSignatureParams(params)) || {}; const signatureParams = (await getRetrieveSignatureParams(params)) || {};

@ -9,6 +9,7 @@ import { ed25519Str } from '../../onions/onionPath';
import { OnionPaths } from '../../onions'; import { OnionPaths } from '../../onions';
import { Onions, SnodePool } from '.'; import { Onions, SnodePool } from '.';
import { SeedNodeAPI } from '../seed_node_api'; import { SeedNodeAPI } from '../seed_node_api';
import { useTestNet } from '../../types';
/** /**
* If we get less than this snode in a swarm, we fetch new snodes for this pubkey * If we get less than this snode in a swarm, we fetch new snodes for this pubkey
*/ */
@ -179,7 +180,8 @@ export async function getRandomSnodePool(): Promise<Array<Data.Snode>> {
*/ */
// tslint:disable: function-name // tslint:disable: function-name
export async function TEST_fetchFromSeedWithRetriesAndWriteToDb() { export async function TEST_fetchFromSeedWithRetriesAndWriteToDb() {
const seedNodes = window.getSeedNodeList(); // tslint:disable-next-line: no-http-string
const seedNodes = useTestNet ? ['http://public.loki.foundation:38157'] : window.getSeedNodeList();
if (!seedNodes || !seedNodes.length) { if (!seedNodes || !seedNodes.length) {
window?.log?.error( window?.log?.error(

@ -163,17 +163,16 @@ export class SwarmPolling {
?.idForLogging() || group.pubkey.key; ?.idForLogging() || group.pubkey.key;
if (diff >= convoPollingTimeout) { if (diff >= convoPollingTimeout) {
window?.log?.info(
`Polling for ${loggingId}; timeout: ${convoPollingTimeout} ; diff: ${diff}`
);
const hardfork190Happened = await getHasSeenHF190(); const hardfork190Happened = await getHasSeenHF190();
const hardfork191Happened = await getHasSeenHF191(); const hardfork191Happened = await getHasSeenHF191();
window?.log?.info(
`Polling for ${loggingId}; timeout: ${convoPollingTimeout}; diff: ${diff} ; hardfork190Happened: ${hardfork190Happened}; hardfork191Happened: ${hardfork191Happened} `
);
if (hardfork190Happened && !hardfork191Happened) { if (hardfork190Happened && !hardfork191Happened) {
// during the transition period, we poll from both namespaces (0 and -10) for groups // during the transition period, we poll from both namespaces (0 and -10) for groups
return Promise.all([ return Promise.all([
this.pollOnceForKey(group.pubkey, true, 0), this.pollOnceForKey(group.pubkey, true, undefined),
this.pollOnceForKey(group.pubkey, true, -10), this.pollOnceForKey(group.pubkey, true, -10),
]).then(() => undefined); ]).then(() => undefined);
} }
@ -184,7 +183,6 @@ export class SwarmPolling {
} }
// before any of those hardforks, we just poll from the default namespace being 0 // before any of those hardforks, we just poll from the default namespace being 0
console.warn('before any of those hardforks');
return this.pollOnceForKey(group.pubkey, true, 0); return this.pollOnceForKey(group.pubkey, true, 0);
} }
window?.log?.info( window?.log?.info(
@ -206,7 +204,7 @@ export class SwarmPolling {
/** /**
* Only exposed as public for testing * Only exposed as public for testing
*/ */
public async pollOnceForKey(pubkey: PubKey, isGroup: boolean, namespace: number) { public async pollOnceForKey(pubkey: PubKey, isGroup: boolean, namespace?: number) {
const pkStr = pubkey.key; const pkStr = pubkey.key;
const swarmSnodes = await snodePool.getSwarmFor(pkStr); const swarmSnodes = await snodePool.getSwarmFor(pkStr);
@ -290,7 +288,7 @@ export class SwarmPolling {
private async pollNodeForKey( private async pollNodeForKey(
node: Snode, node: Snode,
pubkey: PubKey, pubkey: PubKey,
namespace: number namespace?: number
): Promise<Array<any> | null> { ): Promise<Array<any> | null> {
const edkey = node.pubkey_ed25519; const edkey = node.pubkey_ed25519;
@ -299,7 +297,7 @@ export class SwarmPolling {
try { try {
return await pRetry( return await pRetry(
async () => { async () => {
const prevHash = await this.getLastHash(edkey, pkStr, namespace); const prevHash = await this.getLastHash(edkey, pkStr, namespace || 0);
const messages = await retrieveNextMessages(node, prevHash, pkStr, namespace); const messages = await retrieveNextMessages(node, prevHash, pkStr, namespace);
if (!messages.length) { if (!messages.length) {
return []; return [];
@ -310,7 +308,7 @@ export class SwarmPolling {
await this.updateLastHash({ await this.updateLastHash({
edkey: edkey, edkey: edkey,
pubkey, pubkey,
namespace, namespace: namespace || 0,
hash: lastMessage.hash, hash: lastMessage.hash,
expiration: lastMessage.expiration, expiration: lastMessage.expiration,
}); });

@ -276,7 +276,7 @@ async function internalUpdateGuardNodes(updatedGuardNodes: Array<Data.Snode>) {
await Data.updateGuardNodes(edKeys); await Data.updateGuardNodes(edKeys);
} }
export async function TEST_testGuardNode(snode: Data.Snode) { export async function testGuardNode(snode: Data.Snode) {
window?.log?.info(`Testing a candidate guard node ${ed25519Str(snode.pubkey_ed25519)}`); window?.log?.info(`Testing a candidate guard node ${ed25519Str(snode.pubkey_ed25519)}`);
// Send a post request and make sure it is OK // Send a post request and make sure it is OK
@ -381,7 +381,7 @@ export async function selectGuardNodes(): Promise<Array<Data.Snode>> {
// Test all three nodes at once, wait for all to resolve or reject // Test all three nodes at once, wait for all to resolve or reject
// eslint-disable-next-line no-await-in-loop // eslint-disable-next-line no-await-in-loop
const idxOk = ( const idxOk = (
await Promise.allSettled(candidateNodes.map(OnionPaths.TEST_testGuardNode)) await Promise.allSettled(candidateNodes.map(OnionPaths.testGuardNode))
).flatMap(p => (p.status === 'fulfilled' ? p.value : null)); ).flatMap(p => (p.status === 'fulfilled' ? p.value : null));
const goodNodes = _.zip(idxOk, candidateNodes) const goodNodes = _.zip(idxOk, candidateNodes)

@ -22,6 +22,7 @@ import { getConversationController } from '../conversations';
import { ed25519Str } from '../onions/onionPath'; import { ed25519Str } from '../onions/onionPath';
import { EmptySwarmError } from '../utils/errors'; import { EmptySwarmError } from '../utils/errors';
import ByteBuffer from 'bytebuffer'; import ByteBuffer from 'bytebuffer';
import { getHasSeenHF190, getHasSeenHF191 } from '../apis/snode_api/hfHandling';
const DEFAULT_CONNECTIONS = 1; const DEFAULT_CONNECTIONS = 1;
@ -137,29 +138,34 @@ export async function sendMessageToSnode(
const data64 = ByteBuffer.wrap(data).toString('base64'); const data64 = ByteBuffer.wrap(data).toString('base64');
const swarm = await getSwarmFor(pubKey); const swarm = await getSwarmFor(pubKey);
const conversation = getConversationController().get(pubKey);
const isClosedGroup = conversation?.isClosedGroup();
const hardfork190Happened = await getHasSeenHF190();
const hardfork191Happened = await getHasSeenHF191();
const namespace = isClosedGroup ? -10 : 0;
window?.log?.debug( window?.log?.debug(
'Sending envelope with timestamp: ', `Sending envelope with timestamp: ${timestamp} to ${ed25519Str(pubKey)} size base64: ${
timestamp, data64.length
' to ', }; hardfork190Happened:${hardfork190Happened}; hardfork191Happened:${hardfork191Happened} to namespace:${namespace}`
ed25519Str(pubKey),
' size base64:',
data64.length
); );
// send parameters // send parameters
const params = { const params = {
pubKey, pubKey,
ttl: `${ttl}`, ttl: `${ttl}`,
timestamp: `${timestamp}`, timestamp: `${timestamp}`,
data: data64, data: data64,
isSyncMessage, isSyncMessage, // I don't think that's of any use
messageId, messageId, // I don't think that's of any use
namespace,
}; };
const usedNodes = _.slice(swarm, 0, DEFAULT_CONNECTIONS); const usedNodes = _.slice(swarm, 0, DEFAULT_CONNECTIONS);
let successfulSendHash: any; let successfulSendHash: any;
const promises = usedNodes.map(async usedNode => { const promises = usedNodes.map(async usedNode => {
// TODO: Revert back to using snode address instead of IP
// No pRetry here as if this is a bad path it will be handled and retried in lokiOnionFetch. // No pRetry here as if this is a bad path it will be handled and retried in lokiOnionFetch.
// the only case we could care about a retry would be when the usedNode is not correct, // the only case we could care about a retry would be when the usedNode is not correct,
// but considering we trigger this request with a few snode in //, this should be fine. // but considering we trigger this request with a few snode in //, this should be fine.
@ -189,9 +195,6 @@ export async function sendMessageToSnode(
throw new EmptySwarmError(pubKey, 'Ran out of swarm nodes to query'); throw new EmptySwarmError(pubKey, 'Ran out of swarm nodes to query');
} }
const conversation = getConversationController().get(pubKey);
const isClosedGroup = conversation?.isClosedGroup();
// If message also has a sync message, save that hash. Otherwise save the hash from the regular message send i.e. only closed groups in this case. // If message also has a sync message, save that hash. Otherwise save the hash from the regular message send i.e. only closed groups in this case.
if (messageId && (isSyncMessage || isClosedGroup)) { if (messageId && (isSyncMessage || isClosedGroup)) {
const message = await getMessageById(messageId); const message = await getMessageById(messageId);

@ -1,7 +1,8 @@
import { fromHexToArray } from '../utils/String'; import { fromHexToArray } from '../utils/String';
export const getStoragePubKey = (key: string) => export const useTestNet = process.env.NODE_APP_INSTANCE?.includes('testnet');
window.isDev?.() || false ? key.substring(2) : key;
export const getStoragePubKey = (key: string) => (useTestNet ? key.substring(2) : key);
export class PubKey { export class PubKey {
public static readonly PUBKEY_LEN = 66; public static readonly PUBKEY_LEN = 66;

@ -63,7 +63,7 @@ describe('GuardNodes', () => {
SnodePool, SnodePool,
'TEST_fetchFromSeedWithRetriesAndWriteToDb' 'TEST_fetchFromSeedWithRetriesAndWriteToDb'
).resolves(); ).resolves();
const testGuardNode = Sinon.stub(OnionPaths, 'TEST_testGuardNode').resolves(true); const testGuardNode = Sinon.stub(OnionPaths, 'testGuardNode').resolves(true);
Sinon.stub(Data, 'updateGuardNodes').resolves(); Sinon.stub(Data, 'updateGuardNodes').resolves();
// run the command // run the command
@ -98,7 +98,7 @@ describe('GuardNodes', () => {
SnodePool, SnodePool,
'TEST_fetchFromSeedWithRetriesAndWriteToDb' 'TEST_fetchFromSeedWithRetriesAndWriteToDb'
).resolves(); ).resolves();
const testGuardNode = Sinon.stub(OnionPaths, 'TEST_testGuardNode').resolves(false); const testGuardNode = Sinon.stub(OnionPaths, 'testGuardNode').resolves(false);
Sinon.stub(Data, 'updateGuardNodes').resolves(); Sinon.stub(Data, 'updateGuardNodes').resolves();
// run the command // run the command
@ -154,7 +154,7 @@ describe('GuardNodes', () => {
const invalidSndodePool = fakeSnodePool.slice(0, 11); const invalidSndodePool = fakeSnodePool.slice(0, 11);
Sinon.stub(Data, 'getSnodePoolFromDb').resolves(invalidSndodePool); Sinon.stub(Data, 'getSnodePoolFromDb').resolves(invalidSndodePool);
TestUtils.stubWindow('getSeedNodeList', () => [{ url: 'whatever' }]); TestUtils.stubWindow('getSeedNodeList', () => [{ url: 'whatever' }]);
const testGuardNode = Sinon.stub(OnionPaths, 'TEST_testGuardNode').resolves(true); const testGuardNode = Sinon.stub(OnionPaths, 'testGuardNode').resolves(true);
getSnodePoolFromDBOrFetchFromSeed = Sinon.stub( getSnodePoolFromDBOrFetchFromSeed = Sinon.stub(
SnodePool, SnodePool,

@ -74,9 +74,7 @@ describe('SeedNodeAPI', () => {
Sinon.stub(SeedNodeAPI, 'getMinTimeout').returns(20); Sinon.stub(SeedNodeAPI, 'getMinTimeout').returns(20);
// run the command // run the command
const fetched = await SeedNodeAPI.fetchSnodePoolFromSeedNodeWithRetries([ const fetched = await SeedNodeAPI.fetchSnodePoolFromSeedNodeWithRetries(['seednode1']);
{ url: 'seednode1' },
]);
const sortedFetch = fetched.sort((a, b) => (a.pubkey_ed25519 > b.pubkey_ed25519 ? -1 : 1)); const sortedFetch = fetched.sort((a, b) => (a.pubkey_ed25519 > b.pubkey_ed25519 ? -1 : 1));
const sortedFakeSnodePool = fakeSnodePool.sort((a, b) => const sortedFakeSnodePool = fakeSnodePool.sort((a, b) =>

@ -231,7 +231,7 @@ describe('SwarmPolling', () => {
// our pubkey will be polled for, hence the 2 // our pubkey will be polled for, hence the 2
expect(pollOnceForKeySpy.callCount).to.eq(3); expect(pollOnceForKeySpy.callCount).to.eq(3);
expect(pollOnceForKeySpy.firstCall.args).to.deep.eq([ourPubkey, false, 0]); expect(pollOnceForKeySpy.firstCall.args).to.deep.eq([ourPubkey, false, 0]);
expect(pollOnceForKeySpy.secondCall.args).to.deep.eq([groupConvoPubkey, true, 0]); expect(pollOnceForKeySpy.secondCall.args).to.deep.eq([groupConvoPubkey, true, undefined]);
expect(pollOnceForKeySpy.thirdCall.args).to.deep.eq([groupConvoPubkey, true, -10]); expect(pollOnceForKeySpy.thirdCall.args).to.deep.eq([groupConvoPubkey, true, -10]);
getItemByIdStub.restore(); getItemByIdStub.restore();
getItemByIdStub = TestUtils.stubDataItem('getItemById'); getItemByIdStub = TestUtils.stubDataItem('getItemById');

@ -5,7 +5,7 @@
async function sign(key: any, data: any) { async function sign(key: any, data: any) {
return crypto.subtle return crypto.subtle
.importKey('raw', key, { name: 'HMAC', hash: { name: 'SHA-256' } }, false, ['sign']) .importKey('raw', key, { name: 'HMAC', hash: { name: 'SHA-256' } }, false, ['sign'])
.then(async function(secondKey: any) { .then(async function(secondKey) {
return crypto.subtle.sign({ name: 'HMAC', hash: 'SHA-256' }, secondKey, data); return crypto.subtle.sign({ name: 'HMAC', hash: 'SHA-256' }, secondKey, data);
}); });
} }
@ -13,14 +13,14 @@ async function sign(key: any, data: any) {
async function encrypt(key: any, data: any, iv: any) { async function encrypt(key: any, data: any, iv: any) {
return crypto.subtle return crypto.subtle
.importKey('raw', key, { name: 'AES-CBC' }, false, ['encrypt']) .importKey('raw', key, { name: 'AES-CBC' }, false, ['encrypt'])
.then(async function(secondKey: any) { .then(async function(secondKey) {
return crypto.subtle.encrypt({ name: 'AES-CBC', iv: new Uint8Array(iv) }, secondKey, data); return crypto.subtle.encrypt({ name: 'AES-CBC', iv: new Uint8Array(iv) }, secondKey, data);
}); });
} }
async function decrypt(key: any, data: any, iv: any) { async function decrypt(key: any, data: any, iv: any) {
return crypto.subtle return crypto.subtle
.importKey('raw', key, { name: 'AES-CBC' }, false, ['decrypt']) .importKey('raw', key, { name: 'AES-CBC' }, false, ['decrypt'])
.then(async function(secondKey: any) { .then(async function(secondKey) {
return crypto.subtle.decrypt({ name: 'AES-CBC', iv: new Uint8Array(iv) }, secondKey, data); return crypto.subtle.decrypt({ name: 'AES-CBC', iv: new Uint8Array(iv) }, secondKey, data);
}); });
} }

2
ts/window.d.ts vendored

@ -42,7 +42,7 @@ declare global {
onLogin: any; onLogin: any;
persistStore?: Persistor; persistStore?: Persistor;
restart: any; restart: any;
getSeedNodeList: () => Array<any> | undefined; getSeedNodeList: () => Array<string> | undefined;
setPassword: any; setPassword: any;
storage: any; storage: any;
isOnline: boolean; isOnline: boolean;

Loading…
Cancel
Save