diff --git a/.eslintrc.js b/.eslintrc.js index 5b34cf3daef88cc6d2b7852f38c91afc7449b1ee..a01420ef15c8e8b86c1a42faae6a5a993cc5cf1c 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -46,11 +46,7 @@ module.exports = { // Use LF to stay consistent 'linebreak-style': ['error', 'unix'], - quotes: [ - 'error', - 'single', - { avoidEscape: true, allowTemplateLiterals: true }, - ], + quotes: ['error', 'single', { avoidEscape: true, allowTemplateLiterals: true }], // Prettier overrides: 'arrow-parens': 'off', diff --git a/.prettierrc.js b/.prettierrc.js index 600afb3bfab86f56a8c6423dee76b75e3fd2e603..e65203501c8359b1ca42d3c09faf802965bc76d0 100644 --- a/.prettierrc.js +++ b/.prettierrc.js @@ -3,4 +3,5 @@ module.exports = { trailingComma: 'es5', bracketSpacing: true, arrowParens: 'avoid', + printWidth: 100, }; diff --git a/Gruntfile.js b/Gruntfile.js index 9f396ff45a916d99d067c99f970179cb61a74773..25552a2f537ab78c775ae4b064c52b4b53a990ec 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -59,11 +59,7 @@ module.exports = grunt => { dest: 'libloki/test/components.js', }, test: { - src: [ - 'node_modules/mocha/mocha.js', - 'node_modules/chai/chai.js', - 'test/_test.js', - ], + src: ['node_modules/mocha/mocha.js', 'node_modules/chai/chai.js', 'test/_test.js'], dest: 'test/test.js', }, // TODO: Move errors back down? @@ -90,19 +86,11 @@ module.exports = grunt => { dest: 'js/libtextsecure.js', }, libloki: { - src: [ - 'libloki/crypto.js', - 'libloki/service_nodes.js', - 'libloki/storage.js', - ], + src: ['libloki/crypto.js', 'libloki/service_nodes.js', 'libloki/storage.js'], dest: 'js/libloki.js', }, lokitest: { - src: [ - 'node_modules/mocha/mocha.js', - 'node_modules/chai/chai.js', - 'libloki/test/_test.js', - ], + src: ['node_modules/mocha/mocha.js', 'node_modules/chai/chai.js', 'libloki/test/_test.js'], dest: 'libloki/test/test.js', }, libtextsecuretest: { @@ -155,12 +143,7 @@ module.exports = grunt => { tasks: ['sass'], }, transpile: { - files: [ - './ts/**/*.ts', - './ts/**/*.tsx', - './ts/**/**/*.tsx', - './test/ts/**.ts', - ], + files: ['./ts/**/*.ts', './ts/**/*.tsx', './ts/**/**/*.tsx', './test/ts/**.ts'], tasks: ['exec:transpile'], }, }, @@ -222,10 +205,7 @@ module.exports = grunt => { // eslint-disable-next-line no-restricted-syntax for (const key in messages) { if (en[key] !== undefined && messages[key] !== undefined) { - if ( - en[key].placeholders !== undefined && - messages[key].placeholders === undefined - ) { + if (en[key].placeholders !== undefined && messages[key].placeholders === undefined) { messages[key].placeholders = en[key].placeholders; } } @@ -274,8 +254,7 @@ module.exports = grunt => { function runTests(environment, cb) { let failure; const { Application } = spectron; - const electronBinary = - process.platform === 'win32' ? 'electron.cmd' : 'electron'; + const electronBinary = process.platform === 'win32' ? 'electron.cmd' : 'electron'; const app = new Application({ path: path.join(__dirname, 'node_modules', '.bin', electronBinary), args: [path.join(__dirname, 'main.js')], @@ -284,9 +263,7 @@ module.exports = grunt => { }, requireName: 'unused', chromeDriverArgs: [ - `remote-debugging-port=${Math.floor( - Math.random() * (9999 - 9000) + 9000 - )}`, + `remote-debugging-port=${Math.floor(Math.random() * (9999 - 9000) + 9000)}`, ], }); @@ -299,10 +276,7 @@ module.exports = grunt => { .start() .then(() => app.client.waitUntil( - () => - app.client - .execute(getMochaResults) - .then(data => Boolean(data.value)), + () => app.client.execute(getMochaResults).then(data => Boolean(data.value)), 25000, 'Expected to find window.mochaResults set!' ) @@ -312,8 +286,7 @@ module.exports = grunt => { const results = data.value; if (results.failures > 0) { console.error(results.reports); - failure = () => - grunt.fail.fatal(`Found ${results.failures} failing unit tests.`); + failure = () => grunt.fail.fatal(`Found ${results.failures} failing unit tests.`); return app.client.log('browser'); } grunt.log.ok(`${results.passes} tests passed.`); @@ -327,10 +300,7 @@ module.exports = grunt => { } }) .catch(error => { - failure = () => - grunt.fail.fatal( - `Something went wrong: ${error.message} ${error.stack}` - ); + failure = () => grunt.fail.fatal(`Something went wrong: ${error.message} ${error.stack}`); }) .then(() => { // We need to use the failure variable and this early stop to clean up before @@ -371,16 +341,12 @@ module.exports = grunt => { }); } - grunt.registerTask( - 'unit-tests', - 'Run unit tests w/Electron', - function thisNeeded() { - const environment = grunt.option('env') || 'test'; - const done = this.async(); + grunt.registerTask('unit-tests', 'Run unit tests w/Electron', function thisNeeded() { + const environment = grunt.option('env') || 'test'; + const done = this.async(); - runTests(environment, done); - } - ); + runTests(environment, done); + }); grunt.registerTask( 'lib-unit-tests', @@ -393,117 +359,97 @@ module.exports = grunt => { } ); - grunt.registerTask( - 'loki-unit-tests', - 'Run loki unit tests w/Electron', - function thisNeeded() { - const environment = grunt.option('env') || 'test-loki'; - const done = this.async(); + grunt.registerTask('loki-unit-tests', 'Run loki unit tests w/Electron', function thisNeeded() { + const environment = grunt.option('env') || 'test-loki'; + const done = this.async(); - runTests(environment, done); - } - ); + runTests(environment, done); + }); - grunt.registerMultiTask( - 'test-release', - 'Test packaged releases', - function thisNeeded() { - const dir = grunt.option('dir') || 'release'; - const environment = grunt.option('env') || 'production'; - const config = this.data; - const archive = [dir, config.archive].join('/'); - const files = [ - 'config/default.json', - `config/${environment}.json`, - `config/local-${environment}.json`, - ]; + grunt.registerMultiTask('test-release', 'Test packaged releases', function thisNeeded() { + const dir = grunt.option('dir') || 'release'; + const environment = grunt.option('env') || 'production'; + const config = this.data; + const archive = [dir, config.archive].join('/'); + const files = [ + 'config/default.json', + `config/${environment}.json`, + `config/local-${environment}.json`, + ]; - console.log(this.target, archive); - const releaseFiles = files.concat(config.files || []); - releaseFiles.forEach(fileName => { - console.log(fileName); - try { - asar.statFile(archive, fileName); - return true; - } catch (e) { - console.log(e); - throw new Error(`Missing file ${fileName}`); - } - }); + console.log(this.target, archive); + const releaseFiles = files.concat(config.files || []); + releaseFiles.forEach(fileName => { + console.log(fileName); + try { + asar.statFile(archive, fileName); + return true; + } catch (e) { + console.log(e); + throw new Error(`Missing file ${fileName}`); + } + }); - if (config.appUpdateYML) { - const appUpdateYML = [dir, config.appUpdateYML].join('/'); - if (fs.existsSync(appUpdateYML)) { - console.log('auto update ok'); - } else { - throw new Error(`Missing auto update config ${appUpdateYML}`); - } + if (config.appUpdateYML) { + const appUpdateYML = [dir, config.appUpdateYML].join('/'); + if (fs.existsSync(appUpdateYML)) { + console.log('auto update ok'); + } else { + throw new Error(`Missing auto update config ${appUpdateYML}`); } + } - const done = this.async(); - // A simple test to verify a visible window is opened with a title - const { Application } = spectron; + const done = this.async(); + // A simple test to verify a visible window is opened with a title + const { Application } = spectron; - const app = new Application({ - path: [dir, config.exe].join('/'), - requireName: 'unused', - chromeDriverArgs: [ - `remote-debugging-port=${Math.floor( - Math.random() * (9999 - 9000) + 9000 - )}`, - ], - }); + const app = new Application({ + path: [dir, config.exe].join('/'), + requireName: 'unused', + chromeDriverArgs: [ + `remote-debugging-port=${Math.floor(Math.random() * (9999 - 9000) + 9000)}`, + ], + }); - app - .start() - .then(() => app.client.getWindowCount()) - .then(count => { - assert.equal(count, 1); - console.log('window opened'); - }) - .then(() => - // Get the window's title - app.client.getTitle() - ) - .then(title => { - // TODO: restore once fixed on win - if (this.target !== 'win') { - // Verify the window's title - assert.equal(title, packageJson.productName); - console.log('title ok'); - } - }) - .then(() => { - assert( - app.chromeDriver.logLines.indexOf(`NODE_ENV ${environment}`) > -1 - ); - console.log('environment ok'); - }) - .then( - () => - // Successfully completed test - app.stop(), - error => - // Test failed! - app.stop().then(() => { - grunt.fail.fatal(`Test failed: ${error.message} ${error.stack}`); - }) - ) - .then(done); - } - ); + app + .start() + .then(() => app.client.getWindowCount()) + .then(count => { + assert.equal(count, 1); + console.log('window opened'); + }) + .then(() => + // Get the window's title + app.client.getTitle() + ) + .then(title => { + // TODO: restore once fixed on win + if (this.target !== 'win') { + // Verify the window's title + assert.equal(title, packageJson.productName); + console.log('title ok'); + } + }) + .then(() => { + assert(app.chromeDriver.logLines.indexOf(`NODE_ENV ${environment}`) > -1); + console.log('environment ok'); + }) + .then( + () => + // Successfully completed test + app.stop(), + error => + // Test failed! + app.stop().then(() => { + grunt.fail.fatal(`Test failed: ${error.message} ${error.stack}`); + }) + ) + .then(done); + }); - grunt.registerTask('tx', [ - 'exec:tx-pull-new', - 'exec:tx-pull', - 'locale-patch', - ]); + grunt.registerTask('tx', ['exec:tx-pull-new', 'exec:tx-pull', 'locale-patch']); grunt.registerTask('dev', ['default', 'watch']); - grunt.registerTask('test', [ - 'unit-tests', - 'lib-unit-tests', - 'loki-unit-tests', - ]); + grunt.registerTask('test', ['unit-tests', 'lib-unit-tests', 'loki-unit-tests']); grunt.registerTask('date', ['gitinfo', 'getExpireTime']); grunt.registerTask('default', [ 'exec:build-protobuf', diff --git a/app/base_config.d.ts b/app/base_config.d.ts index 3aec7c6076629202a937a4a278809d75311eff66..55c0a3614e0865647478e56ce9308e84ad90e59a 100644 --- a/app/base_config.d.ts +++ b/app/base_config.d.ts @@ -8,8 +8,4 @@ interface Options { allowMalformedOnStartup: boolean; } -export function start( - name: string, - targetPath: string, - options: Options -): BaseConfig; +export function start(name: string, targetPath: string, options: Options): BaseConfig; diff --git a/app/base_config.js b/app/base_config.js index be6096ec3e16811f7d3195f5ec2a6243220561fa..b67cd20beb9c13141c071302bd84f8eab2d9ae02 100644 --- a/app/base_config.js +++ b/app/base_config.js @@ -18,9 +18,7 @@ function start(name, targetPath, options = {}) { console.log(`config/get: Successfully read ${name} config file`); if (!cachedValue) { - console.log( - `config/get: ${name} config value was falsy, cache is now empty object` - ); + console.log(`config/get: ${name} config value was falsy, cache is now empty object`); cachedValue = Object.create(null); } } catch (error) { @@ -28,9 +26,7 @@ function start(name, targetPath, options = {}) { throw error; } - console.log( - `config/get: Did not find ${name} config file, cache is now empty object` - ); + console.log(`config/get: Did not find ${name} config file, cache is now empty object`); cachedValue = Object.create(null); } diff --git a/app/config.js b/app/config.js index 4419147fd2d297495b96060db1b9d6a704939b78..695dce47f15683469d404b484eda279458d7d9b5 100644 --- a/app/config.js +++ b/app/config.js @@ -36,10 +36,8 @@ const config = require('config'); config.environment = environment; // Log resulting env vars in use by config -['NODE_ENV', 'NODE_APP_INSTANCE', 'NODE_CONFIG_DIR', 'NODE_CONFIG'].forEach( - s => { - console.log(`${s} ${config.util.getEnv(s)}`); - } -); +['NODE_ENV', 'NODE_APP_INSTANCE', 'NODE_CONFIG_DIR', 'NODE_CONFIG'].forEach(s => { + console.log(`${s} ${config.util.getEnv(s)}`); +}); module.exports = config; diff --git a/app/locale.js b/app/locale.js index ddf80159e8ef4098357888bc09e8527c041e1674..35a908ec562b2713e1571525f455ac62fa9a2d71 100644 --- a/app/locale.js +++ b/app/locale.js @@ -13,13 +13,7 @@ function normalizeLocaleName(locale) { function getLocaleMessages(locale) { const onDiskLocale = locale.replace('-', '_'); - const targetFile = path.join( - __dirname, - '..', - '_locales', - onDiskLocale, - 'messages.json' - ); + const targetFile = path.join(__dirname, '..', '_locales', onDiskLocale, 'messages.json'); return JSON.parse(fs.readFileSync(targetFile, 'utf-8')); } @@ -49,9 +43,7 @@ function load({ appLocale, logger } = {}) { // We start with english, then overwrite that with anything present in locale messages = _.merge(english, messages); } catch (e) { - logger.error( - `Problem loading messages for locale ${localeName} ${e.stack}` - ); + logger.error(`Problem loading messages for locale ${localeName} ${e.stack}`); logger.error('Falling back to en locale'); localeName = 'en'; diff --git a/app/logging.js b/app/logging.js index 7897b28791a43a4378117e96b317b04126a6be60..720c187b6ee4c369bc5596183669c8b5a9bd93a5 100644 --- a/app/logging.js +++ b/app/logging.js @@ -120,10 +120,7 @@ async function cleanupLogs(logPath) { await eliminateOldEntries(files, earliestDate); } catch (error) { - console.error( - 'Error cleaning logs; deleting and starting over from scratch.', - error.stack - ); + console.error('Error cleaning logs; deleting and starting over from scratch.', error.stack); // delete and re-create the log directory await deleteAllLogs(logPath); @@ -151,26 +148,24 @@ function eliminateOutOfDateFiles(logPath, date) { return Promise.all( _.map(paths, target => - Promise.all([readFirstLine(target), readLastLines(target, 2)]).then( - results => { - const start = results[0]; - const end = results[1].split('\n'); - - const file = { - path: target, - start: isLineAfterDate(start, date), - end: - isLineAfterDate(end[end.length - 1], date) || - isLineAfterDate(end[end.length - 2], date), - }; - - if (!file.start && !file.end) { - fs.unlinkSync(file.path); - } - - return file; + Promise.all([readFirstLine(target), readLastLines(target, 2)]).then(results => { + const start = results[0]; + const end = results[1].split('\n'); + + const file = { + path: target, + start: isLineAfterDate(start, date), + end: + isLineAfterDate(end[end.length - 1], date) || + isLineAfterDate(end[end.length - 2], date), + }; + + if (!file.start && !file.end) { + fs.unlinkSync(file.path); } - ) + + return file; + }) ) ); } @@ -181,10 +176,7 @@ function eliminateOldEntries(files, date) { return Promise.all( _.map(files, file => fetchLog(file.path).then(lines => { - const recent = _.filter( - lines, - line => new Date(line.time).getTime() >= earliest - ); + const recent = _.filter(lines, line => new Date(line.time).getTime() >= earliest); const text = _.map(recent, line => JSON.stringify(line)).join('\n'); return fs.writeFileSync(file.path, `${text}\n`); diff --git a/app/permissions.js b/app/permissions.js index 20697a33dda58b0e8fa4826ea5ac2a569a029900..e28b8df9c9a81a937f45f984d9118fe30652386d 100644 --- a/app/permissions.js +++ b/app/permissions.js @@ -39,9 +39,7 @@ function installPermissionsHandler({ session, userConfig }) { // they've already been used successfully. session.defaultSession.setPermissionRequestHandler(null); - session.defaultSession.setPermissionRequestHandler( - _createPermissionHandler(userConfig) - ); + session.defaultSession.setPermissionRequestHandler(_createPermissionHandler(userConfig)); } module.exports = { diff --git a/app/protocol_filter.js b/app/protocol_filter.js index a065e61c8a633499bfb41b2183f6b4f912c27606..b128d386e8b55c17f2da2bd7325e4a7bf2a6a227 100644 --- a/app/protocol_filter.js +++ b/app/protocol_filter.js @@ -32,19 +32,13 @@ function _createFileHandler({ userDataPath, installPath, isWindows }) { const properCasing = isWindows ? realPath.toLowerCase() : realPath; if (!path.isAbsolute(realPath)) { - console.log( - `Warning: denying request to non-absolute path '${realPath}'` - ); + console.log(`Warning: denying request to non-absolute path '${realPath}'`); return callback(); } if ( - !properCasing.startsWith( - isWindows ? userDataPath.toLowerCase() : userDataPath - ) && - !properCasing.startsWith( - isWindows ? installPath.toLowerCase() : installPath - ) + !properCasing.startsWith(isWindows ? userDataPath.toLowerCase() : userDataPath) && + !properCasing.startsWith(isWindows ? installPath.toLowerCase() : installPath) ) { console.log( `Warning: denying request to path '${realPath}' (userDataPath: '${userDataPath}', installPath: '${installPath}')` @@ -58,12 +52,7 @@ function _createFileHandler({ userDataPath, installPath, isWindows }) { }; } -function installFileHandler({ - protocol, - userDataPath, - installPath, - isWindows, -}) { +function installFileHandler({ protocol, userDataPath, installPath, isWindows }) { protocol.interceptFileProtocol( 'file', _createFileHandler({ userDataPath, installPath, isWindows }) diff --git a/app/sql.js b/app/sql.js index a930bb3660fbb2d48979e96d57a707d67418099d..3864e0b56ea42a57c82f2a7cb0f5d0c9b4679e2e 100644 --- a/app/sql.js +++ b/app/sql.js @@ -7,15 +7,7 @@ const { redactAll } = require('../js/modules/privacy'); const { remove: removeUserConfig } = require('./user_config'); const pify = require('pify'); -const { - map, - isString, - fromPairs, - forEach, - last, - isEmpty, - isObject, -} = require('lodash'); +const { map, isString, fromPairs, forEach, last, isEmpty, isObject } = require('lodash'); // To get long stack traces // https://github.com/mapbox/node-sqlite3/wiki/API#sqlite3verbose @@ -1113,11 +1105,7 @@ async function updateLokiSchema(instance) { `Current loki schema version: ${lokiSchemaVersion};`, `Most recent schema version: ${LOKI_SCHEMA_VERSIONS.length};` ); - for ( - let index = 0, max = LOKI_SCHEMA_VERSIONS.length; - index < max; - index += 1 - ) { + for (let index = 0, max = LOKI_SCHEMA_VERSIONS.length; index < max; index += 1) { const runSchemaUpdate = LOKI_SCHEMA_VERSIONS[index]; // Yes, we really want to do this asynchronously, in order @@ -1127,9 +1115,7 @@ async function updateLokiSchema(instance) { } async function getLokiSchemaVersion(instance) { - const result = await instance.get( - 'SELECT MAX(version) as version FROM loki_schema;' - ); + const result = await instance.get('SELECT MAX(version) as version FROM loki_schema;'); if (!result || !result.version) { return 0; } @@ -1219,10 +1205,7 @@ async function initialize({ configDir, key, messages, passwordAttempt }) { } console.log('Database startup error:', error.stack); const buttonIndex = dialog.showMessageBox({ - buttons: [ - messages.copyErrorAndQuit.message, - messages.clearAllData.message, - ], + buttons: [messages.copyErrorAndQuit.message, messages.clearAllData.message], defaultId: 0, detail: redactAll(error.stack), message: messages.databaseError.message, @@ -1231,9 +1214,7 @@ async function initialize({ configDir, key, messages, passwordAttempt }) { }); if (buttonIndex === 0) { - clipboard.writeText( - `Database startup error:\n\n${redactAll(error.stack)}` - ); + clipboard.writeText(`Database startup error:\n\n${redactAll(error.stack)}`); } else { await close(); await removeDB(); @@ -1389,12 +1370,9 @@ async function createOrUpdate(table, data, instance) { } async function getById(table, id, instance) { - const row = await (db || instance).get( - `SELECT * FROM ${table} WHERE id = $id;`, - { - $id: id, - } - ); + const row = await (db || instance).get(`SELECT * FROM ${table} WHERE id = $id;`, { + $id: id, + }); if (!row) { return null; @@ -1414,10 +1392,7 @@ async function removeById(table, id) { } // Our node interface doesn't seem to allow you to replace one single ? with an array - await db.run( - `DELETE FROM ${table} WHERE id IN ( ${id.map(() => '?').join(', ')} );`, - id - ); + await db.run(`DELETE FROM ${table} WHERE id IN ( ${id.map(() => '?').join(', ')} );`, id); } async function removeAllFromTable(table) { @@ -1427,12 +1402,9 @@ async function removeAllFromTable(table) { // Conversations async function getSwarmNodesForPubkey(pubkey) { - const row = await db.get( - `SELECT * FROM ${NODES_FOR_PUBKEY_TABLE} WHERE pubkey = $pubkey;`, - { - $pubkey: pubkey, - } - ); + const row = await db.get(`SELECT * FROM ${NODES_FOR_PUBKEY_TABLE} WHERE pubkey = $pubkey;`, { + $pubkey: pubkey, + }); if (!row) { return []; @@ -1463,9 +1435,7 @@ async function getConversationCount() { const row = await db.get(`SELECT count(*) from ${CONVERSATIONS_TABLE};`); if (!row) { - throw new Error( - `getConversationCount: Unable to get count of ${CONVERSATIONS_TABLE}` - ); + throw new Error(`getConversationCount: Unable to get count of ${CONVERSATIONS_TABLE}`); } return row['count(*)']; @@ -1563,9 +1533,7 @@ async function removeConversation(id) { // Our node interface doesn't seem to allow you to replace one single ? with an array await db.run( - `DELETE FROM ${CONVERSATIONS_TABLE} WHERE id IN ( ${id - .map(() => '?') - .join(', ')} );`, + `DELETE FROM ${CONVERSATIONS_TABLE} WHERE id IN ( ${id.map(() => '?').join(', ')} );`, id ); } @@ -1590,12 +1558,9 @@ async function savePublicServerToken(data) { // open groups v1 only async function getPublicServerTokenByServerUrl(serverUrl) { - const row = await db.get( - `SELECT * FROM ${SERVERS_TOKEN_TABLE} WHERE serverUrl = $serverUrl;`, - { - $serverUrl: serverUrl, - } - ); + const row = await db.get(`SELECT * FROM ${SERVERS_TOKEN_TABLE} WHERE serverUrl = $serverUrl;`, { + $serverUrl: serverUrl, + }); if (!row) { return null; @@ -1605,12 +1570,9 @@ async function getPublicServerTokenByServerUrl(serverUrl) { } async function getConversationById(id) { - const row = await db.get( - `SELECT * FROM ${CONVERSATIONS_TABLE} WHERE id = $id;`, - { - $id: id, - } - ); + const row = await db.get(`SELECT * FROM ${CONVERSATIONS_TABLE} WHERE id = $id;`, { + $id: id, + }); if (!row) { return null; @@ -1620,16 +1582,12 @@ async function getConversationById(id) { } async function getAllConversations() { - const rows = await db.all( - `SELECT json FROM ${CONVERSATIONS_TABLE} ORDER BY id ASC;` - ); + const rows = await db.all(`SELECT json FROM ${CONVERSATIONS_TABLE} ORDER BY id ASC;`); return map(rows, row => jsonToObject(row.json)); } async function getAllConversationIds() { - const rows = await db.all( - `SELECT id FROM ${CONVERSATIONS_TABLE} ORDER BY id ASC;` - ); + const rows = await db.all(`SELECT id FROM ${CONVERSATIONS_TABLE} ORDER BY id ASC;`); return map(rows, row => row.id); } @@ -1715,11 +1673,7 @@ async function searchMessages(query, { limit } = {}) { })); } -async function searchMessagesInConversation( - query, - conversationId, - { limit } = {} -) { +async function searchMessagesInConversation(query, conversationId, { limit } = {}) { const rows = await db.all( `SELECT messages.json, @@ -1748,9 +1702,7 @@ async function getMessageCount() { const row = await db.get(`SELECT count(*) from ${MESSAGES_TABLE};`); if (!row) { - throw new Error( - `getMessageCount: Unable to get count of ${MESSAGES_TABLE}` - ); + throw new Error(`getMessageCount: Unable to get count of ${MESSAGES_TABLE}`); } return row['count(*)']; @@ -1962,9 +1914,7 @@ async function removeMessage(id) { // Our node interface doesn't seem to allow you to replace one single ? with an array await db.run( - `DELETE FROM ${MESSAGES_TABLE} WHERE id IN ( ${id - .map(() => '?') - .join(', ')} );`, + `DELETE FROM ${MESSAGES_TABLE} WHERE id IN ( ${id.map(() => '?').join(', ')} );`, id ); } @@ -1975,9 +1925,7 @@ async function getMessageIdsFromServerIds(serverIds, conversationId) { } // Sanitize the input as we're going to use it directly in the query - const validIds = serverIds - .map(id => Number(id)) - .filter(n => !Number.isNaN(n)); + const validIds = serverIds.map(id => Number(id)).filter(n => !Number.isNaN(n)); /* Sqlite3 doesn't have a good way to have `IN` query with another query. @@ -2009,16 +1957,12 @@ async function getMessageById(id) { } async function getAllMessages() { - const rows = await db.all( - `SELECT json FROM ${MESSAGES_TABLE} ORDER BY id ASC;` - ); + const rows = await db.all(`SELECT json FROM ${MESSAGES_TABLE} ORDER BY id ASC;`); return map(rows, row => jsonToObject(row.json)); } async function getAllMessageIds() { - const rows = await db.all( - `SELECT id FROM ${MESSAGES_TABLE} ORDER BY id ASC;` - ); + const rows = await db.all(`SELECT id FROM ${MESSAGES_TABLE} ORDER BY id ASC;`); return map(rows, row => row.id); } @@ -2115,13 +2059,10 @@ async function getMessagesBySentAt(sentAt) { } async function getLastHashBySnode(convoId, snode) { - const row = await db.get( - 'SELECT * FROM lastHashes WHERE snode = $snode AND id = $id;', - { - $snode: snode, - $id: convoId, - } - ); + const row = await db.get('SELECT * FROM lastHashes WHERE snode = $snode AND id = $id;', { + $snode: snode, + $id: convoId, + }); if (!row) { return null; @@ -2132,9 +2073,7 @@ async function getLastHashBySnode(convoId, snode) { async function getSeenMessagesByHashList(hashes) { const rows = await db.all( - `SELECT * FROM seenMessages WHERE hash IN ( ${hashes - .map(() => '?') - .join(', ')} );`, + `SELECT * FROM seenMessages WHERE hash IN ( ${hashes.map(() => '?').join(', ')} );`, hashes ); @@ -2224,13 +2163,7 @@ async function updateUnprocessedAttempts(id, attempts) { }); } async function updateUnprocessedWithData(id, data = {}) { - const { - source, - sourceDevice, - serverTimestamp, - decrypted, - senderIdentity, - } = data; + const { source, sourceDevice, serverTimestamp, decrypted, senderIdentity } = data; await db.run( `UPDATE unprocessed SET @@ -2270,9 +2203,7 @@ async function getUnprocessedCount() { } async function getAllUnprocessed() { - const rows = await db.all( - 'SELECT * FROM unprocessed ORDER BY timestamp ASC;' - ); + const rows = await db.all('SELECT * FROM unprocessed ORDER BY timestamp ASC;'); return rows; } @@ -2288,10 +2219,7 @@ async function removeUnprocessed(id) { } // Our node interface doesn't seem to allow you to replace one single ? with an array - await db.run( - `DELETE FROM unprocessed WHERE id IN ( ${id.map(() => '?').join(', ')} );`, - id - ); + await db.run(`DELETE FROM unprocessed WHERE id IN ( ${id.map(() => '?').join(', ')} );`, id); } async function removeAllUnprocessed() { @@ -2318,9 +2246,7 @@ async function getNextAttachmentDownloadJobs(limit, options = {}) { async function saveAttachmentDownloadJob(job) { const { id, pending, timestamp } = job; if (!id) { - throw new Error( - 'saveAttachmentDownloadJob: Provided job did not have a truthy id' - ); + throw new Error('saveAttachmentDownloadJob: Provided job did not have a truthy id'); } await db.run( @@ -2344,18 +2270,13 @@ async function saveAttachmentDownloadJob(job) { ); } async function setAttachmentDownloadJobPending(id, pending) { - await db.run( - 'UPDATE attachment_downloads SET pending = $pending WHERE id = $id;', - { - $id: id, - $pending: pending, - } - ); + await db.run('UPDATE attachment_downloads SET pending = $pending WHERE id = $id;', { + $id: id, + $pending: pending, + }); } async function resetAttachmentDownloadPending() { - await db.run( - 'UPDATE attachment_downloads SET pending = 0 WHERE pending != 0;' - ); + await db.run('UPDATE attachment_downloads SET pending = 0 WHERE pending != 0;'); } async function removeAttachmentDownloadJob(id) { return removeById(ATTACHMENT_DOWNLOADS_TABLE, id); @@ -2400,10 +2321,7 @@ async function removeAllConversations() { await removeAllFromTable(CONVERSATIONS_TABLE); } -async function getMessagesWithVisualMediaAttachments( - conversationId, - { limit } -) { +async function getMessagesWithVisualMediaAttachments(conversationId, { limit }) { const rows = await db.all( `SELECT json FROM ${MESSAGES_TABLE} WHERE conversationId = $conversationId AND @@ -2507,9 +2425,7 @@ async function removeKnownAttachments(allAttachments) { const chunkSize = 50; const total = await getMessageCount(); - console.log( - `removeKnownAttachments: About to iterate through ${total} messages` - ); + console.log(`removeKnownAttachments: About to iterate through ${total} messages`); let count = 0; let complete = false; @@ -2626,28 +2542,19 @@ async function removePrefixFromGroupConversations(instance) { ); // We have another conversation with the same future name. // We decided to keep only the conversation with the higher number of messages - const countMessagesOld = await getMessagesCountByConversation( - instance, - oldId, - { limit: Number.MAX_VALUE } - ); - const countMessagesNew = await getMessagesCountByConversation( - instance, - newId, - { limit: Number.MAX_VALUE } - ); + const countMessagesOld = await getMessagesCountByConversation(instance, oldId, { + limit: Number.MAX_VALUE, + }); + const countMessagesNew = await getMessagesCountByConversation(instance, newId, { + limit: Number.MAX_VALUE, + }); - console.log( - `countMessagesOld: ${countMessagesOld}, countMessagesNew: ${countMessagesNew}` - ); + console.log(`countMessagesOld: ${countMessagesOld}, countMessagesNew: ${countMessagesNew}`); const deleteId = countMessagesOld > countMessagesNew ? newId : oldId; - await instance.run( - `DELETE FROM ${CONVERSATIONS_TABLE} WHERE id = $id;`, - { - $id: deleteId, - } - ); + await instance.run(`DELETE FROM ${CONVERSATIONS_TABLE} WHERE id = $id;`, { + $id: deleteId, + }); } const morphedObject = { @@ -2703,8 +2610,7 @@ function remove05PrefixFromStringIfNeeded(str) { async function updateExistingClosedGroupToClosedGroup(instance) { // the migration is called only once, so all current groups not being open groups are v1 closed group. - const allClosedGroupV1 = - (await getAllClosedGroupConversations(instance)) || []; + const allClosedGroupV1 = (await getAllClosedGroupConversations(instance)) || []; await Promise.all( allClosedGroupV1.map(async groupV1 => { @@ -2751,9 +2657,7 @@ async function getAllEncryptionKeyPairsForGroup(groupPublicKey) { } async function getAllEncryptionKeyPairsForGroupRaw(groupPublicKey) { - const pubkeyAsString = groupPublicKey.key - ? groupPublicKey.key - : groupPublicKey; + const pubkeyAsString = groupPublicKey.key ? groupPublicKey.key : groupPublicKey; const rows = await db.all( `SELECT * FROM ${CLOSED_GROUP_V2_KEY_PAIRS_TABLE} WHERE groupPublicKey = $groupPublicKey ORDER BY timestamp ASC;`, { @@ -2772,11 +2676,7 @@ async function getLatestClosedGroupEncryptionKeyPair(groupPublicKey) { return rows[rows.length - 1]; } -async function addClosedGroupEncryptionKeyPair( - groupPublicKey, - keypair, - instance -) { +async function addClosedGroupEncryptionKeyPair(groupPublicKey, keypair, instance) { const timestamp = Date.now(); await (db || instance).run( @@ -2803,9 +2703,7 @@ async function isKeyPairAlreadySaved( ) { const allKeyPairs = await getAllEncryptionKeyPairsForGroup(groupPublicKey); return (allKeyPairs || []).some( - k => - newKeyPairInHex.publicHex === k.publicHex && - newKeyPairInHex.privateHex === k.privateHex + k => newKeyPairInHex.publicHex === k.publicHex && newKeyPairInHex.privateHex === k.privateHex ); } @@ -2882,10 +2780,7 @@ async function saveV2OpenGroupRoom(opengroupsv2Room) { } async function removeV2OpenGroupRoom(conversationId) { - await db.run( - `DELETE FROM ${OPEN_GROUP_ROOMS_V2_TABLE} WHERE conversationId = $conversationId`, - { - $conversationId: conversationId, - } - ); + await db.run(`DELETE FROM ${OPEN_GROUP_ROOMS_V2_TABLE} WHERE conversationId = $conversationId`, { + $conversationId: conversationId, + }); } diff --git a/app/sql_channel.js b/app/sql_channel.js index f4b99ecea5cf4a82cf8ee66bf0fa3eb10cd96a0a..f7cb999dc1c0fb1e2f4a4e974fe7bb0f544a260b 100644 --- a/app/sql_channel.js +++ b/app/sql_channel.js @@ -24,18 +24,14 @@ function initialize() { try { const fn = sql[callName]; if (!fn) { - throw new Error( - `sql channel: ${callName} is not an available function` - ); + throw new Error(`sql channel: ${callName} is not an available function`); } const result = await fn(...args); event.sender.send(`${SQL_CHANNEL_KEY}-done`, jobId, null, result); } catch (error) { const errorForDisplay = error && error.stack ? error.stack : error; - console.log( - `sql channel error with call ${callName}: ${errorForDisplay}` - ); + console.log(`sql channel error with call ${callName}: ${errorForDisplay}`); // FIXME this line cause the test-integration to fail and we probably don't need it during test if (!process.env.NODE_ENV.includes('test-integration')) { event.sender.send(`${SQL_CHANNEL_KEY}-done`, jobId, errorForDisplay); diff --git a/app/tray_icon.js b/app/tray_icon.js index 7dfdf1fd2ff04f2b0955b5ab274b036c0c098a10..75ab391a4fd499a020f8096c41d65aa27a2b3893 100644 --- a/app/tray_icon.js +++ b/app/tray_icon.js @@ -9,12 +9,7 @@ let tray = null; function createTrayIcon(getMainWindow, messages) { // A smaller icon is needed on macOS const iconSize = process.platform === 'darwin' ? '16' : '256'; - const iconNoNewMessages = path.join( - __dirname, - '..', - 'images', - `icon_${iconSize}.png` - ); + const iconNoNewMessages = path.join(__dirname, '..', 'images', `icon_${iconSize}.png`); tray = new Tray(iconNoNewMessages); @@ -65,8 +60,7 @@ function createTrayIcon(getMainWindow, messages) { trayContextMenu = Menu.buildFromTemplate([ { id: 'toggleWindowVisibility', - label: - messages[mainWindow.isVisible() ? 'appMenuHide' : 'show'].message, + label: messages[mainWindow.isVisible() ? 'appMenuHide' : 'show'].message, click: tray.toggleWindowVisibility, }, { diff --git a/app/user_config.js b/app/user_config.js index cb434935c5934cb2444428fff77600694f3c4c6b..0829c2968e3d78da5ff9a0853ce157ad62f06f41 100644 --- a/app/user_config.js +++ b/app/user_config.js @@ -27,10 +27,7 @@ if (config.has(storageProfile)) { } if (storageProfile) { - const userData = path.join( - app.getPath('appData'), - `Session-${storageProfile}` - ); + const userData = path.join(app.getPath('appData'), `Session-${storageProfile}`); app.setPath('userData', userData); } diff --git a/build/afterPackHook.js b/build/afterPackHook.js index ef42cc389544ca2b8dcc6ed3b52d8b1b54520bce..37d19d3160206f95b847ea92a8b9cc71dbc20e13 100644 --- a/build/afterPackHook.js +++ b/build/afterPackHook.js @@ -19,15 +19,8 @@ module.exports = async function(context) { const executableName = context.packager.executableName; const sourceExecutable = path.join(context.appOutDir, executableName); - const targetExecutable = path.join( - context.appOutDir, - `${executableName}-bin` - ); - const launcherScript = path.join( - context.appOutDir, - 'resources', - 'launcher-script.sh' - ); + const targetExecutable = path.join(context.appOutDir, `${executableName}-bin`); + const launcherScript = path.join(context.appOutDir, 'resources', 'launcher-script.sh'); const chromeSandbox = path.join(context.appOutDir, 'chrome-sandbox'); return Promise.all([ diff --git a/build/notarize.js b/build/notarize.js index 1c797b4e7c3a1e860a2addb730efded63b84de44..7d0879820494395e7f7dc73252eb876f70e042b3 100644 --- a/build/notarize.js +++ b/build/notarize.js @@ -21,16 +21,10 @@ exports.default = async function notarizing(context) { log('Notarizing mac application'); const appName = context.packager.appInfo.productFilename; - const { - SIGNING_APPLE_ID, - SIGNING_APP_PASSWORD, - SIGNING_TEAM_ID, - } = process.env; + const { SIGNING_APPLE_ID, SIGNING_APP_PASSWORD, SIGNING_TEAM_ID } = process.env; if (isEmpty(SIGNING_APPLE_ID) || isEmpty(SIGNING_APP_PASSWORD)) { - log( - 'SIGNING_APPLE_ID or SIGNING_APP_PASSWORD not set.\nTerminating noratization.' - ); + log('SIGNING_APPLE_ID or SIGNING_APP_PASSWORD not set.\nTerminating noratization.'); return; } diff --git a/js/background.js b/js/background.js index 835ccb02136b8ff8c9d75f93b14c15b785a0b76b..fee9f40f7be044c7e9d519178fd3af5a1909e000 100644 --- a/js/background.js +++ b/js/background.js @@ -168,10 +168,7 @@ // Ensure accounts created prior to 1.0.0-beta8 do have their // 'primaryDevicePubKey' defined. - if ( - Whisper.Registration.isDone() && - !storage.get('primaryDevicePubKey', null) - ) { + if (Whisper.Registration.isDone() && !storage.get('primaryDevicePubKey', null)) { storage.put( 'primaryDevicePubKey', window.libsession.Utils.UserUtils.getOurPubKeyStrFromCache() @@ -226,9 +223,7 @@ await storage.put('version', currentVersion); if (newVersion) { - window.log.info( - `New version detected: ${currentVersion}; previous: ${lastVersion}` - ); + window.log.info(`New version detected: ${currentVersion}; previous: ${lastVersion}`); await window.Signal.Data.cleanupOrphanedAttachments(); @@ -265,31 +260,26 @@ } }); - Whisper.events.on( - 'deleteLocalPublicMessages', - async ({ messageServerIds, conversationId }) => { - if (!Array.isArray(messageServerIds)) { - return; - } - const messageIds = await window.Signal.Data.getMessageIdsFromServerIds( - messageServerIds, - conversationId - ); - if (messageIds.length === 0) { - return; - } - - const conversation = window - .getConversationController() - .get(conversationId); - messageIds.forEach(id => { - if (conversation) { - conversation.removeMessage(id); - } - window.Signal.Data.removeMessage(id); - }); + Whisper.events.on('deleteLocalPublicMessages', async ({ messageServerIds, conversationId }) => { + if (!Array.isArray(messageServerIds)) { + return; + } + const messageIds = await window.Signal.Data.getMessageIdsFromServerIds( + messageServerIds, + conversationId + ); + if (messageIds.length === 0) { + return; } - ); + + const conversation = window.getConversationController().get(conversationId); + messageIds.forEach(id => { + if (conversation) { + conversation.removeMessage(id); + } + window.Signal.Data.removeMessage(id); + }); + }); function manageExpiringData() { window.Signal.Data.cleanSeenMessages(); @@ -303,9 +293,7 @@ window.log.info('Cleanup: starting...'); - const results = await Promise.all([ - window.Signal.Data.getOutgoingWithoutExpiresAt(), - ]); + const results = await Promise.all([window.Signal.Data.getOutgoingWithoutExpiresAt()]); // Combine the models const messagesForCleanup = results.reduce( @@ -313,29 +301,20 @@ [] ); - window.log.info( - `Cleanup: Found ${messagesForCleanup.length} messages for cleanup` - ); + window.log.info(`Cleanup: Found ${messagesForCleanup.length} messages for cleanup`); await Promise.all( messagesForCleanup.map(async message => { const delivered = message.get('delivered'); const sentAt = message.get('sent_at'); - const expirationStartTimestamp = message.get( - 'expirationStartTimestamp' - ); + const expirationStartTimestamp = message.get('expirationStartTimestamp'); if (message.hasErrors()) { return; } if (delivered) { - window.log.info( - `Cleanup: Starting timer for delivered message ${sentAt}` - ); - message.set( - 'expirationStartTimestamp', - expirationStartTimestamp || sentAt - ); + window.log.info(`Cleanup: Starting timer for delivered message ${sentAt}`); + message.set('expirationStartTimestamp', expirationStartTimestamp || sentAt); await message.setToExpire(); return; } @@ -485,13 +464,11 @@ profileKey ); - const avatarPointer = await libsession.Utils.AttachmentUtils.uploadAvatar( - { - ...dataResized, - data: encryptedData, - size: encryptedData.byteLength, - } - ); + const avatarPointer = await libsession.Utils.AttachmentUtils.uploadAvatar({ + ...dataResized, + data: encryptedData, + size: encryptedData.byteLength, + }); ({ url } = avatarPointer); @@ -512,12 +489,8 @@ avatar: newAvatarPath, }); await conversation.commit(); - window.libsession.Utils.UserUtils.setLastProfileUpdateTimestamp( - Date.now() - ); - await window.libsession.Utils.SyncUtils.forceSyncConfigurationNowIfNeeded( - true - ); + window.libsession.Utils.UserUtils.setLastProfileUpdateTimestamp(Date.now()); + await window.libsession.Utils.SyncUtils.forceSyncConfigurationNowIfNeeded(true); } catch (error) { window.log.error( 'showEditProfileDialog Error ensuring that image is properly sized:', @@ -531,12 +504,8 @@ }); // might be good to not trigger a sync if the name did not change await conversation.commit(); - window.libsession.Utils.UserUtils.setLastProfileUpdateTimestamp( - Date.now() - ); - await window.libsession.Utils.SyncUtils.forceSyncConfigurationNowIfNeeded( - true - ); + window.libsession.Utils.UserUtils.setLastProfileUpdateTimestamp(Date.now()); + await window.libsession.Utils.SyncUtils.forceSyncConfigurationNowIfNeeded(true); } // inform all your registered public servers @@ -551,9 +520,7 @@ .getConversationController() .getConversations() .filter(convo => convo.isPublic()) - .forEach(convo => - convo.trigger('ourAvatarChanged', { url, profileKey }) - ); + .forEach(convo => convo.trigger('ourAvatarChanged', { url, profileKey })); } }, }); @@ -640,46 +607,37 @@ } }); - Whisper.events.on( - 'publicChatInvitationAccepted', - async (serverAddress, channelId) => { - // To some degree this has been copy-pasted - // form connection_to_server_dialog_view.js: - const rawServerUrl = serverAddress - .replace(/^https?:\/\//i, '') - .replace(/[/\\]+$/i, ''); - const sslServerUrl = `https://${rawServerUrl}`; - const conversationId = `publicChat:${channelId}@${rawServerUrl}`; - - const conversationExists = window - .getConversationController() - .get(conversationId); - if (conversationExists) { - window.log.warn('We are already a member of this public chat'); - window.libsession.Utils.ToastUtils.pushAlreadyMemberOpenGroup(); + Whisper.events.on('publicChatInvitationAccepted', async (serverAddress, channelId) => { + // To some degree this has been copy-pasted + // form connection_to_server_dialog_view.js: + const rawServerUrl = serverAddress.replace(/^https?:\/\//i, '').replace(/[/\\]+$/i, ''); + const sslServerUrl = `https://${rawServerUrl}`; + const conversationId = `publicChat:${channelId}@${rawServerUrl}`; - return; - } + const conversationExists = window.getConversationController().get(conversationId); + if (conversationExists) { + window.log.warn('We are already a member of this public chat'); + window.libsession.Utils.ToastUtils.pushAlreadyMemberOpenGroup(); - const conversation = await window - .getConversationController() - .getOrCreateAndWait(conversationId, 'group'); - await conversation.setPublicSource(sslServerUrl, channelId); - - const channelAPI = await window.lokiPublicChatAPI.findOrCreateChannel( - sslServerUrl, - channelId, - conversationId - ); - if (!channelAPI) { - window.log.warn(`Could not connect to ${serverAddress}`); - return; - } - window.inboxStore.dispatch( - window.actionsCreators.openConversationExternal(conversationId) - ); + return; } - ); + + const conversation = await window + .getConversationController() + .getOrCreateAndWait(conversationId, 'group'); + await conversation.setPublicSource(sslServerUrl, channelId); + + const channelAPI = await window.lokiPublicChatAPI.findOrCreateChannel( + sslServerUrl, + channelId, + conversationId + ); + if (!channelAPI) { + window.log.warn(`Could not connect to ${serverAddress}`); + return; + } + window.inboxStore.dispatch(window.actionsCreators.openConversationExternal(conversationId)); + }); Whisper.events.on('leaveGroup', async groupConvo => { if (appView) { @@ -690,9 +648,7 @@ Whisper.Notifications.on('click', (id, messageId) => { window.showWindow(); if (id) { - window.inboxStore.dispatch( - window.actionsCreators.openConversationExternal(id, messageId) - ); + window.inboxStore.dispatch(window.actionsCreators.openConversationExternal(id, messageId)); } else { appView.openInbox({ initialLoadComplete, @@ -802,9 +758,7 @@ window.addEventListener('offline', onOffline); } if (connectCount === 0 && !navigator.onLine) { - window.log.warn( - 'Starting up offline; will connect when we have network access' - ); + window.log.warn('Starting up offline; will connect when we have network access'); window.addEventListener('online', onOnline); onEmpty(); // this ensures that the loading screen is dismissed return; @@ -841,14 +795,8 @@ initAPIs(); await initSpecialConversations(); messageReceiver = new textsecure.MessageReceiver(); - messageReceiver.addEventListener( - 'message', - window.DataMessageReceiver.handleMessageEvent - ); - messageReceiver.addEventListener( - 'sent', - window.DataMessageReceiver.handleMessageEvent - ); + messageReceiver.addEventListener('message', window.DataMessageReceiver.handleMessageEvent); + messageReceiver.addEventListener('sent', window.DataMessageReceiver.handleMessageEvent); messageReceiver.addEventListener('reconnect', onReconnect); messageReceiver.addEventListener('configuration', onConfiguration); // messageReceiver.addEventListener('typing', onTyping); diff --git a/js/database.js b/js/database.js index 5fc9b1896706a70fd522c0b89c7fa325e2301bd0..d88b4d9046fc777500a69a868e50df9e959e27a7 100644 --- a/js/database.js +++ b/js/database.js @@ -64,11 +64,7 @@ }; request.onerror = () => { - Whisper.Database.handleDOMException( - 'clearStores request error', - request.error, - reject - ); + Whisper.Database.handleDOMException('clearStores request error', request.error, reject); }; }); }); diff --git a/js/delivery_receipts.js b/js/delivery_receipts.js index e69f6eef32467f164b14687124a0307bb09cea26..d24a49207c28a4adc50f22a408a8c379cba027e9 100644 --- a/js/delivery_receipts.js +++ b/js/delivery_receipts.js @@ -35,23 +35,19 @@ } const message = messages.find( - item => - !item.isIncoming() && originalSource === item.get('conversationId') + item => !item.isIncoming() && originalSource === item.get('conversationId') ); if (message) { return message; } - const groups = await window.Signal.Data.getAllGroupsInvolvingId( - originalSource - ); + const groups = await window.Signal.Data.getAllGroupsInvolvingId(originalSource); const ids = groups.pluck('id'); ids.push(originalSource); const target = messages.find( - item => - !item.isIncoming() && _.contains(ids, item.get('conversationId')) + item => !item.isIncoming() && _.contains(ids, item.get('conversationId')) ); if (!target) { return null; @@ -61,14 +57,9 @@ }, async onReceipt(receipt) { try { - const messages = await window.Signal.Data.getMessagesBySentAt( - receipt.get('timestamp') - ); + const messages = await window.Signal.Data.getMessagesBySentAt(receipt.get('timestamp')); - const message = await this.getTargetMessage( - receipt.get('source'), - messages - ); + const message = await this.getTargetMessage(receipt.get('source'), messages); if (!message) { window.log.info( 'No message for delivery receipt', @@ -80,9 +71,7 @@ const deliveries = message.get('delivered') || 0; const deliveredTo = message.get('delivered_to') || []; - const expirationStartTimestamp = message.get( - 'expirationStartTimestamp' - ); + const expirationStartTimestamp = message.get('expirationStartTimestamp'); message.set({ delivered_to: _.union(deliveredTo, [receipt.get('source')]), delivered: deliveries + 1, @@ -98,9 +87,7 @@ } // notify frontend listeners - const conversation = window - .getConversationController() - .get(message.get('conversationId')); + const conversation = window.getConversationController().get(message.get('conversationId')); if (conversation) { conversation.updateLastMessage(); } diff --git a/js/expire.js b/js/expire.js index 23345bdf0a7dc68ce1ee369814a5c6f061ae98d2..9944d37ea5beac3b3533c052f30100a3e5f28dfa 100644 --- a/js/expire.js +++ b/js/expire.js @@ -21,9 +21,7 @@ window.libsession.Utils.UserUtils.getOurPubKeyStrFromCache(); } catch (e) { // give it a minute - log.warn( - 'Could not check to see if newer version is available cause our pubkey is not set' - ); + log.warn('Could not check to see if newer version is available cause our pubkey is not set'); nextWaitSeconds = 60; setTimeout(async () => { await checkForUpgrades(); @@ -81,9 +79,7 @@ if (expiredVersion !== null) { return res(expiredVersion); } - log.info( - `Delaying sending checks for ${nextWaitSeconds}s, no version yet` - ); + log.info(`Delaying sending checks for ${nextWaitSeconds}s, no version yet`); setTimeout(waitForVersion, nextWaitSeconds * 1000); return true; } @@ -112,9 +108,7 @@ let timestamp = NaN; try { - const res = await window.tokenlessFileServerAdnAPI.serverRequest( - 'loki/v1/time' - ); + const res = await window.tokenlessFileServerAdnAPI.serverRequest('loki/v1/time'); if (res.ok) { timestamp = res.response; } diff --git a/js/expiring_messages.js b/js/expiring_messages.js index f18feec3359907f33a6402b5f4cf9bfa5f50d8db..2327f60ec251b9099d94807d1c0f17c0b2dfaddb 100644 --- a/js/expiring_messages.js +++ b/js/expiring_messages.js @@ -81,10 +81,7 @@ clearTimeout(timeout); timeout = setTimeout(destroyExpiredMessages, wait); } - const throttledCheckExpiringMessages = _.throttle( - checkExpiringMessages, - 1000 - ); + const throttledCheckExpiringMessages = _.throttle(checkExpiringMessages, 1000); Whisper.ExpiringMessagesListener = { nextExpiration: null, @@ -103,11 +100,7 @@ ); }, getAbbreviated() { - return i18n( - ['timerOption', this.get('time'), this.get('unit'), 'abbreviated'].join( - '_' - ) - ); + return i18n(['timerOption', this.get('time'), this.get('unit'), 'abbreviated'].join('_')); }, }); Whisper.ExpirationTimerOptions = new (Backbone.Collection.extend({ diff --git a/js/legacy_storage.js b/js/legacy_storage.js index 5a1f1e2d8c4e069e6c21d1a6a277cd99c9c89d69..c454ea59046c1f5c3023853ad0484f3c29016d62 100644 --- a/js/legacy_storage.js +++ b/js/legacy_storage.js @@ -31,10 +31,7 @@ throw new Error('Tried to store undefined'); } if (!ready) { - window.log.warn( - 'Called storage.put before storage is ready. key:', - key - ); + window.log.warn('Called storage.put before storage is ready. key:', key); } const item = items.add({ id: key, value }, { merge: true }); return new Promise((resolve, reject) => { diff --git a/js/modules/attachment_downloads.js b/js/modules/attachment_downloads.js index 87516e560ebd604d3afdd9b23d5e9b462210d910..590f16c77252713423993744858f9485b45a9252 100644 --- a/js/modules/attachment_downloads.js +++ b/js/modules/attachment_downloads.js @@ -136,9 +136,7 @@ async function _runJob(job) { try { if (!job || !attachment || !messageId) { - throw new Error( - `_runJob: Key information required for job was missing. Job id: ${id}` - ); + throw new Error(`_runJob: Key information required for job was missing. Job id: ${id}`); } const found = await getMessageById(messageId); @@ -166,20 +164,14 @@ async function _runJob(job) { ); await _finishJob(message, id); - await _addAttachmentToMessage( - message, - _markAttachmentAsError(attachment), - { type, index } - ); + await _addAttachmentToMessage(message, _markAttachmentAsError(attachment), { type, index }); return; } throw error; } - const upgradedAttachment = await Signal.Migrations.processNewAttachment( - downloaded - ); + const upgradedAttachment = await Signal.Migrations.processNewAttachment(downloaded); await _addAttachmentToMessage(message, upgradedAttachment, { type, index }); @@ -194,11 +186,7 @@ async function _runJob(job) { ); await _finishJob(message, id); - await _addAttachmentToMessage( - message, - _markAttachmentAsError(attachment), - { type, index } - ); + await _addAttachmentToMessage(message, _markAttachmentAsError(attachment), { type, index }); return; } @@ -267,9 +255,7 @@ async function _addAttachmentToMessage(message, attachment, { type, index }) { if (type === 'preview') { const preview = message.get('preview'); if (!preview || preview.length <= index) { - throw new Error( - `_addAttachmentToMessage: preview didn't exist or ${index} was too large` - ); + throw new Error(`_addAttachmentToMessage: preview didn't exist or ${index} was too large`); } const item = preview[index]; if (!item) { @@ -282,9 +268,7 @@ async function _addAttachmentToMessage(message, attachment, { type, index }) { if (type === 'contact') { const contact = message.get('contact'); if (!contact || contact.length <= index) { - throw new Error( - `_addAttachmentToMessage: contact didn't exist or ${index} was too large` - ); + throw new Error(`_addAttachmentToMessage: contact didn't exist or ${index} was too large`); } const item = contact[index]; if (item && item.avatar && item.avatar.avatar) { @@ -312,9 +296,7 @@ async function _addAttachmentToMessage(message, attachment, { type, index }) { const item = attachments[index]; if (!item) { - throw new Error( - `_addAttachmentToMessage: attachment ${index} was falsey` - ); + throw new Error(`_addAttachmentToMessage: attachment ${index} was falsey`); } _replaceAttachment(item, 'thumbnail', attachment, logPrefix); return; diff --git a/js/modules/auto_orient_image.js b/js/modules/auto_orient_image.js index fbdabfd64a240f496016a8c5f3c22f7b8fa89e57..235e88f709492f8b77fb84abcd6d8e5b33a0c51f 100644 --- a/js/modules/auto_orient_image.js +++ b/js/modules/auto_orient_image.js @@ -31,10 +31,7 @@ exports.autoOrientImage = (fileOrBlobOrURL, options = {}) => { } const canvas = canvasOrError; - const dataURL = canvas.toDataURL( - optionsWithDefaults.type, - optionsWithDefaults.quality - ); + const dataURL = canvas.toDataURL(optionsWithDefaults.type, optionsWithDefaults.quality); resolve(dataURL); }, diff --git a/js/modules/backup.js b/js/modules/backup.js index c6f26a5f97690ce60e301000117cb438c94b3170..59cca4034ce758c6ee52066482a47cdd4c66a3c1 100644 --- a/js/modules/backup.js +++ b/js/modules/backup.js @@ -174,8 +174,7 @@ async function importConversationsFromJSON(conversations, options) { for (let i = 0, max = conversations.length; i < max; i += 1) { const toAdd = unstringify(conversations[i]); - const haveConversationAlready = - conversationLookup[getConversationKey(toAdd)]; + const haveConversationAlready = conversationLookup[getConversationKey(toAdd)]; if (haveConversationAlready) { skipCount += 1; @@ -186,23 +185,14 @@ async function importConversationsFromJSON(conversations, options) { count += 1; // eslint-disable-next-line no-await-in-loop - const migrated = await window.Signal.Types.Conversation.migrateConversation( - toAdd, - { - writeNewAttachmentData, - } - ); + const migrated = await window.Signal.Types.Conversation.migrateConversation(toAdd, { + writeNewAttachmentData, + }); // eslint-disable-next-line no-await-in-loop await window.Signal.Data.saveConversation(migrated); } - window.log.info( - 'Done importing conversations:', - 'Total count:', - count, - 'Skipped:', - skipCount - ); + window.log.info('Done importing conversations:', 'Total count:', count, 'Skipped:', skipCount); } async function importFromJsonString(jsonString, targetPath, options) { @@ -229,9 +219,7 @@ async function importFromJsonString(jsonString, targetPath, options) { delete importObject.sessions; delete importObject.unprocessed; - window.log.info( - 'This is a light import; contacts, groups and messages only' - ); + window.log.info('This is a light import; contacts, groups and messages only'); } // We mutate the on-disk backup to prevent the user from importing client @@ -260,9 +248,7 @@ async function importFromJsonString(jsonString, targetPath, options) { _.map(remainingStoreNames, async storeName => { const save = SAVE_FUNCTIONS[storeName]; if (!_.isFunction(save)) { - throw new Error( - `importFromJsonString: Didn't have save function for store ${storeName}` - ); + throw new Error(`importFromJsonString: Didn't have save function for store ${storeName}`); } window.log.info(`Importing items for store ${storeName}`); @@ -279,12 +265,7 @@ async function importFromJsonString(jsonString, targetPath, options) { await save(toAdd); } - window.log.info( - 'Done importing to store', - storeName, - 'Total count:', - toImport.length - ); + window.log.info('Done importing to store', storeName, 'Total count:', toImport.length); }) ); @@ -339,10 +320,7 @@ function readFileAsText(parent, name) { // Buffer instances are also Uint8Array instances, but they might be a view // https://nodejs.org/docs/latest/api/buffer.html#buffer_buffers_and_typedarray const toArrayBuffer = nodeBuffer => - nodeBuffer.buffer.slice( - nodeBuffer.byteOffset, - nodeBuffer.byteOffset + nodeBuffer.byteLength - ); + nodeBuffer.buffer.slice(nodeBuffer.byteOffset, nodeBuffer.byteOffset + nodeBuffer.byteLength); function readFileAsArrayBuffer(targetPath) { return new Promise((resolve, reject) => { @@ -381,9 +359,7 @@ function _getExportAttachmentFileName(message, index, attachment) { if (attachment.contentType) { const components = attachment.contentType.split('/'); - name += `.${ - components.length > 1 ? components[1] : attachment.contentType - }`; + name += `.${components.length > 1 ? components[1] : attachment.contentType}`; } return name; @@ -413,11 +389,7 @@ async function readEncryptedAttachment(dir, attachment, name, options) { const isEncrypted = !_.isUndefined(key); if (isEncrypted) { - attachment.data = await crypto.decryptAttachment( - key, - attachment.path, - data - ); + attachment.data = await crypto.decryptAttachment(key, attachment.path, data); } else { attachment.data = data; } @@ -429,10 +401,7 @@ async function writeQuoteThumbnail(attachment, options) { } const { dir, message, index, key, newKey } = options; - const filename = `${_getAnonymousAttachmentFileName( - message, - index - )}-quote-thumbnail`; + const filename = `${_getAnonymousAttachmentFileName(message, index)}-quote-thumbnail`; const target = path.join(dir, filename); await writeEncryptedAttachment(target, attachment.thumbnail.path, { @@ -485,10 +454,7 @@ async function writeAttachment(attachment, options) { }); if (attachment.thumbnail && _.isString(attachment.thumbnail.path)) { - const thumbnailName = `${_getAnonymousAttachmentFileName( - message, - index - )}-thumbnail`; + const thumbnailName = `${_getAnonymousAttachmentFileName(message, index)}-thumbnail`; const thumbnailTarget = path.join(dir, thumbnailName); await writeEncryptedAttachment(thumbnailTarget, attachment.thumbnail.path, { key, @@ -499,21 +465,14 @@ async function writeAttachment(attachment, options) { } if (attachment.screenshot && _.isString(attachment.screenshot.path)) { - const screenshotName = `${_getAnonymousAttachmentFileName( - message, - index - )}-screenshot`; + const screenshotName = `${_getAnonymousAttachmentFileName(message, index)}-screenshot`; const screenshotTarget = path.join(dir, screenshotName); - await writeEncryptedAttachment( - screenshotTarget, - attachment.screenshot.path, - { - key, - newKey, - filename: screenshotName, - dir, - } - ); + await writeEncryptedAttachment(screenshotTarget, attachment.screenshot.path, { + key, + newKey, + filename: screenshotName, + dir, + }); } } @@ -686,13 +645,10 @@ async function exportConversation(conversation, options = {}) { while (!complete) { // eslint-disable-next-line no-await-in-loop - const collection = await window.Signal.Data.getMessagesByConversation( - conversation.id, - { - limit: CHUNK_SIZE, - receivedAt: lastReceivedAt, - } - ); + const collection = await window.Signal.Data.getMessagesByConversation(conversation.id, { + limit: CHUNK_SIZE, + receivedAt: lastReceivedAt, + }); const messages = getPlainJS(collection); for (let i = 0, max = messages.length; i < max; i += 1) { @@ -712,9 +668,7 @@ async function exportConversation(conversation, options = {}) { const { attachments } = message; // eliminate attachment data from the JSON, since it will go to disk // Note: this is for legacy messages only, which stored attachment data in the db - message.attachments = _.map(attachments, attachment => - _.omit(attachment, ['data']) - ); + message.attachments = _.map(attachments, attachment => _.omit(attachment, ['data'])); // completely drop any attachments in messages cached in error objects // TODO: move to lodash. Sadly, a number of the method signatures have changed! message.errors = _.map(message.errors, error => { @@ -901,22 +855,12 @@ async function loadAttachments(dir, getName, options) { if (attachment.thumbnail && _.isString(attachment.thumbnail.path)) { const thumbnailName = `${name}-thumbnail`; - await readEncryptedAttachment( - dir, - attachment.thumbnail, - thumbnailName, - options - ); + await readEncryptedAttachment(dir, attachment.thumbnail, thumbnailName, options); } if (attachment.screenshot && _.isString(attachment.screenshot.path)) { const screenshotName = `${name}-screenshot`; - await readEncryptedAttachment( - dir, - attachment.screenshot, - screenshotName, - options - ); + await readEncryptedAttachment(dir, attachment.screenshot, screenshotName, options); } }) ); @@ -989,10 +933,7 @@ async function saveAllMessages(rawMessages) { `[REDACTED]${conversationId.slice(-3)}` ); } catch (error) { - window.log.error( - 'saveAllMessages error', - error && error.message ? error.message : error - ); + window.log.error('saveAllMessages error', error && error.message ? error.message : error); } } @@ -1015,18 +956,14 @@ async function importConversation(dir, options) { try { contents = await readFileAsText(dir, 'messages.json'); } catch (error) { - window.log.error( - `Warning: could not access messages.json in directory: ${dir}` - ); + window.log.error(`Warning: could not access messages.json in directory: ${dir}`); } let promiseChain = Promise.resolve(); const json = JSON.parse(contents); if (json.messages && json.messages.length) { - conversationId = `[REDACTED]${(json.messages[0].conversationId || '').slice( - -3 - )}`; + conversationId = `[REDACTED]${(json.messages[0].conversationId || '').slice(-3)}`; } total = json.messages.length; @@ -1040,9 +977,7 @@ async function importConversation(dir, options) { const hasAttachments = message.attachments && message.attachments.length; const hasQuotedAttachments = - message.quote && - message.quote.attachments && - message.quote.attachments.length > 0; + message.quote && message.quote.attachments && message.quote.attachments.length > 0; const hasContacts = message.contact && message.contact.length; const hasPreviews = message.preview && message.preview.length; @@ -1051,8 +986,7 @@ async function importConversation(dir, options) { const getName = attachmentsDir ? _getAnonymousAttachmentFileName : _getExportAttachmentFileName; - const parentDir = - attachmentsDir || path.join(dir, message.received_at.toString()); + const parentDir = attachmentsDir || path.join(dir, message.received_at.toString()); await loadAttachments(parentDir, getName, { message, @@ -1229,10 +1163,7 @@ async function exportToDirectory(directory, options) { window.log.info('done backing up!'); return directory; } catch (error) { - window.log.error( - 'The backup went wrong!', - error && error.stack ? error.stack : error - ); + window.log.error('The backup went wrong!', error && error.stack ? error.stack : error); throw error; } finally { if (stagingDir) { @@ -1255,10 +1186,7 @@ async function importFromDirectory(directory, options) { options = options || {}; try { - const lookups = await Promise.all([ - loadMessagesLookup(), - loadConversationLookup(), - ]); + const lookups = await Promise.all([loadMessagesLookup(), loadConversationLookup()]); const [messageLookup, conversationLookup] = lookups; options = Object.assign({}, options, { messageLookup, @@ -1274,9 +1202,7 @@ async function importFromDirectory(directory, options) { // we're in the world of an encrypted, zipped backup if (!options.key) { - throw new Error( - 'Importing an encrypted backup; decryption key is required!' - ); + throw new Error('Importing an encrypted backup; decryption key is required!'); } let stagingDir; @@ -1315,10 +1241,7 @@ async function importFromDirectory(directory, options) { window.log.info('Done importing!'); return result; } catch (error) { - window.log.error( - 'The import went wrong!', - error && error.stack ? error.stack : error - ); + window.log.error('The import went wrong!', error && error.stack ? error.stack : error); throw error; } } diff --git a/js/modules/crypto.js b/js/modules/crypto.js index c67a9053eb09190f9dc5259bfd97e4eb5b851288..e76a1e83d89f30f058a376b2f8d44fa18342cec1 100644 --- a/js/modules/crypto.js +++ b/js/modules/crypto.js @@ -129,11 +129,7 @@ async function encryptSymmetric(key, plaintext) { const cipherKey = await hmacSha256(key, nonce); const macKey = await hmacSha256(key, cipherKey); - const cipherText = await _encrypt_aes256_CBC_PKCSPadding( - cipherKey, - iv, - plaintext - ); + const cipherText = await _encrypt_aes256_CBC_PKCSPadding(cipherKey, iv, plaintext); const mac = _getFirstBytes(await hmacSha256(macKey, cipherText), MAC_LENGTH); return concatenateBytes(nonce, cipherText, mac); @@ -143,24 +139,15 @@ async function decryptSymmetric(key, data) { const iv = getZeroes(IV_LENGTH); const nonce = _getFirstBytes(data, NONCE_LENGTH); - const cipherText = _getBytes( - data, - NONCE_LENGTH, - data.byteLength - NONCE_LENGTH - MAC_LENGTH - ); + const cipherText = _getBytes(data, NONCE_LENGTH, data.byteLength - NONCE_LENGTH - MAC_LENGTH); const theirMac = _getBytes(data, data.byteLength - MAC_LENGTH, MAC_LENGTH); const cipherKey = await hmacSha256(key, nonce); const macKey = await hmacSha256(key, cipherKey); - const ourMac = _getFirstBytes( - await hmacSha256(macKey, cipherText), - MAC_LENGTH - ); + const ourMac = _getFirstBytes(await hmacSha256(macKey, cipherText), MAC_LENGTH); if (!constantTimeEqual(theirMac, ourMac)) { - throw new Error( - 'decryptSymmetric: Failed to decrypt; MAC verification failed' - ); + throw new Error('decryptSymmetric: Failed to decrypt; MAC verification failed'); } return _decrypt_aes256_CBC_PKCSPadding(cipherKey, iv, cipherText); @@ -189,13 +176,9 @@ async function hmacSha256(key, plaintext) { }; const extractable = false; - const cryptoKey = await window.crypto.subtle.importKey( - 'raw', - key, - algorithm, - extractable, - ['sign'] - ); + const cryptoKey = await window.crypto.subtle.importKey('raw', key, algorithm, extractable, [ + 'sign', + ]); return window.crypto.subtle.sign(algorithm, cryptoKey, plaintext); } @@ -207,13 +190,9 @@ async function _encrypt_aes256_CBC_PKCSPadding(key, iv, plaintext) { }; const extractable = false; - const cryptoKey = await window.crypto.subtle.importKey( - 'raw', - key, - algorithm, - extractable, - ['encrypt'] - ); + const cryptoKey = await window.crypto.subtle.importKey('raw', key, algorithm, extractable, [ + 'encrypt', + ]); return window.crypto.subtle.encrypt(algorithm, cryptoKey, plaintext); } @@ -225,13 +204,9 @@ async function _decrypt_aes256_CBC_PKCSPadding(key, iv, plaintext) { }; const extractable = false; - const cryptoKey = await window.crypto.subtle.importKey( - 'raw', - key, - algorithm, - extractable, - ['decrypt'] - ); + const cryptoKey = await window.crypto.subtle.importKey('raw', key, algorithm, extractable, [ + 'decrypt', + ]); return window.crypto.subtle.decrypt(algorithm, cryptoKey, plaintext); } @@ -243,19 +218,9 @@ async function encryptAesCtr(key, plaintext, counter) { length: 128, }; - const cryptoKey = await crypto.subtle.importKey( - 'raw', - key, - algorithm, - extractable, - ['encrypt'] - ); + const cryptoKey = await crypto.subtle.importKey('raw', key, algorithm, extractable, ['encrypt']); - const ciphertext = await crypto.subtle.encrypt( - algorithm, - cryptoKey, - plaintext - ); + const ciphertext = await crypto.subtle.encrypt(algorithm, cryptoKey, plaintext); return ciphertext; } @@ -268,18 +233,8 @@ async function decryptAesCtr(key, ciphertext, counter) { length: 128, }; - const cryptoKey = await crypto.subtle.importKey( - 'raw', - key, - algorithm, - extractable, - ['decrypt'] - ); - const plaintext = await crypto.subtle.decrypt( - algorithm, - cryptoKey, - ciphertext - ); + const cryptoKey = await crypto.subtle.importKey('raw', key, algorithm, extractable, ['decrypt']); + const plaintext = await crypto.subtle.decrypt(algorithm, cryptoKey, ciphertext); return plaintext; } @@ -290,13 +245,7 @@ async function _encrypt_aes_gcm(key, iv, plaintext) { }; const extractable = false; - const cryptoKey = await crypto.subtle.importKey( - 'raw', - key, - algorithm, - extractable, - ['encrypt'] - ); + const cryptoKey = await crypto.subtle.importKey('raw', key, algorithm, extractable, ['encrypt']); return crypto.subtle.encrypt(algorithm, cryptoKey, plaintext); } @@ -338,10 +287,7 @@ function getViewOfArrayBuffer(buffer, start, finish) { } function concatenateBytes(...elements) { - const length = elements.reduce( - (total, element) => total + element.byteLength, - 0 - ); + const length = elements.reduce((total, element) => total + element.byteLength, 0); const result = new Uint8Array(length); let position = 0; diff --git a/js/modules/database.js b/js/modules/database.js index 18c3845f7554409577beeeb41155934809c2fbef..8be2c085bab2736e460ef2841080b38062ec6ac1 100644 --- a/js/modules/database.js +++ b/js/modules/database.js @@ -26,8 +26,7 @@ exports.open = (name, version, { onUpgradeNeeded } = {}) => { reject( new Error( - 'Database upgrade required:' + - ` oldVersion: ${oldVersion}, newVersion: ${newVersion}` + 'Database upgrade required:' + ` oldVersion: ${oldVersion}, newVersion: ${newVersion}` ) ); }; diff --git a/js/modules/deferred_to_promise.d.ts b/js/modules/deferred_to_promise.d.ts index 67f9ff212af61dbf66b44364ffe44d8ac60080fd..b4e87b0121c29805752481fea4b9271e76118b11 100644 --- a/js/modules/deferred_to_promise.d.ts +++ b/js/modules/deferred_to_promise.d.ts @@ -1,3 +1 @@ -export function deferredToPromise<T>( - deferred: JQuery.Deferred<any, any, any> -): Promise<T>; +export function deferredToPromise<T>(deferred: JQuery.Deferred<any, any, any>): Promise<T>; diff --git a/js/modules/i18n.js b/js/modules/i18n.js index a394090af7d93a5b899b15ab9f1ba1959b498b9f..d507c177b82362d48d0a2dddc9a947508d7c3a76 100644 --- a/js/modules/i18n.js +++ b/js/modules/i18n.js @@ -12,9 +12,7 @@ exports.setup = (locale, messages) => { function getMessage(key, substitutions) { const entry = messages[key]; if (!entry) { - log.error( - `i18n: Attempted to get translation for nonexistent key '${key}'` - ); + log.error(`i18n: Attempted to get translation for nonexistent key '${key}'`); return ''; } diff --git a/js/modules/link_previews.js b/js/modules/link_previews.js index 554161e0b30a99346d029b9535767a8c499797d0..058d42db1ed5fb01457bde1ed4a5117a70381da8 100644 --- a/js/modules/link_previews.js +++ b/js/modules/link_previews.js @@ -151,9 +151,6 @@ function isLinkSneaky(href) { // We can't use `url.pathname` (and so on) because it automatically encodes strings. // For example, it turns `/aquÃ` into `/aqu%C3%AD`. const startOfPathAndHash = href.indexOf('/', url.protocol.length + 4); - const pathAndHash = - startOfPathAndHash === -1 ? '' : href.substr(startOfPathAndHash); - return [...pathAndHash].some( - character => !VALID_URI_CHARACTERS.has(character) - ); + const pathAndHash = startOfPathAndHash === -1 ? '' : href.substr(startOfPathAndHash); + return [...pathAndHash].some(character => !VALID_URI_CHARACTERS.has(character)); } diff --git a/js/modules/loki_app_dot_net_api.d.ts b/js/modules/loki_app_dot_net_api.d.ts index 7123d6de9db380dce0b1f689e44d86d312bccc42..1026f2f53d163ec57ba2f4737731a623836582b6 100644 --- a/js/modules/loki_app_dot_net_api.d.ts +++ b/js/modules/loki_app_dot_net_api.d.ts @@ -1,8 +1,4 @@ -import { - Quote, - AttachmentPointer, - Preview, -} from '../../ts/session/messages/outgoing'; +import { Quote, AttachmentPointer, Preview } from '../../ts/session/messages/outgoing'; interface UploadResponse { url: string; diff --git a/js/modules/loki_app_dot_net_api.js b/js/modules/loki_app_dot_net_api.js index 7567d872749d676677b79a6bf13785df83ff8520..1ce0ae8a81427481c2ecd7b02a3e56bbb680486f 100644 --- a/js/modules/loki_app_dot_net_api.js +++ b/js/modules/loki_app_dot_net_api.js @@ -13,12 +13,9 @@ const PUBLICCHAT_CHAN_POLL_EVERY = 20 * 1000; // 20s const PUBLICCHAT_DELETION_POLL_EVERY = 5 * 1000; // 5s const PUBLICCHAT_MOD_POLL_EVERY = 30 * 1000; // 30s -const LOKIFOUNDATION_DEVFILESERVER_PUBKEY = - 'BSZiMVxOco/b3sYfaeyiMWv/JnqokxGXkHoclEx8TmZ6'; -const LOKIFOUNDATION_FILESERVER_PUBKEY = - 'BWJQnVm97sQE3Q1InB4Vuo+U/T1hmwHBv0ipkiv8tzEc'; -const LOKIFOUNDATION_APNS_PUBKEY = - 'BWQqZYWRl0LlotTcUSRJZPvNi8qyt1YSQH3li4EHQNBJ'; +const LOKIFOUNDATION_DEVFILESERVER_PUBKEY = 'BSZiMVxOco/b3sYfaeyiMWv/JnqokxGXkHoclEx8TmZ6'; +const LOKIFOUNDATION_FILESERVER_PUBKEY = 'BWJQnVm97sQE3Q1InB4Vuo+U/T1hmwHBv0ipkiv8tzEc'; +const LOKIFOUNDATION_APNS_PUBKEY = 'BWQqZYWRl0LlotTcUSRJZPvNi8qyt1YSQH3li4EHQNBJ'; const urlPubkeyMap = { 'https://file-dev.getsession.org': LOKIFOUNDATION_DEVFILESERVER_PUBKEY, @@ -64,27 +61,15 @@ class LokiAppDotNetServerAPI { // channel getter/factory async findOrCreateChannel(chatAPI, channelId, conversationId) { - let thisChannel = this.channels.find( - channel => channel.channelId === channelId - ); + let thisChannel = this.channels.find(channel => channel.channelId === channelId); if (!thisChannel) { // make sure we're subscribed // eventually we'll need to move to account registration/add server await this.serverRequest(`channels/${channelId}/subscribe`, { method: 'POST', }); - thisChannel = new LokiPublicChannelAPI( - chatAPI, - this, - channelId, - conversationId - ); - log.info( - 'LokiPublicChannelAPI started for', - channelId, - 'on', - this.baseServerUrl - ); + thisChannel = new LokiPublicChannelAPI(chatAPI, this, channelId, conversationId); + log.info('LokiPublicChannelAPI started for', channelId, 'on', this.baseServerUrl); this.channels.push(thisChannel); } return thisChannel; @@ -127,9 +112,7 @@ class LokiAppDotNetServerAPI { // Hard coded let pubKeyAB; if (urlPubkeyMap && urlPubkeyMap[this.baseServerUrl]) { - pubKeyAB = window.Signal.Crypto.base64ToArrayBuffer( - urlPubkeyMap[this.baseServerUrl] - ); + pubKeyAB = window.Signal.Crypto.base64ToArrayBuffer(urlPubkeyMap[this.baseServerUrl]); } // do we have their pubkey locally? @@ -142,8 +125,7 @@ class LokiAppDotNetServerAPI { window.lokiPublicChatAPI.openGroupPubKeys && window.lokiPublicChatAPI.openGroupPubKeys[this.baseServerUrl] ) { - pubKeyAB = - window.lokiPublicChatAPI.openGroupPubKeys[this.baseServerUrl]; + pubKeyAB = window.lokiPublicChatAPI.openGroupPubKeys[this.baseServerUrl]; } } // else will fail validation later @@ -189,10 +171,7 @@ class LokiAppDotNetServerAPI { // no big deal if it fails... if (res.err || !res.response || !res.response.data) { if (res.err) { - log.error( - `setProfileName Error ${res.err} ${res.statusCode}`, - this.baseServerUrl - ); + log.error(`setProfileName Error ${res.err} ${res.statusCode}`, this.baseServerUrl); } return []; } @@ -243,9 +222,7 @@ class LokiAppDotNetServerAPI { if (this.token) { return this.token; } - token = await Signal.Data.getPublicServerTokenByServerUrl( - this.baseServerUrl - ); + token = await Signal.Data.getPublicServerTokenByServerUrl(this.baseServerUrl); } if (!token) { token = await this.refreshServerToken(); @@ -360,25 +337,12 @@ class LokiAppDotNetServerAPI { // not really an error, from a client's pov, network servers can fail... if (e.code === 'ECONNREFUSED') { // down - log.warn( - 'requestToken request can not connect', - this.baseServerUrl, - e.message - ); + log.warn('requestToken request can not connect', this.baseServerUrl, e.message); } else if (e.code === 'ECONNRESET') { // got disconnected - log.warn( - 'requestToken request lost connection', - this.baseServerUrl, - e.message - ); + log.warn('requestToken request lost connection', this.baseServerUrl, e.message); } else { - log.error( - 'requestToken request failed', - this.baseServerUrl, - e.code, - e.message - ); + log.error('requestToken request failed', this.baseServerUrl, e.code, e.message); } return null; } @@ -448,9 +412,7 @@ class LokiAppDotNetServerAPI { log.warn('No channelId provided to getModerators!'); return []; } - const res = await this.serverRequest( - `loki/v1/channels/${channelId}/moderators` - ); + const res = await this.serverRequest(`loki/v1/channels/${channelId}/moderators`); return (!res.err && res.response && res.response.moderators) || []; } @@ -590,11 +552,7 @@ class LokiAppDotNetServerAPI { if (res.err || !res.response || !res.response.data) { if (res.err) { - log.error( - `loki_app_dot_net:::getUsers - Error: ${res.err} for ${pubKeys.join( - ',' - )}` - ); + log.error(`loki_app_dot_net:::getUsers - Error: ${res.err} for ${pubKeys.join(',')}`); } return []; } @@ -639,10 +597,7 @@ class LokiAppDotNetServerAPI { throw new Error(`Failed to upload avatar to ${this.baseServerUrl}`); } - const url = - response.data && - response.data.avatar_image && - response.data.avatar_image.url; + const url = response.data && response.data.avatar_image && response.data.avatar_image.url; if (!url) { throw new Error(`Failed to upload data: Invalid url.`); @@ -720,9 +675,7 @@ class LokiAppDotNetServerAPI { }); if (window.lokiFeatureFlags.useFileOnionRequestsV2) { - const buffer = dcodeIO.ByteBuffer.fromBase64( - res.response - ).toArrayBuffer(); + const buffer = dcodeIO.ByteBuffer.fromBase64(res.response).toArrayBuffer(); return buffer; } return new Uint8Array(res.response.data).buffer; @@ -737,9 +690,7 @@ class LokiPublicChannelAPI { this.channelId = channelId; this.baseChannelUrl = `channels/${this.channelId}`; this.conversationId = conversationId; - this.conversation = window - .getConversationController() - .getOrThrow(conversationId); + this.conversation = window.getConversationController().getOrThrow(conversationId); this.lastMessageServerID = null; this.modStatus = false; this.deleteLastId = 1; @@ -755,9 +706,7 @@ class LokiPublicChannelAPI { // end properties - log.info( - `registered LokiPublicChannel ${channelId} on ${this.serverAPI.baseServerUrl}` - ); + log.info(`registered LokiPublicChannel ${channelId} on ${this.serverAPI.baseServerUrl}`); // start polling this.open(); } @@ -775,12 +724,9 @@ class LokiPublicChannelAPI { } async banUser(pubkey) { - const res = await this.serverRequest( - `loki/v1/moderation/blacklist/@${pubkey}`, - { - method: 'POST', - } - ); + const res = await this.serverRequest(`loki/v1/moderation/blacklist/@${pubkey}`, { + method: 'POST', + }); if (res.err || !res.response || !res.response.data) { if (res.err) { @@ -793,9 +739,7 @@ class LokiPublicChannelAPI { } open() { - log.info( - `LokiPublicChannel open ${this.channelId} on ${this.serverAPI.baseServerUrl}` - ); + log.info(`LokiPublicChannel open ${this.channelId} on ${this.serverAPI.baseServerUrl}`); if (this.running) { log.warn( `LokiPublicChannel already open ${this.channelId} on ${this.serverAPI.baseServerUrl}` @@ -818,9 +762,7 @@ class LokiPublicChannelAPI { } stop() { - log.info( - `LokiPublicChannel close ${this.channelId} on ${this.serverAPI.baseServerUrl}` - ); + log.info(`LokiPublicChannel close ${this.channelId} on ${this.serverAPI.baseServerUrl}`); if (!this.running) { log.warn( `LokiPublicChannel already open ${this.channelId} on ${this.serverAPI.baseServerUrl}` @@ -862,11 +804,7 @@ class LokiPublicChannelAPI { try { await this.pollOnceForModerators(); } catch (e) { - log.warn( - 'Error while polling for public chat moderators:', - e.code, - e.message - ); + log.warn('Error while polling for public chat moderators:', e.code, e.message); } if (this.running) { this.timers.moderator = setTimeout(() => { @@ -878,9 +816,7 @@ class LokiPublicChannelAPI { // get moderator status async pollOnceForModerators() { // get moderator status - const res = await this.serverRequest( - `loki/v1/channels/${this.channelId}/moderators` - ); + const res = await this.serverRequest(`loki/v1/channels/${this.channelId}/moderators`); const ourNumberDevice = window.libsession.Utils.UserUtils.getOurPubKeyStrFromCache(); // Get the list of moderators if no errors occurred @@ -911,15 +847,12 @@ class LokiPublicChannelAPI { log.warn(`public chat channel state unknown, skipping set: ${res.err}`); return false; } - let notes = - res.response && res.response.data && res.response.data.annotations; + let notes = res.response && res.response.data && res.response.data.annotations; if (!notes) { // ok if nothing is set yet notes = []; } - let settingNotes = notes.filter( - note => note.type === SETTINGS_CHANNEL_ANNOTATION_TYPE - ); + let settingNotes = notes.filter(note => note.type === SETTINGS_CHANNEL_ANNOTATION_TYPE); if (!settingNotes) { // default name, description, avatar settingNotes = [ @@ -936,10 +869,10 @@ class LokiPublicChannelAPI { // update settings settingNotes[0].value = Object.assign(settingNotes[0].value, settings); // commit settings - const updateRes = await this.serverRequest( - `loki/v1/${this.baseChannelUrl}`, - { method: 'PUT', objBody: { annotations: settingNotes } } - ); + const updateRes = await this.serverRequest(`loki/v1/${this.baseChannelUrl}`, { + method: 'PUT', + objBody: { annotations: settingNotes }, + }); if (updateRes.err || !updateRes.response || !updateRes.response.data) { if (updateRes.err) { log.error(`setChannelSettings Error ${updateRes.err}`); @@ -967,17 +900,13 @@ class LokiPublicChannelAPI { { method: 'DELETE', params: { ids: serverIds } } ); if (!res.err) { - const deletedIds = res.response.data - .filter(d => d.is_deleted) - .map(d => d.id); + const deletedIds = res.response.data.filter(d => d.is_deleted).map(d => d.id); if (deletedIds.length > 0) { log.info(`deleted ${serverIds} on ${this.baseChannelUrl}`); } - const failedIds = res.response.data - .filter(d => !d.is_deleted) - .map(d => d.id); + const failedIds = res.response.data.filter(d => !d.is_deleted).map(d => d.id); if (failedIds.length > 0) { log.warn(`failed to delete ${failedIds} on ${this.baseChannelUrl}`); @@ -985,10 +914,7 @@ class LokiPublicChannelAPI { // Note: if there is no entry for message, we assume it wasn't found // on the server, so it is not treated as explicitly failed - const ignoredIds = _.difference( - serverIds, - _.union(failedIds, deletedIds) - ); + const ignoredIds = _.difference(serverIds, _.union(failedIds, deletedIds)); if (ignoredIds.length > 0) { log.warn(`No response for ${ignoredIds} on ${this.baseChannelUrl}`); @@ -997,9 +923,7 @@ class LokiPublicChannelAPI { return { deletedIds, ignoredIds }; } if (canThrow) { - throw new textsecure.PublicChatError( - 'Failed to delete public chat message' - ); + throw new textsecure.PublicChatError('Failed to delete public chat message'); } return { deletedIds: [], ignoredIds: [] }; } @@ -1015,11 +939,7 @@ class LokiPublicChannelAPI { try { await this.pollForChannelOnce(); } catch (e) { - log.warn( - 'Error while polling for public chat room details', - e.code, - e.message - ); + log.warn('Error while polling for public chat room details', e.code, e.message); } if (this.running) { this.timers.channel = setTimeout(() => { @@ -1072,16 +992,11 @@ class LokiPublicChannelAPI { } else { // relative URL avatar const avatarAbsUrl = this.serverAPI.baseServerUrl + note.value.avatar; - const { - writeNewAttachmentData, - deleteAttachmentData, - } = window.Signal.Migrations; + const { writeNewAttachmentData, deleteAttachmentData } = window.Signal.Migrations; // do we already have this image? no, then // download a copy and save it - const imageData = await this.serverAPI.downloadAttachment( - avatarAbsUrl - ); + const imageData = await this.serverAPI.downloadAttachment(avatarAbsUrl); const newAttributes = await window.Signal.Types.Conversation.maybeUpdateAvatar( this.conversation.attributes, @@ -1111,11 +1026,7 @@ class LokiPublicChannelAPI { try { await this.pollOnceForDeletions(); } catch (e) { - log.warn( - 'Error while polling for public chat deletions:', - e.code, - e.message - ); + log.warn('Error while polling for public chat deletions:', e.code, e.message); } if (this.running) { this.timers.delete = setTimeout(() => { @@ -1138,18 +1049,10 @@ class LokiPublicChannelAPI { // grab the next 200 deletions from where we last checked // eslint-disable-next-line no-await-in-loop - const res = await this.serverRequest( - `loki/v1/channel/${this.channelId}/deletes`, - { params } - ); + const res = await this.serverRequest(`loki/v1/channel/${this.channelId}/deletes`, { params }); // if any problems, abort out - if ( - res.err || - !res.response || - !res.response.data || - !res.response.meta - ) { + if (res.err || !res.response || !res.response.data || !res.response.meta) { if (res.statusCode === 403) { // token is now invalid this.serverAPI.getOrRefreshServerToken(true); @@ -1157,9 +1060,7 @@ class LokiPublicChannelAPI { if (res.err) { log.error(`pollOnceForDeletions Error ${res.err}`); } else { - log.error( - `pollOnceForDeletions Error: Received incorrect response ${res.response}` - ); + log.error(`pollOnceForDeletions Error: Received incorrect response ${res.response}`); } break; } @@ -1175,20 +1076,11 @@ class LokiPublicChannelAPI { // update where we last checked this.deleteLastId = res.response.meta.max_id; - more = - res.response.meta.more && - res.response.data.length >= params.count && - this.running; + more = res.response.meta.more && res.response.data.length >= params.count && this.running; } } - static getSigData( - sigVer, - noteValue, - attachmentAnnotations, - previewAnnotations, - adnMessage - ) { + static getSigData(sigVer, noteValue, attachmentAnnotations, previewAnnotations, adnMessage) { let sigString = ''; sigString += adnMessage.text.trim(); sigString += noteValue.timestamp; @@ -1210,10 +1102,7 @@ class LokiPublicChannelAPI { } async getMessengerData(adnMessage) { - if ( - !Array.isArray(adnMessage.annotations) || - adnMessage.annotations.length === 0 - ) { + if (!Array.isArray(adnMessage.annotations) || adnMessage.annotations.length === 0) { return false; } const noteValue = adnMessage.annotations[0].value; @@ -1293,8 +1182,7 @@ class LokiPublicChannelAPI { return { timestamp, - serverTimestamp: - new Date(`${adnMessage.created_at}`).getTime() || timestamp, + serverTimestamp: new Date(`${adnMessage.created_at}`).getTime() || timestamp, attachments, preview, quote, @@ -1309,11 +1197,7 @@ class LokiPublicChannelAPI { try { await this.pollOnceForMessages(); } catch (e) { - log.warn( - 'Error while polling for public chat messages:', - e.code, - e.message - ); + log.warn('Error while polling for public chat messages:', e.code, e.message); } if (this.running) { this.timers.message = setTimeout(() => { @@ -1386,8 +1270,7 @@ class LokiPublicChannelAPI { // get our profile name const ourNumberDevice = window.libsession.Utils.UserUtils.getOurPubKeyStrFromCache(); // if no primaryDevicePubKey fall back to ourNumberDevice - const ourNumberProfile = - window.storage.get('primaryDevicePubKey') || ourNumberDevice; + const ourNumberProfile = window.storage.get('primaryDevicePubKey') || ourNumberDevice; let lastProfileName = false; // the signature forces this to be async @@ -1437,11 +1320,7 @@ class LokiPublicChannelAPI { // message is one of the object of this.lastMessagesCache // testedMessage is the adnMessage object const isDuplicate = (message, testedMessage) => - DataMessage.isDuplicate( - message, - testedMessage, - testedMessage.user.username - ); + DataMessage.isDuplicate(message, testedMessage, testedMessage.user.username); const isThisMessageDuplicate = this.lastMessagesCache.some(m => isDuplicate(m, adnMessage) ); @@ -1503,8 +1382,7 @@ class LokiPublicChannelAPI { receivedAt, isPublic: true, message: { - body: - adnMessage.text === timestamp.toString() ? '' : adnMessage.text, + body: adnMessage.text === timestamp.toString() ? '' : adnMessage.text, attachments, group: { id: this.conversationId, @@ -1571,9 +1449,7 @@ class LokiPublicChannelAPI { // if we received one of our own messages if (lastProfileName !== false) { // get current profileName - const profileConvo = window - .getConversationController() - .get(ourNumberProfile); + const profileConvo = window.getConversationController().get(ourNumberProfile); const profileName = profileConvo.getProfileName(); // check to see if it out of sync if (profileName !== lastProfileName) { @@ -1668,12 +1544,8 @@ class LokiPublicChannelAPI { async sendMessage(data, messageTimeStamp) { const { quote, attachments, preview } = data; const text = data.body || messageTimeStamp.toString(); - const attachmentAnnotations = attachments.map( - LokiPublicChannelAPI.getAnnotationFromAttachment - ); - const previewAnnotations = preview.map( - LokiPublicChannelAPI.getAnnotationFromPreview - ); + const attachmentAnnotations = attachments.map(LokiPublicChannelAPI.getAnnotationFromAttachment); + const previewAnnotations = preview.map(LokiPublicChannelAPI.getAnnotationFromPreview); const payload = { text, @@ -1721,10 +1593,7 @@ class LokiPublicChannelAPI { previewAnnotations.map(anno => anno.value), mockAdnMessage ); - const sig = await libsignal.Curve.async.calculateSignature( - privKey, - sigData - ); + const sig = await libsignal.Curve.async.calculateSignature(privKey, sigData); payload.annotations[0].value.sig = StringView.arrayBufferToHex(sig); payload.annotations[0].value.sigver = sigVer; const res = await this.serverRequest(`${this.baseChannelUrl}/messages`, { diff --git a/js/modules/loki_file_server_api.js b/js/modules/loki_file_server_api.js index cc66739522997761ba9791c1ed09d3f49e0d91da..60935bfce0af8aaf8c9bfdabcfffa86fead53d51 100644 --- a/js/modules/loki_file_server_api.js +++ b/js/modules/loki_file_server_api.js @@ -63,9 +63,7 @@ class LokiFileServerFactoryAPI { } establishHomeConnection(serverUrl) { - let thisServer = this.servers.find( - server => server._server.baseServerUrl === serverUrl - ); + let thisServer = this.servers.find(server => server._server.baseServerUrl === serverUrl); if (!thisServer) { thisServer = new LokiHomeServerInstance(this.ourKey); log.info(`Registering HomeServer ${serverUrl}`); @@ -77,9 +75,7 @@ class LokiFileServerFactoryAPI { } async establishConnection(serverUrl) { - let thisServer = this.servers.find( - server => server._server.baseServerUrl === serverUrl - ); + let thisServer = this.servers.find(server => server._server.baseServerUrl === serverUrl); if (!thisServer) { thisServer = new LokiFileServerInstance(this.ourKey); log.info(`Registering FileServer ${serverUrl}`); diff --git a/js/modules/loki_message_api.js b/js/modules/loki_message_api.js index a2c17e23ba007f59acd42333601586fad4357d27..439a050658007a42e9a52f380cdb003f3dcd6c85 100644 --- a/js/modules/loki_message_api.js +++ b/js/modules/loki_message_api.js @@ -45,9 +45,7 @@ class LokiMessageAPI { }; if (isPublic) { - window.log.warn( - 'this sendMessage() should not be called anymore with an open group message' - ); + window.log.warn('this sendMessage() should not be called anymore with an open group message'); return; } @@ -98,10 +96,7 @@ class LokiMessageAPI { throw e; } if (!snode) { - throw new window.textsecure.EmptySwarmError( - pubKey, - 'Ran out of swarm nodes to query' - ); + throw new window.textsecure.EmptySwarmError(pubKey, 'Ran out of swarm nodes to query'); } else { log.info( `loki_message:::sendMessage - Successfully stored message to ${pubKey} via ${snode.ip}:${snode.port}` diff --git a/js/modules/loki_primitives.d.ts b/js/modules/loki_primitives.d.ts index 32ad3e232d0601f3ecc883d32a950d0a6189343d..aaf658032091c694043ce34775601ec3ba820d08 100644 --- a/js/modules/loki_primitives.d.ts +++ b/js/modules/loki_primitives.d.ts @@ -1,6 +1,3 @@ export async function sleepFor(ms: number); -export async function abortableIterator( - array: Array<any>, - action: (any) => void -); +export async function abortableIterator(array: Array<any>, action: (any) => void); diff --git a/js/modules/loki_public_chat_api.d.ts b/js/modules/loki_public_chat_api.d.ts index 6c85482e0bce87335a990f0033da82789a2b30ff..0c8524c5e11c367396e9143c5e92a777a6f9ef05 100644 --- a/js/modules/loki_public_chat_api.d.ts +++ b/js/modules/loki_public_chat_api.d.ts @@ -1,7 +1,4 @@ -import { - LokiAppDotNetServerInterface, - LokiPublicChannelAPI, -} from './loki_app_dot_net_api'; +import { LokiAppDotNetServerInterface, LokiPublicChannelAPI } from './loki_app_dot_net_api'; export interface LokiPublicChatFactoryInterface { ourKey: string; @@ -12,16 +9,11 @@ export interface LokiPublicChatFactoryInterface { channelId: number, conversationId: string ): Promise<LokiPublicChannelAPI | null>; - getListOfMembers(): Promise< - Array<{ authorPhoneNumber: string; authorProfileName?: string }> - >; - setListOfMembers( - members: Array<{ authorPhoneNumber: string; authorProfileName?: string }> - ); + getListOfMembers(): Promise<Array<{ authorPhoneNumber: string; authorProfileName?: string }>>; + setListOfMembers(members: Array<{ authorPhoneNumber: string; authorProfileName?: string }>); } -declare class LokiPublicChatFactoryAPI - implements LokiPublicChatFactoryInterface { +declare class LokiPublicChatFactoryAPI implements LokiPublicChatFactoryInterface { constructor(ourKey: string); } diff --git a/js/modules/loki_public_chat_api.js b/js/modules/loki_public_chat_api.js index f5512cff85e8c8c5a346b608546821ccac70c1d9..fc361a1d681a89728eecf5e2338df004b0c1116b 100644 --- a/js/modules/loki_public_chat_api.js +++ b/js/modules/loki_public_chat_api.js @@ -26,20 +26,14 @@ class LokiPublicChatFactoryAPI extends EventEmitter { // server getter/factory async findOrCreateServer(serverUrl) { - let thisServer = this.servers.find( - server => server.baseServerUrl === serverUrl - ); + let thisServer = this.servers.find(server => server.baseServerUrl === serverUrl); if (!thisServer) { log.info(`loki_public_chat::findOrCreateServer - creating ${serverUrl}`); - const serverIsValid = await OpenGroupUtils.validOpenGroupServer( - serverUrl - ); + const serverIsValid = await OpenGroupUtils.validOpenGroupServer(serverUrl); if (!serverIsValid) { // FIXME: add toast? - log.error( - `loki_public_chat::findOrCreateServer - error: ${serverUrl} is not valid` - ); + log.error(`loki_public_chat::findOrCreateServer - error: ${serverUrl} is not valid`); return null; } @@ -53,18 +47,14 @@ class LokiPublicChatFactoryAPI extends EventEmitter { if (this.openGroupPubKeys[serverUrl]) { thisServer.getPubKeyForUrl(); if (!thisServer.pubKeyHex) { - log.warn( - `loki_public_chat::findOrCreateServer - failed to set public key` - ); + log.warn(`loki_public_chat::findOrCreateServer - failed to set public key`); } } } const gotToken = await thisServer.getOrRefreshServerToken(); if (!gotToken) { - log.warn( - `loki_public_chat::findOrCreateServer - Invalid server ${serverUrl}` - ); + log.warn(`loki_public_chat::findOrCreateServer - Invalid server ${serverUrl}`); return null; } @@ -85,9 +75,7 @@ class LokiPublicChatFactoryAPI extends EventEmitter { // deallocate resources server uses unregisterChannel(serverUrl, channelId) { - const i = this.servers.findIndex( - server => server.baseServerUrl === serverUrl - ); + const i = this.servers.findIndex(server => server.baseServerUrl === serverUrl); if (i === -1) { log.warn(`Tried to unregister from nonexistent server ${serverUrl}`); return; diff --git a/js/modules/loki_push_notification_server_api.js b/js/modules/loki_push_notification_server_api.js index 91531a47b9ef11cee7733a50b6ba8fba52c51080..092a142f17a2a4c03981fd2fd329f15a3c9dc1a5 100644 --- a/js/modules/loki_push_notification_server_api.js +++ b/js/modules/loki_push_notification_server_api.js @@ -4,8 +4,7 @@ const LokiAppDotNetAPI = require('./loki_app_dot_net_api'); class LokiPushNotificationServerApi { constructor() { - this.ourKey = - '642a6585919742e5a2d4dc51244964fbcd8bcab2b75612407de58b810740d049'; + this.ourKey = '642a6585919742e5a2d4dc51244964fbcd8bcab2b75612407de58b810740d049'; this.serverUrl = 'https://live.apns.getsession.org'; this._server = new LokiAppDotNetAPI(this.ourKey, this.serverUrl); diff --git a/js/modules/loki_snode_api.js b/js/modules/loki_snode_api.js index 984b8941e8176a0f918e07d7f9873f50751ff8b6..eb17104c18f858ff5376ddd336d9d2095ed6c937 100644 --- a/js/modules/loki_snode_api.js +++ b/js/modules/loki_snode_api.js @@ -32,9 +32,7 @@ class LokiSnodeAPI { // Timeouts const maxTimeoutVal = 2 ** 31 - 1; const timeoutPromise = () => - new Promise((_resolve, reject) => - setTimeout(() => reject(), timeout || maxTimeoutVal) - ); + new Promise((_resolve, reject) => setTimeout(() => reject(), timeout || maxTimeoutVal)); // Get nodes capable of doing LNS const lnsNodes = await window.SnodePool.getNodesMinVersion( @@ -72,9 +70,7 @@ class LokiSnodeAPI { if (res && res.result && res.result.status === 'OK') { const hasMapping = res.result.entries && res.result.entries.length > 0; - const resValue = hasMapping - ? res.result.entries[0].encrypted_value - : null; + const resValue = hasMapping ? res.result.entries[0].encrypted_value : null; confirmedNodes.push(resValue); @@ -84,10 +80,7 @@ class LokiSnodeAPI { return; } - const [winner, count] = _.maxBy( - _.entries(_.countBy(confirmedNodes)), - x => x[1] - ); + const [winner, count] = _.maxBy(_.entries(_.countBy(confirmedNodes)), x => x[1]); if (count >= numRequiredConfirms) { ciphertextHex = winner === String(null) ? null : winner; diff --git a/js/modules/settings.js b/js/modules/settings.js index 391b548d65752203eccae33d23ea664af88162aa..f641958c9c0e63f39f605ac2f217534ad41e36a8 100644 --- a/js/modules/settings.js +++ b/js/modules/settings.js @@ -26,8 +26,7 @@ exports.getMessageExportLastIndex = connection => exports._getItem(connection, MESSAGE_LAST_INDEX_KEY); exports.setMessageExportLastIndex = (connection, lastIndex) => exports._setItem(connection, MESSAGE_LAST_INDEX_KEY, lastIndex); -exports.getMessageExportCount = connection => - exports._getItem(connection, MESSAGE_COUNT_KEY); +exports.getMessageExportCount = connection => exports._getItem(connection, MESSAGE_COUNT_KEY); exports.setMessageExportCount = (connection, count) => exports._setItem(connection, MESSAGE_COUNT_KEY, count); @@ -52,8 +51,7 @@ exports._getItem = (connection, key) => { return new Promise((resolve, reject) => { request.onerror = event => reject(event.target.error); - request.onsuccess = event => - resolve(event.target.result ? event.target.result.value : null); + request.onsuccess = event => resolve(event.target.result ? event.target.result.value : null); }); }; diff --git a/js/modules/signal.js b/js/modules/signal.js index c836880b676dc77e8828ef8bf3c32588346638de..493ca8f6871ab4b9301282ea6f18a042ccf5f630 100644 --- a/js/modules/signal.js +++ b/js/modules/signal.js @@ -15,42 +15,24 @@ const { Message } = require('../../ts/components/conversation/Message'); // Components const { EditProfileDialog } = require('../../ts/components/EditProfileDialog'); const { UserDetailsDialog } = require('../../ts/components/UserDetailsDialog'); -const { - SessionSeedModal, -} = require('../../ts/components/session/SessionSeedModal'); -const { - SessionIDResetDialog, -} = require('../../ts/components/session/SessionIDResetDialog'); -const { - SessionRegistrationView, -} = require('../../ts/components/session/SessionRegistrationView'); +const { SessionSeedModal } = require('../../ts/components/session/SessionSeedModal'); +const { SessionIDResetDialog } = require('../../ts/components/session/SessionIDResetDialog'); +const { SessionRegistrationView } = require('../../ts/components/session/SessionRegistrationView'); -const { - SessionInboxView, -} = require('../../ts/components/session/SessionInboxView'); -const { - SessionPasswordModal, -} = require('../../ts/components/session/SessionPasswordModal'); -const { - SessionConfirm, -} = require('../../ts/components/session/SessionConfirm'); +const { SessionInboxView } = require('../../ts/components/session/SessionInboxView'); +const { SessionPasswordModal } = require('../../ts/components/session/SessionPasswordModal'); +const { SessionConfirm } = require('../../ts/components/session/SessionConfirm'); -const { - UpdateGroupNameDialog, -} = require('../../ts/components/conversation/UpdateGroupNameDialog'); +const { UpdateGroupNameDialog } = require('../../ts/components/conversation/UpdateGroupNameDialog'); const { UpdateGroupMembersDialog, } = require('../../ts/components/conversation/UpdateGroupMembersDialog'); -const { - InviteContactsDialog, -} = require('../../ts/components/conversation/InviteContactsDialog'); +const { InviteContactsDialog } = require('../../ts/components/conversation/InviteContactsDialog'); const { AdminLeaveClosedGroupDialog, } = require('../../ts/components/conversation/AdminLeaveClosedGroupDialog'); -const { - AddModeratorsDialog, -} = require('../../ts/components/conversation/ModeratorsAddDialog'); +const { AddModeratorsDialog } = require('../../ts/components/conversation/ModeratorsAddDialog'); const { RemoveModeratorsDialog, } = require('../../ts/components/conversation/ModeratorsRemoveDialog'); @@ -68,13 +50,7 @@ const SettingsType = require('../../ts/types/Settings'); // Views const Initialization = require('./views/initialization'); -function initializeMigrations({ - userDataPath, - Attachments, - Type, - VisualType, - logger, -}) { +function initializeMigrations({ userDataPath, Attachments, Type, VisualType, logger }) { if (!Attachments) { return null; } @@ -146,8 +122,7 @@ function initializeMigrations({ logger, }), writeNewAttachmentData: createWriterForNew(attachmentsPath), - writeAttachment: ({ data, path }) => - createWriterForExisting(attachmentsPath)({ data, path }), + writeAttachment: ({ data, path }) => createWriterForExisting(attachmentsPath)({ data, path }), }; } diff --git a/js/modules/types/attachment.js b/js/modules/types/attachment.js index 946514bb845e05b3bf4e6820a145effc06bd1178..834401f3982c1d56abc192297be0a683967a99f0 100644 --- a/js/modules/types/attachment.js +++ b/js/modules/types/attachment.js @@ -4,15 +4,9 @@ const AttachmentTS = require('../../../ts/types/Attachment'); const GoogleChrome = require('../../../ts/util/GoogleChrome'); const MIME = require('../../../ts/types/MIME'); const { toLogFormat } = require('./errors'); -const { - arrayBufferToBlob, - blobToArrayBuffer, - dataURLToBlob, -} = require('blob-util'); +const { arrayBufferToBlob, blobToArrayBuffer, dataURLToBlob } = require('blob-util'); const { autoOrientImage } = require('../auto_orient_image'); -const { - migrateDataToFileSystem, -} = require('./attachment/migrate_data_to_file_system'); +const { migrateDataToFileSystem } = require('./attachment/migrate_data_to_file_system'); // // Incoming message attachment fields // { @@ -61,10 +55,7 @@ exports.autoOrientJPEG = async attachment => { return attachment; } - const dataBlob = await arrayBufferToBlob( - attachment.data, - attachment.contentType - ); + const dataBlob = await arrayBufferToBlob(attachment.data, attachment.contentType); const newDataBlob = await dataURLToBlob(await autoOrientImage(dataBlob)); const newDataArrayBuffer = await blobToArrayBuffer(newDataBlob); @@ -125,10 +116,7 @@ exports.replaceUnicodeV2 = async attachment => { return attachment; } - const fileName = attachment.fileName.replace( - V2_UNWANTED_UNICODE, - UNICODE_REPLACEMENT_CHARACTER - ); + const fileName = attachment.fileName.replace(V2_UNWANTED_UNICODE, UNICODE_REPLACEMENT_CHARACTER); return { ...attachment, @@ -138,10 +126,7 @@ exports.replaceUnicodeV2 = async attachment => { exports.removeSchemaVersion = ({ attachment, logger }) => { if (!exports.isValid(attachment)) { - logger.error( - 'Attachment.removeSchemaVersion: Invalid input attachment:', - attachment - ); + logger.error('Attachment.removeSchemaVersion: Invalid input attachment:', attachment); return attachment; } @@ -294,10 +279,7 @@ exports.captureDimensionsAndScreenshot = async ( logger, }) ); - screenshotObjectUrl = makeObjectUrl( - screenshotBuffer, - THUMBNAIL_CONTENT_TYPE - ); + screenshotObjectUrl = makeObjectUrl(screenshotBuffer, THUMBNAIL_CONTENT_TYPE); const { width, height } = await getImageDimensions({ objectUrl: screenshotObjectUrl, logger, diff --git a/js/modules/types/attachment/migrate_data_to_file_system.js b/js/modules/types/attachment/migrate_data_to_file_system.js index dded244ad3d8b2746958210407ab77c35381b1dc..c75f2eafc0008bc3c9a7d4c34db55f9676d33cd1 100644 --- a/js/modules/types/attachment/migrate_data_to_file_system.js +++ b/js/modules/types/attachment/migrate_data_to_file_system.js @@ -7,10 +7,7 @@ const { isArrayBuffer, isFunction, isUndefined, omit } = require('lodash'); // migrateDataToFileSystem :: Attachment -> // Context -> // Promise Attachment -exports.migrateDataToFileSystem = async ( - attachment, - { writeNewAttachmentData } = {} -) => { +exports.migrateDataToFileSystem = async (attachment, { writeNewAttachmentData } = {}) => { if (!isFunction(writeNewAttachmentData)) { throw new TypeError("'writeNewAttachmentData' must be a function"); } @@ -25,15 +22,12 @@ exports.migrateDataToFileSystem = async ( const isValidData = isArrayBuffer(data); if (!isValidData) { throw new TypeError( - 'Expected `attachment.data` to be an array buffer;' + - ` got: ${typeof attachment.data}` + 'Expected `attachment.data` to be an array buffer;' + ` got: ${typeof attachment.data}` ); } const path = await writeNewAttachmentData(data); - const attachmentWithoutData = omit(Object.assign({}, attachment, { path }), [ - 'data', - ]); + const attachmentWithoutData = omit(Object.assign({}, attachment, { path }), ['data']); return attachmentWithoutData; }; diff --git a/js/modules/types/contact.js b/js/modules/types/contact.js index b2e5c0df4b34a13e659f6b13ab618f55c24288cb..2eda53eadfef7418e21a725301e80fd2664218f3 100644 --- a/js/modules/types/contact.js +++ b/js/modules/types/contact.js @@ -5,10 +5,7 @@ const { SignalService } = require('../../../ts/protobuf'); const DEFAULT_PHONE_TYPE = SignalService.DataMessage.Contact.Phone.Type.HOME; -exports.parseAndWriteAvatar = upgradeAttachment => async ( - contact, - context = {} -) => { +exports.parseAndWriteAvatar = upgradeAttachment => async (contact, context = {}) => { const { message, logger } = context; const { avatar } = contact; @@ -31,10 +28,7 @@ exports.parseAndWriteAvatar = upgradeAttachment => async ( messageId: idForLogging(message), }); if (error) { - logger.error( - 'Contact.parseAndWriteAvatar: contact was malformed.', - toLogFormat(error) - ); + logger.error('Contact.parseAndWriteAvatar: contact was malformed.', toLogFormat(error)); } return parsedContact; @@ -60,9 +54,7 @@ exports._validate = (contact, options = {}) => { const { name, number, organization } = contact; if ((!name || !name.displayName) && !organization) { - return new Error( - `Message ${messageId}: Contact had neither 'displayName' nor 'organization'` - ); + return new Error(`Message ${messageId}: Contact had neither 'displayName' nor 'organization'`); } if (!number || !number.length) { diff --git a/js/modules/types/conversation.js b/js/modules/types/conversation.js index a73de9e311c67a49e3e766672ca45a4fc993cccc..cf21231512dafcf18d6eeed3a61f59622bb41a78 100644 --- a/js/modules/types/conversation.js +++ b/js/modules/types/conversation.js @@ -18,14 +18,10 @@ function buildAvatarUpdater({ field }) { const avatar = conversation[field]; const { writeNewAttachmentData, deleteAttachmentData } = options; if (!isFunction(writeNewAttachmentData)) { - throw new Error( - 'Conversation.buildAvatarUpdater: writeNewAttachmentData must be a function' - ); + throw new Error('Conversation.buildAvatarUpdater: writeNewAttachmentData must be a function'); } if (!isFunction(deleteAttachmentData)) { - throw new Error( - 'Conversation.buildAvatarUpdater: deleteAttachmentData must be a function' - ); + throw new Error('Conversation.buildAvatarUpdater: deleteAttachmentData must be a function'); } const newHash = await computeHash(data); @@ -70,9 +66,7 @@ async function upgradeToVersion2(conversation, options) { const { writeNewAttachmentData } = options; if (!isFunction(writeNewAttachmentData)) { - throw new Error( - 'Conversation.upgradeToVersion2: writeNewAttachmentData must be a function' - ); + throw new Error('Conversation.upgradeToVersion2: writeNewAttachmentData must be a function'); } let { avatar, profileAvatar, profileKey } = conversation; @@ -123,9 +117,7 @@ async function deleteExternalFiles(conversation, options = {}) { const { deleteAttachmentData } = options; if (!isFunction(deleteAttachmentData)) { - throw new Error( - 'Conversation.buildAvatarUpdater: deleteAttachmentData must be a function' - ); + throw new Error('Conversation.buildAvatarUpdater: deleteAttachmentData must be a function'); } const { avatar, profileAvatar } = conversation; diff --git a/js/modules/types/message.js b/js/modules/types/message.js index fdb22090855ad42cd5e8055fde541d26af7d60bf..d06cc7e89c069a950090ce47433ce8140b456d15 100644 --- a/js/modules/types/message.js +++ b/js/modules/types/message.js @@ -60,15 +60,12 @@ exports.isValid = () => true; // Schema exports.initializeSchemaVersion = ({ message, logger }) => { - const isInitialized = - SchemaVersion.isValid(message.schemaVersion) && message.schemaVersion >= 1; + const isInitialized = SchemaVersion.isValid(message.schemaVersion) && message.schemaVersion >= 1; if (isInitialized) { return message; } - const numAttachments = Array.isArray(message.attachments) - ? message.attachments.length - : 0; + const numAttachments = Array.isArray(message.attachments) ? message.attachments.length : 0; const hasAttachments = numAttachments > 0; if (!hasAttachments) { return Object.assign({}, message, { @@ -79,9 +76,7 @@ exports.initializeSchemaVersion = ({ message, logger }) => { // All attachments should have the same schema version, so we just pick // the first one: const firstAttachment = message.attachments[0]; - const inheritedSchemaVersion = SchemaVersion.isValid( - firstAttachment.schemaVersion - ) + const inheritedSchemaVersion = SchemaVersion.isValid(firstAttachment.schemaVersion) ? firstAttachment.schemaVersion : INITIAL_SCHEMA_VERSION; const messageWithInitialSchema = Object.assign({}, message, { @@ -108,17 +103,12 @@ exports._withSchemaVersion = ({ schemaVersion, upgrade }) => { return async (message, context) => { if (!context || !isObject(context.logger)) { - throw new TypeError( - '_withSchemaVersion: context must have logger object' - ); + throw new TypeError('_withSchemaVersion: context must have logger object'); } const { logger } = context; if (!exports.isValid(message)) { - logger.error( - 'Message._withSchemaVersion: Invalid input message:', - message - ); + logger.error('Message._withSchemaVersion: Invalid input message:', message); return message; } @@ -150,10 +140,7 @@ exports._withSchemaVersion = ({ schemaVersion, upgrade }) => { } if (!exports.isValid(upgradedMessage)) { - logger.error( - 'Message._withSchemaVersion: Invalid upgraded message:', - upgradedMessage - ); + logger.error('Message._withSchemaVersion: Invalid upgraded message:', upgradedMessage); return message; } @@ -166,11 +153,8 @@ exports._withSchemaVersion = ({ schemaVersion, upgrade }) => { // (Message, Context) -> // Promise Message exports._mapAttachments = upgradeAttachment => async (message, context) => { - const upgradeWithContext = attachment => - upgradeAttachment(attachment, context); - const attachments = await Promise.all( - (message.attachments || []).map(upgradeWithContext) - ); + const upgradeWithContext = attachment => upgradeAttachment(attachment, context); + const attachments = await Promise.all((message.attachments || []).map(upgradeWithContext)); return Object.assign({}, message, { attachments }); }; @@ -180,21 +164,15 @@ exports._mapAttachments = upgradeAttachment => async (message, context) => { // Promise Message exports._mapContact = upgradeContact => async (message, context) => { const contextWithMessage = Object.assign({}, context, { message }); - const upgradeWithContext = contact => - upgradeContact(contact, contextWithMessage); - const contact = await Promise.all( - (message.contact || []).map(upgradeWithContext) - ); + const upgradeWithContext = contact => upgradeContact(contact, contextWithMessage); + const contact = await Promise.all((message.contact || []).map(upgradeWithContext)); return Object.assign({}, message, { contact }); }; // _mapQuotedAttachments :: (QuotedAttachment -> Promise QuotedAttachment) -> // (Message, Context) -> // Promise Message -exports._mapQuotedAttachments = upgradeAttachment => async ( - message, - context -) => { +exports._mapQuotedAttachments = upgradeAttachment => async (message, context) => { if (!message.quote) { return message; } @@ -216,9 +194,7 @@ exports._mapQuotedAttachments = upgradeAttachment => async ( const quotedAttachments = (message.quote && message.quote.attachments) || []; - const attachments = await Promise.all( - quotedAttachments.map(upgradeWithContext) - ); + const attachments = await Promise.all(quotedAttachments.map(upgradeWithContext)); return Object.assign({}, message, { quote: Object.assign({}, message.quote, { attachments, @@ -229,10 +205,7 @@ exports._mapQuotedAttachments = upgradeAttachment => async ( // _mapPreviewAttachments :: (PreviewAttachment -> Promise PreviewAttachment) -> // (Message, Context) -> // Promise Message -exports._mapPreviewAttachments = upgradeAttachment => async ( - message, - context -) => { +exports._mapPreviewAttachments = upgradeAttachment => async (message, context) => { if (!message.preview) { return message; } @@ -252,9 +225,7 @@ exports._mapPreviewAttachments = upgradeAttachment => async ( }); }; - const preview = await Promise.all( - (message.preview || []).map(upgradeWithContext) - ); + const preview = await Promise.all((message.preview || []).map(upgradeWithContext)); return Object.assign({}, message, { preview, }); @@ -284,9 +255,7 @@ const toVersion5 = exports._withSchemaVersion({ }); const toVersion6 = exports._withSchemaVersion({ schemaVersion: 6, - upgrade: exports._mapContact( - Contact.parseAndWriteAvatar(Attachment.migrateDataToFileSystem) - ), + upgrade: exports._mapContact(Contact.parseAndWriteAvatar(Attachment.migrateDataToFileSystem)), }); // IMPORTANT: We’ve updated our definition of `initializeAttachmentMetadata`, so // we need to run it again on existing items that have previously been incorrectly @@ -435,39 +404,31 @@ exports.processNewAttachment = async ( } const rotatedAttachment = await Attachment.autoOrientJPEG(attachment); - const onDiskAttachment = await Attachment.migrateDataToFileSystem( - rotatedAttachment, - { writeNewAttachmentData } - ); - const finalAttachment = await Attachment.captureDimensionsAndScreenshot( - onDiskAttachment, - { - writeNewAttachmentData, - getAbsoluteAttachmentPath, - makeObjectUrl, - revokeObjectUrl, - getImageDimensions, - makeImageThumbnail, - makeVideoScreenshot, - logger, - } - ); + const onDiskAttachment = await Attachment.migrateDataToFileSystem(rotatedAttachment, { + writeNewAttachmentData, + }); + const finalAttachment = await Attachment.captureDimensionsAndScreenshot(onDiskAttachment, { + writeNewAttachmentData, + getAbsoluteAttachmentPath, + makeObjectUrl, + revokeObjectUrl, + getImageDimensions, + makeImageThumbnail, + makeVideoScreenshot, + logger, + }); return finalAttachment; }; exports.createAttachmentLoader = loadAttachmentData => { if (!isFunction(loadAttachmentData)) { - throw new TypeError( - 'createAttachmentLoader: loadAttachmentData is required' - ); + throw new TypeError('createAttachmentLoader: loadAttachmentData is required'); } return async message => Object.assign({}, message, { - attachments: await Promise.all( - message.attachments.map(loadAttachmentData) - ), + attachments: await Promise.all(message.attachments.map(loadAttachmentData)), }); }; @@ -528,15 +489,11 @@ exports.loadPreviewData = loadAttachmentData => { exports.deleteAllExternalFiles = ({ deleteAttachmentData, deleteOnDisk }) => { if (!isFunction(deleteAttachmentData)) { - throw new TypeError( - 'deleteAllExternalFiles: deleteAttachmentData must be a function' - ); + throw new TypeError('deleteAllExternalFiles: deleteAttachmentData must be a function'); } if (!isFunction(deleteOnDisk)) { - throw new TypeError( - 'deleteAllExternalFiles: deleteOnDisk must be a function' - ); + throw new TypeError('deleteAllExternalFiles: deleteOnDisk must be a function'); } return async message => { @@ -590,10 +547,7 @@ exports.deleteAllExternalFiles = ({ deleteAttachmentData, deleteOnDisk }) => { // createAttachmentDataWriter :: (RelativePath -> IO Unit) // Message -> // IO (Promise Message) -exports.createAttachmentDataWriter = ({ - writeExistingAttachmentData, - logger, -}) => { +exports.createAttachmentDataWriter = ({ writeExistingAttachmentData, logger }) => { if (!isFunction(writeExistingAttachmentData)) { throw new TypeError( 'createAttachmentDataWriter: writeExistingAttachmentData must be a function' @@ -633,15 +587,11 @@ exports.createAttachmentDataWriter = ({ (attachments || []).forEach(attachment => { if (!Attachment.hasData(attachment)) { - throw new TypeError( - "'attachment.data' is required during message import" - ); + throw new TypeError("'attachment.data' is required during message import"); } if (!isString(attachment.path)) { - throw new TypeError( - "'attachment.path' is required during message import" - ); + throw new TypeError("'attachment.path' is required during message import"); } }); diff --git a/js/modules/types/visual_attachment.js b/js/modules/types/visual_attachment.js index e85bc7aedcda38e0334adb8a3e901bdeb2d84d68..a72574d02e8e1a31e510e9dc44d7daf4fdb3edf2 100644 --- a/js/modules/types/visual_attachment.js +++ b/js/modules/types/visual_attachment.js @@ -26,20 +26,12 @@ exports.getImageDimensions = ({ objectUrl, logger }) => reject(error); }); // TODO image/jpeg is hard coded, but it does not look to cause any issues - DecryptedAttachmentsManager.getDecryptedMediaUrl( - objectUrl, - 'image/jpg' - ).then(decryptedUrl => { + DecryptedAttachmentsManager.getDecryptedMediaUrl(objectUrl, 'image/jpg').then(decryptedUrl => { image.src = decryptedUrl; }); }); -exports.makeImageThumbnail = ({ - size, - objectUrl, - contentType = 'image/png', - logger, -}) => +exports.makeImageThumbnail = ({ size, objectUrl, contentType = 'image/png', logger }) => new Promise((resolve, reject) => { const image = document.createElement('img'); @@ -76,19 +68,12 @@ exports.makeImageThumbnail = ({ reject(error); }); - DecryptedAttachmentsManager.getDecryptedMediaUrl( - objectUrl, - contentType - ).then(decryptedUrl => { + DecryptedAttachmentsManager.getDecryptedMediaUrl(objectUrl, contentType).then(decryptedUrl => { image.src = decryptedUrl; }); }); -exports.makeVideoScreenshot = ({ - objectUrl, - contentType = 'image/png', - logger, -}) => +exports.makeVideoScreenshot = ({ objectUrl, contentType = 'image/png', logger }) => new Promise((resolve, reject) => { const video = document.createElement('video'); @@ -96,9 +81,7 @@ exports.makeVideoScreenshot = ({ const canvas = document.createElement('canvas'); canvas.width = video.videoWidth; canvas.height = video.videoHeight; - canvas - .getContext('2d') - .drawImage(video, 0, 0, canvas.width, canvas.height); + canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height); const image = dataURLToBlobSync(canvas.toDataURL(contentType)); @@ -114,10 +97,7 @@ exports.makeVideoScreenshot = ({ reject(error); }); - DecryptedAttachmentsManager.getDecryptedMediaUrl( - objectUrl, - contentType - ).then(decryptedUrl => { + DecryptedAttachmentsManager.getDecryptedMediaUrl(objectUrl, contentType).then(decryptedUrl => { video.src = decryptedUrl; video.muted = true; // for some reason, this is to be started, otherwise the generated thumbnail will be empty diff --git a/js/modules/util_worker_interface.js b/js/modules/util_worker_interface.js index 436c384cf940883447768ee0646ddddd562f224f..c2c8a34951252007a7219db12beeb7d924497b0b 100644 --- a/js/modules/util_worker_interface.js +++ b/js/modules/util_worker_interface.js @@ -36,9 +36,7 @@ class WorkerInterface { if (errorForDisplay) { return reject( - new Error( - `Error received from worker job ${jobId} (${fnName}): ${errorForDisplay}` - ) + new Error(`Error received from worker job ${jobId} (${fnName}): ${errorForDisplay}`) ); } @@ -72,18 +70,14 @@ class WorkerInterface { this._removeJob(id); const end = Date.now(); if (this._DEBUG) { - window.log.info( - `Worker job ${id} (${fnName}) succeeded in ${end - start}ms` - ); + window.log.info(`Worker job ${id} (${fnName}) succeeded in ${end - start}ms`); } return resolve(value); }, reject: error => { this._removeJob(id); const end = Date.now(); - window.log.info( - `Worker job ${id} (${fnName}) failed in ${end - start}ms` - ); + window.log.info(`Worker job ${id} (${fnName}) failed in ${end - start}ms`); return reject(error); }, }; @@ -114,10 +108,7 @@ class WorkerInterface { }); setTimeout( - () => - reject( - new TimedOutError(`Worker job ${jobId} (${fnName}) timed out`) - ), + () => reject(new TimedOutError(`Worker job ${jobId} (${fnName}) timed out`)), this.timeout ); }); diff --git a/js/notifications.js b/js/notifications.js index 4c341e31fade2c4f9cab21ff06be3c1934927893..f96f5db124c3ad0cf318b5630ea9cba66d6e006a 100644 --- a/js/notifications.js +++ b/js/notifications.js @@ -57,8 +57,7 @@ const { isEnabled } = this; const isAppFocused = isFocused(); - const isAudioNotificationEnabled = - storage.get('audio-notification') || false; + const isAudioNotificationEnabled = storage.get('audio-notification') || false; const isAudioNotificationSupported = Settings.isAudioNotificationSupported(); // const isNotificationGroupingSupported = Settings.isNotificationGroupingSupported(); const numNotifications = this.length; @@ -99,9 +98,7 @@ // e.g. Russian: // http://docs.translatehouse.org/projects/localization-guide/en/latest/l10n/pluralforms.html const newMessageCountLabel = `${messagesNotificationCount} ${ - messagesNotificationCount === 1 - ? i18n('newMessage') - : i18n('newMessages') + messagesNotificationCount === 1 ? i18n('newMessage') : i18n('newMessages') }`; const last = this.last().toJSON(); @@ -141,14 +138,11 @@ iconUrl = last.iconUrl; break; default: - window.log.error( - `Error: Unknown user notification setting: '${userSetting}'` - ); + window.log.error(`Error: Unknown user notification setting: '${userSetting}'`); break; } - const shouldHideExpiringMessageBody = - last.isExpiringMessage && Signal.OS.isMacOS(); + const shouldHideExpiringMessageBody = last.isExpiringMessage && Signal.OS.isMacOS(); if (shouldHideExpiringMessageBody) { message = i18n('newMessage'); } @@ -160,8 +154,7 @@ icon: iconUrl, silent: !status.shouldPlayNotificationSound, }); - this.lastNotification.onclick = () => - this.trigger('click', last.conversationId, last.id); + this.lastNotification.onclick = () => this.trigger('click', last.conversationId, last.id); // We continue to build up more and more messages for our notifications // until the user comes back to our app or closes the app. Then we’ll diff --git a/js/read_receipts.js b/js/read_receipts.js index 4c865d17c40737d2a96cb41e551c4843f0b83ad2..5f254c2661a060b73735341a1af0ca859a37a76e 100644 --- a/js/read_receipts.js +++ b/js/read_receipts.js @@ -61,14 +61,9 @@ }, async onReceipt(receipt) { try { - const messages = await window.Signal.Data.getMessagesBySentAt( - receipt.get('timestamp') - ); + const messages = await window.Signal.Data.getMessagesBySentAt(receipt.get('timestamp')); - const message = await this.getTargetMessage( - receipt.get('reader'), - messages - ); + const message = await this.getTargetMessage(receipt.get('reader'), messages); if (!message) { window.log.info( @@ -80,9 +75,7 @@ } const readBy = message.get('read_by') || []; - const expirationStartTimestamp = message.get( - 'expirationStartTimestamp' - ); + const expirationStartTimestamp = message.get('expirationStartTimestamp'); readBy.push(receipt.get('reader')); message.set({ @@ -99,9 +92,7 @@ } // notify frontend listeners - const conversation = window - .getConversationController() - .get(message.get('conversationId')); + const conversation = window.getConversationController().get(message.get('conversationId')); if (conversation) { conversation.updateLastMessage(); } diff --git a/js/read_syncs.js b/js/read_syncs.js index 021d86d2d498dc4584f33b323dc1095c48bc92ef..70aebf1c41e73d1a1b3f86576255c0d4014d7e7f 100644 --- a/js/read_syncs.js +++ b/js/read_syncs.js @@ -27,20 +27,15 @@ }, async onReceipt(receipt) { try { - const messages = await window.Signal.Data.getMessagesBySentAt( - receipt.get('timestamp') - ); + const messages = await window.Signal.Data.getMessagesBySentAt(receipt.get('timestamp')); const found = messages.find( - item => - item.isIncoming() && item.get('source') === receipt.get('sender') + item => item.isIncoming() && item.get('source') === receipt.get('sender') ); const notificationForMessage = found ? Whisper.Notifications.findWhere({ messageId: found.id }) : null; - const removedNotification = Whisper.Notifications.remove( - notificationForMessage - ); + const removedNotification = Whisper.Notifications.remove(notificationForMessage); const receiptSender = receipt.get('sender'); const receiptTimestamp = receipt.get('timestamp'); const wasMessageFound = Boolean(found); @@ -89,10 +84,7 @@ this.remove(receipt); } catch (error) { - window.log.error( - 'ReadSyncs.onReceipt error:', - error && error.stack ? error.stack : error - ); + window.log.error('ReadSyncs.onReceipt error:', error && error.stack ? error.stack : error); } }, }))(); diff --git a/js/util_worker_tasks.js b/js/util_worker_tasks.js index 10c50721c82c01e75bb50904941f59dee3ee952a..fa8567c77b960e48387507f7b8d537eda355824c 100644 --- a/js/util_worker_tasks.js +++ b/js/util_worker_tasks.js @@ -46,13 +46,5 @@ function calcPoW( increment = 1, startNonce = 0 ) { - return pow.calcPoW( - timestamp, - ttl, - pubKey, - data, - difficulty, - increment, - startNonce - ); + return pow.calcPoW(timestamp, ttl, pubKey, data, difficulty, increment, startNonce); } diff --git a/js/views/app_view.js b/js/views/app_view.js index 616e343dc1998c1152cb47b77e0167740bae629e..0464dfe8434fcc5b411c113a4bc394a9f60b4649 100644 --- a/js/views/app_view.js +++ b/js/views/app_view.js @@ -145,8 +145,7 @@ }, getThemeObject() { const themeSettings = storage.get('theme-setting') || 'light'; - const theme = - themeSettings === 'light' ? window.lightTheme : window.darkTheme; + const theme = themeSettings === 'light' ? window.lightTheme : window.darkTheme; return theme; }, showUpdateGroupNameDialog(groupConvo) { @@ -165,9 +164,7 @@ }, showLeaveGroupDialog(groupConvo) { if (!groupConvo.isGroup()) { - throw new Error( - 'showLeaveGroupDialog() called with a non group convo.' - ); + throw new Error('showLeaveGroupDialog() called with a non group convo.'); } const title = i18n('leaveGroup'); diff --git a/js/views/debug_log_view.js b/js/views/debug_log_view.js index 9f0ffaa2c1628adbaf4d68e1e13db0d5c752aca7..1ed68153896f98db8c7e751877632732245a00e1 100644 --- a/js/views/debug_log_view.js +++ b/js/views/debug_log_view.js @@ -67,10 +67,7 @@ .focus() .select(); } catch (error) { - window.log.error( - 'DebugLogView error:', - error && error.stack ? error.stack : error - ); + window.log.error('DebugLogView error:', error && error.stack ? error.stack : error); this.$('.loading').removeClass('loading'); this.$('.result').text(i18n('debugLogError')); } diff --git a/js/views/import_view.js b/js/views/import_view.js index f225ed59316ca6fc1598b295624553869fe747d9..e5f0e5c561e6c951ed11e8d6d7ab524f8ec705a5 100644 --- a/js/views/import_view.js +++ b/js/views/import_view.js @@ -140,10 +140,7 @@ Whisper.Import.reset() ) .then(() => - Promise.all([ - Whisper.Import.start(), - window.Signal.Backup.importFromDirectory(directory), - ]) + Promise.all([Whisper.Import.start(), window.Signal.Backup.importFromDirectory(directory)]) ) .then(results => { const importResult = results[1]; @@ -158,10 +155,7 @@ return this.finishLightImport(directory); }) .catch(error => { - window.log.error( - 'Error importing:', - error && error.stack ? error.stack : error - ); + window.log.error('Error importing:', error && error.stack ? error.stack : error); this.error = error || new Error('Something went wrong!'); this.state = null; @@ -177,10 +171,7 @@ .getConversationController() .load() .then(() => - Promise.all([ - Whisper.Import.saveLocation(directory), - Whisper.Import.complete(), - ]) + Promise.all([Whisper.Import.saveLocation(directory), Whisper.Import.complete()]) ) .then(() => { this.state = State.LIGHT_COMPLETE; diff --git a/js/views/invite_contacts_dialog_view.js b/js/views/invite_contacts_dialog_view.js index 6a4c7239d2f7efd06df42308f0686c59f40d00ec..1d58261979102472a5451eae716a37f4e2741ea9 100644 --- a/js/views/invite_contacts_dialog_view.js +++ b/js/views/invite_contacts_dialog_view.js @@ -15,12 +15,7 @@ const convos = window.getConversationController().getConversations(); this.contacts = convos.filter( - d => - !!d && - !d.isBlocked() && - d.isPrivate() && - !d.isMe() && - !!d.get('active_at') + d => !!d && !d.isBlocked() && d.isPrivate() && !d.isMe() && !!d.get('active_at') ); if (!convo.isPublic()) { const members = convo.get('members') || []; @@ -93,19 +88,13 @@ return; } - const allMembers = window.Lodash.concat(existingMembers, newMembers, [ - ourPK, - ]); + const allMembers = window.Lodash.concat(existingMembers, newMembers, [ourPK]); const uniqMembers = _.uniq(allMembers, true, d => d); const groupId = this.convo.get('id'); const groupName = this.convo.get('name'); - window.libsession.ClosedGroup.initiateGroupUpdate( - groupId, - groupName, - uniqMembers - ); + window.libsession.ClosedGroup.initiateGroupUpdate(groupId, groupName, uniqMembers); } } }, diff --git a/js/views/react_wrapper_view.js b/js/views/react_wrapper_view.js index a256fff1888c0452847ab974b8524479dac410ee..af1f456e2afc9a7c4d01dcf2a9bf514c17105659 100644 --- a/js/views/react_wrapper_view.js +++ b/js/views/react_wrapper_view.js @@ -40,9 +40,7 @@ }, update(props) { const updatedProps = this.augmentProps(props); - const reactElement = this.JSX - ? this.JSX - : React.createElement(this.Component, updatedProps); + const reactElement = this.JSX ? this.JSX : React.createElement(this.Component, updatedProps); ReactDOM.render(reactElement, this.el, () => { if (this.hasRendered) { return; diff --git a/js/views/update_group_dialog_view.js b/js/views/update_group_dialog_view.js index 813c1c81327f8fffa9c670de40b93c131f77fd45..74e3d461d2f1be79961576ec71d5dd255dcbdb71 100644 --- a/js/views/update_group_dialog_view.js +++ b/js/views/update_group_dialog_view.js @@ -31,9 +31,7 @@ this.titleText = i18n('updateGroupDialogTitle', this.groupName); // I'd much prefer to integrate mods with groupAdmins // but lets discuss first... - this.isAdmin = groupConvo.isAdmin( - window.storage.get('primaryDevicePubKey') - ); + this.isAdmin = groupConvo.isAdmin(window.storage.get('primaryDevicePubKey')); } this.$el.focus(); @@ -92,9 +90,7 @@ this.titleText = i18n('updateGroupDialogTitle', this.groupName); // I'd much prefer to integrate mods with groupAdmins // but lets discuss first... - this.isAdmin = groupConvo.isAdmin( - window.storage.get('primaryDevicePubKey') - ); + this.isAdmin = groupConvo.isAdmin(window.storage.get('primaryDevicePubKey')); // zero out contactList for now this.contactsAndMembers = []; this.existingMembers = []; @@ -116,11 +112,7 @@ this.contactsAndMembers = convos.filter( d => this.existingMembers.includes(d.id) && d.isPrivate() && !d.isMe() ); - this.contactsAndMembers = _.uniq( - this.contactsAndMembers, - true, - d => d.id - ); + this.contactsAndMembers = _.uniq(this.contactsAndMembers, true, d => d.id); // at least make sure it's an array if (!Array.isArray(this.existingMembers)) { @@ -160,24 +152,16 @@ const allMembers = window.Lodash.concat(newMembers, [ourPK]); // We need to NOT trigger an group update if the list of member is the same. - const notPresentInOld = allMembers.filter( - m => !this.existingMembers.includes(m) - ); + const notPresentInOld = allMembers.filter(m => !this.existingMembers.includes(m)); - const membersToRemove = this.existingMembers.filter( - m => !allMembers.includes(m) - ); + const membersToRemove = this.existingMembers.filter(m => !allMembers.includes(m)); // If any extra devices of removed exist in newMembers, ensure that you filter them - const filteredMemberes = allMembers.filter( - member => !_.includes(membersToRemove, member) - ); + const filteredMemberes = allMembers.filter(member => !_.includes(membersToRemove, member)); const xor = _.xor(membersToRemove, notPresentInOld); if (xor.length === 0) { - window.log.info( - 'skipping group update: no detected changes in group member list' - ); + window.log.info('skipping group update: no detected changes in group member list'); return; } diff --git a/js/views/user_details_dialog_view.js b/js/views/user_details_dialog_view.js index 2bbda3c61593645979bd6a99c87fc0fc310262ac..17f308f253bc403c05b4209c6846e8eedfd65681 100644 --- a/js/views/user_details_dialog_view.js +++ b/js/views/user_details_dialog_view.js @@ -8,14 +8,7 @@ Whisper.UserDetailsDialogView = Whisper.View.extend({ className: 'loki-dialog modal', - initialize({ - profileName, - avatarPath, - pubkey, - onOk, - onStartConversation, - theme, - }) { + initialize({ profileName, avatarPath, pubkey, onOk, onStartConversation, theme }) { this.close = this.close.bind(this); this.profileName = profileName; diff --git a/libloki/crypto.d.ts b/libloki/crypto.d.ts index 5b26ed94aaca7d4b9db474b3d241e7ab1d048a04..2de3701fe107e5dc186b9b9a936e6e0885eaec04 100644 --- a/libloki/crypto.d.ts +++ b/libloki/crypto.d.ts @@ -1,14 +1,8 @@ export interface CryptoInterface { DHDecrypt: any; DHEncrypt: any; - DecryptAESGCM: ( - symmetricKey: ArrayBuffer, - ivAndCiphertext: ArrayBuffer - ) => Promise<ArrayBuffer>; // AES-GCM - deriveSymmetricKey: ( - pubkey: ArrayBuffer, - seckey: ArrayBuffer - ) => Promise<ArrayBuffer>; + DecryptAESGCM: (symmetricKey: ArrayBuffer, ivAndCiphertext: ArrayBuffer) => Promise<ArrayBuffer>; // AES-GCM + deriveSymmetricKey: (pubkey: ArrayBuffer, seckey: ArrayBuffer) => Promise<ArrayBuffer>; EncryptAESGCM: any; // AES-GCM _decodeSnodeAddressToPubKey: any; decryptToken: any; diff --git a/libloki/crypto.js b/libloki/crypto.js index 0a372a03fb202d137319f8cda339d80b5ba682ca..54d089878b1b1d52aa4b6c43f927dc149791e189 100644 --- a/libloki/crypto.js +++ b/libloki/crypto.js @@ -19,14 +19,8 @@ async function DHEncrypt(symmetricKey, plainText) { const iv = libsignal.crypto.getRandomBytes(IV_LENGTH); - const ciphertext = await libsignal.crypto.encrypt( - symmetricKey, - plainText, - iv - ); - const ivAndCiphertext = new Uint8Array( - iv.byteLength + ciphertext.byteLength - ); + const ciphertext = await libsignal.crypto.encrypt(symmetricKey, plainText, iv); + const ivAndCiphertext = new Uint8Array(iv.byteLength + ciphertext.byteLength); ivAndCiphertext.set(new Uint8Array(iv)); ivAndCiphertext.set(new Uint8Array(ciphertext), iv.byteLength); return ivAndCiphertext; @@ -71,13 +65,9 @@ async function EncryptAESGCM(symmetricKey, plaintext) { const nonce = crypto.getRandomValues(new Uint8Array(NONCE_LENGTH)); - const key = await crypto.subtle.importKey( - 'raw', - symmetricKey, - { name: 'AES-GCM' }, - false, - ['encrypt'] - ); + const key = await crypto.subtle.importKey('raw', symmetricKey, { name: 'AES-GCM' }, false, [ + 'encrypt', + ]); const ciphertext = await crypto.subtle.encrypt( { name: 'AES-GCM', iv: nonce, tagLength: 128 }, @@ -85,9 +75,7 @@ plaintext ); - const ivAndCiphertext = new Uint8Array( - NONCE_LENGTH + ciphertext.byteLength - ); + const ivAndCiphertext = new Uint8Array(NONCE_LENGTH + ciphertext.byteLength); ivAndCiphertext.set(nonce); ivAndCiphertext.set(new Uint8Array(ciphertext), nonce.byteLength); @@ -99,19 +87,11 @@ const nonce = ivAndCiphertext.slice(0, NONCE_LENGTH); const ciphertext = ivAndCiphertext.slice(NONCE_LENGTH); - const key = await crypto.subtle.importKey( - 'raw', - symmetricKey, - { name: 'AES-GCM' }, - false, - ['decrypt'] - ); + const key = await crypto.subtle.importKey('raw', symmetricKey, { name: 'AES-GCM' }, false, [ + 'decrypt', + ]); - return crypto.subtle.decrypt( - { name: 'AES-GCM', iv: nonce }, - key, - ciphertext - ); + return crypto.subtle.decrypt({ name: 'AES-GCM', iv: nonce }, key, ciphertext); } async function DHDecrypt(symmetricKey, ivAndCiphertext) { @@ -152,10 +132,7 @@ throw new Error('Failed to get keypair for token decryption'); } const { privKey } = keyPair; - const symmetricKey = await libsignal.Curve.async.calculateAgreement( - serverPubKey, - privKey - ); + const symmetricKey = await libsignal.Curve.async.calculateAgreement(serverPubKey, privKey); const token = await DHDecrypt(symmetricKey, ivAndCiphertext); diff --git a/libloki/proof-of-work.js b/libloki/proof-of-work.js index b537e17af3134bda90712140287b04367be87348..44eefbeb6599d60127c833c7c2da02b712dfd391 100644 --- a/libloki/proof-of-work.js +++ b/libloki/proof-of-work.js @@ -62,15 +62,7 @@ const pow = { }, // Return nonce that hashes together with payload lower than the target - async calcPoW( - timestamp, - ttl, - pubKey, - data, - _difficulty = null, - increment = 1, - startNonce = 0 - ) { + async calcPoW(timestamp, ttl, pubKey, data, _difficulty = null, increment = 1, startNonce = 0) { const payload = new Uint8Array( dcodeIO.ByteBuffer.wrap( timestamp.toString() + ttl.toString() + pubKey + data, @@ -84,9 +76,7 @@ const pow = { let nonce = new Uint8Array(NONCE_LEN); nonce = pow.incrementNonce(nonce, startNonce); // initial value let trialValue = new Uint8Array([255, 255, 255, 255, 255, 255, 255, 255]); - const initialHash = new Uint8Array( - await crypto.subtle.digest('SHA-512', payload) - ); + const initialHash = new Uint8Array(await crypto.subtle.digest('SHA-512', payload)); const innerPayload = new Uint8Array(initialHash.length + NONCE_LEN); innerPayload.set(initialHash, NONCE_LEN); let resultHash; @@ -97,9 +87,10 @@ const pow = { innerPayload.set(nonce); // eslint-disable-next-line no-await-in-loop resultHash = await crypto.subtle.digest('SHA-512', innerPayload); - trialValue = new Uint8Array( - dcodeIO.ByteBuffer.wrap(resultHash, 'hex').toArrayBuffer() - ).slice(0, NONCE_LEN); + trialValue = new Uint8Array(dcodeIO.ByteBuffer.wrap(resultHash, 'hex').toArrayBuffer()).slice( + 0, + NONCE_LEN + ); } return pow.bufferToBase64(nonce); }, @@ -121,10 +112,7 @@ const pow = { // totalLen + innerFrac const lenPlusInnerFrac = JSBI.add(totalLen, innerFrac); // difficulty * lenPlusInnerFrac - const denominator = JSBI.multiply( - JSBI.BigInt(difficulty), - lenPlusInnerFrac - ); + const denominator = JSBI.multiply(JSBI.BigInt(difficulty), lenPlusInnerFrac); // 2^64 - 1 const two64 = JSBI.subtract( JSBI.exponentiate(JSBI.BigInt(2), JSBI.BigInt(64)), // 2^64 diff --git a/libloki/test/metrics.js b/libloki/test/metrics.js index 6a783823a3998ffdf6daf41495ac9c8e856da7d4..69a2f44e4aab650e8022a0991fdce5da2abc4c88 100644 --- a/libloki/test/metrics.js +++ b/libloki/test/metrics.js @@ -5,13 +5,9 @@ let plotlyDiv; const workers = []; async function run(messageLength, numWorkers = 1, difficulty = 100, ttl = 72) { const timestamp = Math.floor(Date.now() / 1000); - const pubKey = - '05ec8635a07a13743516c7c9b3412f3e8252efb7fcaf67eb1615ffba62bebc6802'; + const pubKey = '05ec8635a07a13743516c7c9b3412f3e8252efb7fcaf67eb1615ffba62bebc6802'; const message = randomString(messageLength); - const messageBuffer = dcodeIO.ByteBuffer.wrap( - message, - 'utf8' - ).toArrayBuffer(); + const messageBuffer = dcodeIO.ByteBuffer.wrap(message, 'utf8').toArrayBuffer(); const data = dcodeIO.ByteBuffer.wrap(messageBuffer).toString('base64'); const promises = []; const t0 = performance.now(); @@ -48,13 +44,7 @@ async function run(messageLength, numWorkers = 1, difficulty = 100, ttl = 72) { workers.forEach(worker => worker.terminate()); } -async function runPoW({ - iteration, - difficulty, - numWorkers, - messageLength = 50, - ttl = 72, -}) { +async function runPoW({ iteration, difficulty, numWorkers, messageLength = 50, ttl = 72 }) { const name = `W:${numWorkers} - NT: ${difficulty} - L:${messageLength} - TTL:${ttl}`; Plotly.addTraces(plotlyDiv, { y: [], @@ -74,8 +64,7 @@ async function runPoW({ function randomString(length) { let text = ''; - const possible = - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; for (let i = 0; i < length; i += 1) { text += possible.charAt(Math.floor(Math.random() * possible.length)); } @@ -89,21 +78,11 @@ async function startMessageLengthRun() { const iteration0 = parseFloat(document.getElementById('iteration0').value); const difficulty0 = parseFloat(document.getElementById('difficulty0').value); const numWorkers0 = parseFloat(document.getElementById('numWorkers0').value); - const messageLengthStart0 = parseFloat( - document.getElementById('messageLengthStart0').value - ); - const messageLengthStop0 = parseFloat( - document.getElementById('messageLengthStop0').value - ); - const messageLengthStep0 = parseFloat( - document.getElementById('messageLengthStep0').value - ); + const messageLengthStart0 = parseFloat(document.getElementById('messageLengthStart0').value); + const messageLengthStop0 = parseFloat(document.getElementById('messageLengthStop0').value); + const messageLengthStep0 = parseFloat(document.getElementById('messageLengthStep0').value); const TTL0 = parseFloat(document.getElementById('TTL0').value); - for ( - let l = messageLengthStart0; - l < messageLengthStop0; - l += messageLengthStep0 - ) { + for (let l = messageLengthStart0; l < messageLengthStop0; l += messageLengthStep0) { // eslint-disable-next-line no-await-in-loop await runPoW({ iteration: iteration0, @@ -117,21 +96,11 @@ async function startMessageLengthRun() { async function startNumWorkerRun() { const iteration1 = parseFloat(document.getElementById('iteration1').value); const difficulty1 = parseFloat(document.getElementById('difficulty1').value); - const numWorkersStart1 = parseFloat( - document.getElementById('numWorkersStart1').value - ); - const numWorkersEnd1 = parseFloat( - document.getElementById('numWorkersEnd1').value - ); - const messageLength1 = parseFloat( - document.getElementById('messageLength1').value - ); + const numWorkersStart1 = parseFloat(document.getElementById('numWorkersStart1').value); + const numWorkersEnd1 = parseFloat(document.getElementById('numWorkersEnd1').value); + const messageLength1 = parseFloat(document.getElementById('messageLength1').value); const TTL1 = parseFloat(document.getElementById('TTL1').value); - for ( - let numWorkers = numWorkersStart1; - numWorkers <= numWorkersEnd1; - numWorkers += 1 - ) { + for (let numWorkers = numWorkersStart1; numWorkers <= numWorkersEnd1; numWorkers += 1) { // eslint-disable-next-line no-await-in-loop await runPoW({ iteration: iteration1, @@ -144,19 +113,11 @@ async function startNumWorkerRun() { } async function startDifficultyRun() { const iteration2 = parseFloat(document.getElementById('iteration2').value); - const messageLength2 = parseFloat( - document.getElementById('messageLength2').value - ); + const messageLength2 = parseFloat(document.getElementById('messageLength2').value); const numWorkers2 = parseFloat(document.getElementById('numWorkers2').value); - const difficultyStart2 = parseFloat( - document.getElementById('difficultyStart2').value - ); - const difficultyStop2 = parseFloat( - document.getElementById('difficultyStop2').value - ); - const difficultyStep2 = parseFloat( - document.getElementById('difficultyStep2').value - ); + const difficultyStart2 = parseFloat(document.getElementById('difficultyStart2').value); + const difficultyStop2 = parseFloat(document.getElementById('difficultyStop2').value); + const difficultyStep2 = parseFloat(document.getElementById('difficultyStep2').value); const TTL2 = parseFloat(document.getElementById('TTL2').value); for (let n = difficultyStart2; n < difficultyStop2; n += difficultyStep2) { // eslint-disable-next-line no-await-in-loop @@ -172,9 +133,7 @@ async function startDifficultyRun() { async function starTTLRun() { const iteration3 = parseFloat(document.getElementById('iteration3').value); const difficulty3 = parseFloat(document.getElementById('difficulty3').value); - const messageLength3 = parseFloat( - document.getElementById('messageLength3').value - ); + const messageLength3 = parseFloat(document.getElementById('messageLength3').value); const numWorkers3 = parseFloat(document.getElementById('numWorkers3').value); const TTLStart3 = parseFloat(document.getElementById('TTLStart3').value); const TTLStop3 = parseFloat(document.getElementById('TTLStop3').value); diff --git a/libloki/test/proof-of-work_test.js b/libloki/test/proof-of-work_test.js index 9b5aaa9f62707f42c857f25845feddbe80e06ad8..85ace33254bb41cc4f87fced5633fc643645d1b0 100644 --- a/libloki/test/proof-of-work_test.js +++ b/libloki/test/proof-of-work_test.js @@ -1,12 +1,6 @@ /* global assert, JSBI, pow */ -const { - calcTarget, - incrementNonce, - bufferToBase64, - bigIntToUint8Array, - greaterThan, -} = pow; +const { calcTarget, incrementNonce, bufferToBase64, bigIntToUint8Array, greaterThan } = pow; describe('Proof of Work', () => { describe('#incrementNonce', () => { @@ -25,20 +19,14 @@ describe('Proof of Work', () => { it('should increment a Uint8Array nonce correctly in a loop', () => { let arr = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0]); - assert.deepEqual( - incrementNonce(arr), - new Uint8Array([0, 0, 0, 0, 0, 0, 0, 1]) - ); + assert.deepEqual(incrementNonce(arr), new Uint8Array([0, 0, 0, 0, 0, 0, 0, 1])); arr = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0]); for (let i = 0; i <= 255; i += 1) { arr = incrementNonce(arr); } assert.deepEqual(arr, new Uint8Array([0, 0, 0, 0, 0, 0, 1, 0])); arr = new Uint8Array([255, 255, 255, 255, 255, 255, 255, 255]); - assert.deepEqual( - incrementNonce(arr), - new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0]) - ); + assert.deepEqual(incrementNonce(arr), new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0])); }); }); diff --git a/libtextsecure/crypto.js b/libtextsecure/crypto.js index 4d0f115e5119152803def0aeacf98d1c7ed3b2d7..afe1ce7527193b2f10296943981838d2089ad696 100644 --- a/libtextsecure/crypto.js +++ b/libtextsecure/crypto.js @@ -43,14 +43,8 @@ const iv = encryptedBin.slice(0, 16); const ciphertext = encryptedBin.slice(16, encryptedBin.byteLength - 32); - const ivAndCiphertext = encryptedBin.slice( - 0, - encryptedBin.byteLength - 32 - ); - const mac = encryptedBin.slice( - encryptedBin.byteLength - 32, - encryptedBin.byteLength - ); + const ivAndCiphertext = encryptedBin.slice(0, encryptedBin.byteLength - 32); + const mac = encryptedBin.slice(encryptedBin.byteLength - 32, encryptedBin.byteLength); return verifyMAC(ivAndCiphertext, macKey, mac, 32) .then(() => { @@ -63,10 +57,7 @@ }, encryptAttachment(plaintext, keys, iv) { - if ( - !(plaintext instanceof ArrayBuffer) && - !ArrayBuffer.isView(plaintext) - ) { + if (!(plaintext instanceof ArrayBuffer) && !ArrayBuffer.isView(plaintext)) { throw new TypeError( `\`plaintext\` must be an \`ArrayBuffer\` or \`ArrayBufferView\`; got: ${typeof plaintext}` ); @@ -109,20 +100,11 @@ .importKey('raw', key, { name: 'AES-GCM' }, false, ['encrypt']) .then(keyForEncryption => crypto.subtle - .encrypt( - { name: 'AES-GCM', iv, tagLength: PROFILE_TAG_LENGTH }, - keyForEncryption, - data - ) + .encrypt({ name: 'AES-GCM', iv, tagLength: PROFILE_TAG_LENGTH }, keyForEncryption, data) .then(ciphertext => { - const ivAndCiphertext = new Uint8Array( - PROFILE_IV_LENGTH + ciphertext.byteLength - ); + const ivAndCiphertext = new Uint8Array(PROFILE_IV_LENGTH + ciphertext.byteLength); ivAndCiphertext.set(new Uint8Array(iv)); - ivAndCiphertext.set( - new Uint8Array(ciphertext), - PROFILE_IV_LENGTH - ); + ivAndCiphertext.set(new Uint8Array(ciphertext), PROFILE_IV_LENGTH); return ivAndCiphertext.buffer; }) ); @@ -166,10 +148,7 @@ return textsecure.crypto.encryptProfile(padded.buffer, key); }, decryptProfileName(encryptedProfileName, key) { - const data = dcodeIO.ByteBuffer.wrap( - encryptedProfileName, - 'base64' - ).toArrayBuffer(); + const data = dcodeIO.ByteBuffer.wrap(encryptedProfileName, 'base64').toArrayBuffer(); return textsecure.crypto.decryptProfile(data, key).then(decrypted => { // unpad const padded = new Uint8Array(decrypted); diff --git a/libtextsecure/helpers.js b/libtextsecure/helpers.js index 31a6605d01b8f65b522d50ccb9e1676e1c8f5b13..87574d9757cc2fd93aab19fb82cf85944cfc38b6 100644 --- a/libtextsecure/helpers.js +++ b/libtextsecure/helpers.js @@ -44,8 +44,7 @@ function getStringable(thing) { window.textsecure.utils = (() => { const self = {}; self.unencodeNumber = number => number.split('.'); - self.isNumberSane = number => - number[0] === '+' && /^[0-9]+$/.test(number.substring(1)); + self.isNumberSane = number => number[0] === '+' && /^[0-9]+$/.test(number.substring(1)); /** ************************ *** JSON'ing Utilities *** diff --git a/libtextsecure/libsignal-protocol.d.ts b/libtextsecure/libsignal-protocol.d.ts index 539ae4ebb15c354d4a19a30ceca5b0d5701d0edf..eeb0982dfaf572b2b6507230aa75e8ff23896f16 100644 --- a/libtextsecure/libsignal-protocol.d.ts +++ b/libtextsecure/libsignal-protocol.d.ts @@ -27,11 +27,7 @@ interface CurveSync { generateKeyPair(): KeyPair; createKeyPair(privKey: ArrayBuffer): KeyPair; calculateAgreement(pubKey: ArrayBuffer, privKey: ArrayBuffer): ArrayBuffer; - verifySignature( - pubKey: ArrayBuffer, - msg: ArrayBuffer, - sig: ArrayBuffer - ): void; + verifySignature(pubKey: ArrayBuffer, msg: ArrayBuffer, sig: ArrayBuffer): void; calculateSignature(privKey: ArrayBuffer, message: ArrayBuffer): ArrayBuffer; validatePubKeyFormat(pubKey: ArrayBuffer): ArrayBuffer; } @@ -39,19 +35,9 @@ interface CurveSync { interface CurveAsync { generateKeyPair(): Promise<KeyPair>; createKeyPair(privKey: ArrayBuffer): Promise<KeyPair>; - calculateAgreement( - pubKey: ArrayBuffer, - privKey: ArrayBuffer - ): Promise<ArrayBuffer>; - verifySignature( - pubKey: ArrayBuffer, - msg: ArrayBuffer, - sig: ArrayBuffer - ): Promise<void>; - calculateSignature( - privKey: ArrayBuffer, - message: ArrayBuffer - ): Promise<ArrayBuffer>; + calculateAgreement(pubKey: ArrayBuffer, privKey: ArrayBuffer): Promise<ArrayBuffer>; + verifySignature(pubKey: ArrayBuffer, msg: ArrayBuffer, sig: ArrayBuffer): Promise<void>; + calculateSignature(privKey: ArrayBuffer, message: ArrayBuffer): Promise<ArrayBuffer>; validatePubKeyFormat(pubKey: ArrayBuffer): Promise<ArrayBuffer>; } @@ -60,23 +46,10 @@ export interface CurveInterface extends CurveSync { } export interface CryptoInterface { - encrypt( - key: ArrayBuffer, - data: ArrayBuffer, - iv: ArrayBuffer - ): Promise<ArrayBuffer>; - decrypt( - key: ArrayBuffer, - data: ArrayBuffer, - iv: ArrayBuffer - ): Promise<ArrayBuffer>; + encrypt(key: ArrayBuffer, data: ArrayBuffer, iv: ArrayBuffer): Promise<ArrayBuffer>; + decrypt(key: ArrayBuffer, data: ArrayBuffer, iv: ArrayBuffer): Promise<ArrayBuffer>; calculateMAC(key: ArrayBuffer, data: ArrayBuffer): Promise<ArrayBuffer>; - verifyMAC( - data: ArrayBuffer, - key: ArrayBuffer, - mac: ArrayBuffer, - length: number - ): Promise<void>; + verifyMAC(data: ArrayBuffer, key: ArrayBuffer, mac: ArrayBuffer, length: number): Promise<void>; getRandomBytes(size: number): ArrayBuffer; } diff --git a/libtextsecure/message_receiver.js b/libtextsecure/message_receiver.js index d339603c87574f414b93d0220d2cfdfa7e465280..4b58ea34803590c50267cc813dbcef20887ce740 100644 --- a/libtextsecure/message_receiver.js +++ b/libtextsecure/message_receiver.js @@ -80,12 +80,8 @@ window.textsecure = window.textsecure || {}; textsecure.MessageReceiver = function MessageReceiverWrapper() { const messageReceiver = new MessageReceiver(); - this.addEventListener = messageReceiver.addEventListener.bind( - messageReceiver - ); - this.removeEventListener = messageReceiver.removeEventListener.bind( - messageReceiver - ); + this.addEventListener = messageReceiver.addEventListener.bind(messageReceiver); + this.removeEventListener = messageReceiver.removeEventListener.bind(messageReceiver); this.close = messageReceiver.close.bind(messageReceiver); this.stopProcessing = messageReceiver.stopProcessing.bind(messageReceiver); @@ -97,9 +93,6 @@ textsecure.MessageReceiver.prototype = { constructor: textsecure.MessageReceiver, }; -textsecure.MessageReceiver.stringToArrayBuffer = - MessageReceiver.stringToArrayBuffer; -textsecure.MessageReceiver.arrayBufferToString = - MessageReceiver.arrayBufferToString; -textsecure.MessageReceiver.arrayBufferToStringBase64 = - MessageReceiver.arrayBufferToStringBase64; +textsecure.MessageReceiver.stringToArrayBuffer = MessageReceiver.stringToArrayBuffer; +textsecure.MessageReceiver.arrayBufferToString = MessageReceiver.arrayBufferToString; +textsecure.MessageReceiver.arrayBufferToStringBase64 = MessageReceiver.arrayBufferToStringBase64; diff --git a/libtextsecure/protobufs.js b/libtextsecure/protobufs.js index 06888ee7ded892a2a779e145edd1cd00210a0139..8315278d491f6c0350591bc113f9a65927dcd22b 100644 --- a/libtextsecure/protobufs.js +++ b/libtextsecure/protobufs.js @@ -10,9 +10,9 @@ { root: window.PROTO_ROOT, file: filename }, (error, result) => { if (error) { - const text = `Error loading protos from ${filename} (root: ${ - window.PROTO_ROOT - }) ${error && error.stack ? error.stack : error}`; + const text = `Error loading protos from ${filename} (root: ${window.PROTO_ROOT}) ${ + error && error.stack ? error.stack : error + }`; window.log.error(text); throw error; } diff --git a/libtextsecure/storage.js b/libtextsecure/storage.js index d59b83e2767cb4effa387bd553a8fdd32bb4bfcf..300f7e91333d1c3741caae4337602718370c7e48 100644 --- a/libtextsecure/storage.js +++ b/libtextsecure/storage.js @@ -33,8 +33,7 @@ }, }; - window.textsecure.storage.put = (key, value) => - textsecure.storage.impl.put(key, value); + window.textsecure.storage.put = (key, value) => textsecure.storage.impl.put(key, value); window.textsecure.storage.get = (key, defaultValue) => textsecure.storage.impl.get(key, defaultValue); window.textsecure.storage.remove = key => textsecure.storage.impl.remove(key); diff --git a/libtextsecure/storage/user.js b/libtextsecure/storage/user.js index 63975535f2e7fbd59f8a71b95b59398cfa699910..8f518322420e264f77220696e719b16c2bf9e813 100644 --- a/libtextsecure/storage/user.js +++ b/libtextsecure/storage/user.js @@ -41,10 +41,7 @@ }, setLastProfileUpdateTimestamp(lastUpdateTimestamp) { - textsecure.storage.put( - 'last_profile_update_timestamp', - lastUpdateTimestamp - ); + textsecure.storage.put('last_profile_update_timestamp', lastUpdateTimestamp); }, getDeviceId() { diff --git a/libtextsecure/stringview.js b/libtextsecure/stringview.js index effd71165bcad33277c540f0092ba108387f0de6..6b8a304ffbe40cf216d6ef01bf64b70d522047d5 100644 --- a/libtextsecure/stringview.js +++ b/libtextsecure/stringview.js @@ -38,20 +38,11 @@ let nMod3; let nMod4; - for ( - let nUint24 = 0, nOutIdx = 0, nInIdx = 0; - nInIdx < nInLen; - nInIdx += 1 - ) { + for (let nUint24 = 0, nOutIdx = 0, nInIdx = 0; nInIdx < nInLen; nInIdx += 1) { nMod4 = nInIdx & 3; - nUint24 |= - StringView.b64ToUint6(sB64Enc.charCodeAt(nInIdx)) << (18 - 6 * nMod4); + nUint24 |= StringView.b64ToUint6(sB64Enc.charCodeAt(nInIdx)) << (18 - 6 * nMod4); if (nMod4 === 3 || nInLen - nInIdx === 1) { - for ( - nMod3 = 0; - nMod3 < 3 && nOutIdx < nOutLen; - nMod3 += 1, nOutIdx += 1 - ) { + for (nMod3 = 0; nMod3 < 3 && nOutIdx < nOutLen; nMod3 += 1, nOutIdx += 1) { taBytes[nOutIdx] = (nUint24 >>> ((16 >>> nMod3) & 24)) & 255; } nUint24 = 0; @@ -77,11 +68,7 @@ bytesToBase64(aBytes) { let nMod3; let sB64Enc = ''; - for ( - let nLen = aBytes.length, nUint24 = 0, nIdx = 0; - nIdx < nLen; - nIdx += 1 - ) { + for (let nLen = aBytes.length, nUint24 = 0, nIdx = 0; nIdx < nLen; nIdx += 1) { nMod3 = nIdx % 3; if (nIdx > 0 && ((nIdx * 4) / 3) % 76 === 0) { sB64Enc += '\r\n'; @@ -102,16 +89,12 @@ arrayBufferToHex(aArrayBuffer) { return Array.prototype.map - .call(new Uint8Array(aArrayBuffer), x => - `00${x.toString(16)}`.slice(-2) - ) + .call(new Uint8Array(aArrayBuffer), x => `00${x.toString(16)}`.slice(-2)) .join(''); }, hexToArrayBuffer(aString) { - return new Uint8Array( - aString.match(/[\da-f]{2}/gi).map(h => parseInt(h, 16)) - ).buffer; + return new Uint8Array(aString.match(/[\da-f]{2}/gi).map(h => parseInt(h, 16))).buffer; }, }; })(); diff --git a/libtextsecure/task_with_timeout.js b/libtextsecure/task_with_timeout.js index e0c96ef9eae02a186258c7f163fc473164b2b59f..c44a2a0e74baa2656d6baa1fdc523fc8dbef7cc8 100644 --- a/libtextsecure/task_with_timeout.js +++ b/libtextsecure/task_with_timeout.js @@ -15,8 +15,7 @@ let complete = false; let timer = setTimeout(() => { if (!complete) { - const message = `${id || - ''} task did not complete in time. Calling stack: ${ + const message = `${id || ''} task did not complete in time. Calling stack: ${ errorForStack.stack }`; diff --git a/libtextsecure/test/crypto_test.js b/libtextsecure/test/crypto_test.js index 298a273b87287fe3bb6fa688a9745753e8db10c2..e94cc2f833d93657fa7bcec3857cc1a07742e23f 100644 --- a/libtextsecure/test/crypto_test.js +++ b/libtextsecure/test/crypto_test.js @@ -8,70 +8,48 @@ describe('encrypting and decrypting profile data', () => { const buffer = dcodeIO.ByteBuffer.wrap(name).toArrayBuffer(); const key = libsignal.crypto.getRandomBytes(32); - return textsecure.crypto - .encryptProfileName(buffer, key) - .then(encrypted => { - assert(encrypted.byteLength === NAME_PADDED_LENGTH + 16 + 12); - return textsecure.crypto - .decryptProfileName(encrypted, key) - .then(decrypted => { - assert.strictEqual( - dcodeIO.ByteBuffer.wrap(decrypted).toString('utf8'), - 'Alice' - ); - }); + return textsecure.crypto.encryptProfileName(buffer, key).then(encrypted => { + assert(encrypted.byteLength === NAME_PADDED_LENGTH + 16 + 12); + return textsecure.crypto.decryptProfileName(encrypted, key).then(decrypted => { + assert.strictEqual(dcodeIO.ByteBuffer.wrap(decrypted).toString('utf8'), 'Alice'); }); + }); }); it('works for empty string', () => { const name = dcodeIO.ByteBuffer.wrap('').toArrayBuffer(); const key = libsignal.crypto.getRandomBytes(32); - return textsecure.crypto - .encryptProfileName(name.buffer, key) - .then(encrypted => { - assert(encrypted.byteLength === NAME_PADDED_LENGTH + 16 + 12); - return textsecure.crypto - .decryptProfileName(encrypted, key) - .then(decrypted => { - assert.strictEqual(decrypted.byteLength, 0); - assert.strictEqual( - dcodeIO.ByteBuffer.wrap(decrypted).toString('utf8'), - '' - ); - }); + return textsecure.crypto.encryptProfileName(name.buffer, key).then(encrypted => { + assert(encrypted.byteLength === NAME_PADDED_LENGTH + 16 + 12); + return textsecure.crypto.decryptProfileName(encrypted, key).then(decrypted => { + assert.strictEqual(decrypted.byteLength, 0); + assert.strictEqual(dcodeIO.ByteBuffer.wrap(decrypted).toString('utf8'), ''); }); + }); }); }); describe('encrypting and decrypting profile avatars', () => { it('encrypts and decrypts', () => { - const buffer = dcodeIO.ByteBuffer.wrap( - 'This is an avatar' - ).toArrayBuffer(); + const buffer = dcodeIO.ByteBuffer.wrap('This is an avatar').toArrayBuffer(); const key = libsignal.crypto.getRandomBytes(32); return textsecure.crypto.encryptProfile(buffer, key).then(encrypted => { assert(encrypted.byteLength === buffer.byteLength + 16 + 12); - return textsecure.crypto - .decryptProfile(encrypted, key) - .then(decrypted => { - assertEqualArrayBuffers(buffer, decrypted); - }); + return textsecure.crypto.decryptProfile(encrypted, key).then(decrypted => { + assertEqualArrayBuffers(buffer, decrypted); + }); }); }); it('throws when decrypting with the wrong key', () => { - const buffer = dcodeIO.ByteBuffer.wrap( - 'This is an avatar' - ).toArrayBuffer(); + const buffer = dcodeIO.ByteBuffer.wrap('This is an avatar').toArrayBuffer(); const key = libsignal.crypto.getRandomBytes(32); const badKey = libsignal.crypto.getRandomBytes(32); return textsecure.crypto.encryptProfile(buffer, key).then(encrypted => { assert(encrypted.byteLength === buffer.byteLength + 16 + 12); - return textsecure.crypto - .decryptProfile(encrypted, badKey) - .catch(error => { - assert.strictEqual(error.name, 'ProfileDecryptError'); - }); + return textsecure.crypto.decryptProfile(encrypted, badKey).catch(error => { + assert.strictEqual(error.name, 'ProfileDecryptError'); + }); }); }); }); diff --git a/main.js b/main.js index 7867306fc7a35ae26a00a01a90098fd833a4b47a..5b292a6e21fc54af88e5edac3c2db1f81e4fb9d8 100644 --- a/main.js +++ b/main.js @@ -46,8 +46,7 @@ function getMainWindow() { // Tray icon and related objects let tray = null; const startInTray = process.argv.some(arg => arg === '--start-in-tray'); -const usingTrayIcon = - startInTray || process.argv.some(arg => arg === '--use-tray-icon'); +const usingTrayIcon = startInTray || process.argv.some(arg => arg === '--use-tray-icon'); const config = require('./app/config'); @@ -56,8 +55,7 @@ const config = require('./app/config'); const userConfig = require('./app/user_config'); const passwordUtil = require('./ts/util/passwordUtils'); -const importMode = - process.argv.some(arg => arg === '--import') || config.get('import'); +const importMode = process.argv.some(arg => arg === '--import') || config.get('import'); const development = config.environment === 'development'; const appInstance = config.util.getEnv('NODE_APP_INSTANCE') || 0; @@ -76,10 +74,7 @@ const sql = require('./app/sql'); const sqlChannels = require('./app/sql_channel'); const windowState = require('./app/window_state'); const { createTemplate } = require('./app/menu'); -const { - installFileHandler, - installWebHandler, -} = require('./app/protocol_filter'); +const { installFileHandler, installWebHandler } = require('./app/protocol_filter'); const { installPermissionsHandler } = require('./app/permissions'); const _sodium = require('libsodium-wrappers'); @@ -218,10 +213,7 @@ function getWindowSize() { const { minWidth, minHeight, defaultWidth, defaultHeight } = WINDOW_SIZE; // Ensure that the screen can fit within the default size const width = Math.min(defaultWidth, Math.max(minWidth, screenSize.width)); - const height = Math.min( - defaultHeight, - Math.max(minHeight, screenSize.height) - ); + const height = Math.min(defaultHeight, Math.max(minHeight, screenSize.height)); return { width, height, minWidth, minHeight }; } @@ -234,15 +226,12 @@ function isVisible(window, bounds) { const BOUNDS_BUFFER = 100; // requiring BOUNDS_BUFFER pixels on the left or right side - const rightSideClearOfLeftBound = - window.x + window.width >= boundsX + BOUNDS_BUFFER; - const leftSideClearOfRightBound = - window.x <= boundsX + boundsWidth - BOUNDS_BUFFER; + const rightSideClearOfLeftBound = window.x + window.width >= boundsX + BOUNDS_BUFFER; + const leftSideClearOfRightBound = window.x <= boundsX + boundsWidth - BOUNDS_BUFFER; // top can't be offscreen, and must show at least BOUNDS_BUFFER pixels at bottom const topClearOfUpperBound = window.y >= boundsY; - const topClearOfLowerBound = - window.y <= boundsY + boundsHeight - BOUNDS_BUFFER; + const topClearOfLowerBound = window.y <= boundsY + boundsHeight - BOUNDS_BUFFER; return ( rightSideClearOfLeftBound && @@ -275,14 +264,7 @@ async function createWindow() { }, icon: path.join(__dirname, 'images', 'session', 'session_icon_64.png'), }, - _.pick(windowConfig, [ - 'maximized', - 'autoHideMenuBar', - 'width', - 'height', - 'x', - 'y', - ]) + _.pick(windowConfig, ['maximized', 'autoHideMenuBar', 'width', 'height', 'x', 'y']) ); if (!_.isNumber(windowOptions.width) || windowOptions.width < minWidth) { @@ -315,10 +297,7 @@ async function createWindow() { delete windowOptions.fullscreen; } - logger.info( - 'Initializing BrowserWindow config: %s', - JSON.stringify(windowOptions) - ); + logger.info('Initializing BrowserWindow config: %s', JSON.stringify(windowOptions)); // Create the browser window. mainWindow = new BrowserWindow(windowOptions); @@ -355,10 +334,7 @@ async function createWindow() { windowConfig.fullscreen = true; } - logger.info( - 'Updating BrowserWindow config: %s', - JSON.stringify(windowConfig) - ); + logger.info('Updating BrowserWindow config: %s', JSON.stringify(windowConfig)); ephemeralConfig.set('window', windowConfig); } @@ -377,13 +353,9 @@ async function createWindow() { if (config.environment === 'test') { mainWindow.loadURL(prepareURL([__dirname, 'test', 'index.html'])); } else if (config.environment === 'test-lib') { - mainWindow.loadURL( - prepareURL([__dirname, 'libtextsecure', 'test', 'index.html']) - ); + mainWindow.loadURL(prepareURL([__dirname, 'libtextsecure', 'test', 'index.html'])); } else if (config.environment === 'test-loki') { - mainWindow.loadURL( - prepareURL([__dirname, 'libloki', 'test', 'index.html']) - ); + mainWindow.loadURL(prepareURL([__dirname, 'libloki', 'test', 'index.html'])); } else if (config.environment.includes('test-integration')) { mainWindow.loadURL(prepareURL([__dirname, 'background_test.html'])); } else { @@ -422,10 +394,7 @@ async function createWindow() { // On Mac, or on other platforms when the tray icon is in use, the window // should be only hidden, not closed, when the user clicks the close button - if ( - !windowState.shouldQuit() && - (usingTrayIcon || process.platform === 'darwin') - ) { + if (!windowState.shouldQuit() && (usingTrayIcon || process.platform === 'darwin')) { // toggle the visibility of the show/hide tray icon menu entries if (tray) { tray.updateContextMenu(); @@ -476,10 +445,7 @@ async function readyForUpdates() { await updater.start(getMainWindow, userConfig, locale.messages, logger); } catch (error) { const log = logger || console; - log.error( - 'Error starting update checks:', - error && error.stack ? error.stack : error - ); + log.error('Error starting update checks:', error && error.stack ? error.stack : error); } } ipc.once('ready-for-updates', readyForUpdates); @@ -555,10 +521,7 @@ function showPasswordWindow() { // On Mac, or on other platforms when the tray icon is in use, the window // should be only hidden, not closed, when the user clicks the close button - if ( - !windowState.shouldQuit() && - (usingTrayIcon || process.platform === 'darwin') - ) { + if (!windowState.shouldQuit() && (usingTrayIcon || process.platform === 'darwin')) { // toggle the visibility of the show/hide tray icon menu entries if (tray) { tray.updateContextMenu(); @@ -717,9 +680,7 @@ app.on('ready', async () => { function getDefaultSQLKey() { let key = userConfig.get('key'); if (!key) { - console.log( - 'key/initialize: Generating new encryption key, since we did not find it on disk' - ); + console.log('key/initialize: Generating new encryption key, since we did not find it on disk'); // https://www.zetetic.net/sqlcipher/sqlcipher-api/#key key = crypto.randomBytes(32).toString('hex'); userConfig.set('key', key); @@ -754,9 +715,7 @@ async function showMainWindow(sqlKey, passwordAttempt = false) { async function cleanupOrphanedAttachments() { const allAttachments = await attachments.getAllAttachments(userDataPath); - const orphanedAttachments = await sql.removeKnownAttachments( - allAttachments - ); + const orphanedAttachments = await sql.removeKnownAttachments(allAttachments); await attachments.deleteAll({ userDataPath, attachments: orphanedAttachments, @@ -823,9 +782,7 @@ async function requestShutdown() { // yet listening for these events), or if there are a whole lot of stacked-up tasks. // Note: two minutes is also our timeout for SQL tasks in data.ts in the browser. setTimeout(() => { - console.log( - 'requestShutdown: Response never received; forcing shutdown.' - ); + console.log('requestShutdown: Response never received; forcing shutdown.'); resolve(); }, 2 * 60 * 1000); }); @@ -833,10 +790,7 @@ async function requestShutdown() { try { await request; } catch (error) { - console.log( - 'requestShutdown error:', - error && error.stack ? error.stack : error - ); + console.log('requestShutdown error:', error && error.stack ? error.stack : error); } } @@ -954,8 +908,7 @@ ipc.on('update-tray-icon', (event, unreadCount) => { // Password screen related IPC calls ipc.on('password-window-login', async (event, passPhrase) => { - const sendResponse = e => - event.sender.send('password-window-login-response', e); + const sendResponse = e => event.sender.send('password-window-login-response', e); try { const passwordAttempt = true; @@ -977,8 +930,7 @@ ipc.on('set-password', async (event, passPhrase, oldPhrase) => { if (hash && !hashMatches) { const incorrectOldPassword = locale.messages.invalidOldPassword.message; sendResponse( - incorrectOldPassword || - 'Failed to set password: Old password provided is invalid' + incorrectOldPassword || 'Failed to set password: Old password provided is invalid' ); return; } diff --git a/metrics_app.js b/metrics_app.js index 2f9c0f18dd05251064e846517e6380ae7f4ce490..21ffdab4050e102b88f9deb37bc25b7ede498cbd 100644 --- a/metrics_app.js +++ b/metrics_app.js @@ -31,9 +31,7 @@ http // Avoid https://en.wikipedia.org/wiki/Directory_traversal_attack // e.g curl --path-as-is http://localhost:9000/../fileInDanger.txt // by limiting the path to current directory only - const sanitizePath = path - .normalize(parsedUrl.pathname) - .replace(/^(\.\.[/\\])+/, ''); + const sanitizePath = path.normalize(parsedUrl.pathname).replace(/^(\.\.[/\\])+/, ''); let pathname = path.join(__dirname, sanitizePath); fs.exists(pathname, exist => { if (!exist) { diff --git a/password_preload.js b/password_preload.js index 8d04b1f6f70886074b377b0b927050d613dff08c..e0fd3e13dc7ef6d5bf3bee0787e534195c646ddf 100644 --- a/password_preload.js +++ b/password_preload.js @@ -24,9 +24,7 @@ window.getAppInstance = () => config.appInstance; const electron = require('electron'); const ipc = electron.ipcRenderer; -const { - SessionPasswordPrompt, -} = require('./ts/components/session/SessionPasswordPrompt'); +const { SessionPasswordPrompt } = require('./ts/components/session/SessionPasswordPrompt'); window.Signal = { Components: { diff --git a/preload.js b/preload.js index 6b6cc820c24d0a664c2ba2db0a202196624df103..69d2f430544b2fda7727a354160a02ad4664da54 100644 --- a/preload.js +++ b/preload.js @@ -67,10 +67,7 @@ window.lokiFeatureFlags = { padOutgoingAttachments: false, }; -if ( - typeof process.env.NODE_ENV === 'string' && - process.env.NODE_ENV.includes('test-integration') -) { +if (typeof process.env.NODE_ENV === 'string' && process.env.NODE_ENV.includes('test-integration')) { window.electronRequire = require; // during test-integration, file server is started on localhost window.getDefaultFileServer = () => 'http://127.0.0.1:7070'; @@ -100,8 +97,7 @@ window.CONSTANTS = new (function() { this.LNS_MAX_LENGTH = 64; // Conforms to naming rules here // https://loki.network/2020/03/25/loki-name-system-the-facts/ - this.LNS_REGEX = `^[a-zA-Z0-9_]([a-zA-Z0-9_-]{0,${this.LNS_MAX_LENGTH - - 2}}[a-zA-Z0-9_]){0,1}$`; + this.LNS_REGEX = `^[a-zA-Z0-9_]([a-zA-Z0-9_-]{0,${this.LNS_MAX_LENGTH - 2}}[a-zA-Z0-9_]){0,1}$`; this.MIN_GUARD_COUNT = 2; this.DESIRED_GUARD_COUNT = 3; })(); @@ -185,11 +181,9 @@ window.showWindow = () => { ipc.send('show-window'); }; -window.setAutoHideMenuBar = autoHide => - ipc.send('set-auto-hide-menu-bar', autoHide); +window.setAutoHideMenuBar = autoHide => ipc.send('set-auto-hide-menu-bar', autoHide); -window.setMenuBarVisibility = visibility => - ipc.send('set-menu-bar-visibility', visibility); +window.setMenuBarVisibility = visibility => ipc.send('set-menu-bar-visibility', visibility); window.restart = () => { window.log.info('restart'); @@ -213,10 +207,7 @@ window.onUnblockNumber = async number => { const conversation = window.getConversationController().get(number); await conversation.unblock(); } catch (e) { - window.log.info( - 'IPC on unblock: failed to fetch conversation for number: ', - number - ); + window.log.info('IPC on unblock: failed to fetch conversation for number: ', number); } } }; @@ -228,8 +219,7 @@ ipc.on('mediaPermissionsChanged', () => { window.closeAbout = () => ipc.send('close-about'); window.readyForUpdates = () => ipc.send('ready-for-updates'); -window.updateTrayIcon = unreadCount => - ipc.send('update-tray-icon', unreadCount); +window.updateTrayIcon = unreadCount => ipc.send('update-tray-icon', unreadCount); ipc.on('set-up-with-import', () => { Whisper.events.trigger('setupWithImport'); @@ -288,13 +278,11 @@ window.setSettingValue = (settingID, value) => { }; window.getMediaPermissions = () => ipc.sendSync('get-media-permissions'); -window.setMediaPermissions = value => - ipc.send('set-media-permissions', !!value); +window.setMediaPermissions = value => ipc.send('set-media-permissions', !!value); // Auto update setting window.getAutoUpdateEnabled = () => ipc.sendSync('get-auto-update-setting'); -window.setAutoUpdateEnabled = value => - ipc.send('set-auto-update-setting', !!value); +window.setAutoUpdateEnabled = value => ipc.send('set-auto-update-setting', !!value); ipc.on('get-ready-for-shutdown', async () => { const { shutdown } = window.Events || {}; @@ -308,10 +296,7 @@ ipc.on('get-ready-for-shutdown', async () => { await shutdown(); ipc.send('now-ready-for-shutdown'); } catch (error) { - ipc.send( - 'now-ready-for-shutdown', - error && error.stack ? error.stack : error - ); + ipc.send('now-ready-for-shutdown', error && error.stack ? error.stack : error); } }); @@ -411,8 +396,7 @@ window.models = require('./ts/models'); window.Signal = window.Signal || {}; window.Signal.Data = require('./ts/data/data'); -window.getMessageController = () => - window.libsession.Messages.MessageController.getInstance(); +window.getMessageController = () => window.libsession.Messages.MessageController.getInstance(); window.getConversationController = () => window.libsession.Conversations.ConversationController.getInstance(); @@ -422,9 +406,7 @@ window.Signal.Backup = require('./js/modules/backup'); window.Signal.Logs = require('./js/modules/logs'); window.addEventListener('contextmenu', e => { - const editable = e.target.closest( - 'textarea, input, [contenteditable="true"]' - ); + const editable = e.target.closest('textarea, input, [contenteditable="true"]'); const link = e.target.closest('a'); const selection = Boolean(window.getSelection().toString()); if (!editable && !selection && !link) { @@ -438,9 +420,7 @@ window.NewSnodeAPI = require('./ts/session/snode_api/serviceNodeAPI'); window.SnodePool = require('./ts/session/snode_api/snodePool'); if (process.env.USE_STUBBED_NETWORK) { - const { - SwarmPollingStub, - } = require('./ts/session/snode_api/swarmPollingStub'); + const { SwarmPollingStub } = require('./ts/session/snode_api/swarmPollingStub'); window.SwarmPolling = new SwarmPollingStub(); } else { const { SwarmPolling } = require('./ts/session/snode_api/swarmPolling'); @@ -486,8 +466,6 @@ if (config.environment.includes('test-integration')) { // Blocking -const { - BlockedNumberController, -} = require('./ts/util/blockedNumberController'); +const { BlockedNumberController } = require('./ts/util/blockedNumberController'); window.BlockedNumberController = BlockedNumberController; diff --git a/stylesheets/_session_left_pane.scss b/stylesheets/_session_left_pane.scss index c30d9dcc2b27f9c399fcbcdf7f37470cfe30c615..26166af9c5159bca723dc79b38163eb4abce23bd 100644 --- a/stylesheets/_session_left_pane.scss +++ b/stylesheets/_session_left_pane.scss @@ -356,8 +356,8 @@ $session-compose-margin: 20px; .session-brand-logo { height: 180px; - filter: brightness(0) saturate(100%) invert(75%) sepia(84%) saturate(3272%) - hue-rotate(103deg) brightness(106%) contrast(103%); + filter: brightness(0) saturate(100%) invert(75%) sepia(84%) saturate(3272%) hue-rotate(103deg) + brightness(106%) contrast(103%); } .session-text-logo { diff --git a/stylesheets/_variables.scss b/stylesheets/_variables.scss index a0a90bd427250e3ff31a446439f34bf93254d375..4321dcbbfa01cadf4914ecd5902ab564bf4652a0 100644 --- a/stylesheets/_variables.scss +++ b/stylesheets/_variables.scss @@ -4,11 +4,7 @@ $color-loki-dark-gray: #323232; $color-loki-extra-dark-gray: #101010; $color-loki-green: #3bd110; $color-loki-green-dark: #32b10e; -$color-loki-green-gradient: linear-gradient( - to right, - rgb(120, 190, 32) 0%, - rgb(0, 133, 34) 100% -); +$color-loki-green-gradient: linear-gradient(to right, rgb(120, 190, 32) 0%, rgb(0, 133, 34) 100%); $color-white: #ffffff; $color-gray-02: #f8f9f9; diff --git a/test/app/logging_test.js b/test/app/logging_test.js index bfdf20fac36a57e28001090236913944883634dc..6ab81b3d7ea9716c3e96dacc7d91c3895e650a47 100644 --- a/test/app/logging_test.js +++ b/test/app/logging_test.js @@ -174,9 +174,7 @@ describe('app/logging', () => { JSON.stringify({ time: '2018-01-04T19:17:02.014Z' }), JSON.stringify({ time: '2018-01-04T19:17:03.014Z' }), ].join('\n'); - const expected = [ - JSON.stringify({ time: '2018-01-04T19:17:03.014Z' }), - ].join('\n'); + const expected = [JSON.stringify({ time: '2018-01-04T19:17:03.014Z' })].join('\n'); const target = path.join(basePath, 'log.log'); const files = [ @@ -267,10 +265,7 @@ describe('app/logging', () => { }); }); it('returns sorted entries from all files', () => { - const first = [ - JSON.stringify({ msg: 2, time: '2018-01-04T19:17:05.014Z' }), - '', - ].join('\n'); + const first = [JSON.stringify({ msg: 2, time: '2018-01-04T19:17:05.014Z' }), ''].join('\n'); const second = [ JSON.stringify({ msg: 1, time: '2018-01-04T19:17:00.014Z' }), JSON.stringify({ msg: 3, time: '2018-01-04T19:18:00.014Z' }), diff --git a/test/app/menu_test.js b/test/app/menu_test.js index 15f8c57c81461653704af78a59e6fb9e69b92eaf..97f6395a7aeddd1eebd696c93b15027beba2ade6 100644 --- a/test/app/menu_test.js +++ b/test/app/menu_test.js @@ -61,9 +61,7 @@ describe('SignalMenu', () => { const { messages } = loadLocale({ appLocale, logger }); const actual = SignalMenu.createTemplate(options, messages); - const fixturePath = includeSetup - ? fixtures.setup - : fixtures.default; + const fixturePath = includeSetup ? fixtures.setup : fixtures.default; // eslint-disable-next-line global-require, import/no-dynamic-require const fixture = require(fixturePath); assert.deepEqual(actual, fixture); diff --git a/test/app/protocol_filter_test.js b/test/app/protocol_filter_test.js index 11964224591f3c4d2ebe7ff53b5bd93cd0d75b02..da2b1fee338cfe7d8699f9aff4868dfc47ac8919 100644 --- a/test/app/protocol_filter_test.js +++ b/test/app/protocol_filter_test.js @@ -5,10 +5,8 @@ const { _urlToPath } = require('../../app/protocol_filter'); describe('Protocol Filter', () => { describe('_urlToPath', () => { it('returns proper file path for unix style file URI with hash', () => { - const path = - 'file:///Users/someone/Development/signal/electron/background.html#first-page'; - const expected = - '/Users/someone/Development/signal/electron/background.html'; + const path = 'file:///Users/someone/Development/signal/electron/background.html#first-page'; + const expected = '/Users/someone/Development/signal/electron/background.html'; const actual = _urlToPath(path); expect(actual).to.equal(expected); @@ -17,8 +15,7 @@ describe('Protocol Filter', () => { it('returns proper file path for unix style file URI with querystring', () => { const path = 'file:///Users/someone/Development/signal/electron/background.html?name=Signal&locale=en&version=2.4.0'; - const expected = - '/Users/someone/Development/signal/electron/background.html'; + const expected = '/Users/someone/Development/signal/electron/background.html'; const actual = _urlToPath(path); expect(actual).to.equal(expected); @@ -27,8 +24,7 @@ describe('Protocol Filter', () => { it('returns proper file path for unix style file URI with hash and querystring', () => { const path = 'file:///Users/someone/Development/signal/electron/background.html#somewhere?name=Signal'; - const expected = - '/Users/someone/Development/signal/electron/background.html'; + const expected = '/Users/someone/Development/signal/electron/background.html'; const actual = _urlToPath(path); expect(actual).to.equal(expected); @@ -45,20 +41,16 @@ describe('Protocol Filter', () => { }); it('translates from URL format to filesystem format', () => { - const path = - 'file:///Users/someone/Development%20Files/signal/electron/background.html'; - const expected = - '/Users/someone/Development Files/signal/electron/background.html'; + const path = 'file:///Users/someone/Development%20Files/signal/electron/background.html'; + const expected = '/Users/someone/Development Files/signal/electron/background.html'; const actual = _urlToPath(path); expect(actual).to.equal(expected); }); it('translates from URL format to filesystem format', () => { - const path = - 'file:///Users/someone/Development%20Files/signal/electron/background.html'; - const expected = - '/Users/someone/Development Files/signal/electron/background.html'; + const path = 'file:///Users/someone/Development%20Files/signal/electron/background.html'; + const expected = '/Users/someone/Development Files/signal/electron/background.html'; const actual = _urlToPath(path); expect(actual).to.equal(expected); diff --git a/test/backup_test.js b/test/backup_test.js index dcbcbd155bb67dc08a73226b48fad92f37132467..90f79fc4f53ce94d4887fbe8ce1624e1bfe7deb5 100644 --- a/test/backup_test.js +++ b/test/backup_test.js @@ -27,8 +27,7 @@ describe('Backup', () => { }); it('handles a file with a long extension', () => { - const initial = - '0123456789012345678901234567890123456789.01234567890123456789'; + const initial = '0123456789012345678901234567890123456789.01234567890123456789'; const expected = '012345678901234567890123456789'; assert.strictEqual(Signal.Backup._trimFileName(initial), expected); }); @@ -51,11 +50,7 @@ describe('Backup', () => { }; const expected = 'blah.jpg'; - const actual = Signal.Backup._getExportAttachmentFileName( - message, - index, - attachment - ); + const actual = Signal.Backup._getExportAttachmentFileName(message, index, attachment); assert.strictEqual(actual, expected); }); @@ -69,11 +64,7 @@ describe('Backup', () => { }; const expected = '123'; - const actual = Signal.Backup._getExportAttachmentFileName( - message, - index, - attachment - ); + const actual = Signal.Backup._getExportAttachmentFileName(message, index, attachment); assert.strictEqual(actual, expected); }); @@ -88,11 +79,7 @@ describe('Backup', () => { }; const expected = '123.jpeg'; - const actual = Signal.Backup._getExportAttachmentFileName( - message, - index, - attachment - ); + const actual = Signal.Backup._getExportAttachmentFileName(message, index, attachment); assert.strictEqual(actual, expected); }); @@ -107,11 +94,7 @@ describe('Backup', () => { }; const expected = '123.something'; - const actual = Signal.Backup._getExportAttachmentFileName( - message, - index, - attachment - ); + const actual = Signal.Backup._getExportAttachmentFileName(message, index, attachment); assert.strictEqual(actual, expected); }); }); @@ -128,11 +111,7 @@ describe('Backup', () => { }; const expected = 'id-45'; - const actual = Signal.Backup._getAnonymousAttachmentFileName( - message, - index, - attachment - ); + const actual = Signal.Backup._getAnonymousAttachmentFileName(message, index, attachment); assert.strictEqual(actual, expected); }); @@ -147,11 +126,7 @@ describe('Backup', () => { }; const expected = 'id-45-1'; - const actual = Signal.Backup._getAnonymousAttachmentFileName( - message, - index, - attachment - ); + const actual = Signal.Backup._getAnonymousAttachmentFileName(message, index, attachment); assert.strictEqual(actual, expected); }); }); @@ -164,10 +139,7 @@ describe('Backup', () => { id: 'id', }; const expected = '123 (012345678901234567890123456789 id)'; - assert.strictEqual( - Signal.Backup._getConversationDirName(conversation), - expected - ); + assert.strictEqual(Signal.Backup._getConversationDirName(conversation), expected); }); it('uses just id if name is not available', () => { @@ -176,10 +148,7 @@ describe('Backup', () => { id: 'id', }; const expected = '123 (id)'; - assert.strictEqual( - Signal.Backup._getConversationDirName(conversation), - expected - ); + assert.strictEqual(Signal.Backup._getConversationDirName(conversation), expected); }); it('uses inactive for missing active_at', () => { @@ -188,10 +157,7 @@ describe('Backup', () => { id: 'id', }; const expected = 'inactive (name id)'; - assert.strictEqual( - Signal.Backup._getConversationDirName(conversation), - expected - ); + assert.strictEqual(Signal.Backup._getConversationDirName(conversation), expected); }); }); @@ -203,10 +169,7 @@ describe('Backup', () => { type: 'private', }; const expected = '123 (id)'; - assert.strictEqual( - Signal.Backup._getConversationLoggingName(conversation), - expected - ); + assert.strictEqual(Signal.Backup._getConversationLoggingName(conversation), expected); }); it('uses just id if name is not available', () => { @@ -216,10 +179,7 @@ describe('Backup', () => { type: 'group', }; const expected = '123 ([REDACTED_GROUP]pId)'; - assert.strictEqual( - Signal.Backup._getConversationLoggingName(conversation), - expected - ); + assert.strictEqual(Signal.Backup._getConversationLoggingName(conversation), expected); }); it('uses inactive for missing active_at', () => { @@ -228,10 +188,7 @@ describe('Backup', () => { type: 'private', }; const expected = 'inactive (id)'; - assert.strictEqual( - Signal.Backup._getConversationLoggingName(conversation), - expected - ); + assert.strictEqual(Signal.Backup._getConversationLoggingName(conversation), expected); }); }); @@ -245,17 +202,12 @@ describe('Backup', () => { // because it always fails due to lstat permission error. // Don't know how to fix it so this is a temp work around. if (isWindows || !isWindows) { - console.log( - 'Skipping exports then imports to produce the same data we started' - ); + console.log('Skipping exports then imports to produce the same data we started'); this.skip(); return; } - const { - upgradeMessageSchema, - loadAttachmentData, - } = window.Signal.Migrations; + const { upgradeMessageSchema, loadAttachmentData } = window.Signal.Migrations; const staticKeyPair = await libsignal.KeyHelper.generateIdentityKeyPair(); const attachmentsPattern = path.join(attachmentsPath, '**'); @@ -278,9 +230,7 @@ describe('Backup', () => { jpg: getFixture('fixtures/koushik-chowdavarapu-105425-unsplash.jpg'), mp3: getFixture('fixtures/incompetech-com-Agnus-Dei-X.mp3'), txt: getFixture('fixtures/lorem-ipsum.txt'), - png: getFixture( - 'fixtures/freepngs-2cd43b_bed7d1327e88454487397574d87b64dc_mv2.png' - ), + png: getFixture('fixtures/freepngs-2cd43b_bed7d1327e88454487397574d87b64dc_mv2.png'), }; async function wrappedLoadAttachment(attachment) { @@ -308,8 +258,7 @@ describe('Backup', () => { Object.entries(object) .filter(([, value]) => value === undefined) .map(([name]) => name); - const omitUndefinedKeys = object => - _.omit(object, getUndefinedKeys(object)); + const omitUndefinedKeys = object => _.omit(object, getUndefinedKeys(object)); // We want to know which paths have two slashes, since that tells us which files // in the attachment fan-out are files vs. directories. @@ -340,14 +289,11 @@ describe('Backup', () => { }); }; - const quotedAttachments = - (message.quote && message.quote.attachments) || []; + const quotedAttachments = (message.quote && message.quote.attachments) || []; return Object.assign({}, message, { quote: Object.assign({}, message.quote, { - attachments: await Promise.all( - quotedAttachments.map(wrappedMapper) - ), + attachments: await Promise.all(quotedAttachments.map(wrappedMapper)), }), }); }; @@ -369,9 +315,7 @@ describe('Backup', () => { return contact && contact.avatar && contact.avatar.avatar ? Object.assign({}, contact, { avatar: Object.assign({}, contact.avatar, { - avatar: await wrappedLoadAttachment( - contact.avatar.avatar - ), + avatar: await wrappedLoadAttachment(contact.avatar.avatar), }), }) : contact; @@ -518,9 +462,7 @@ describe('Backup', () => { console.log({ conversation }); await window.Signal.Data.saveConversation(conversation); - console.log( - 'Backup test: Ensure that all attachments were saved to disk' - ); + console.log('Backup test: Ensure that all attachments were saved to disk'); const attachmentFiles = removeDirs(glob.sync(attachmentsPattern)); console.log({ attachmentFiles }); assert.strictEqual(ATTACHMENT_COUNT, attachmentFiles.length); @@ -537,9 +479,7 @@ describe('Backup', () => { const messageZipExists = fse.existsSync(archivePath); assert.strictEqual(true, messageZipExists); - console.log( - 'Backup test: Ensure that all attachments made it to backup dir' - ); + console.log('Backup test: Ensure that all attachments made it to backup dir'); const backupAttachmentPattern = path.join(backupDir, 'attachments/*'); const backupAttachments = glob.sync(backupAttachmentPattern); console.log({ backupAttachments }); @@ -569,10 +509,7 @@ describe('Backup', () => { ]; const conversationFromDB = conversationCollection.at(0).attributes; console.log({ conversationFromDB, conversation }); - assert.deepEqual( - _.omit(conversationFromDB, ommited), - _.omit(conversation, ommited) - ); + assert.deepEqual(_.omit(conversationFromDB, ommited), _.omit(conversation, ommited)); console.log('Backup test: Check messages'); const allMessages = await window.Signal.Data.getAllMessages(); @@ -583,19 +520,13 @@ describe('Backup', () => { assert.deepEqual(messageFromDB, expectedMessage); console.log('Backup test: ensure that all attachments were imported'); - const recreatedAttachmentFiles = removeDirs( - glob.sync(attachmentsPattern) - ); + const recreatedAttachmentFiles = removeDirs(glob.sync(attachmentsPattern)); console.log({ recreatedAttachmentFiles }); assert.strictEqual(ATTACHMENT_COUNT, recreatedAttachmentFiles.length); assert.deepEqual(attachmentFiles, recreatedAttachmentFiles); - console.log( - 'Backup test: Check that all attachments were successfully imported' - ); - const messageWithAttachmentsFromDB = await loadAllFilesFromDisk( - messageFromDB - ); + console.log('Backup test: Check that all attachments were successfully imported'); + const messageWithAttachmentsFromDB = await loadAllFilesFromDisk(messageFromDB); const expectedMessageWithAttachments = await loadAllFilesFromDisk( omitUndefinedKeys(message) ); diff --git a/test/crypto_test.js b/test/crypto_test.js index a5a6b0ac1099d327dff8e5f151bf6793ec21aaf9..f36a640b91c5d91c19c27284f4f3ca9727b2c65f 100644 --- a/test/crypto_test.js +++ b/test/crypto_test.js @@ -19,10 +19,7 @@ describe('Crypto', () => { describe('symmetric encryption', () => { it('roundtrips', async () => { const message = 'this is my message'; - const plaintext = dcodeIO.ByteBuffer.wrap( - message, - 'binary' - ).toArrayBuffer(); + const plaintext = dcodeIO.ByteBuffer.wrap(message, 'binary').toArrayBuffer(); const key = textsecure.crypto.getRandomBytes(32); const encrypted = await Signal.Crypto.encryptSymmetric(key, plaintext); @@ -36,10 +33,7 @@ describe('Crypto', () => { it('roundtrip fails if nonce is modified', async () => { const message = 'this is my message'; - const plaintext = dcodeIO.ByteBuffer.wrap( - message, - 'binary' - ).toArrayBuffer(); + const plaintext = dcodeIO.ByteBuffer.wrap(message, 'binary').toArrayBuffer(); const key = textsecure.crypto.getRandomBytes(32); const encrypted = await Signal.Crypto.encryptSymmetric(key, plaintext); @@ -61,10 +55,7 @@ describe('Crypto', () => { it('roundtrip fails if mac is modified', async () => { const message = 'this is my message'; - const plaintext = dcodeIO.ByteBuffer.wrap( - message, - 'binary' - ).toArrayBuffer(); + const plaintext = dcodeIO.ByteBuffer.wrap(message, 'binary').toArrayBuffer(); const key = textsecure.crypto.getRandomBytes(32); const encrypted = await Signal.Crypto.encryptSymmetric(key, plaintext); @@ -86,10 +77,7 @@ describe('Crypto', () => { it('roundtrip fails if encrypted contents are modified', async () => { const message = 'this is my message'; - const plaintext = dcodeIO.ByteBuffer.wrap( - message, - 'binary' - ).toArrayBuffer(); + const plaintext = dcodeIO.ByteBuffer.wrap(message, 'binary').toArrayBuffer(); const key = textsecure.crypto.getRandomBytes(32); const encrypted = await Signal.Crypto.encryptSymmetric(key, plaintext); @@ -115,8 +103,7 @@ describe('Crypto', () => { const staticKeyPair = await libsignal.KeyHelper.generateIdentityKeyPair(); const message = 'this is my message'; const plaintext = Signal.Crypto.bytesFromString(message); - const path = - 'fa/facdf99c22945b1c9393345599a276f4b36ad7ccdc8c2467f5441b742c2d11fa'; + const path = 'fa/facdf99c22945b1c9393345599a276f4b36ad7ccdc8c2467f5441b742c2d11fa'; const encrypted = await Signal.Crypto.encryptAttachment( staticKeyPair.pubKey.slice(1), diff --git a/test/fixtures_test.js b/test/fixtures_test.js index e0256e62fc386380e4b9fcfb15bbf77e22f021a8..bb88cec62998dce593bceef2ec1dc0a2259a2b18 100644 --- a/test/fixtures_test.js +++ b/test/fixtures_test.js @@ -15,10 +15,7 @@ describe('Fixtures', () => { await window .getConversationController() - .getOrCreateAndWait( - window.libsession.Utils.UserUtils.getOurPubKeyStrFromCache(), - 'private' - ); + .getOrCreateAndWait(window.libsession.Utils.UserUtils.getOurPubKeyStrFromCache(), 'private'); }); it('renders', async () => { diff --git a/test/i18n_test.js b/test/i18n_test.js index 8530b8cbfef032d9fa5c0480e99fbf17c3e3b7ad..3698476dd6f34acbe6076d06736794f2d5385320 100644 --- a/test/i18n_test.js +++ b/test/i18n_test.js @@ -14,10 +14,7 @@ describe('i18n', () => { }); it('returns message with multiple substitutions', () => { const actual = i18n('theyChangedTheTimer', ['Someone', '5 minutes']); - assert.equal( - actual, - 'Someone set the disappearing message timer to 5 minutes' - ); + assert.equal(actual, 'Someone set the disappearing message timer to 5 minutes'); }); }); diff --git a/test/modules/privacy_test.js b/test/modules/privacy_test.js index 2596351b1a4c8e2aafce61599b65d3ca3d9ca1d5..e09443196280db816e754974ff3d9d26bc672d54 100644 --- a/test/modules/privacy_test.js +++ b/test/modules/privacy_test.js @@ -15,8 +15,7 @@ describe('Privacy', () => { const actual = Privacy.redactSessionID(text); const expected = - 'This is a log line with a session ID [REDACTED]\n' + - 'and another one [REDACTED]'; + 'This is a log line with a session ID [REDACTED]\n' + 'and another one [REDACTED]'; assert.equal(actual, expected); }); @@ -33,8 +32,7 @@ describe('Privacy', () => { describe('redactGroupIds', () => { it('should redact all group IDs', () => { const text = - 'This is a log line with two group IDs: group(123456789)\n' + - 'and group(abcdefghij)'; + 'This is a log line with two group IDs: group(123456789)\n' + 'and group(abcdefghij)'; const actual = Privacy.redactGroupIds(text); const expected = @@ -45,8 +43,7 @@ describe('Privacy', () => { it('should remove newlines from redacted group IDs', () => { const text = - 'This is a log line with two group IDs: group(12345678\n9)\n' + - 'and group(abc\ndefghij)'; + 'This is a log line with two group IDs: group(12345678\n9)\n' + 'and group(abc\ndefghij)'; const actual = Privacy.redactGroupIds(text); const expected = @@ -126,10 +123,8 @@ describe('Privacy', () => { }); it('should redact stack traces with both forward and backslashes', () => { - const testPath = - 'C:/Users/Meow/AppData/Local/Programs/loki-messenger-beta'; - const modifiedTestPath = - 'C:\\Users\\Meow\\AppData\\Local\\Programs\\loki-messenger-beta'; + const testPath = 'C:/Users/Meow/AppData/Local/Programs/loki-messenger-beta'; + const modifiedTestPath = 'C:\\Users\\Meow\\AppData\\Local\\Programs\\loki-messenger-beta'; const text = 'This is a log line with sensitive information:\n' + `path1 ${testPath}\\main.js\n` + @@ -148,8 +143,7 @@ describe('Privacy', () => { }); it('should redact stack traces with escaped backslashes', () => { - const testPath = - 'C:\\Users\\Meow\\AppData\\Local\\Programs\\loki-messenger-beta'; + const testPath = 'C:\\Users\\Meow\\AppData\\Local\\Programs\\loki-messenger-beta'; const modifiedTestPath = 'C:\\\\Users\\\\Meow\\\\AppData\\\\Local\\\\Programs\\\\loki-messenger-beta'; const text = diff --git a/test/modules/types/attachment_test.js b/test/modules/types/attachment_test.js index f55aacef01d78c2cea0bead11c339869f6029975..73bffc732b8c52a826948f2a43084692bdfabfdf 100644 --- a/test/modules/types/attachment_test.js +++ b/test/modules/types/attachment_test.js @@ -3,9 +3,7 @@ require('mocha-testcheck').install(); const { assert } = require('chai'); const Attachment = require('../../../js/modules/types/attachment'); -const { - stringToArrayBuffer, -} = require('../../../js/modules/string_to_array_buffer'); +const { stringToArrayBuffer } = require('../../../js/modules/string_to_array_buffer'); describe('Attachment', () => { describe('replaceUnicodeOrderOverrides', () => { diff --git a/test/modules/types/errors_test.js b/test/modules/types/errors_test.js index 5d988492a2d64c01626fde4b48ab307beb33e4bc..ef37acbf0733476ef9b06bd6716e40048c82b5f8 100644 --- a/test/modules/types/errors_test.js +++ b/test/modules/types/errors_test.js @@ -14,11 +14,7 @@ describe('Errors', () => { const formattedError = Errors.toLogFormat(error); assert.include(formattedError, 'errors_test.js'); - assert.include( - formattedError, - APP_ROOT_PATH, - 'Formatted stack has app path' - ); + assert.include(formattedError, APP_ROOT_PATH, 'Formatted stack has app path'); }); it('should return error string representation if stack is missing', () => { diff --git a/test/modules/types/message_test.js b/test/modules/types/message_test.js index 8bcfb89f19b5a57d40ad67bacbc3af3ef16409a7..c42bfe966e1d181a830b07c212d9e109cc0a4fbf 100644 --- a/test/modules/types/message_test.js +++ b/test/modules/types/message_test.js @@ -3,9 +3,7 @@ const sinon = require('sinon'); const Message = require('../../../js/modules/types/message'); const { SignalService } = require('../../../ts/protobuf'); -const { - stringToArrayBuffer, -} = require('../../../js/modules/string_to_array_buffer'); +const { stringToArrayBuffer } = require('../../../js/modules/string_to_array_buffer'); describe('Message', () => { const logger = { @@ -77,10 +75,7 @@ describe('Message', () => { const writeExistingAttachmentData = attachment => { assert.equal(attachment.path, 'ab/abcdefghi'); - assert.deepEqual( - attachment.data, - stringToArrayBuffer('It’s easy if you try') - ); + assert.deepEqual(attachment.data, stringToArrayBuffer('It’s easy if you try')); }; const actual = await Message.createAttachmentDataWriter({ @@ -125,10 +120,7 @@ describe('Message', () => { const writeExistingAttachmentData = attachment => { assert.equal(attachment.path, 'ab/abcdefghi'); - assert.deepEqual( - attachment.data, - stringToArrayBuffer('It’s easy if you try') - ); + assert.deepEqual(attachment.data, stringToArrayBuffer('It’s easy if you try')); }; const actual = await Message.createAttachmentDataWriter({ @@ -176,10 +168,7 @@ describe('Message', () => { const writeExistingAttachmentData = attachment => { assert.equal(attachment.path, 'ab/abcdefghi'); - assert.deepEqual( - attachment.data, - stringToArrayBuffer('It’s easy if you try') - ); + assert.deepEqual(attachment.data, stringToArrayBuffer('It’s easy if you try')); }; const actual = await Message.createAttachmentDataWriter({ @@ -291,9 +280,7 @@ describe('Message', () => { contact: [], }; - const expectedAttachmentData = stringToArrayBuffer( - 'It’s easy if you try' - ); + const expectedAttachmentData = stringToArrayBuffer('It’s easy if you try'); const context = { writeNewAttachmentData: async attachmentData => { assert.deepEqual(attachmentData, expectedAttachmentData); @@ -340,13 +327,11 @@ describe('Message', () => { schemaVersion: 1, }; - const v1 = async message => - Object.assign({}, message, { hasUpgradedToVersion1: true }); + const v1 = async message => Object.assign({}, message, { hasUpgradedToVersion1: true }); const v2 = async () => { throw new Error('boom'); }; - const v3 = async message => - Object.assign({}, message, { hasUpgradedToVersion3: true }); + const v3 = async message => Object.assign({}, message, { hasUpgradedToVersion3: true }); const toVersion1 = Message._withSchemaVersion({ schemaVersion: 1, @@ -363,10 +348,7 @@ describe('Message', () => { const context = { logger }; const upgradeSchema = async message => - toVersion3( - await toVersion2(await toVersion1(message, context), context), - context - ); + toVersion3(await toVersion2(await toVersion1(message, context), context), context); const actual = await upgradeSchema(input); assert.deepEqual(actual, expected); @@ -421,10 +403,7 @@ describe('Message', () => { const context = { logger }; // NOTE: We upgrade to 3 before 2, i.e. the pipeline should abort: const upgradeSchema = async attachment => - toVersion2( - await toVersion3(await toVersion1(attachment, context), context), - context - ); + toVersion2(await toVersion3(await toVersion1(attachment, context), context), context); const actual = await upgradeSchema(input); assert.deepEqual(actual, expected); @@ -436,8 +415,7 @@ describe('Message', () => { it('should require a version number', () => { const toVersionX = () => {}; assert.throws( - () => - Message._withSchemaVersion({ schemaVersion: toVersionX, upgrade: 2 }), + () => Message._withSchemaVersion({ schemaVersion: toVersionX, upgrade: 2 }), '_withSchemaVersion: schemaVersion is invalid' ); }); @@ -450,8 +428,7 @@ describe('Message', () => { }); it('should skip upgrading if message has already been upgraded', async () => { - const upgrade = async message => - Object.assign({}, message, { foo: true }); + const upgrade = async message => Object.assign({}, message, { foo: true }); const upgradeWithVersion = Message._withSchemaVersion({ schemaVersion: 3, upgrade, @@ -512,9 +489,7 @@ describe('Message', () => { describe('_mapQuotedAttachments', () => { it('handles message with no quote', async () => { - const upgradeAttachment = sinon - .stub() - .throws(new Error("Shouldn't be called")); + const upgradeAttachment = sinon.stub().throws(new Error("Shouldn't be called")); const upgradeVersion = Message._mapQuotedAttachments(upgradeAttachment); const message = { @@ -525,9 +500,7 @@ describe('Message', () => { }); it('handles quote with no attachments', async () => { - const upgradeAttachment = sinon - .stub() - .throws(new Error("Shouldn't be called")); + const upgradeAttachment = sinon.stub().throws(new Error("Shouldn't be called")); const upgradeVersion = Message._mapQuotedAttachments(upgradeAttachment); const message = { @@ -548,9 +521,7 @@ describe('Message', () => { }); it('handles zero attachments', async () => { - const upgradeAttachment = sinon - .stub() - .throws(new Error("Shouldn't be called")); + const upgradeAttachment = sinon.stub().throws(new Error("Shouldn't be called")); const upgradeVersion = Message._mapQuotedAttachments(upgradeAttachment); const message = { @@ -565,9 +536,7 @@ describe('Message', () => { }); it('handles attachments with no thumbnail', async () => { - const upgradeAttachment = sinon - .stub() - .throws(new Error("Shouldn't be called")); + const upgradeAttachment = sinon.stub().throws(new Error("Shouldn't be called")); const upgradeVersion = Message._mapQuotedAttachments(upgradeAttachment); const message = { @@ -587,9 +556,7 @@ describe('Message', () => { }); it('does not eliminate thumbnails with missing data field', async () => { - const upgradeAttachment = sinon - .stub() - .returns({ fileName: 'processed!' }); + const upgradeAttachment = sinon.stub().returns({ fileName: 'processed!' }); const upgradeVersion = Message._mapQuotedAttachments(upgradeAttachment); const message = { @@ -665,9 +632,7 @@ describe('Message', () => { describe('_mapContact', () => { it('handles message with no contact field', async () => { - const upgradeContact = sinon - .stub() - .throws(new Error("Shouldn't be called")); + const upgradeContact = sinon.stub().throws(new Error("Shouldn't be called")); const upgradeVersion = Message._mapContact(upgradeContact); const message = { diff --git a/ts/attachments/attachments.ts b/ts/attachments/attachments.ts index b4612c8d8ec40e640961f7cb0c856017c9029105..b67c928c3228180f3d0fa48b8b902c19742216cc 100644 --- a/ts/attachments/attachments.ts +++ b/ts/attachments/attachments.ts @@ -6,10 +6,7 @@ import { default as glob } from 'glob'; import fse from 'fs-extra'; import toArrayBuffer from 'to-arraybuffer'; import { isArrayBuffer, isString, map } from 'lodash'; -import { - decryptAttachmentBuffer, - encryptAttachmentBuffer, -} from '../../ts/types/Attachment'; +import { decryptAttachmentBuffer, encryptAttachmentBuffer } from '../../ts/types/Attachment'; const PATH = 'attachments.noindex'; @@ -111,9 +108,7 @@ export const createWriterForExisting = (root: any) => { } await fse.ensureFile(normalized); - const { encryptedBufferWithHeader } = await encryptAttachmentBuffer( - arrayBuffer - ); + const { encryptedBufferWithHeader } = await encryptAttachmentBuffer(arrayBuffer); const buffer = Buffer.from(encryptedBufferWithHeader.buffer); await fse.writeFile(normalized, buffer); @@ -175,9 +170,7 @@ export const getRelativePath = (name: any) => { }; // createAbsolutePathGetter :: RootPath -> RelativePath -> AbsolutePath -export const createAbsolutePathGetter = (rootPath: string) => ( - relativePath: string -) => { +export const createAbsolutePathGetter = (rootPath: string) => (relativePath: string) => { const absolutePath = path.join(rootPath, relativePath); const normalized = path.normalize(absolutePath); if (!normalized.startsWith(rootPath)) { diff --git a/ts/components/Avatar.tsx b/ts/components/Avatar.tsx index 1cd0097bdea4246e257572387d0d0f79a32abb3e..8d7eea7db27b1409275861acea6d538a5c2e3cfd 100644 --- a/ts/components/Avatar.tsx +++ b/ts/components/Avatar.tsx @@ -47,13 +47,7 @@ const NoImage = (props: { const { memberAvatars, size } = props; // if no image but we have conversations set for the group, renders group members avatars if (memberAvatars) { - return ( - <ClosedGroupAvatar - size={size} - memberAvatars={memberAvatars} - i18n={window.i18n} - /> - ); + return <ClosedGroupAvatar size={size} memberAvatars={memberAvatars} i18n={window.i18n} />; } return <Identicon {...props} />; @@ -87,10 +81,7 @@ export const Avatar = (props: Props) => { const { urlToLoad } = useEncryptedFileFetch(avatarPath || '', ''); const handleImageError = () => { - window.log.warn( - 'Avatar: Image failed to load; failing over to placeholder', - urlToLoad - ); + window.log.warn('Avatar: Image failed to load; failing over to placeholder', urlToLoad); setImageBroken(true); }; diff --git a/ts/components/AvatarPlaceHolder/AvatarPlaceHolder.tsx b/ts/components/AvatarPlaceHolder/AvatarPlaceHolder.tsx index e8accab547177f4036216be8d76eef46dfe7aeeb..3ccf6f55f356b6f90e1e88417a9dfa4ab7152022 100644 --- a/ts/components/AvatarPlaceHolder/AvatarPlaceHolder.tsx +++ b/ts/components/AvatarPlaceHolder/AvatarPlaceHolder.tsx @@ -11,10 +11,7 @@ type Props = { const sha512FromPubkey = async (pubkey: string): Promise<string> => { // tslint:disable-next-line: await-promise - const buf = await crypto.subtle.digest( - 'SHA-512', - new TextEncoder().encode(pubkey) - ); + const buf = await crypto.subtle.digest('SHA-512', new TextEncoder().encode(pubkey)); // tslint:disable: prefer-template restrict-plus-operands return Array.prototype.map diff --git a/ts/components/AvatarPlaceHolder/ClosedGroupAvatar.tsx b/ts/components/AvatarPlaceHolder/ClosedGroupAvatar.tsx index 298543b36ab9177504081c7dd2e48ea15bb4fa76..276cafcd5fd5ee823778c391fd942e34d85e470c 100644 --- a/ts/components/AvatarPlaceHolder/ClosedGroupAvatar.tsx +++ b/ts/components/AvatarPlaceHolder/ClosedGroupAvatar.tsx @@ -24,9 +24,7 @@ export class ClosedGroupAvatar extends React.PureComponent<Props> { case AvatarSize.HUGE: return AvatarSize.XL; default: - throw new Error( - `Invalid size request for closed group avatar: ${size}` - ); + throw new Error(`Invalid size request for closed group avatar: ${size}`); } } diff --git a/ts/components/CaptionEditor.tsx b/ts/components/CaptionEditor.tsx index a7f31a601489777c85b292cc70ced6de3ae119d3..432ac0364122943a9d35459a66a10acd7121d237 100644 --- a/ts/components/CaptionEditor.tsx +++ b/ts/components/CaptionEditor.tsx @@ -6,11 +6,7 @@ import * as GoogleChrome from '../util/GoogleChrome'; import { AttachmentType } from '../types/Attachment'; import { SessionInput } from './session/SessionInput'; -import { - SessionButton, - SessionButtonColor, - SessionButtonType, -} from './session/SessionButton'; +import { SessionButton, SessionButtonColor, SessionButtonType } from './session/SessionButton'; import { darkTheme, lightTheme } from '../state/ducks/SessionTheme'; interface Props { @@ -87,14 +83,8 @@ export class CaptionEditor extends React.Component<Props, State> { return ( <div role="dialog" className="module-caption-editor"> - <div - role="button" - onClick={onClose} - className="module-caption-editor__close-button" - /> - <div className="module-caption-editor__media-container"> - {this.renderObject()} - </div> + <div role="button" onClick={onClose} className="module-caption-editor__close-button" /> + <div className="module-caption-editor__media-container">{this.renderObject()}</div> <div className="module-caption-editor__bottom-bar"> <div className="module-caption-editor__input-container"> <SessionInput diff --git a/ts/components/ContactListItem.tsx b/ts/components/ContactListItem.tsx index 8780007e29bdddf858bf40c7b552bef27986ce72..47a58f5c501e667dab8ef92872c6c7c1e4ca4b80 100644 --- a/ts/components/ContactListItem.tsx +++ b/ts/components/ContactListItem.tsx @@ -23,12 +23,7 @@ export class ContactListItem extends React.Component<Props> { const userName = name || profileName || phoneNumber; return ( - <Avatar - avatarPath={avatarPath} - name={userName} - size={AvatarSize.S} - pubkey={phoneNumber} - /> + <Avatar avatarPath={avatarPath} name={userName} size={AvatarSize.S} pubkey={phoneNumber} /> ); } @@ -42,11 +37,7 @@ export class ContactListItem extends React.Component<Props> { !isMe && profileName && !name ? ( <span className="module-contact-list-item__text__profile-name"> ~ - <Emojify - text={profileName} - i18n={i18n} - key={`emojify-list-item-${phoneNumber}`} - /> + <Emojify text={profileName} i18n={i18n} key={`emojify-list-item-${phoneNumber}`} /> </span> ) : null; diff --git a/ts/components/ConversationListItem.tsx b/ts/components/ConversationListItem.tsx index 9165f8917ab2cb0b6d683cd068b3ef0b3665833c..bbf0eb86f9596b562ea8f40db65ea986fc02ba4f 100644 --- a/ts/components/ConversationListItem.tsx +++ b/ts/components/ConversationListItem.tsx @@ -49,10 +49,7 @@ type PropsHousekeeping = { type Props = ConversationListItemProps & PropsHousekeeping; const Portal = ({ children }: { children: any }) => { - return createPortal( - children, - document.querySelector('.inbox.index') as Element - ); + return createPortal(children, document.querySelector('.inbox.index') as Element); }; class ConversationListItem extends React.PureComponent<Props> { @@ -61,13 +58,7 @@ class ConversationListItem extends React.PureComponent<Props> { } public renderAvatar() { - const { - avatarPath, - name, - phoneNumber, - profileName, - memberAvatars, - } = this.props; + const { avatarPath, name, phoneNumber, profileName, memberAvatars } = this.props; const userName = name || profileName || phoneNumber; @@ -91,11 +82,7 @@ class ConversationListItem extends React.PureComponent<Props> { let unreadCountDiv = null; if (unreadCount > 0) { atSymbol = mentionedUs ? <p className="at-symbol">@</p> : null; - unreadCountDiv = ( - <p className="module-conversation-list-item__unread-count"> - {unreadCount} - </p> - ); + unreadCountDiv = <p className="module-conversation-list-item__unread-count">{unreadCount}</p>; } return ( @@ -103,9 +90,7 @@ class ConversationListItem extends React.PureComponent<Props> { <div className={classNames( 'module-conversation-list-item__header__name', - unreadCount > 0 - ? 'module-conversation-list-item__header__name--with-unread' - : null + unreadCount > 0 ? 'module-conversation-list-item__header__name--with-unread' : null )} > {this.renderUser()} @@ -116,9 +101,7 @@ class ConversationListItem extends React.PureComponent<Props> { <div className={classNames( 'module-conversation-list-item__header__date', - unreadCount > 0 - ? 'module-conversation-list-item__header__date--has-unread' - : null + unreadCount > 0 ? 'module-conversation-list-item__header__date--has-unread' : null )} > { @@ -152,9 +135,7 @@ class ConversationListItem extends React.PureComponent<Props> { <div className={classNames( 'module-conversation-list-item__message__text', - unreadCount > 0 - ? 'module-conversation-list-item__message__text--has-unread' - : null + unreadCount > 0 ? 'module-conversation-list-item__message__text--has-unread' : null )} > {isTyping ? ( @@ -212,12 +193,8 @@ class ConversationListItem extends React.PureComponent<Props> { style={style} className={classNames( 'module-conversation-list-item', - unreadCount > 0 - ? 'module-conversation-list-item--has-unread' - : null, - unreadCount > 0 && mentionedUs - ? 'module-conversation-list-item--mentioned-us' - : null, + unreadCount > 0 ? 'module-conversation-list-item--has-unread' : null, + unreadCount > 0 && mentionedUs ? 'module-conversation-list-item--mentioned-us' : null, isSelected ? 'module-conversation-list-item--is-selected' : null, isBlocked ? 'module-conversation-list-item--is-blocked' : null )} diff --git a/ts/components/EditProfileDialog.tsx b/ts/components/EditProfileDialog.tsx index 709209cc4d29ac99952fec1efe32258024d742bf..c2f623d5da69747e27846f593214fb1ef07c784d 100644 --- a/ts/components/EditProfileDialog.tsx +++ b/ts/components/EditProfileDialog.tsx @@ -4,17 +4,9 @@ import { QRCode } from 'react-qr-svg'; import { Avatar, AvatarSize } from './Avatar'; -import { - SessionButton, - SessionButtonColor, - SessionButtonType, -} from './session/SessionButton'; - -import { - SessionIconButton, - SessionIconSize, - SessionIconType, -} from './session/icon'; +import { SessionButton, SessionButtonColor, SessionButtonType } from './session/SessionButton'; + +import { SessionIconButton, SessionIconSize, SessionIconType } from './session/icon'; import { SessionModal } from './session/SessionModal'; import { PillDivider } from './session/PillDivider'; import { ToastUtils, UserUtils } from '../session/utils'; @@ -104,14 +96,7 @@ export class EditProfileDialog extends React.Component<Props, State> { <div className="session-id-section"> <PillDivider text={window.i18n('yourSessionID')} /> - <p - className={classNames( - 'text-selectable', - 'session-id-section-display' - )} - > - {sessionID} - </p> + <p className={classNames('text-selectable', 'session-id-section-display')}>{sessionID}</p> <div className="spacer-lg" /> <SessionSpinner loading={this.state.loading} /> @@ -149,11 +134,7 @@ export class EditProfileDialog extends React.Component<Props, State> { <div className="avatar-center"> <div className="avatar-center-inner"> {this.renderAvatar()} - <div - className="image-upload-section" - role="button" - onClick={this.fireInputEvent} - /> + <div className="image-upload-section" role="button" onClick={this.fireInputEvent} /> <input type="file" ref={this.inputEl} @@ -237,12 +218,7 @@ export class EditProfileDialog extends React.Component<Props, State> { return ( <div className="qr-image"> - <QRCode - value={sessionID} - bgColor={bgColor} - fgColor={fgColor} - level="L" - /> + <QRCode value={sessionID} bgColor={bgColor} fgColor={fgColor} level="L" /> </div> ); } @@ -261,14 +237,7 @@ export class EditProfileDialog extends React.Component<Props, State> { const { pubkey } = this.props; const userName = profileName || pubkey; - return ( - <Avatar - avatarPath={avatar} - name={userName} - size={AvatarSize.XL} - pubkey={pubkey} - /> - ); + return <Avatar avatarPath={avatar} name={userName} size={AvatarSize.XL} pubkey={pubkey} />; } private onNameEdited(event: any) { diff --git a/ts/components/Intl.tsx b/ts/components/Intl.tsx index d5a353fd82ba0471eb8c6edfbcfb3b489797c09d..01d5b000ad3f92ca7146f771f3e089c574677b02 100644 --- a/ts/components/Intl.tsx +++ b/ts/components/Intl.tsx @@ -22,9 +22,7 @@ export class Intl extends React.Component<Props> { if (!components || !components.length || components.length <= index) { // tslint:disable-next-line no-console - console.log( - `Error: Intl missing provided components for id ${id}, index ${index}` - ); + console.log(`Error: Intl missing provided components for id ${id}, index ${index}`); return; } diff --git a/ts/components/LeftPane.tsx b/ts/components/LeftPane.tsx index 2c47e5a67e8d34ad31eda200817262c019f902ed..28b76c6a672b8bbb6afadabb5809d8aca6f7b71b 100644 --- a/ts/components/LeftPane.tsx +++ b/ts/components/LeftPane.tsx @@ -12,11 +12,7 @@ import { SessionExpiredWarning } from './session/network/SessionExpiredWarning'; import { getFocusedSection } from '../state/selectors/section'; import { useDispatch, useSelector } from 'react-redux'; import { getLeftPaneLists } from '../state/selectors/conversations'; -import { - getQuery, - getSearchResults, - isSearching, -} from '../state/selectors/search'; +import { getQuery, getSearchResults, isSearching } from '../state/selectors/search'; import { clearSearch, search, updateSearchTerm } from '../state/ducks/search'; import { getTheme } from '../state/selectors/theme'; diff --git a/ts/components/Lightbox.tsx b/ts/components/Lightbox.tsx index e00304c71627404068c3c1b01323bb7084fb473a..961626ae469298b980e812960a0bdf3927e1b3c9 100644 --- a/ts/components/Lightbox.tsx +++ b/ts/components/Lightbox.tsx @@ -6,11 +6,7 @@ import is from '@sindresorhus/is'; import * as GoogleChrome from '../util/GoogleChrome'; import * as MIME from '../types/MIME'; -import { - SessionIconButton, - SessionIconSize, - SessionIconType, -} from './session/icon'; +import { SessionIconButton, SessionIconSize, SessionIconType } from './session/icon'; import { Flex } from './session/Flex'; import { DefaultTheme } from 'styled-components'; // useCss has some issues on our setup. so import it directly @@ -179,17 +175,13 @@ const IconButton = ({ onClick, type, theme }: IconButtonProps) => { ); }; -const IconButtonPlaceholder = () => ( - <div style={styles.iconButtonPlaceholder} /> -); +const IconButtonPlaceholder = () => <div style={styles.iconButtonPlaceholder} />; const Icon = ({ onClick, url, }: { - onClick?: ( - event: React.MouseEvent<HTMLImageElement | HTMLDivElement> - ) => void; + onClick?: (event: React.MouseEvent<HTMLImageElement | HTMLDivElement>) => void; url: string; }) => ( <div @@ -252,13 +244,7 @@ export const LightboxObject = ({ }); if (isImageTypeSupported) { - return ( - <img - style={styles.object} - alt={window.i18n('lightboxImageAlt')} - src={urlToLoad} - /> - ); + return <img style={styles.object} alt={window.i18n('lightboxImageAlt')} src={urlToLoad} />; } const isVideoTypeSupported = GoogleChrome.isVideoTypeSupported(contentType); @@ -280,14 +266,10 @@ export const LightboxObject = ({ ); } - const isUnsupportedImageType = - !isImageTypeSupported && MIME.isImage(contentType); - const isUnsupportedVideoType = - !isVideoTypeSupported && MIME.isVideo(contentType); + const isUnsupportedImageType = !isImageTypeSupported && MIME.isImage(contentType); + const isUnsupportedVideoType = !isVideoTypeSupported && MIME.isVideo(contentType); if (isUnsupportedImageType || isUnsupportedVideoType) { - const iconUrl = isUnsupportedVideoType - ? 'images/video.svg' - : 'images/image.svg'; + const iconUrl = isUnsupportedVideoType ? 'images/video.svg' : 'images/image.svg'; return <Icon url={iconUrl} onClick={onObjectClick} />; } @@ -351,12 +333,7 @@ export const Lightbox = (props: Props) => { </Flex> {onSave ? ( - <IconButton - type="save" - onClick={onSave} - style={styles.saveButton} - theme={theme} - /> + <IconButton type="save" onClick={onSave} style={styles.saveButton} theme={theme} /> ) : null} </div> </div> diff --git a/ts/components/LightboxGallery.tsx b/ts/components/LightboxGallery.tsx index 80fe42416780e9aa385dc8d5fd5033f596a2aae3..91e31ba1386d5ee3e8b8d34a4ccdacfbc88c9ab9 100644 --- a/ts/components/LightboxGallery.tsx +++ b/ts/components/LightboxGallery.tsx @@ -23,11 +23,7 @@ export interface MediaItemType { type Props = { close: () => void; media: Array<MediaItemType>; - onSave?: (options: { - attachment: AttachmentType; - message: Message; - index: number; - }) => void; + onSave?: (options: { attachment: AttachmentType; message: Message; index: number }) => void; selectedIndex: number; }; diff --git a/ts/components/MainViewController.tsx b/ts/components/MainViewController.tsx index 1beac675d8280d9986d680f32f4fa349e8738663..99e0d140f5e6dfd0f54538ee9c9119782a8a14ad 100644 --- a/ts/components/MainViewController.tsx +++ b/ts/components/MainViewController.tsx @@ -41,17 +41,11 @@ async function createClosedGroup( ): Promise<boolean> { // Validate groupName and groupMembers length if (groupName.length === 0) { - ToastUtils.pushToastError( - 'invalidGroupName', - window.i18n('invalidGroupNameTooShort') - ); + ToastUtils.pushToastError('invalidGroupName', window.i18n('invalidGroupNameTooShort')); return false; } else if (groupName.length > window.CONSTANTS.MAX_GROUP_NAME_LENGTH) { - ToastUtils.pushToastError( - 'invalidGroupName', - window.i18n('invalidGroupNameTooLong') - ); + ToastUtils.pushToastError('invalidGroupName', window.i18n('invalidGroupNameTooLong')); return false; } @@ -59,16 +53,10 @@ async function createClosedGroup( // the same is valid with groups count < 1 if (groupMembers.length < 1) { - ToastUtils.pushToastError( - 'pickClosedGroupMember', - window.i18n('pickClosedGroupMember') - ); + ToastUtils.pushToastError('pickClosedGroupMember', window.i18n('pickClosedGroupMember')); return false; } else if (groupMembers.length >= window.CONSTANTS.CLOSED_GROUP_SIZE_LIMIT) { - ToastUtils.pushToastError( - 'closedGroupMaxSize', - window.i18n('closedGroupMaxSize') - ); + ToastUtils.pushToastError('closedGroupMaxSize', window.i18n('closedGroupMaxSize')); return false; } diff --git a/ts/components/MessageBodyHighlight.tsx b/ts/components/MessageBodyHighlight.tsx index 3cb2652b52b28906ca8155938638087103dacf3a..53cce10c4fae57c0fa3ecad58cf341c2169d5e09 100644 --- a/ts/components/MessageBodyHighlight.tsx +++ b/ts/components/MessageBodyHighlight.tsx @@ -50,14 +50,7 @@ export class MessageBodyHighlight extends React.Component<Props> { let count = 1; if (!match) { - return ( - <MessageBody - disableJumbomoji={true} - disableLinks={true} - text={text} - i18n={i18n} - /> - ); + return <MessageBody disableJumbomoji={true} disableLinks={true} text={text} i18n={i18n} />; } const sizeClass = ''; diff --git a/ts/components/MessageSearchResult.tsx b/ts/components/MessageSearchResult.tsx index 83b3629f8323a1c61f67d14aac95687fa56a64ee..8b1a9c43de5f0c389086ffa500031547afa9f99e 100644 --- a/ts/components/MessageSearchResult.tsx +++ b/ts/components/MessageSearchResult.tsx @@ -49,17 +49,11 @@ class MessageSearchResultInner extends React.PureComponent<Props> { if (from.isMe && to.isMe) { return ( - <span className="module-message-search-result__header__name"> - {i18n('noteToSelf')} - </span> + <span className="module-message-search-result__header__name">{i18n('noteToSelf')}</span> ); } if (from.isMe) { - return ( - <span className="module-message-search-result__header__name"> - {i18n('you')} - </span> - ); + return <span className="module-message-search-result__header__name">{i18n('you')}</span>; } return ( @@ -95,11 +89,7 @@ class MessageSearchResultInner extends React.PureComponent<Props> { ); } - return ( - <div className="module-message-search-result__header__from"> - {fromName} - </div> - ); + return <div className="module-message-search-result__header__from">{fromName}</div>; } public renderAvatar() { diff --git a/ts/components/SearchResults.tsx b/ts/components/SearchResults.tsx index 857e9ccc32a4b9e6675e855850f66ffe14e63f73..f36100021e7dc56b0362fd538ccb40043513ca94 100644 --- a/ts/components/SearchResults.tsx +++ b/ts/components/SearchResults.tsx @@ -1,12 +1,6 @@ import React from 'react'; -import { - ConversationListItemProps, - ConversationListItemWithDetails, -} from './ConversationListItem'; -import { - MessageSearchResult, - MessageSearchResultProps, -} from './MessageSearchResult'; +import { ConversationListItemProps, ConversationListItemWithDetails } from './ConversationListItem'; +import { MessageSearchResult, MessageSearchResultProps } from './MessageSearchResult'; import { LocalizerType } from '../types/Util'; @@ -64,16 +58,12 @@ export class SearchResults extends React.Component<Props> { ))} </div> ) : null} - {haveContacts - ? this.renderContacts(i18n('contactsHeader'), contacts) - : null} + {haveContacts ? this.renderContacts(i18n('contactsHeader'), contacts) : null} {haveMessages ? ( <div className="module-search-results__messages"> {hideMessagesHeader ? null : ( - <div className="module-search-results__messages-header"> - {i18n('messagesHeader')} - </div> + <div className="module-search-results__messages-header">{i18n('messagesHeader')}</div> )} {messages.map(message => ( <MessageSearchResult @@ -88,10 +78,7 @@ export class SearchResults extends React.Component<Props> { </div> ); } - private renderContacts( - header: string, - items: Array<ConversationListItemProps> - ) { + private renderContacts(header: string, items: Array<ConversationListItemProps>) { const { i18n, openConversationExternal } = this.props; return ( diff --git a/ts/components/UserDetailsDialog.tsx b/ts/components/UserDetailsDialog.tsx index 0c998f4af9a90d81b52415c4762a06578cb84580..137331bf2caa770c84a93fa136036bf4231352c2 100644 --- a/ts/components/UserDetailsDialog.tsx +++ b/ts/components/UserDetailsDialog.tsx @@ -2,11 +2,7 @@ import React from 'react'; import { Avatar, AvatarSize } from './Avatar'; import { SessionModal } from './session/SessionModal'; -import { - SessionButton, - SessionButtonColor, - SessionButtonType, -} from './session/SessionButton'; +import { SessionButton, SessionButtonColor, SessionButtonType } from './session/SessionButton'; import { SessionIdEditable } from './session/SessionIdEditable'; import { DefaultTheme } from 'styled-components'; @@ -63,9 +59,7 @@ export class UserDetailsDialog extends React.Component<Props, State> { private renderAvatar() { const { avatarPath, pubkey, profileName } = this.props; - const size = this.state.isEnlargedImageShown - ? AvatarSize.HUGE - : AvatarSize.XL; + const size = this.state.isEnlargedImageShown ? AvatarSize.HUGE : AvatarSize.XL; const userName = profileName || pubkey; return ( diff --git a/ts/components/conversation/AddMentions.tsx b/ts/components/conversation/AddMentions.tsx index f48dafb5285314f486bb6fa6ca59aeeca117afce..da9b0f6e8ed3dabbc613fa57314d7ee14dc5194e 100644 --- a/ts/components/conversation/AddMentions.tsx +++ b/ts/components/conversation/AddMentions.tsx @@ -20,10 +20,7 @@ const Mention = (props: MentionProps) => { const tryRenameMention = async () => { if (!found) { - const foundMember = await FindMember.findMember( - props.text.slice(1), - props.convoId - ); + const foundMember = await FindMember.findMember(props.text.slice(1), props.convoId); if (foundMember) { const itsUs = UserUtils.isUsFromCache(foundMember.id); @@ -38,17 +35,12 @@ const Mention = (props: MentionProps) => { if (found) { // TODO: We don't have to search the database of message just to know that the message is for us! - const className = classNames( - 'mention-profile-name', - us && 'mention-profile-name-us' - ); + const className = classNames('mention-profile-name', us && 'mention-profile-name-us'); const displayedName = found.getContactProfileNameOrShortenedPubKey(); return <span className={className}>{displayedName}</span>; } else { - return ( - <span className="mention-profile-name">{PubKey.shorten(props.text)}</span> - ); + return <span className="mention-profile-name">{PubKey.shorten(props.text)}</span>; } }; diff --git a/ts/components/conversation/AddNewLines.tsx b/ts/components/conversation/AddNewLines.tsx index 356b1a6a8aa2bbf25b843d1eec5c830b10adf56e..c1b5d092c983096a13f0839a25b707674312f4c1 100644 --- a/ts/components/conversation/AddNewLines.tsx +++ b/ts/components/conversation/AddNewLines.tsx @@ -36,9 +36,7 @@ export class AddNewLines extends React.Component<Props> { while (match) { if (last < match.index) { const textWithNoNewline = text.slice(last, match.index); - results.push( - renderNonNewLine({ text: textWithNoNewline, key: count++, convoId }) - ); + results.push(renderNonNewLine({ text: textWithNoNewline, key: count++, convoId })); } results.push(<br key={count++} />); @@ -49,9 +47,7 @@ export class AddNewLines extends React.Component<Props> { } if (last < text.length) { - results.push( - renderNonNewLine({ text: text.slice(last), key: count++, convoId }) - ); + results.push(renderNonNewLine({ text: text.slice(last), key: count++, convoId })); } return results; diff --git a/ts/components/conversation/AdminLeaveClosedGroupDialog.tsx b/ts/components/conversation/AdminLeaveClosedGroupDialog.tsx index 0da00f1f306275f998b9c63200be1367dbcb118b..9ec41777198352d0442d8602d469e2a658ee50f3 100644 --- a/ts/components/conversation/AdminLeaveClosedGroupDialog.tsx +++ b/ts/components/conversation/AdminLeaveClosedGroupDialog.tsx @@ -25,11 +25,7 @@ class AdminLeaveClosedGroupDialogInner extends React.Component<Props> { const okText = window.i18n('leaveAndRemoveForEveryone'); return ( - <SessionModal - title={titleText} - onClose={this.closeDialog} - theme={this.props.theme} - > + <SessionModal title={titleText} onClose={this.closeDialog} theme={this.props.theme}> <div className="spacer-lg" /> <p>{warningAsAdmin}</p> diff --git a/ts/components/conversation/AttachmentList.tsx b/ts/components/conversation/AttachmentList.tsx index bb1c41b249fdb4b06aca78c2719a76c81c870844..dd25cd2629eddd5354545ce9949e6f54474fb09d 100644 --- a/ts/components/conversation/AttachmentList.tsx +++ b/ts/components/conversation/AttachmentList.tsx @@ -1,9 +1,6 @@ import React from 'react'; -import { - isImageTypeSupported, - isVideoTypeSupported, -} from '../../util/GoogleChrome'; +import { isImageTypeSupported, isVideoTypeSupported } from '../../util/GoogleChrome'; import { Image } from './Image'; import { StagedGenericAttachment } from './StagedGenericAttachment'; import { StagedPlaceholderAttachment } from './StagedPlaceholderAttachment'; @@ -47,31 +44,20 @@ export class AttachmentList extends React.Component<Props> { <div className="module-attachments"> {attachments.length > 1 ? ( <div className="module-attachments__header"> - <div - role="button" - onClick={onClose} - className="module-attachments__close-button" - /> + <div role="button" onClick={onClose} className="module-attachments__close-button" /> </div> ) : null} <div className="module-attachments__rail"> {(attachments || []).map((attachment, index) => { const { contentType } = attachment; - if ( - isImageTypeSupported(contentType) || - isVideoTypeSupported(contentType) - ) { - const imageKey = - getUrl(attachment) || attachment.fileName || index; - const clickCallback = - attachments.length > 1 ? onClickAttachment : undefined; + if (isImageTypeSupported(contentType) || isVideoTypeSupported(contentType)) { + const imageKey = getUrl(attachment) || attachment.fileName || index; + const clickCallback = attachments.length > 1 ? onClickAttachment : undefined; return ( <Image key={imageKey} - alt={window.i18n('stagedImageAttachment', [ - attachment.fileName, - ])} + alt={window.i18n('stagedImageAttachment', [attachment.fileName])} i18n={window.i18n} attachment={attachment} softCorners={true} @@ -86,8 +72,7 @@ export class AttachmentList extends React.Component<Props> { ); } - const genericKey = - getUrl(attachment) || attachment.fileName || index; + const genericKey = getUrl(attachment) || attachment.fileName || index; return ( <StagedGenericAttachment @@ -98,9 +83,7 @@ export class AttachmentList extends React.Component<Props> { /> ); })} - {allVisualAttachments ? ( - <StagedPlaceholderAttachment onClick={onAddAttachment} /> - ) : null} + {allVisualAttachments ? <StagedPlaceholderAttachment onClick={onAddAttachment} /> : null} </div> </div> ); diff --git a/ts/components/conversation/ConversationHeader.tsx b/ts/components/conversation/ConversationHeader.tsx index e2a8e0df16634f1dcf17173249a9b43c1a0d585b..38270bf40da793bd90ba27233f62735f95d8d951 100644 --- a/ts/components/conversation/ConversationHeader.tsx +++ b/ts/components/conversation/ConversationHeader.tsx @@ -2,17 +2,9 @@ import React from 'react'; import { Avatar, AvatarSize } from '../Avatar'; -import { - SessionIconButton, - SessionIconSize, - SessionIconType, -} from '../session/icon'; +import { SessionIconButton, SessionIconSize, SessionIconType } from '../session/icon'; -import { - SessionButton, - SessionButtonColor, - SessionButtonType, -} from '../session/SessionButton'; +import { SessionButton, SessionButtonColor, SessionButtonType } from '../session/SessionButton'; import { ConversationAvatar, usingClosedConversationDetails, @@ -129,11 +121,7 @@ class ConversationHeaderInner extends React.Component<Props> { const { i18n } = window; if (isMe) { - return ( - <div className="module-conversation-header__title"> - {i18n('noteToSelf')} - </div> - ); + return <div className="module-conversation-header__title">{i18n('noteToSelf')}</div>; } const memberCount: number = (() => { @@ -170,13 +158,7 @@ class ConversationHeaderInner extends React.Component<Props> { } public renderAvatar() { - const { - avatarPath, - memberAvatars, - name, - phoneNumber, - profileName, - } = this.props; + const { avatarPath, memberAvatars, name, phoneNumber, profileName } = this.props; const userName = name || profileName || phoneNumber; @@ -218,9 +200,7 @@ class ConversationHeaderInner extends React.Component<Props> { const { i18n } = window; const isServerDeletable = isPublic; - const deleteMessageButtonText = i18n( - isServerDeletable ? 'deleteForEveryone' : 'delete' - ); + const deleteMessageButtonText = i18n(isServerDeletable ? 'deleteForEveryone' : 'delete'); return ( <div className="message-selection-overlay"> diff --git a/ts/components/conversation/Emojify.tsx b/ts/components/conversation/Emojify.tsx index 6e6f93000e289a95d7cfd1d9660458a736c2ec92..839fdd1c0edd3f1a7210e7b94330e9f3c69a33a6 100644 --- a/ts/components/conversation/Emojify.tsx +++ b/ts/components/conversation/Emojify.tsx @@ -26,14 +26,7 @@ export class Emojify extends React.Component<Props> { }; public render() { - const { - text, - sizeClass, - renderNonEmoji, - i18n, - isGroup, - convoId, - } = this.props; + const { text, sizeClass, renderNonEmoji, i18n, isGroup, convoId } = this.props; const results: Array<any> = []; const regex = getRegex(); diff --git a/ts/components/conversation/ExpireTimer.tsx b/ts/components/conversation/ExpireTimer.tsx index 351a26ae6dda46e045dc8ad894e94c1e1d182e47..c743310d5b0456176f8bc598378ca71e3b7ddfcd 100644 --- a/ts/components/conversation/ExpireTimer.tsx +++ b/ts/components/conversation/ExpireTimer.tsx @@ -14,9 +14,9 @@ type Props = { theme: DefaultTheme; }; -const ExpireTimerCount = styled(props => ( - <OpacityMetadataComponent {...props} /> -))<{ color: string }>` +const ExpireTimerCount = styled(props => <OpacityMetadataComponent {...props} />)<{ + color: string; +}>` margin-inline-start: 6px; font-size: 11px; line-height: 16px; @@ -26,9 +26,9 @@ const ExpireTimerCount = styled(props => ( color: ${props => props.color}; `; -const ExpireTimerBucket = styled(props => ( - <OpacityMetadataComponent {...props} /> -))<{ color: string }>` +const ExpireTimerBucket = styled(props => <OpacityMetadataComponent {...props} />)<{ + color: string; +}>` margin-inline-start: 6px; font-size: 11px; line-height: 16px; @@ -41,17 +41,11 @@ const ExpireTimerBucket = styled(props => ( export const ExpireTimer = (props: Props) => { const { expirationLength, expirationTimestamp, withImageNoCaption } = props; - const initialTimeLeft = Math.max( - Math.round((expirationTimestamp - Date.now()) / 1000), - 0 - ); + const initialTimeLeft = Math.max(Math.round((expirationTimestamp - Date.now()) / 1000), 0); const [timeLeft, setTimeLeft] = useState(initialTimeLeft); const update = () => { - const newTimeLeft = Math.max( - Math.round((expirationTimestamp - Date.now()) / 1000), - 0 - ); + const newTimeLeft = Math.max(Math.round((expirationTimestamp - Date.now()) / 1000), 0); if (newTimeLeft !== timeLeft) { setTimeLeft(newTimeLeft); } @@ -61,14 +55,10 @@ export const ExpireTimer = (props: Props) => { useInterval(update, updateFrequency); - const expireTimerColor = withImageNoCaption - ? 'white' - : props.theme.colors.textColor; + const expireTimerColor = withImageNoCaption ? 'white' : props.theme.colors.textColor; if (timeLeft <= 60) { - return ( - <ExpireTimerCount color={expireTimerColor}>{timeLeft}</ExpireTimerCount> - ); + return <ExpireTimerCount color={expireTimerColor}>{timeLeft}</ExpireTimerCount>; } const bucket = getTimerBucketIcon(expirationTimestamp, expirationLength); diff --git a/ts/components/conversation/GroupInvitation.tsx b/ts/components/conversation/GroupInvitation.tsx index 1195aabaa45883362561889d1b46e6eee15a70d2..0faa862a34057d04e9379074e47a74840d3e0f10 100644 --- a/ts/components/conversation/GroupInvitation.tsx +++ b/ts/components/conversation/GroupInvitation.tsx @@ -30,11 +30,7 @@ export class GroupInvitation extends React.Component<Props> { <span className="group-name">{this.props.serverName}</span> <span className="group-address">{this.props.serverAddress}</span> </span> - <span - role="button" - className="join-btn" - onClick={this.props.onClick} - > + <span role="button" className="join-btn" onClick={this.props.onClick}> Join </span> </div> diff --git a/ts/components/conversation/GroupNotification.tsx b/ts/components/conversation/GroupNotification.tsx index 3799a4027a7e93e33c0d9172e1ca1b35d9508b7b..d54997ef882bc363f854d31e624238e99359ac39 100644 --- a/ts/components/conversation/GroupNotification.tsx +++ b/ts/components/conversation/GroupNotification.tsx @@ -53,8 +53,7 @@ export const GroupNotification = (props: Props) => { throw new Error('Group update add is missing contacts'); } - const joinKey = - contacts.length > 1 ? 'multipleJoinedTheGroup' : 'joinedTheGroup'; + const joinKey = contacts.length > 1 ? 'multipleJoinedTheGroup' : 'joinedTheGroup'; return <Intl i18n={i18n} id={joinKey} components={[people]} />; case 'remove': @@ -66,8 +65,7 @@ export const GroupNotification = (props: Props) => { throw new Error('Group update remove is missing contacts'); } - const leftKey = - contacts.length > 1 ? 'multipleLeftTheGroup' : 'leftTheGroup'; + const leftKey = contacts.length > 1 ? 'multipleLeftTheGroup' : 'leftTheGroup'; return <Intl i18n={i18n} id={leftKey} components={[people]} />; case 'kicked': @@ -79,10 +77,7 @@ export const GroupNotification = (props: Props) => { throw new Error('Group update kicked is missing contacts'); } - const kickedKey = - contacts.length > 1 - ? 'multipleKickedFromTheGroup' - : 'kickedFromTheGroup'; + const kickedKey = contacts.length > 1 ? 'multipleKickedFromTheGroup' : 'kickedFromTheGroup'; return <Intl i18n={i18n} id={kickedKey} components={[people]} />; case 'general': diff --git a/ts/components/conversation/Image.tsx b/ts/components/conversation/Image.tsx index e1af0fd571813bc496dc7eb35e2b5bdae7ee1cd7..06875ff28122394c6cea1ad8e0afd3905a994931 100644 --- a/ts/components/conversation/Image.tsx +++ b/ts/components/conversation/Image.tsx @@ -64,10 +64,7 @@ export const Image = (props: Props) => { const canClick = onClick && !pending; const role = canClick ? 'button' : undefined; - const { loading, urlToLoad } = useEncryptedFileFetch( - url, - attachment.contentType - ); + const { loading, urlToLoad } = useEncryptedFileFetch(url, attachment.contentType); // data will be url if loading is finished and '' if not const srcData = !loading ? urlToLoad : ''; @@ -159,10 +156,7 @@ export const Image = (props: Props) => { </div> ) : null} {overlayText ? ( - <div - className="module-image__text-container" - style={{ lineHeight: `${height}px` }} - > + <div className="module-image__text-container" style={{ lineHeight: `${height}px` }}> {overlayText} </div> ) : null} diff --git a/ts/components/conversation/ImageGrid.tsx b/ts/components/conversation/ImageGrid.tsx index c2ef4741209b36498f7051ba22c6d38e951b0f50..2d77d845b9afe01a839178754a4adc4bce265391 100644 --- a/ts/components/conversation/ImageGrid.tsx +++ b/ts/components/conversation/ImageGrid.tsx @@ -56,12 +56,7 @@ export const ImageGrid = (props: Props) => { const { height, width } = getImageDimensions(attachments[0]); return ( - <div - className={classNames( - 'module-image-grid', - 'module-image-grid--one-image' - )} - > + <div className={classNames('module-image-grid', 'module-image-grid--one-image')}> <Image alt={getAlt(attachments[0], i18n)} i18n={i18n} @@ -229,9 +224,7 @@ export const ImageGrid = (props: Props) => { } const moreMessagesOverlay = attachments.length > 5; - const moreMessagesOverlayText = moreMessagesOverlay - ? `+${attachments.length - 5}` - : undefined; + const moreMessagesOverlayText = moreMessagesOverlay ? `+${attachments.length - 5}` : undefined; return ( <div className="module-image-grid"> diff --git a/ts/components/conversation/InviteContactsDialog.tsx b/ts/components/conversation/InviteContactsDialog.tsx index 63961ddc4b6e8d3c778811ca9db2d5363093450f..3727f479eeedbe11a8181eac4a0ffe449f2710c3 100644 --- a/ts/components/conversation/InviteContactsDialog.tsx +++ b/ts/components/conversation/InviteContactsDialog.tsx @@ -2,10 +2,7 @@ import React from 'react'; import { SessionModal } from '../session/SessionModal'; import { SessionButton, SessionButtonColor } from '../session/SessionButton'; -import { - ContactType, - SessionMemberListItem, -} from '../session/SessionMemberListItem'; +import { ContactType, SessionMemberListItem } from '../session/SessionMemberListItem'; import { DefaultTheme, withTheme } from 'styled-components'; interface Props { @@ -33,9 +30,7 @@ class InviteContactsDialogInner extends React.Component<Props, State> { contacts = contacts.map(d => { const lokiProfile = d.getLokiProfile(); - const name = lokiProfile - ? lokiProfile.displayName - : window.i18n('anonymous'); + const name = lokiProfile ? lokiProfile.displayName : window.i18n('anonymous'); // TODO: should take existing members into account const existingMember = false; @@ -67,11 +62,7 @@ class InviteContactsDialogInner extends React.Component<Props, State> { const hasContacts = this.state.contactList.length !== 0; return ( - <SessionModal - title={titleText} - onClose={this.closeDialog} - theme={this.props.theme} - > + <SessionModal title={titleText} onClose={this.closeDialog} theme={this.props.theme}> <div className="spacer-lg" /> <div className="contact-selection-list">{this.renderMemberList()}</div> @@ -99,9 +90,7 @@ class InviteContactsDialogInner extends React.Component<Props, State> { } private onClickOK() { - const selectedContacts = this.state.contactList - .filter(d => d.checkmarked) - .map(d => d.id); + const selectedContacts = this.state.contactList.filter(d => d.checkmarked).map(d => d.id); if (selectedContacts.length > 0) { this.props.onSubmit(selectedContacts); @@ -112,9 +101,7 @@ class InviteContactsDialogInner extends React.Component<Props, State> { private renderMemberList() { const members = this.state.contactList; - const selectedContacts = this.state.contactList - .filter(d => d.checkmarked) - .map(d => d.id); + const selectedContacts = this.state.contactList.filter(d => d.checkmarked).map(d => d.id); return members.map((member: ContactType, index: number) => ( <SessionMemberListItem diff --git a/ts/components/conversation/Linkify.tsx b/ts/components/conversation/Linkify.tsx index df2824f5fb401aad92d4af622294c825d39882e1..630c4e43dc058edc48262372bfbdcc0fb1b8521a 100644 --- a/ts/components/conversation/Linkify.tsx +++ b/ts/components/conversation/Linkify.tsx @@ -40,36 +40,25 @@ export class Linkify extends React.Component<Props> { return renderNonLink({ text, key: 0 }); } - matchData.forEach( - (match: { - index: number; - url: string; - lastIndex: number; - text: string; - }) => { - if (last < match.index) { - const textWithNoLink = text.slice(last, match.index); - results.push(renderNonLink({ text: textWithNoLink, key: count++ })); - } - - const { url, text: originalText } = match; - if ( - SUPPORTED_PROTOCOLS.test(url) && - !isLinkSneaky(url) && - !HAS_AT.test(url) - ) { - results.push( - <a key={count++} href={url} onClick={this.handleClick}> - {originalText} - </a> - ); - } else { - results.push(renderNonLink({ text: originalText, key: count++ })); - } - - last = match.lastIndex; + matchData.forEach((match: { index: number; url: string; lastIndex: number; text: string }) => { + if (last < match.index) { + const textWithNoLink = text.slice(last, match.index); + results.push(renderNonLink({ text: textWithNoLink, key: count++ })); } - ); + + const { url, text: originalText } = match; + if (SUPPORTED_PROTOCOLS.test(url) && !isLinkSneaky(url) && !HAS_AT.test(url)) { + results.push( + <a key={count++} href={url} onClick={this.handleClick}> + {originalText} + </a> + ); + } else { + results.push(renderNonLink({ text: originalText, key: count++ })); + } + + last = match.lastIndex; + }); if (last < text.length) { results.push(renderNonLink({ text: text.slice(last), key: count++ })); diff --git a/ts/components/conversation/Message.tsx b/ts/components/conversation/Message.tsx index 045134a17dea8173e6236e1029820ebf1ad80225..6ee0c105e8f6eb74b582b7148c068b0e36d6bd88 100644 --- a/ts/components/conversation/Message.tsx +++ b/ts/components/conversation/Message.tsx @@ -13,10 +13,7 @@ import { Quote } from './Quote'; import H5AudioPlayer from 'react-h5-audio-player'; // import 'react-h5-audio-player/lib/styles.css'; -const AudioPlayerWithEncryptedFile = (props: { - src: string; - contentType: string; -}) => { +const AudioPlayerWithEncryptedFile = (props: { src: string; contentType: string }) => { const theme = useTheme(); const { urlToLoad } = useEncryptedFileFetch(props.src, props.contentType); return ( @@ -198,8 +195,7 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> { // For attachments which aren't full-frame const withContentBelow = Boolean(text); const withContentAbove = - Boolean(quote) || - (conversationType === 'group' && direction === 'incoming'); + Boolean(quote) || (conversationType === 'group' && direction === 'incoming'); const displayImage = canDisplayImage(attachments); if ( @@ -212,12 +208,8 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> { <div className={classNames( 'module-message__attachment-container', - withContentAbove - ? 'module-message__attachment-container--with-content-above' - : null, - withContentBelow - ? 'module-message__attachment-container--with-content-below' - : null + withContentAbove ? 'module-message__attachment-container--with-content-above' : null, + withContentBelow ? 'module-message__attachment-container--with-content-below' : null )} > <ImageGrid @@ -260,12 +252,8 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> { <div className={classNames( 'module-message__generic-attachment', - withContentBelow - ? 'module-message__generic-attachment--with-content-below' - : null, - withContentAbove - ? 'module-message__generic-attachment--with-content-above' - : null + withContentBelow ? 'module-message__generic-attachment--with-content-below' : null, + withContentAbove ? 'module-message__generic-attachment--with-content-above' : null )} > {pending ? ( @@ -346,8 +334,7 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> { } const withContentAbove = - Boolean(quote) || - (conversationType === 'group' && direction === 'incoming'); + Boolean(quote) || (conversationType === 'group' && direction === 'incoming'); const previewHasImage = first.image && isImageAttachment(first.image); const width = first.image && first.image.width; @@ -358,9 +345,7 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> { role="button" className={classNames( 'module-message__link-preview', - withContentAbove - ? 'module-message__link-preview--with-content-above' - : null + withContentAbove ? 'module-message__link-preview--with-content-above' : null )} onClick={() => { if (onClickLinkPreview) { @@ -408,12 +393,8 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> { : null )} > - <div className="module-message__link-preview__title"> - {first.title} - </div> - <div className="module-message__link-preview__location"> - {first.domain} - </div> + <div className="module-message__link-preview__title">{first.title}</div> + <div className="module-message__link-preview__location">{first.domain}</div> </div> </div> </div> @@ -435,14 +416,11 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> { return null; } - const withContentAbove = - conversationType === 'group' && direction === 'incoming'; + const withContentAbove = conversationType === 'group' && direction === 'incoming'; const shortenedPubkey = PubKey.shorten(quote.authorPhoneNumber); - const displayedPubkey = quote.authorProfileName - ? shortenedPubkey - : quote.authorPhoneNumber; + const displayedPubkey = quote.authorProfileName ? shortenedPubkey : quote.authorPhoneNumber; return ( <Quote @@ -454,11 +432,7 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> { this.props.onSelectMessage(id); return; } - const { - authorPhoneNumber, - messageId: quoteId, - referencedMessageNotFound, - } = quote; + const { authorPhoneNumber, messageId: quoteId, referencedMessageNotFound } = quote; quote?.onClick({ quoteAuthor: authorPhoneNumber, quoteId, @@ -496,11 +470,7 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> { firstMessageOfSeries, } = this.props; - if ( - collapseMetadata || - conversationType !== 'group' || - direction === 'outgoing' - ) { + if (collapseMetadata || conversationType !== 'group' || direction === 'outgoing') { return; } const userName = authorName || authorProfileName || authorPhoneNumber; @@ -530,19 +500,10 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> { } public renderText() { - const { - text, - direction, - status, - conversationType, - convoId, - multiSelectMode, - } = this.props; + const { text, direction, status, conversationType, convoId, multiSelectMode } = this.props; const contents = - direction === 'incoming' && status === 'error' - ? window.i18n('incomingError') - : text; + direction === 'incoming' && status === 'error' ? window.i18n('incomingError') : text; if (!contents) { return null; @@ -554,9 +515,7 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> { className={classNames( 'module-message__text', `module-message__text--${direction}`, - status === 'error' && direction === 'incoming' - ? 'module-message__text--error' - : null + status === 'error' && direction === 'incoming' ? 'module-message__text--error' : null )} > <MessageBody @@ -580,10 +539,7 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> { return ( <div className="module-message__error-container"> <div - className={classNames( - 'module-message__error', - `module-message__error--${direction}` - )} + className={classNames('module-message__error', `module-message__error--${direction}`)} /> </div> ); @@ -647,13 +603,9 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> { ) : null} <Item onClick={onCopyText}>{window.i18n('copyMessage')}</Item> - <Item onClick={this.onReplyPrivate}> - {window.i18n('replyToMessage')} - </Item> + <Item onClick={this.onReplyPrivate}>{window.i18n('replyToMessage')}</Item> <Item onClick={onShowDetail}>{window.i18n('moreInformation')}</Item> - {showRetry ? ( - <Item onClick={onRetrySend}>{window.i18n('resend')}</Item> - ) : null} + {showRetry ? <Item onClick={onRetrySend}>{window.i18n('resend')}</Item> : null} {isDeletable ? ( <> <Item @@ -672,18 +624,12 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> { </Item> </> ) : null} - {weAreAdmin && isPublic ? ( - <Item onClick={onBanUser}>{window.i18n('banUser')}</Item> - ) : null} + {weAreAdmin && isPublic ? <Item onClick={onBanUser}>{window.i18n('banUser')}</Item> : null} {weAreAdmin && isPublic && !isAdmin ? ( - <Item onClick={this.onAddModerator}> - {window.i18n('addAsModerator')} - </Item> + <Item onClick={this.onAddModerator}>{window.i18n('addAsModerator')}</Item> ) : null} {weAreAdmin && isPublic && isAdmin ? ( - <Item onClick={this.onRemoveFromModerator}> - {window.i18n('removeFromModerators')} - </Item> + <Item onClick={this.onRemoveFromModerator}>{window.i18n('removeFromModerators')}</Item> ) : null} </Menu> ); @@ -707,11 +653,7 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> { } const { width } = first.image; - if ( - isImageAttachment(first.image) && - width && - width >= MINIMUM_LINK_PREVIEW_IMAGE_WIDTH - ) { + if (isImageAttachment(first.image) && width && width >= MINIMUM_LINK_PREVIEW_IMAGE_WIDTH) { const dimensions = getImageDimensions(first.image); if (dimensions) { return dimensions.width; @@ -781,8 +723,7 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> { // message differently const regex = new RegExp(`@${PubKey.regexForPubkeys}`, 'g'); const mentions = (text ? text.match(regex) : []) as Array<string>; - const mentionMe = - mentions && mentions.some(m => UserUtils.isUsFromCache(m.slice(1))); + const mentionMe = mentions && mentions.some(m => UserUtils.isUsFromCache(m.slice(1))); const isIncoming = direction === 'incoming'; const shouldHightlight = mentionMe && isIncoming && isPublic; @@ -872,10 +813,7 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> { // User clicked on message body const target = event.target as HTMLDivElement; - if ( - target.className === 'text-selectable' || - window.contextMenuShown - ) { + if (target.className === 'text-selectable' || window.contextMenuShown) { return; } @@ -889,10 +827,7 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> { {this.renderAttachment()} {this.renderPreview()} {this.renderText()} - <MessageMetadata - {...this.props} - isShowingImage={this.isShowingImage()} - /> + <MessageMetadata {...this.props} isShowingImage={this.isShowingImage()} /> </div> {this.renderError(!isIncoming)} {this.renderContextMenu()} @@ -935,9 +870,7 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> { const shortenedPubkey = PubKey.shorten(authorPhoneNumber); - const displayedPubkey = authorProfileName - ? shortenedPubkey - : authorPhoneNumber; + const displayedPubkey = authorProfileName ? shortenedPubkey : authorPhoneNumber; return ( <div className="module-message__author"> diff --git a/ts/components/conversation/MessageBody.tsx b/ts/components/conversation/MessageBody.tsx index b81acd62d79c75027688e0bf20ea3f7cc0108024..a8347c9ab2d447236a44b70ded4454ec166da580 100644 --- a/ts/components/conversation/MessageBody.tsx +++ b/ts/components/conversation/MessageBody.tsx @@ -87,14 +87,7 @@ export class MessageBody extends React.Component<Props> { } public render() { - const { - text, - disableJumbomoji, - disableLinks, - i18n, - isGroup, - convoId, - } = this.props; + const { text, disableJumbomoji, disableLinks, i18n, isGroup, convoId } = this.props; const sizeClass = disableJumbomoji ? undefined : getSizeClass(text); if (disableLinks) { diff --git a/ts/components/conversation/MessageDetail.tsx b/ts/components/conversation/MessageDetail.tsx index 540e2c0beb730e75a400ac72a8a98f6e8eb2c0eb..7349179ab65104811b0922932441ec0089ee6c06 100644 --- a/ts/components/conversation/MessageDetail.tsx +++ b/ts/components/conversation/MessageDetail.tsx @@ -36,12 +36,7 @@ export class MessageDetail extends React.Component<Props> { const userName = name || profileName || phoneNumber; return ( - <Avatar - avatarPath={avatarPath} - name={userName} - size={AvatarSize.S} - pubkey={phoneNumber} - /> + <Avatar avatarPath={avatarPath} name={userName} size={AvatarSize.S} pubkey={phoneNumber} /> ); } @@ -130,9 +125,7 @@ export class MessageDetail extends React.Component<Props> { <tbody> {(errors || []).map((error, index) => ( <tr key={index}> - <td className="module-message-detail__label"> - {i18n('error')} - </td> + <td className="module-message-detail__label">{i18n('error')}</td> <td> {' '} <span className="error-message">{error.message}</span>{' '} @@ -143,21 +136,15 @@ export class MessageDetail extends React.Component<Props> { <td className="module-message-detail__label">{i18n('sent')}</td> <td> {moment(sentAt).format('LLLL')}{' '} - <span className="module-message-detail__unix-timestamp"> - ({sentAt}) - </span> + <span className="module-message-detail__unix-timestamp">({sentAt})</span> </td> </tr> {receivedAt ? ( <tr> - <td className="module-message-detail__label"> - {i18n('received')} - </td> + <td className="module-message-detail__label">{i18n('received')}</td> <td> {moment(receivedAt).format('LLLL')}{' '} - <span className="module-message-detail__unix-timestamp"> - ({receivedAt}) - </span> + <span className="module-message-detail__unix-timestamp">({receivedAt})</span> </td> </tr> ) : null} diff --git a/ts/components/conversation/ModeratorsAddDialog.tsx b/ts/components/conversation/ModeratorsAddDialog.tsx index 1ea17a5c370276b3ac54569cad64058adfc09087..97bfeacd3484bf85bb8dc53b2c35e132664fbbfa 100644 --- a/ts/components/conversation/ModeratorsAddDialog.tsx +++ b/ts/components/conversation/ModeratorsAddDialog.tsx @@ -1,9 +1,5 @@ import React from 'react'; -import { - SessionButton, - SessionButtonColor, - SessionButtonType, -} from '../session/SessionButton'; +import { SessionButton, SessionButtonColor, SessionButtonType } from '../session/SessionButton'; import { PubKey } from '../../session/types'; import { ToastUtils } from '../../session/utils'; import { SessionModal } from '../session/SessionModal'; @@ -49,10 +45,7 @@ export class AddModeratorsDialog extends React.Component<Props, State> { // if we don't have valid data entered by the user const pubkey = PubKey.from(this.state.inputBoxValue); if (!pubkey) { - window.log.info( - 'invalid pubkey for adding as moderator:', - this.state.inputBoxValue - ); + window.log.info('invalid pubkey for adding as moderator:', this.state.inputBoxValue); ToastUtils.pushInvalidPubKey(); return; } @@ -96,11 +89,7 @@ export class AddModeratorsDialog extends React.Component<Props, State> { const renderContent = !firstLoading; return ( - <SessionModal - title={title} - onClose={() => this.props.onClose()} - theme={this.props.theme} - > + <SessionModal title={title} onClose={() => this.props.onClose()} theme={this.props.theme}> <Flex container={true} flexDirection="column" alignItems="center"> {renderContent && ( <> diff --git a/ts/components/conversation/ModeratorsRemoveDialog.tsx b/ts/components/conversation/ModeratorsRemoveDialog.tsx index 31f153a0fefa59e3eed5dae3c357644bf13e9f2b..bd7feb6318c034b8b5b8b3cdd50b034ddc599651 100644 --- a/ts/components/conversation/ModeratorsRemoveDialog.tsx +++ b/ts/components/conversation/ModeratorsRemoveDialog.tsx @@ -4,15 +4,8 @@ import { ConversationModel } from '../../models/conversation'; import { ConversationController } from '../../session/conversations'; import { ToastUtils } from '../../session/utils'; import { Flex } from '../session/Flex'; -import { - SessionButton, - SessionButtonColor, - SessionButtonType, -} from '../session/SessionButton'; -import { - ContactType, - SessionMemberListItem, -} from '../session/SessionMemberListItem'; +import { SessionButton, SessionButtonColor, SessionButtonType } from '../session/SessionButton'; +import { ContactType, SessionMemberListItem } from '../session/SessionMemberListItem'; import { SessionModal } from '../session/SessionModal'; import { SessionSpinner } from '../session/SessionSpinner'; interface Props { @@ -62,18 +55,12 @@ export class RemoveModeratorsDialog extends React.Component<Props, State> { const renderContent = !firstLoading; return ( - <SessionModal - title={title} - onClose={this.closeDialog} - theme={this.props.theme} - > + <SessionModal title={title} onClose={this.closeDialog} theme={this.props.theme}> <Flex container={true} flexDirection="column" alignItems="center"> {renderContent && ( <> <p>Existing moderators:</p> - <div className="contact-selection-list"> - {this.renderMemberList()} - </div> + <div className="contact-selection-list">{this.renderMemberList()}</div> {hasMods ? null : <p>{i18n('noModeratorsToRemove')}</p>} <SessionSpinner loading={removingInProgress} /> @@ -187,9 +174,7 @@ export class RemoveModeratorsDialog extends React.Component<Props, State> { } private async removeThem() { - const removedMods = this.state.modList - .filter(d => !d.checkmarked) - .map(d => d.id); + const removedMods = this.state.modList.filter(d => !d.checkmarked).map(d => d.id); if (removedMods.length === 0) { window.log.info('No moderators removed. Nothing todo'); diff --git a/ts/components/conversation/Quote.tsx b/ts/components/conversation/Quote.tsx index aa699feb5653a4f7ff2ee5da247ea515621c5ada..ce1edf8edb06c6daa325dcb00eec8407ea09a144 100644 --- a/ts/components/conversation/Quote.tsx +++ b/ts/components/conversation/Quote.tsx @@ -129,11 +129,7 @@ export class Quote extends React.Component<Props, State> { return ( <div className="module-quote__icon-container"> - <img - src={url} - alt={i18n('quoteThumbnailAlt')} - onError={this.handleImageErrorBound} - /> + <img src={url} alt={i18n('quoteThumbnailAlt')} onError={this.handleImageErrorBound} /> {iconElement} </div> ); @@ -217,14 +213,7 @@ export class Quote extends React.Component<Props, State> { } public renderText() { - const { - i18n, - text, - attachment, - isIncoming, - conversationType, - convoId, - } = this.props; + const { i18n, text, attachment, isIncoming, conversationType, convoId } = this.props; if (text) { return ( @@ -286,11 +275,7 @@ export class Quote extends React.Component<Props, State> { // We need the container to give us the flexibility to implement the iOS design. return ( <div className="module-quote__close-container"> - <div - className="module-quote__close-button" - role="button" - onClick={onClick} - /> + <div className="module-quote__close-button" role="button" onClick={onClick} /> </div> ); } @@ -346,17 +331,13 @@ export class Quote extends React.Component<Props, State> { <div className={classNames( 'module-quote__reference-warning__icon', - isIncoming - ? 'module-quote__reference-warning__icon--incoming' - : null + isIncoming ? 'module-quote__reference-warning__icon--incoming' : null )} /> <div className={classNames( 'module-quote__reference-warning__text', - isIncoming - ? 'module-quote__reference-warning__text--incoming' - : null + isIncoming ? 'module-quote__reference-warning__text--incoming' : null )} > {i18n('originalMessageNotFound')} @@ -366,12 +347,7 @@ export class Quote extends React.Component<Props, State> { } public render() { - const { - isIncoming, - onClick, - referencedMessageNotFound, - withContentAbove, - } = this.props; + const { isIncoming, onClick, referencedMessageNotFound, withContentAbove } = this.props; if (!validateQuote(this.props)) { return null; @@ -392,9 +368,7 @@ export class Quote extends React.Component<Props, State> { isIncoming ? 'module-quote--incoming' : 'module-quote--outgoing', !onClick ? 'module-quote--no-click' : null, withContentAbove ? 'module-quote--with-content-above' : null, - referencedMessageNotFound - ? 'module-quote--with-reference-warning' - : null + referencedMessageNotFound ? 'module-quote--with-reference-warning' : null )} > <div className="module-quote__primary"> diff --git a/ts/components/conversation/StagedGenericAttachment.tsx b/ts/components/conversation/StagedGenericAttachment.tsx index 3783828b16a5ccafbcae45c1629deba7f3b8175c..9e79030815b62386a0fd214b3b44bfaa62e584f2 100644 --- a/ts/components/conversation/StagedGenericAttachment.tsx +++ b/ts/components/conversation/StagedGenericAttachment.tsx @@ -28,14 +28,10 @@ export class StagedGenericAttachment extends React.Component<Props> { /> <div className="module-staged-generic-attachment__icon"> {extension ? ( - <div className="module-staged-generic-attachment__icon__extension"> - {extension} - </div> + <div className="module-staged-generic-attachment__icon__extension">{extension}</div> ) : null} </div> - <div className="module-staged-generic-attachment__filename"> - {fileName} - </div> + <div className="module-staged-generic-attachment__filename">{fileName}</div> </div> ); } diff --git a/ts/components/conversation/StagedLinkPreview.tsx b/ts/components/conversation/StagedLinkPreview.tsx index 56a8a6194909d9787162ebd8776f7557be917daa..cb913fe11196aa076b68c5c915edffb28ee19756 100644 --- a/ts/components/conversation/StagedLinkPreview.tsx +++ b/ts/components/conversation/StagedLinkPreview.tsx @@ -33,9 +33,7 @@ export const StagedLinkPreview = (props: Props) => { )} > {!isLoaded ? ( - <div className="module-staged-link-preview__loading"> - {i18n('loading')} - </div> + <div className="module-staged-link-preview__loading">{i18n('loading')}</div> ) : null} {isLoaded && image && isImage ? ( <div className="module-staged-link-preview__icon-container"> @@ -54,9 +52,7 @@ export const StagedLinkPreview = (props: Props) => { <div className="module-staged-link-preview__content"> <div className="module-staged-link-preview__title">{title}</div> {description && ( - <div className="module-staged-link-preview__description"> - {description} - </div> + <div className="module-staged-link-preview__description">{description}</div> )} <div className="module-staged-link-preview__footer"> <div className="module-staged-link-preview__location">{domain}</div> diff --git a/ts/components/conversation/StagedPlaceholderAttachment.tsx b/ts/components/conversation/StagedPlaceholderAttachment.tsx index b036777dea5910d11fd7dfdc68440efd6823c925..910ba8b400755353fec7346d571c0a23ec877916 100644 --- a/ts/components/conversation/StagedPlaceholderAttachment.tsx +++ b/ts/components/conversation/StagedPlaceholderAttachment.tsx @@ -9,11 +9,7 @@ export class StagedPlaceholderAttachment extends React.Component<Props> { const { onClick } = this.props; return ( - <div - className="module-staged-placeholder-attachment" - role="button" - onClick={onClick} - > + <div className="module-staged-placeholder-attachment" role="button" onClick={onClick}> <div className="module-staged-placeholder-attachment__plus-icon" /> </div> ); diff --git a/ts/components/conversation/TimerNotification.tsx b/ts/components/conversation/TimerNotification.tsx index 3742f92a4fd3700435d92477172966b25640bf96..9e435fe95145c4250684453d34a943f2dd8bb849 100644 --- a/ts/components/conversation/TimerNotification.tsx +++ b/ts/components/conversation/TimerNotification.tsx @@ -18,28 +18,17 @@ type Props = { export const TimerNotification = (props: Props) => { function renderContents() { const { phoneNumber, profileName, timespan, type, disabled } = props; - const changeKey = disabled - ? 'disabledDisappearingMessages' - : 'theyChangedTheTimer'; + const changeKey = disabled ? 'disabledDisappearingMessages' : 'theyChangedTheTimer'; const contact = ( - <span - key={`external-${phoneNumber}`} - className="module-timer-notification__contact" - > + <span key={`external-${phoneNumber}`} className="module-timer-notification__contact"> {profileName || phoneNumber} </span> ); switch (type) { case 'fromOther': - return ( - <Intl - i18n={window.i18n} - id={changeKey} - components={[contact, timespan]} - /> - ); + return <Intl i18n={window.i18n} id={changeKey} components={[contact, timespan]} />; case 'fromMe': return disabled ? window.i18n('youDisabledDisappearingMessages') diff --git a/ts/components/conversation/Timestamp.tsx b/ts/components/conversation/Timestamp.tsx index 99bebc25d3a15646723b9abe23b7599e722a180c..31338ad5df7b7bc23b082f1913859f2a00efb3b2 100644 --- a/ts/components/conversation/Timestamp.tsx +++ b/ts/components/conversation/Timestamp.tsx @@ -18,9 +18,9 @@ type Props = { const UPDATE_FREQUENCY = 60 * 1000; -const TimestampContainerListItem = styled(props => ( - <OpacityMetadataComponent {...props} /> -))<{ color: string }>` +const TimestampContainerListItem = styled(props => <OpacityMetadataComponent {...props} />)<{ + color: string; +}>` flex-shrink: 0; margin-inline-start: 6px; font-size: 11px; @@ -33,9 +33,9 @@ const TimestampContainerListItem = styled(props => ( color: ${props => props.theme.colors.textColor}; `; -const TimestampContainerNotListItem = styled(props => ( - <OpacityMetadataComponent {...props} /> -))<{ color: string }>` +const TimestampContainerNotListItem = styled(props => <OpacityMetadataComponent {...props} />)<{ + color: string; +}>` font-size: 11px; line-height: 16px; letter-spacing: 0.3px; @@ -63,8 +63,7 @@ export const Timestamp = (props: Props) => { // Use relative time for under 24hrs ago. const now = Math.floor(Date.now()); - const messageAgeInDays = - (now - timestamp) / (window.CONSTANTS.SECS_IN_DAY * 1000); + const messageAgeInDays = (now - timestamp) / (window.CONSTANTS.SECS_IN_DAY * 1000); const daysBeforeRelativeTiming = 1; let dateString; @@ -80,9 +79,7 @@ export const Timestamp = (props: Props) => { dateString = dateString.replace('minutes', 'mins').replace('minute', 'min'); } - const timestampColor = withImageNoCaption - ? 'white' - : props.theme.colors.textColor; + const timestampColor = withImageNoCaption ? 'white' : props.theme.colors.textColor; const title = moment(timestamp).format('llll'); if (props.isConversationListItem) { return ( @@ -92,10 +89,7 @@ export const Timestamp = (props: Props) => { ); } return ( - <TimestampContainerNotListItem - timestampColor={timestampColor} - title={title} - > + <TimestampContainerNotListItem timestampColor={timestampColor} title={title}> {dateString} </TimestampContainerNotListItem> ); diff --git a/ts/components/conversation/UpdateGroupMembersDialog.tsx b/ts/components/conversation/UpdateGroupMembersDialog.tsx index 3850b069fabe2391b2193447eace47c51467c566..52c8f1678fa02e25f2767e55a092982fa4016fcd 100644 --- a/ts/components/conversation/UpdateGroupMembersDialog.tsx +++ b/ts/components/conversation/UpdateGroupMembersDialog.tsx @@ -3,10 +3,7 @@ import classNames from 'classnames'; import { SessionModal } from '../session/SessionModal'; import { SessionButton, SessionButtonColor } from '../session/SessionButton'; -import { - ContactType, - SessionMemberListItem, -} from '../session/SessionMemberListItem'; +import { ContactType, SessionMemberListItem } from '../session/SessionMemberListItem'; import { DefaultTheme } from 'styled-components'; import { ToastUtils } from '../../session/utils'; @@ -71,9 +68,7 @@ export class UpdateGroupMembersDialog extends React.Component<Props, State> { } public onClickOK() { - const members = this.getWouldBeMembers(this.state.contactList).map( - d => d.id - ); + const members = this.getWouldBeMembers(this.state.contactList).map(d => d.id); this.props.onSubmit(members); @@ -103,9 +98,7 @@ export class UpdateGroupMembersDialog extends React.Component<Props, State> { <p className={errorMessageClasses}>{errorMsg}</p> <div className="spacer-md" /> - <div className="group-member-list__selection"> - {this.renderMemberList()} - </div> + <div className="group-member-list__selection">{this.renderMemberList()}</div> {showNoMembersMessage && <p>{window.i18n('noMembersInThisGroup')}</p>} <div className="spacer-lg" /> @@ -155,10 +148,7 @@ export class UpdateGroupMembersDialog extends React.Component<Props, State> { // current state in `users` private getWouldBeMembers(users: Array<ContactType>) { return users.filter(d => { - return ( - (d.existingMember && !d.checkmarked) || - (!d.existingMember && d.checkmarked) - ); + return (d.existingMember && !d.checkmarked) || (!d.existingMember && d.checkmarked); }); } diff --git a/ts/components/conversation/UpdateGroupNameDialog.tsx b/ts/components/conversation/UpdateGroupNameDialog.tsx index 2fdcaded2f550f39a3154332c43f2f38c4634bdc..bf568e278b17b013d2d2099d8885378cbd813631 100644 --- a/ts/components/conversation/UpdateGroupNameDialog.tsx +++ b/ts/components/conversation/UpdateGroupNameDialog.tsx @@ -59,10 +59,7 @@ class UpdateGroupNameDialogInner extends React.Component<Props, State> { return; } - const avatar = - this?.inputEl?.current?.files?.length > 0 - ? this.inputEl.current.files[0] - : null; // otherwise use the current avatar + const avatar = this?.inputEl?.current?.files?.length > 0 ? this.inputEl.current.files[0] : null; // otherwise use the current avatar onSubmit(this.state.groupName, avatar); @@ -176,11 +173,7 @@ class UpdateGroupNameDialogInner extends React.Component<Props, State> { return ( <div className="avatar-center"> <div className="avatar-center-inner"> - <Avatar - avatarPath={avatarPath} - size={AvatarSize.XL} - pubkey={this.props.pubkey} - /> + <Avatar avatarPath={avatarPath} size={AvatarSize.XL} pubkey={this.props.pubkey} /> <div className="image-upload-section" role="button" diff --git a/ts/components/conversation/media-gallery/AttachmentSection.tsx b/ts/components/conversation/media-gallery/AttachmentSection.tsx index e8ec59a4fcd3f3f43f6600586b6fd2fd35674b41..63c5a7a426db5bff40ed014ecabf19c93fd5d861 100644 --- a/ts/components/conversation/media-gallery/AttachmentSection.tsx +++ b/ts/components/conversation/media-gallery/AttachmentSection.tsx @@ -21,9 +21,7 @@ export class AttachmentSection extends React.Component<Props> { return ( <div className="module-attachment-section"> <div className="module-attachment-section__items"> - <div className={`module-attachment-section__items-${type}`}> - {this.renderItems()} - </div> + <div className={`module-attachment-section__items-${type}`}>{this.renderItems()}</div> </div> </div> ); diff --git a/ts/components/conversation/media-gallery/DocumentListItem.tsx b/ts/components/conversation/media-gallery/DocumentListItem.tsx index 0d5590ebdfdec1873dcc63fccdc4967402dba7b9..1ec504f752db1e80f26121fe89c9c70304f1286e 100644 --- a/ts/components/conversation/media-gallery/DocumentListItem.tsx +++ b/ts/components/conversation/media-gallery/DocumentListItem.tsx @@ -28,9 +28,7 @@ export class DocumentListItem extends React.Component<Props> { <div className={classNames( 'module-document-list-item', - shouldShowSeparator - ? 'module-document-list-item--with-separator' - : null + shouldShowSeparator ? 'module-document-list-item--with-separator' : null )} > {this.renderContent()} @@ -49,9 +47,7 @@ export class DocumentListItem extends React.Component<Props> { > <div className="module-document-list-item__icon" /> <div className="module-document-list-item__metadata"> - <span className="module-document-list-item__file-name"> - {fileName} - </span> + <span className="module-document-list-item__file-name">{fileName}</span> <span className="module-document-list-item__file-size"> {typeof fileSize === 'number' ? formatFileSize(fileSize) : ''} </span> diff --git a/ts/components/conversation/media-gallery/MediaGallery.tsx b/ts/components/conversation/media-gallery/MediaGallery.tsx index 35cee99612601b288b00756cd71d09adcc9ed7a6..e4ecda6675d01b33eab32fa280045353bbb15b43 100644 --- a/ts/components/conversation/media-gallery/MediaGallery.tsx +++ b/ts/components/conversation/media-gallery/MediaGallery.tsx @@ -77,9 +77,7 @@ export class MediaGallery extends React.Component<Props, State> { onSelect={this.handleTabSelect} /> </div> - <div className="module-media-gallery__content"> - {this.renderSections()} - </div> + <div className="module-media-gallery__content">{this.renderSections()}</div> </div> ); } diff --git a/ts/components/conversation/media-gallery/MediaGridItem.tsx b/ts/components/conversation/media-gallery/MediaGridItem.tsx index ca474789d21df74c4822b4b55788370231a44dd6..c65fe313e18444a7963b3f467cae11f615fc9d5e 100644 --- a/ts/components/conversation/media-gallery/MediaGridItem.tsx +++ b/ts/components/conversation/media-gallery/MediaGridItem.tsx @@ -1,10 +1,7 @@ import React, { useState } from 'react'; import classNames from 'classnames'; -import { - isImageTypeSupported, - isVideoTypeSupported, -} from '../../../util/GoogleChrome'; +import { isImageTypeSupported, isVideoTypeSupported } from '../../../util/GoogleChrome'; import { LocalizerType } from '../../../types/Util'; import { MediaItemType } from '../../LightboxGallery'; import { useEncryptedFileFetch } from '../../../hooks/useEncryptedFileFetch'; @@ -22,18 +19,13 @@ const MediaGridItemContent = (props: Props) => { const urlToDecrypt = mediaItem.thumbnailObjectUrl || ''; const [imageBroken, setImageBroken] = useState(false); - const { loading, urlToLoad } = useEncryptedFileFetch( - urlToDecrypt, - contentType - ); + const { loading, urlToLoad } = useEncryptedFileFetch(urlToDecrypt, contentType); // data will be url if loading is finished and '' if not const srcData = !loading ? urlToLoad : ''; const onImageError = () => { // tslint:disable-next-line no-console - console.log( - 'MediaGridItem: Image failed to load; failing over to placeholder' - ); + console.log('MediaGridItem: Image failed to load; failing over to placeholder'); setImageBroken(true); }; @@ -90,21 +82,14 @@ const MediaGridItemContent = (props: Props) => { return ( <div - className={classNames( - 'module-media-grid-item__icon', - 'module-media-grid-item__icon-generic' - )} + className={classNames('module-media-grid-item__icon', 'module-media-grid-item__icon-generic')} /> ); }; export const MediaGridItem = (props: Props) => { return ( - <div - className="module-media-grid-item" - role="button" - onClick={props.onClick} - > + <div className="module-media-grid-item" role="button" onClick={props.onClick}> <MediaGridItemContent {...props} /> </div> ); diff --git a/ts/components/conversation/media-gallery/groupMediaItemsByDate.ts b/ts/components/conversation/media-gallery/groupMediaItemsByDate.ts index 570657992b9f3529b42ead141669651cf60e780d..0e78649ecfab201466ad95ca2533abd1045f444b 100644 --- a/ts/components/conversation/media-gallery/groupMediaItemsByDate.ts +++ b/ts/components/conversation/media-gallery/groupMediaItemsByDate.ts @@ -29,13 +29,9 @@ export const groupMediaItemsByDate = ( return -message.received_at; }); - const messagesWithSection = sortedMediaItem.map( - withSection(referenceDateTime) - ); + const messagesWithSection = sortedMediaItem.map(withSection(referenceDateTime)); const groupedMediaItem = groupBy(messagesWithSection, 'type'); - const yearMonthMediaItem = Object.values( - groupBy(groupedMediaItem.yearMonth, 'order') - ).reverse(); + const yearMonthMediaItem = Object.values(groupBy(groupedMediaItem.yearMonth, 'order')).reverse(); return compact([ toSection(groupedMediaItem.today), @@ -53,15 +49,12 @@ const toSection = ( return; } - const firstMediaItemWithSection: MediaItemWithSection = - messagesWithSection[0]; + const firstMediaItemWithSection: MediaItemWithSection = messagesWithSection[0]; if (!firstMediaItemWithSection) { return; } - const mediaItems = messagesWithSection.map( - messageWithSection => messageWithSection.mediaItem - ); + const mediaItems = messagesWithSection.map(messageWithSection => messageWithSection.mediaItem); switch (firstMediaItemWithSection.type) { case 'today': case 'yesterday': @@ -92,18 +85,12 @@ interface GenericMediaItemWithSection<T> { type: T; mediaItem: MediaItemType; } -type MediaItemWithStaticSection = GenericMediaItemWithSection< - StaticSectionType ->; -type MediaItemWithYearMonthSection = GenericMediaItemWithSection< - YearMonthSectionType -> & { +type MediaItemWithStaticSection = GenericMediaItemWithSection<StaticSectionType>; +type MediaItemWithYearMonthSection = GenericMediaItemWithSection<YearMonthSectionType> & { year: number; month: number; }; -type MediaItemWithSection = - | MediaItemWithStaticSection - | MediaItemWithYearMonthSection; +type MediaItemWithSection = MediaItemWithStaticSection | MediaItemWithYearMonthSection; const withSection = (referenceDateTime: moment.Moment) => ( mediaItem: MediaItemType diff --git a/ts/components/conversation/message/MessageMetadata.tsx b/ts/components/conversation/message/MessageMetadata.tsx index 25802ff18340cc285ce2ee09215dbda0f3be3842..0eca6b4e7fa8406b96afed50fd61ce0953bc7c91 100644 --- a/ts/components/conversation/message/MessageMetadata.tsx +++ b/ts/components/conversation/message/MessageMetadata.tsx @@ -1,10 +1,7 @@ import React from 'react'; import classNames from 'classnames'; -import { - MessageSendingErrorText, - MetadataSpacer, -} from './MetadataUtilComponent'; +import { MessageSendingErrorText, MetadataSpacer } from './MetadataUtilComponent'; import { OutgoingMessageStatus } from './OutgoingMessageStatus'; import { Spinner } from '../../Spinner'; import { MetadataBadges } from './MetadataBadge'; @@ -85,16 +82,11 @@ export const MessageMetadata = (props: Props) => { const showError = status === 'error' && isOutgoing; const showStatus = Boolean(status?.length && isOutgoing); - const messageStatusColor = withImageNoCaption - ? 'white' - : props.theme.colors.sentMessageText; + const messageStatusColor = withImageNoCaption ? 'white' : props.theme.colors.sentMessageText; return ( <MetadatasContainer withImageNoCaption={withImageNoCaption} {...props}> {showError ? ( - <MessageSendingErrorText - withImageNoCaption={withImageNoCaption} - theme={theme} - /> + <MessageSendingErrorText withImageNoCaption={withImageNoCaption} theme={theme} /> ) : ( <Timestamp timestamp={serverTimestamp || timestamp} diff --git a/ts/components/conversation/message/MetadataBadge.tsx b/ts/components/conversation/message/MetadataBadge.tsx index 18864c49d225a37ee32122a62b19c383c8b86047..a8ebca367325aff9b2898c206be60fda7a4ae7d3 100644 --- a/ts/components/conversation/message/MetadataBadge.tsx +++ b/ts/components/conversation/message/MetadataBadge.tsx @@ -10,9 +10,7 @@ type BadgeProps = { children?: ReactNode; }; -const BadgeText = styled(props => <OpacityMetadataComponent {...props} />)< - BadgeProps ->` +const BadgeText = styled(props => <OpacityMetadataComponent {...props} />)<BadgeProps>` font-weight: bold; padding-inline-end: 5px; font-size: 11px; @@ -20,16 +18,14 @@ const BadgeText = styled(props => <OpacityMetadataComponent {...props} />)< letter-spacing: 0.3px; text-transform: uppercase; user-select: none; - color: ${props => - props.withImageNoCaption ? 'white' : props.theme.colors.textColor}; + color: ${props => (props.withImageNoCaption ? 'white' : props.theme.colors.textColor)}; `; -const BadgeSeparator = styled(props => ( - <OpacityMetadataComponent {...props} /> -))<{ withImageNoCaption: boolean }>` +const BadgeSeparator = styled(props => <OpacityMetadataComponent {...props} />)<{ + withImageNoCaption: boolean; +}>` margin-top: -2px; - color: ${props => - props.withImageNoCaption ? 'white' : props.theme.colors.textColor}; + color: ${props => (props.withImageNoCaption ? 'white' : props.theme.colors.textColor)}; `; export const MetadataBadge = (props: BadgeProps): JSX.Element => { @@ -51,10 +47,9 @@ type BadgesProps = { export const MetadataBadges = (props: BadgesProps): JSX.Element => { const { id, direction, isPublic, isAdmin, withImageNoCaption } = props; - const badges = [ - (isPublic && 'Public') || null, - (isPublic && isAdmin && 'Mod') || null, - ].filter(nonNullish); + const badges = [(isPublic && 'Public') || null, (isPublic && isAdmin && 'Mod') || null].filter( + nonNullish + ); if (!badges || badges.length === 0) { return <></>; diff --git a/ts/components/conversation/message/MetadataUtilComponent.tsx b/ts/components/conversation/message/MetadataUtilComponent.tsx index 6e512cf1c9086115eecdc87e69f5b3e226c07b9d..49ff99ebee521849df64d0adec84ffd157e1acba 100644 --- a/ts/components/conversation/message/MetadataUtilComponent.tsx +++ b/ts/components/conversation/message/MetadataUtilComponent.tsx @@ -7,16 +7,16 @@ export const MetadataSpacer = styled.span` flex-grow: 1; `; -const MessageSendingErrorContainer = styled(props => ( - <OpacityMetadataComponent {...props} /> -))<{ withImageNoCaption: boolean; theme: DefaultTheme }>` +const MessageSendingErrorContainer = styled(props => <OpacityMetadataComponent {...props} />)<{ + withImageNoCaption: boolean; + theme: DefaultTheme; +}>` font-size: 11px; line-height: 16px; letter-spacing: 0.3px; text-transform: uppercase; user-select: none; - color: ${props => - props.withImageNoCaption ? 'white' : props.theme.colors.sentMessageText}; + color: ${props => (props.withImageNoCaption ? 'white' : props.theme.colors.sentMessageText)}; `; export const MessageSendingErrorText = (props: { withImageNoCaption: boolean; diff --git a/ts/components/conversation/message/OutgoingMessageStatus.tsx b/ts/components/conversation/message/OutgoingMessageStatus.tsx index 225c057be242a9cb2fff3372703cd61e4a6d7922..2ad84232ccc503dde2b148c777d751d27a346e58 100644 --- a/ts/components/conversation/message/OutgoingMessageStatus.tsx +++ b/ts/components/conversation/message/OutgoingMessageStatus.tsx @@ -1,24 +1,15 @@ import React from 'react'; import styled, { DefaultTheme } from 'styled-components'; -import { - SessionIcon, - SessionIconSize, - SessionIconType, -} from '../../session/icon'; +import { SessionIcon, SessionIconSize, SessionIconType } from '../../session/icon'; import { OpacityMetadataComponent } from './MessageMetadata'; -const MessageStatusSendingContainer = styled(props => ( - <OpacityMetadataComponent {...props} /> -))` +const MessageStatusSendingContainer = styled(props => <OpacityMetadataComponent {...props} />)` display: inline-block; margin-bottom: 2px; margin-inline-start: 5px; `; -const MessageStatusSending = (props: { - theme: DefaultTheme; - iconColor: string; -}) => { +const MessageStatusSending = (props: { theme: DefaultTheme; iconColor: string }) => { return ( <MessageStatusSendingContainer> <SessionIcon @@ -32,10 +23,7 @@ const MessageStatusSending = (props: { ); }; -const MessageStatusSent = (props: { - theme: DefaultTheme; - iconColor: string; -}) => { +const MessageStatusSent = (props: { theme: DefaultTheme; iconColor: string }) => { return ( <MessageStatusSendingContainer> <SessionIcon @@ -48,10 +36,7 @@ const MessageStatusSent = (props: { ); }; -const MessageStatusDelivered = (props: { - theme: DefaultTheme; - iconColor: string; -}) => { +const MessageStatusDelivered = (props: { theme: DefaultTheme; iconColor: string }) => { return ( <MessageStatusSendingContainer> <SessionIcon @@ -64,10 +49,7 @@ const MessageStatusDelivered = (props: { ); }; -const MessageStatusRead = (props: { - theme: DefaultTheme; - iconColor: string; -}) => { +const MessageStatusRead = (props: { theme: DefaultTheme; iconColor: string }) => { return ( <MessageStatusSendingContainer> <SessionIcon diff --git a/ts/components/session/ActionsPanel.tsx b/ts/components/session/ActionsPanel.tsx index 4cea8c4c776d2d6eacfc61b825ed8af51ce24115..b693aa92a6c30d07e2e591bbd3c859e98b6527e5 100644 --- a/ts/components/session/ActionsPanel.tsx +++ b/ts/components/session/ActionsPanel.tsx @@ -28,10 +28,7 @@ import { getFocusedSection } from '../../state/selectors/section'; import { useInterval } from '../../hooks/useInterval'; import { clearSearch } from '../../state/ducks/search'; import { showLeftPaneSection } from '../../state/ducks/section'; -import { - joinOpenGroupV2, - parseOpenGroupV2, -} from '../../opengroup/opengroupV2/JoinOpenGroupV2'; +import { joinOpenGroupV2, parseOpenGroupV2 } from '../../opengroup/opengroupV2/JoinOpenGroupV2'; import { downloadPreviewOpenGroupV2, getMessages, @@ -113,8 +110,7 @@ const Section = (props: { type: SectionType; avatarPath?: string }) => { iconType = SessionIconType.Moon; } - const unreadToShow = - type === SectionType.Message ? unreadMessageCount : undefined; + const unreadToShow = type === SectionType.Message ? unreadMessageCount : undefined; return ( <SessionIconButton @@ -153,10 +149,7 @@ export const ActionsPanel = () => { // For the action panel, it means this is called only one per app start/with a user loggedin useEffect(() => { void window.setClockParams(); - if ( - window.lokiFeatureFlags.useOnionRequests || - window.lokiFeatureFlags.useFileOnionRequests - ) { + if (window.lokiFeatureFlags.useOnionRequests || window.lokiFeatureFlags.useFileOnionRequests) { // Initialize paths for onion requests void OnionPaths.getInstance().buildNewOnionPaths(); } @@ -227,10 +220,7 @@ export const ActionsPanel = () => { // wait for cleanUpMediasInterval and then start cleaning up medias // this would be way easier to just be able to not trigger a call with the setInterval useEffect(() => { - const timeout = global.setTimeout( - () => setStartCleanUpMedia(true), - cleanUpMediasInterval - ); + const timeout = global.setTimeout(() => setStartCleanUpMedia(true), cleanUpMediasInterval); return () => global.clearTimeout(timeout); }, []); @@ -253,10 +243,7 @@ export const ActionsPanel = () => { return ( <div className="module-left-pane__sections-container"> - <Section - type={SectionType.Profile} - avatarPath={ourPrimaryConversation.avatarPath} - /> + <Section type={SectionType.Profile} avatarPath={ourPrimaryConversation.avatarPath} /> <Section type={SectionType.Message} /> <Section type={SectionType.Contact} /> <Section type={SectionType.Settings} /> diff --git a/ts/components/session/LeftPaneContactSection.tsx b/ts/components/session/LeftPaneContactSection.tsx index 72dbb8e180ce2cc65e39b10725e18578087468c1..f4818a9b5e92e1f1bd578ba37380ddb1acc7d529 100644 --- a/ts/components/session/LeftPaneContactSection.tsx +++ b/ts/components/session/LeftPaneContactSection.tsx @@ -2,17 +2,10 @@ import React from 'react'; import { ConversationListItemWithDetails } from '../ConversationListItem'; import { RowRendererParamsType } from '../LeftPane'; -import { - SessionButton, - SessionButtonColor, - SessionButtonType, -} from './SessionButton'; +import { SessionButton, SessionButtonColor, SessionButtonType } from './SessionButton'; import { AutoSizer, List } from 'react-virtualized'; import { ConversationType as ReduxConversationType } from '../../state/ducks/conversations'; -import { - SessionClosableOverlay, - SessionClosableOverlayType, -} from './SessionClosableOverlay'; +import { SessionClosableOverlay, SessionClosableOverlayType } from './SessionClosableOverlay'; import { ToastUtils } from '../../session/utils'; import { DefaultTheme } from 'styled-components'; import { LeftPaneSectionHeader } from './LeftPaneSectionHeader'; @@ -43,9 +36,7 @@ export class LeftPaneContactSection extends React.Component<Props, State> { this.handleToggleOverlay = this.handleToggleOverlay.bind(this); this.handleOnAddContact = this.handleOnAddContact.bind(this); - this.handleRecipientSessionIDChanged = this.handleRecipientSessionIDChanged.bind( - this - ); + this.handleRecipientSessionIDChanged = this.handleRecipientSessionIDChanged.bind(this); this.closeOverlay = this.closeOverlay.bind(this); } @@ -59,30 +50,19 @@ export class LeftPaneContactSection extends React.Component<Props, State> { } public renderHeader(): JSX.Element | undefined { - return ( - <LeftPaneSectionHeader - label={window.i18n('contactsHeader')} - theme={this.props.theme} - /> - ); + return <LeftPaneSectionHeader label={window.i18n('contactsHeader')} theme={this.props.theme} />; } public render(): JSX.Element { return ( <div className="left-pane-contact-section"> {this.renderHeader()} - {this.state.showAddContactView - ? this.renderClosableOverlay() - : this.renderContacts()} + {this.state.showAddContactView ? this.renderClosableOverlay() : this.renderContacts()} </div> ); } - public renderRow = ({ - index, - key, - style, - }: RowRendererParamsType): JSX.Element | undefined => { + public renderRow = ({ index, key, style }: RowRendererParamsType): JSX.Element | undefined => { const { directContacts } = this.props; const item = directContacts[index]; diff --git a/ts/components/session/LeftPaneMessageSection.tsx b/ts/components/session/LeftPaneMessageSection.tsx index 8feb3d359c1eb947b55335c144e7a646a96006e4..ee05b71019b820f2ed41e69fa8819a11fd1e5763 100644 --- a/ts/components/session/LeftPaneMessageSection.tsx +++ b/ts/components/session/LeftPaneMessageSection.tsx @@ -14,17 +14,10 @@ import { debounce } from 'lodash'; import { cleanSearchTerm } from '../../util/cleanSearchTerm'; import { SearchOptions } from '../../types/Search'; import { RowRendererParamsType } from '../LeftPane'; -import { - SessionClosableOverlay, - SessionClosableOverlayType, -} from './SessionClosableOverlay'; +import { SessionClosableOverlay, SessionClosableOverlayType } from './SessionClosableOverlay'; import { SessionIconType } from './icon'; import { ContactType } from './SessionMemberListItem'; -import { - SessionButton, - SessionButtonColor, - SessionButtonType, -} from './SessionButton'; +import { SessionButton, SessionButtonColor, SessionButtonType } from './SessionButton'; import { PubKey } from '../../session/types'; import { ToastUtils, UserUtils } from '../../session/utils'; import { DefaultTheme } from 'styled-components'; @@ -84,12 +77,8 @@ export class LeftPaneMessageSection extends React.Component<Props, State> { this.handleToggleOverlay = this.handleToggleOverlay.bind(this); this.handleMessageButtonClick = this.handleMessageButtonClick.bind(this); - this.handleNewSessionButtonClick = this.handleNewSessionButtonClick.bind( - this - ); - this.handleJoinChannelButtonClick = this.handleJoinChannelButtonClick.bind( - this - ); + this.handleNewSessionButtonClick = this.handleNewSessionButtonClick.bind(this); + this.handleJoinChannelButtonClick = this.handleJoinChannelButtonClick.bind(this); this.onCreateClosedGroup = this.onCreateClosedGroup.bind(this); this.renderClosableOverlay = this.renderClosableOverlay.bind(this); @@ -106,11 +95,7 @@ export class LeftPaneMessageSection extends React.Component<Props, State> { window.Whisper.events.off('calculatingPoW', this.closeOverlay); } - public renderRow = ({ - index, - key, - style, - }: RowRendererParamsType): JSX.Element => { + public renderRow = ({ index, key, style }: RowRendererParamsType): JSX.Element => { const { conversations, openConversationExternal } = this.props; if (!conversations) { @@ -131,11 +116,7 @@ export class LeftPaneMessageSection extends React.Component<Props, State> { }; public renderList(): JSX.Element | Array<JSX.Element | null> { - const { - conversations, - openConversationExternal, - searchResults, - } = this.props; + const { conversations, openConversationExternal, searchResults } = this.props; const contacts = searchResults?.contacts || []; if (searchResults) { @@ -150,9 +131,7 @@ export class LeftPaneMessageSection extends React.Component<Props, State> { } if (!conversations) { - throw new Error( - 'render: must provided conversations if no search results are provided' - ); + throw new Error('render: must provided conversations if no search results are provided'); } const length = conversations.length; @@ -205,9 +184,7 @@ export class LeftPaneMessageSection extends React.Component<Props, State> { return ( <div className="session-left-pane-section-content"> {this.renderHeader()} - {overlay - ? this.renderClosableOverlay(overlay) - : this.renderConversations()} + {overlay ? this.renderClosableOverlay(overlay) : this.renderConversations()} </div> ); } @@ -298,10 +275,9 @@ export class LeftPaneMessageSection extends React.Component<Props, State> { onCloseClick={() => { this.handleToggleOverlay(undefined); }} - onButtonClick={async ( - groupName: string, - groupMembers: Array<ContactType> - ) => this.onCreateClosedGroup(groupName, groupMembers)} + onButtonClick={async (groupName: string, groupMembers: Array<ContactType>) => + this.onCreateClosedGroup(groupName, groupMembers) + } searchTerm={searchTerm} updateSearch={this.updateSearchBound} showSpinner={loading} @@ -382,10 +358,7 @@ export class LeftPaneMessageSection extends React.Component<Props, State> { const { openConversationExternal } = this.props; if (!this.state.valuePasted && !this.props.searchTerm) { - ToastUtils.pushToastError( - 'invalidPubKey', - window.i18n('invalidNumberError') - ); + ToastUtils.pushToastError('invalidPubKey', window.i18n('invalidNumberError')); return; } let pubkey: string; @@ -413,28 +386,19 @@ export class LeftPaneMessageSection extends React.Component<Props, State> { // Server URL valid? if (serverUrl.length === 0 || !OpenGroup.validate(serverUrl)) { - ToastUtils.pushToastError( - 'connectToServer', - window.i18n('invalidOpenGroupUrl') - ); + ToastUtils.pushToastError('connectToServer', window.i18n('invalidOpenGroupUrl')); return; } // Already connected? if (OpenGroup.getConversation(serverUrl)) { - ToastUtils.pushToastError( - 'publicChatExists', - window.i18n('publicChatExists') - ); + ToastUtils.pushToastError('publicChatExists', window.i18n('publicChatExists')); return; } // Connect to server try { - ToastUtils.pushToastInfo( - 'connectingToServer', - window.i18n('connectingToServer') - ); + ToastUtils.pushToastInfo('connectingToServer', window.i18n('connectingToServer')); this.setState({ loading: true }); await OpenGroup.join(serverUrl); @@ -444,42 +408,29 @@ export class LeftPaneMessageSection extends React.Component<Props, State> { window.i18n('connectToServerSuccess') ); } else { - throw new Error( - 'Open group joined but the corresponding server does not exist' - ); + throw new Error('Open group joined but the corresponding server does not exist'); } this.setState({ loading: false }); const openGroupConversation = OpenGroup.getConversation(serverUrl); if (!openGroupConversation) { - window.log.error( - 'Joined an opengroup but did not find ther corresponding conversation' - ); + window.log.error('Joined an opengroup but did not find ther corresponding conversation'); } this.handleToggleOverlay(undefined); } catch (e) { window.log.error('Failed to connect to server:', e); - ToastUtils.pushToastError( - 'connectToServerFail', - window.i18n('connectToServerFail') - ); + ToastUtils.pushToastError('connectToServerFail', window.i18n('connectToServerFail')); this.setState({ loading: false }); } } - private async onCreateClosedGroup( - groupName: string, - groupMembers: Array<ContactType> - ) { + private async onCreateClosedGroup(groupName: string, groupMembers: Array<ContactType>) { if (this.state.loading) { window.log.warn('Closed group creation already in progress'); return; } this.setState({ loading: true }, async () => { - const groupCreated = await MainViewController.createClosedGroup( - groupName, - groupMembers - ); + const groupCreated = await MainViewController.createClosedGroup(groupName, groupMembers); if (groupCreated) { this.handleToggleOverlay(undefined); diff --git a/ts/components/session/LeftPaneSectionHeader.tsx b/ts/components/session/LeftPaneSectionHeader.tsx index 540d4894864167f0cb134171ff59db74fd63fc9e..4c3a59c04b63a6ace44d2054ebeb85c2fc1d9aab 100644 --- a/ts/components/session/LeftPaneSectionHeader.tsx +++ b/ts/components/session/LeftPaneSectionHeader.tsx @@ -23,10 +23,7 @@ const Tab = ({ return ( <h1 - className={classNames( - 'module-left-pane__title', - isSelected ? 'active' : null - )} + className={classNames('module-left-pane__title', isSelected ? 'active' : null)} onClick={handleClick} role="button" > @@ -49,11 +46,7 @@ export const LeftPaneSectionHeader = (props: Props) => { <div className="module-left-pane__header"> {label && <Tab label={label} type={0} isSelected={true} key={label} />} {buttonIcon && ( - <SessionButton - onClick={buttonClicked} - key="compose" - theme={props.theme} - > + <SessionButton onClick={buttonClicked} key="compose" theme={props.theme}> <SessionIcon iconType={buttonIcon} iconSize={SessionIconSize.Small} diff --git a/ts/components/session/LeftPaneSettingSection.tsx b/ts/components/session/LeftPaneSettingSection.tsx index c2aeb0710ca995095008924c94bc1a8a87d8ea55..bc82f8520bd4140b32a639bbaf9720e0a77e467d 100644 --- a/ts/components/session/LeftPaneSettingSection.tsx +++ b/ts/components/session/LeftPaneSettingSection.tsx @@ -1,11 +1,7 @@ import React from 'react'; import classNames from 'classnames'; -import { - SessionButton, - SessionButtonColor, - SessionButtonType, -} from './SessionButton'; +import { SessionButton, SessionButtonColor, SessionButtonType } from './SessionButton'; import { SessionIcon, SessionIconSize, SessionIconType } from './icon'; import { SessionSettingCategory } from './settings/SessionSettings'; @@ -156,10 +152,7 @@ export const LeftPaneSettingSection = () => { return ( <div className="left-pane-setting-section"> - <LeftPaneSectionHeader - label={window.i18n('settingsHeader')} - theme={theme} - /> + <LeftPaneSectionHeader label={window.i18n('settingsHeader')} theme={theme} /> <div className="left-pane-setting-content"> <LeftPaneSettingsCategories /> <LeftPaneBottomButtons /> diff --git a/ts/components/session/SessionButton.tsx b/ts/components/session/SessionButton.tsx index 05b64bbef55b23c377006bb74a864456ec4ca337..772fd68b54db62c6ea449d27f1a8f14ac51ca984 100644 --- a/ts/components/session/SessionButton.tsx +++ b/ts/components/session/SessionButton.tsx @@ -54,12 +54,7 @@ export const SessionButton = (props: Props) => { return ( <div - className={classNames( - 'session-button', - ...buttonTypes, - buttonColor, - disabled && 'disabled' - )} + className={classNames('session-button', ...buttonTypes, buttonColor, disabled && 'disabled')} role="button" onClick={onClickFn} > diff --git a/ts/components/session/SessionClosableOverlay.tsx b/ts/components/session/SessionClosableOverlay.tsx index 813f92fb73d80d38f4a61ae45777c62734e266ec..08579b7a0f34cf67cad59db542f8c704df8e800e 100644 --- a/ts/components/session/SessionClosableOverlay.tsx +++ b/ts/components/session/SessionClosableOverlay.tsx @@ -6,11 +6,7 @@ import { SessionIdEditable } from './SessionIdEditable'; import { UserSearchDropdown } from './UserSearchDropdown'; import { ContactType, SessionMemberListItem } from './SessionMemberListItem'; import { ConversationType } from '../../state/ducks/conversations'; -import { - SessionButton, - SessionButtonColor, - SessionButtonType, -} from './SessionButton'; +import { SessionButton, SessionButtonColor, SessionButtonType } from './SessionButton'; import { SessionSpinner } from './SessionSpinner'; import { PillDivider } from './PillDivider'; import { DefaultTheme } from 'styled-components'; @@ -70,12 +66,9 @@ export class SessionClosableOverlay extends React.Component<Props, State> { const contactsList = this.props.contacts ?? []; // Depending on the rendered overlay type we have to filter the contact list. let filteredContactsList = contactsList; - const isClosedGroupView = - overlayMode === SessionClosableOverlayType.ClosedGroup; + const isClosedGroupView = overlayMode === SessionClosableOverlayType.ClosedGroup; if (isClosedGroupView) { - filteredContactsList = filteredContactsList.filter( - c => c.type === 'direct' && !c.isMe - ); + filteredContactsList = filteredContactsList.filter(c => c.type === 'direct' && !c.isMe); } return filteredContactsList.map((d: any) => { @@ -118,10 +111,8 @@ export class SessionClosableOverlay extends React.Component<Props, State> { const isAddContactView = overlayMode === SessionClosableOverlayType.Contact; const isMessageView = overlayMode === SessionClosableOverlayType.Message; - const isOpenGroupView = - overlayMode === SessionClosableOverlayType.OpenGroup; - const isClosedGroupView = - overlayMode === SessionClosableOverlayType.ClosedGroup; + const isOpenGroupView = overlayMode === SessionClosableOverlayType.OpenGroup; + const isClosedGroupView = overlayMode === SessionClosableOverlayType.ClosedGroup; let title; let buttonText; @@ -165,8 +156,7 @@ export class SessionClosableOverlay extends React.Component<Props, State> { const contacts = this.getContacts(); const noContactsForClosedGroup = - overlayMode === SessionClosableOverlayType.ClosedGroup && - contacts.length === 0; + overlayMode === SessionClosableOverlayType.ClosedGroup && contacts.length === 0; const showLoadingSpinner = showSpinner === undefined ? false : showSpinner; @@ -234,9 +224,7 @@ export class SessionClosableOverlay extends React.Component<Props, State> { </> )} - {descriptionLong && ( - <div className="session-description-long">{descriptionLong}</div> - )} + {descriptionLong && <div className="session-description-long">{descriptionLong}</div>} {isMessageView && false && <h4>{window.i18n('or')}</h4>} {/* FIXME enable back those two items when they are working */} {isMessageView && false && ( @@ -249,16 +237,10 @@ export class SessionClosableOverlay extends React.Component<Props, State> { /> )} - {isAddContactView && ( - <PillDivider text={window.i18n('yourSessionID')} /> - )} + {isAddContactView && <PillDivider text={window.i18n('yourSessionID')} />} {isAddContactView && ( - <SessionIdEditable - editable={false} - placeholder="" - text={ourSessionID} - /> + <SessionIdEditable editable={false} placeholder="" text={ourSessionID} /> )} <SessionButton diff --git a/ts/components/session/SessionConfirm.tsx b/ts/components/session/SessionConfirm.tsx index 42ab6b7ffc564811688d2a7d01eb4ccee58fea32..8c567bdc4dc62f88fe767efbd4424f0800c3cbea 100644 --- a/ts/components/session/SessionConfirm.tsx +++ b/ts/components/session/SessionConfirm.tsx @@ -56,20 +56,12 @@ const SessionConfirmInner = (props: Props) => { <div className="session-modal__centered"> {sessionIcon && iconSize && ( <> - <SessionIcon - iconType={sessionIcon} - iconSize={iconSize} - theme={props.theme} - /> + <SessionIcon iconType={sessionIcon} iconSize={iconSize} theme={props.theme} /> <div className="spacer-lg" /> </> )} - <SessionHtmlRenderer - tag="span" - className={messageSubText} - html={message} - /> + <SessionHtmlRenderer tag="span" className={messageSubText} html={message} /> <SessionHtmlRenderer tag="span" className="session-confirm-sub-message subtle" @@ -78,18 +70,10 @@ const SessionConfirmInner = (props: Props) => { </div> <div className="session-modal__button-group"> - <SessionButton - text={okText} - buttonColor={okTheme} - onClick={onClickOk} - /> + <SessionButton text={okText} buttonColor={okTheme} onClick={onClickOk} /> {!hideCancel && ( - <SessionButton - text={cancelText} - buttonColor={closeTheme} - onClick={onClickClose} - /> + <SessionButton text={cancelText} buttonColor={closeTheme} onClick={onClickClose} /> )} </div> </SessionModal> diff --git a/ts/components/session/SessionDropdown.tsx b/ts/components/session/SessionDropdown.tsx index 3487f9f903ddef485e66a473a0279313f91d301b..4c6e0a93fffd752685ad66687d626f5cb00d0f9b 100644 --- a/ts/components/session/SessionDropdown.tsx +++ b/ts/components/session/SessionDropdown.tsx @@ -2,10 +2,7 @@ import React, { useContext, useState } from 'react'; import { ThemeContext } from 'styled-components'; import { SessionIcon, SessionIconSize, SessionIconType } from './icon/'; -import { - SessionDropdownItem, - SessionDropDownItemType, -} from './SessionDropdownItem'; +import { SessionDropdownItem, SessionDropDownItemType } from './SessionDropdownItem'; // THIS IS DROPDOWN ACCORDIAN STYLE OPTIONS SELECTOR ELEMENT, NOT A CONTEXTMENU diff --git a/ts/components/session/SessionDropdownItem.tsx b/ts/components/session/SessionDropdownItem.tsx index 052a8c0c9351853e3b0039373d738bb324be1f89..c9c72ba596ae1577de4d4efc845198a307ed2c16 100644 --- a/ts/components/session/SessionDropdownItem.tsx +++ b/ts/components/session/SessionDropdownItem.tsx @@ -38,15 +38,7 @@ export const SessionDropdownItem = (props: Props) => { role="button" onClick={clickHandler} > - {icon ? ( - <SessionIcon - iconType={icon} - iconSize={SessionIconSize.Small} - theme={theme} - /> - ) : ( - '' - )} + {icon ? <SessionIcon iconType={icon} iconSize={SessionIconSize.Small} theme={theme} /> : ''} <div className="item-content">{content}</div> </div> ); diff --git a/ts/components/session/SessionHTMLRenderer.tsx b/ts/components/session/SessionHTMLRenderer.tsx index 438213be5eb1da0ca92897b78627f1e25521ad45..da0310f724d1f95302b02c673903a04f71d091c8 100644 --- a/ts/components/session/SessionHTMLRenderer.tsx +++ b/ts/components/session/SessionHTMLRenderer.tsx @@ -11,12 +11,7 @@ interface ReceivedProps { // Needed because of https://github.com/microsoft/tslint-microsoft-contrib/issues/339 type Props = ReceivedProps; -export const SessionHtmlRenderer: React.SFC<Props> = ({ - tag = 'div', - key, - html, - className, -}) => { +export const SessionHtmlRenderer: React.SFC<Props> = ({ tag = 'div', key, html, className }) => { const clean = DOMPurify.sanitize(html, { USE_PROFILES: { html: true }, FORBID_ATTR: ['script'], diff --git a/ts/components/session/SessionIDResetDialog.tsx b/ts/components/session/SessionIDResetDialog.tsx index 4763f86a74530b4698ba639235537564faae42be..f5a2d36beb6b83d2f2ea948335f82c611a58e40b 100644 --- a/ts/components/session/SessionIDResetDialog.tsx +++ b/ts/components/session/SessionIDResetDialog.tsx @@ -18,11 +18,7 @@ const SessionIDResetDialogInner = (props: Props) => { Your existing contacts and conversations will be lost, but you’ll be able to use Session knowing you have the best privacy and security possible.'; return ( - <SessionModal - title="Mandatory Upgrade Session ID" - onClose={() => null} - theme={props.theme} - > + <SessionModal title="Mandatory Upgrade Session ID" onClose={() => null} theme={props.theme}> <div className="spacer-sm" /> <div className="session-modal__centered text-center"> <SessionIcon diff --git a/ts/components/session/SessionIdEditable.tsx b/ts/components/session/SessionIdEditable.tsx index ff46691ff59a40a03944838d23dea1dbf2c16d97..a3ba8da84bf9e54b8427839208bf495a66ec817d 100644 --- a/ts/components/session/SessionIdEditable.tsx +++ b/ts/components/session/SessionIdEditable.tsx @@ -29,27 +29,15 @@ export class SessionIdEditable extends React.PureComponent<Props> { } public render() { - const { - placeholder, - editable, - text, - value, - maxLength, - isGroup, - } = this.props; + const { placeholder, editable, text, value, maxLength, isGroup } = this.props; return ( <div - className={classNames( - 'session-id-editable', - !editable && 'session-id-editable-disabled' - )} + className={classNames('session-id-editable', !editable && 'session-id-editable-disabled')} > <textarea className={classNames( - isGroup - ? 'group-id-editable-textarea' - : 'session-id-editable-textarea' + isGroup ? 'group-id-editable-textarea' : 'session-id-editable-textarea' )} ref={this.inputRef} placeholder={placeholder} diff --git a/ts/components/session/SessionInboxView.tsx b/ts/components/session/SessionInboxView.tsx index b12e042a7ff245e4238ce2f46410b9dbe57cbbf8..c5a7b20f9f122084e2ffe6cc4fd0a35daad059e1 100644 --- a/ts/components/session/SessionInboxView.tsx +++ b/ts/components/session/SessionInboxView.tsx @@ -63,8 +63,8 @@ export class SessionInboxView extends React.Component<any, State> { private async setupLeftPane() { // Here we set up a full redux store with initial state for our LeftPane Root const convoCollection = ConversationController.getInstance().getConversations(); - const conversations = convoCollection.map( - (conversation: ConversationModel) => conversation.getProps() + const conversations = convoCollection.map((conversation: ConversationModel) => + conversation.getProps() ); const filledConversations = conversations.map((conv: any) => { @@ -91,10 +91,7 @@ export class SessionInboxView extends React.Component<any, State> { window.inboxStore = this.store; // Enables our redux store to be updated by backbone events in the outside world - const { messageExpired } = bindActionCreators( - conversationActions, - this.store.dispatch - ); + const { messageExpired } = bindActionCreators(conversationActions, this.store.dispatch); window.actionsCreators = conversationActions; // messageExpired is currently inboked fropm js. So we link it to Redux that way diff --git a/ts/components/session/SessionInput.tsx b/ts/components/session/SessionInput.tsx index 21223668952193121e1d432acab2abaa66d93c5f..9a9a35196f6eab5a353a6e841c42be05c9e9b467 100644 --- a/ts/components/session/SessionInput.tsx +++ b/ts/components/session/SessionInput.tsx @@ -38,15 +38,7 @@ export class SessionInput extends React.PureComponent<Props, State> { } public render() { - const { - autoFocus, - placeholder, - type, - value, - maxLength, - enableShowHide, - error, - } = this.props; + const { autoFocus, placeholder, type, value, maxLength, enableShowHide, error } = this.props; const { forceShow } = this.state; const correctType = forceShow ? 'text' : type; @@ -64,9 +56,7 @@ export class SessionInput extends React.PureComponent<Props, State> { onChange={e => { this.updateInputValue(e); }} - className={classNames( - enableShowHide ? 'session-input-floating-label-show-hide' : '' - )} + className={classNames(enableShowHide ? 'session-input-floating-label-show-hide' : '')} // just incase onChange isn't triggered onBlur={e => { this.updateInputValue(e); @@ -109,9 +99,7 @@ export class SessionInput extends React.PureComponent<Props, State> { return ( <label htmlFor="session-input-floating-label" - className={classNames( - 'session-input-with-label-container filled error' - )} + className={classNames('session-input-with-label-container filled error')} > {error} </label> diff --git a/ts/components/session/SessionMemberListItem.tsx b/ts/components/session/SessionMemberListItem.tsx index 9d38227e10f9dd014b3a5e6e3d0fc11a6a464595..550511a375515e22763cdc9e1074b199a6abb18e 100644 --- a/ts/components/session/SessionMemberListItem.tsx +++ b/ts/components/session/SessionMemberListItem.tsx @@ -44,8 +44,7 @@ class SessionMemberListItemInner extends React.Component<Props> { public render() { const { isSelected, member } = this.props; - const name = - member.authorProfileName || PubKey.shorten(member.authorPhoneNumber); + const name = member.authorProfileName || PubKey.shorten(member.authorPhoneNumber); return ( <div @@ -58,17 +57,10 @@ class SessionMemberListItemInner extends React.Component<Props> { role="button" > <div className="session-member-item__info"> - <span className="session-member-item__avatar"> - {this.renderAvatar()} - </span> + <span className="session-member-item__avatar">{this.renderAvatar()}</span> <span className="session-member-item__name">{name}</span> </div> - <span - className={classNames( - 'session-member-item__checkmark', - isSelected && 'selected' - )} - > + <span className={classNames('session-member-item__checkmark', isSelected && 'selected')}> <SessionIcon iconType={SessionIconType.Check} iconSize={SessionIconSize.Medium} diff --git a/ts/components/session/SessionModal.tsx b/ts/components/session/SessionModal.tsx index 84856a2199431b36dbf70ecadc526686d1395aee..31a850a0d3e584bc14730019b8971fa666dd03a0 100644 --- a/ts/components/session/SessionModal.tsx +++ b/ts/components/session/SessionModal.tsx @@ -69,25 +69,14 @@ export class SessionModal extends React.PureComponent<Props, State> { }; public render() { - const { - title, - headerIconButtons, - showExitIcon, - showHeader, - headerReverse, - } = this.props; + const { title, headerIconButtons, showExitIcon, showHeader, headerReverse } = this.props; const { isVisible } = this.state; return isVisible ? ( <div ref={node => (this.node = node)} className={'session-modal'}> {showHeader ? ( <> - <div - className={classNames( - 'session-modal__header', - headerReverse && 'reverse' - )} - > + <div className={classNames('session-modal__header', headerReverse && 'reverse')}> <div className="session-modal__header__close"> {showExitIcon ? ( <SessionIconButton diff --git a/ts/components/session/SessionPasswordModal.tsx b/ts/components/session/SessionPasswordModal.tsx index 64c4872eb9a66fc8302e5fc09785ee3ea5aebe7c..2df85324dbcfdec0b40bf7a622af7ffb8e62941e 100644 --- a/ts/components/session/SessionPasswordModal.tsx +++ b/ts/components/session/SessionPasswordModal.tsx @@ -62,9 +62,7 @@ class SessionPasswordModalInner extends React.Component<Props, State> { : [window.i18n('enterPassword'), window.i18n('confirmPassword')]; const confirmButtonColor = - action === PasswordAction.Remove - ? SessionButtonColor.Danger - : SessionButtonColor.Primary; + action === PasswordAction.Remove ? SessionButtonColor.Danger : SessionButtonColor.Primary; return ( <SessionModal @@ -104,10 +102,7 @@ class SessionPasswordModalInner extends React.Component<Props, State> { onClick={this.setPassword} /> - <SessionButton - text={window.i18n('cancel')} - onClick={this.closeDialog} - /> + <SessionButton text={window.i18n('cancel')} onClick={this.closeDialog} /> </div> </SessionModal> ); @@ -144,10 +139,7 @@ class SessionPasswordModalInner extends React.Component<Props, State> { */ private validatePassword(firstPassword: string) { // if user did not fill the first password field, we can't do anything - const errorFirstInput = PasswordUtil.validatePassword( - firstPassword, - window.i18n - ); + const errorFirstInput = PasswordUtil.validatePassword(firstPassword, window.i18n); if (errorFirstInput !== null) { this.setState({ error: errorFirstInput, @@ -157,10 +149,7 @@ class SessionPasswordModalInner extends React.Component<Props, State> { return true; } - private async handleActionSet( - enteredPassword: string, - enteredPasswordConfirm: string - ) { + private async handleActionSet(enteredPassword: string, enteredPasswordConfirm: string) { // be sure both password are valid if (!this.validatePassword(enteredPassword)) { return; @@ -191,9 +180,7 @@ class SessionPasswordModalInner extends React.Component<Props, State> { if (!this.validatePassword(newPassword)) { return; } - const isValidWithStoredInDB = Boolean( - await this.validatePasswordHash(oldPassword) - ); + const isValidWithStoredInDB = Boolean(await this.validatePasswordHash(oldPassword)); if (!isValidWithStoredInDB) { this.setState({ error: window.i18n('changePasswordInvalid'), @@ -215,9 +202,7 @@ class SessionPasswordModalInner extends React.Component<Props, State> { private async handleActionRemove(oldPassword: string) { // We don't validate oldPassword on change: this is validate on the validatePasswordHash below - const isValidWithStoredInDB = Boolean( - await this.validatePasswordHash(oldPassword) - ); + const isValidWithStoredInDB = Boolean(await this.validatePasswordHash(oldPassword)); if (!isValidWithStoredInDB) { this.setState({ error: window.i18n('removePasswordInvalid'), @@ -239,10 +224,7 @@ class SessionPasswordModalInner extends React.Component<Props, State> { // tslint:disable-next-line: cyclomatic-complexity private async setPassword() { const { action } = this.props; - const { - currentPasswordEntered, - currentPasswordConfirmEntered, - } = this.state; + const { currentPasswordEntered, currentPasswordConfirmEntered } = this.state; const { Set, Remove, Change } = PasswordAction; // Trim leading / trailing whitespace for UX @@ -255,10 +237,7 @@ class SessionPasswordModalInner extends React.Component<Props, State> { return; } case Change: { - await this.handleActionChange( - firstPasswordEntered, - secondPasswordEntered - ); + await this.handleActionChange(firstPasswordEntered, secondPasswordEntered); return; } case Remove: { diff --git a/ts/components/session/SessionPasswordPrompt.tsx b/ts/components/session/SessionPasswordPrompt.tsx index 250731b7cc66aeaf6480694d241344bf2add2fca..bb14be962999112876b20eb5858d2de63f584df2 100644 --- a/ts/components/session/SessionPasswordPrompt.tsx +++ b/ts/components/session/SessionPasswordPrompt.tsx @@ -2,11 +2,7 @@ import React from 'react'; import classNames from 'classnames'; import { SessionIcon, SessionIconType } from './icon'; -import { - SessionButton, - SessionButtonColor, - SessionButtonType, -} from './SessionButton'; +import { SessionButton, SessionButtonColor, SessionButtonType } from './SessionButton'; import { Constants } from '../../session'; import { DefaultTheme, withTheme } from 'styled-components'; @@ -18,10 +14,7 @@ interface State { export const MAX_LOGIN_TRIES = 3; -class SessionPasswordPromptInner extends React.PureComponent< - { theme: DefaultTheme }, - State -> { +class SessionPasswordPromptInner extends React.PureComponent<{ theme: DefaultTheme }, State> { private readonly inputRef: React.RefObject<HTMLInputElement>; constructor(props: any) { @@ -54,9 +47,7 @@ class SessionPasswordPromptInner extends React.PureComponent< const containerClass = this.state.clearDataView ? 'clear-data-container' : 'password-prompt-container'; - const infoAreaClass = this.state.clearDataView - ? 'warning-info-area' - : 'password-info-area'; + const infoAreaClass = this.state.clearDataView ? 'warning-info-area' : 'password-info-area'; const infoTitle = this.state.clearDataView ? window.i18n('clearAllData') : window.i18n('passwordViewTitle'); @@ -95,9 +86,7 @@ class SessionPasswordPromptInner extends React.PureComponent< {this.state.error && ( <> {showResetElements ? ( - <div className="session-label warning"> - {window.i18n('maxPasswordAttempts')} - </div> + <div className="session-label warning">{window.i18n('maxPasswordAttempts')}</div> ) : ( <div className="session-label primary">{this.state.error}</div> )} @@ -149,9 +138,7 @@ class SessionPasswordPromptInner extends React.PureComponent< } private async initLogin() { - const passPhrase = String( - (this.inputRef.current as HTMLInputElement).value - ); + const passPhrase = String((this.inputRef.current as HTMLInputElement).value); await this.onLogin(passPhrase); } diff --git a/ts/components/session/SessionProgress.tsx b/ts/components/session/SessionProgress.tsx index b3e94ac1c990f29935a4979d98dc232d9a6caf21..fcaad12da84bbd07cd3279174e4536d2a01b6afb 100644 --- a/ts/components/session/SessionProgress.tsx +++ b/ts/components/session/SessionProgress.tsx @@ -57,8 +57,7 @@ export class SessionProgress extends React.PureComponent<Props, State> { const failureColor = Constants.UI.COLORS.DANGER_ALT; const backgroundColor = sendStatus === -1 ? failureColor : successColor; - const shiftDurationMs = - this.getShiftDuration(this.props.value, prevValue) * 1000; + const shiftDurationMs = this.getShiftDuration(this.props.value, prevValue) * 1000; const showDurationMs = 500; const showOffsetMs = shiftDurationMs + 500; diff --git a/ts/components/session/SessionSearchInput.tsx b/ts/components/session/SessionSearchInput.tsx index 73fc1c6dfa7e72c43226160ac92a1ac608459dc8..ab79b5e3af19c76a445aad9569cc525d8c66ffdc 100644 --- a/ts/components/session/SessionSearchInput.tsx +++ b/ts/components/session/SessionSearchInput.tsx @@ -45,22 +45,12 @@ export class SessionSearchInput extends React.Component<Props> { /> </div> <Menu id={triggerId} animation={animation.fade}> - <Item onClick={() => document.execCommand('undo')}> - {window.i18n('editMenuUndo')} - </Item> - <Item onClick={() => document.execCommand('redo')}> - {window.i18n('editMenuRedo')} - </Item> + <Item onClick={() => document.execCommand('undo')}>{window.i18n('editMenuUndo')}</Item> + <Item onClick={() => document.execCommand('redo')}>{window.i18n('editMenuRedo')}</Item> <hr /> - <Item onClick={() => document.execCommand('cut')}> - {window.i18n('editMenuCut')} - </Item> - <Item onClick={() => document.execCommand('copy')}> - {window.i18n('editMenuCopy')} - </Item> - <Item onClick={() => document.execCommand('paste')}> - {window.i18n('editMenuPaste')} - </Item> + <Item onClick={() => document.execCommand('cut')}>{window.i18n('editMenuCut')}</Item> + <Item onClick={() => document.execCommand('copy')}>{window.i18n('editMenuCopy')}</Item> + <Item onClick={() => document.execCommand('paste')}>{window.i18n('editMenuPaste')}</Item> <Item onClick={() => document.execCommand('selectAll')}> {window.i18n('editMenuSelectAll')} </Item> diff --git a/ts/components/session/SessionSeedModal.tsx b/ts/components/session/SessionSeedModal.tsx index 0b7000c3118e1c7f4f19661ebf36ff9ab5ccebed..691672556bf2532fb46bdeec2d1ab97d17814d61 100644 --- a/ts/components/session/SessionSeedModal.tsx +++ b/ts/components/session/SessionSeedModal.tsx @@ -123,23 +123,14 @@ class SessionSeedModalInner extends React.Component<Props, State> { return ( <> <div className="session-modal__centered text-center"> - <p className="session-modal__description"> - {i18n('recoveryPhraseSavePromptMain')} - </p> + <p className="session-modal__description">{i18n('recoveryPhraseSavePromptMain')}</p> <div className="spacer-xs" /> - <i className="session-modal__text-highlight"> - {this.state.recoveryPhrase} - </i> + <i className="session-modal__text-highlight">{this.state.recoveryPhrase}</i> </div> <div className="spacer-lg" /> <div className="qr-image"> - <QRCode - value={hexEncodedSeed} - bgColor={bgColor} - fgColor={fgColor} - level="L" - /> + <QRCode value={hexEncodedSeed} bgColor={bgColor} fgColor={fgColor} level="L" /> </div> <div className="spacer-lg" /> <div className="session-modal__button-group"> @@ -157,10 +148,7 @@ class SessionSeedModalInner extends React.Component<Props, State> { private confirmPassword() { const passwordHash = this.state.passwordHash; const passwordValue = jQuery('#seed-input-password').val(); - const isPasswordValid = PasswordUtil.matchesHash( - passwordValue as string, - passwordHash - ); + const isPasswordValid = PasswordUtil.matchesHash(passwordValue as string, passwordHash); if (!passwordValue) { this.setState({ diff --git a/ts/components/session/SessionToast.tsx b/ts/components/session/SessionToast.tsx index e3621a08dbcbc2303dcf611e6ca9916ac7a20d8c..dd2a70745f0f353596bdfbc22866d4fac68f66e9 100644 --- a/ts/components/session/SessionToast.tsx +++ b/ts/components/session/SessionToast.tsx @@ -50,9 +50,7 @@ export const SessionToast = (props: Props) => { const theme = useContext(ThemeContext); const toastDesc = description ? description : ''; - const toastIconSize = toastDesc - ? SessionIconSize.Huge - : SessionIconSize.Medium; + const toastIconSize = toastDesc ? SessionIconSize.Huge : SessionIconSize.Medium; // Set a custom icon or allow the theme to define the icon let toastIcon = icon || undefined; @@ -77,17 +75,9 @@ export const SessionToast = (props: Props) => { return ( // tslint:disable-next-line: use-simple-attributes - <Flex - container={true} - alignItems="center" - onClick={props?.onToastClick || noop} - > + <Flex container={true} alignItems="center" onClick={props?.onToastClick || noop}> <IconDiv> - <SessionIcon - iconType={toastIcon} - iconSize={toastIconSize} - theme={theme} - /> + <SessionIcon iconType={toastIcon} iconSize={toastIconSize} theme={theme} /> </IconDiv> <Flex container={true} diff --git a/ts/components/session/SessionToastContainer.tsx b/ts/components/session/SessionToastContainer.tsx index 360cde0a4fafe5600a2332b21f26b9bbf534d521..0846aa5b7078915954d17fd73cfd58127d77b81d 100644 --- a/ts/components/session/SessionToastContainer.tsx +++ b/ts/components/session/SessionToastContainer.tsx @@ -30,11 +30,9 @@ const WrappedToastContainer = ({ ); // tslint:disable-next-line: no-default-export -export const SessionToastContainer = styled(SessionToastContainerPrivate).attrs( - { - // custom props - } -)` +export const SessionToastContainer = styled(SessionToastContainerPrivate).attrs({ + // custom props +})` .Toastify__toast-container { } .Toastify__toast { diff --git a/ts/components/session/SessionToggle.tsx b/ts/components/session/SessionToggle.tsx index e569789731fd3330a42a3e0652127d5954700ed4..b9d79625e7bb1bffbf7236215e498fb4a0822397 100644 --- a/ts/components/session/SessionToggle.tsx +++ b/ts/components/session/SessionToggle.tsx @@ -39,10 +39,7 @@ export class SessionToggle extends React.PureComponent<Props, State> { public render() { return ( <div - className={classNames( - 'session-toggle', - this.state.active ? 'active' : '' - )} + className={classNames('session-toggle', this.state.active ? 'active' : '')} role="button" onClick={this.clickHandler} > diff --git a/ts/components/session/UserSearchDropdown.tsx b/ts/components/session/UserSearchDropdown.tsx index 6d03bb59775824e9cf24016082133d1f01bf36b7..c6b3949dbb0b1eec2752728565693ecb6c4e0404 100644 --- a/ts/components/session/UserSearchDropdown.tsx +++ b/ts/components/session/UserSearchDropdown.tsx @@ -52,14 +52,8 @@ export class UserSearchDropdown extends React.Component<Props, State> { this.setState(prevState => ({ selectedContact: +prevState.selectedContact + 1, })); - } else if ( - e.key === 'Enter' && - searchResults && - searchResults.contacts.length > 0 - ) { - this.handleContactSelected( - searchResults.contacts[selectedContact].phoneNumber - ); + } else if (e.key === 'Enter' && searchResults && searchResults.contacts.length > 0) { + this.handleContactSelected(searchResults.contacts[selectedContact].phoneNumber); } } diff --git a/ts/components/session/conversation/SessionCompositionBox.tsx b/ts/components/session/conversation/SessionCompositionBox.tsx index 3c7882fe9ffc27d611ec8efab8a9e4a20d153c20..055bd7b71326e4240df720e20ee9dc1621617634 100644 --- a/ts/components/session/conversation/SessionCompositionBox.tsx +++ b/ts/components/session/conversation/SessionCompositionBox.tsx @@ -161,15 +161,10 @@ export class SessionCompositionBox extends React.Component<Props, State> { } public componentDidUpdate(prevProps: Props, _prevState: State) { // reset the state on new conversation key - if ( - prevProps.selectedConversationKey !== this.props.selectedConversationKey - ) { + if (prevProps.selectedConversationKey !== this.props.selectedConversationKey) { this.setState(getDefaultState(), this.focusCompositionBox); this.lastBumpTypingMessageLength = 0; - } else if ( - this.props.stagedAttachments?.length !== - prevProps.stagedAttachments?.length - ) { + } else if (this.props.stagedAttachments?.length !== prevProps.stagedAttachments?.length) { // if number of staged attachment changed, focus the composition box for a more natural UI this.focusCompositionBox(); } @@ -184,9 +179,7 @@ export class SessionCompositionBox extends React.Component<Props, State> { {this.renderStagedLinkPreview()} {this.renderAttachmentsStaged()} <div className="composition-container"> - {showRecordingView - ? this.renderRecordingView() - : this.renderCompositionView()} + {showRecordingView ? this.renderRecordingView() : this.renderCompositionView()} </div> </Flex> ); @@ -304,16 +297,9 @@ export class SessionCompositionBox extends React.Component<Props, State> { </div> {typingEnabled && ( - <div - ref={ref => (this.emojiPanel = ref)} - onKeyDown={this.onKeyDown} - role="button" - > + <div ref={ref => (this.emojiPanel = ref)} onKeyDown={this.onKeyDown} role="button"> {showEmojiPanel && ( - <SessionEmojiPanel - onEmojiClicked={this.onEmojiClick} - show={showEmojiPanel} - /> + <SessionEmojiPanel onEmojiClicked={this.onEmojiClick} show={showEmojiPanel} /> )} </div> )} @@ -360,13 +346,7 @@ export class SessionCompositionBox extends React.Component<Props, State> { // this is only for the composition box visible content. The real stuff on the backend box is the @markup displayTransform={(_id, display) => `@${display}`} data={this.fetchUsersForGroup} - renderSuggestion={( - suggestion, - _search, - _highlightedDisplay, - _index, - focused - ) => ( + renderSuggestion={(suggestion, _search, _highlightedDisplay, _index, focused) => ( <SessionMemberListItem theme={theme} isSelected={focused} @@ -410,9 +390,7 @@ export class SessionCompositionBox extends React.Component<Props, State> { members .filter(d => !!d) .filter(d => d.authorProfileName !== 'Anonymous') - .filter(d => - d.authorProfileName?.toLowerCase()?.includes(query.toLowerCase()) - ) + .filter(d => d.authorProfileName?.toLowerCase()?.includes(query.toLowerCase())) ) // Transform the users to what react-mentions expects .then(members => { @@ -452,8 +430,7 @@ export class SessionCompositionBox extends React.Component<Props, State> { .filter(d => !!d) .filter( d => - d.authorProfileName?.toLowerCase()?.includes(query.toLowerCase()) || - !d.authorProfileName + d.authorProfileName?.toLowerCase()?.includes(query.toLowerCase()) || !d.authorProfileName ); // Transform the users to what react-mentions expects @@ -478,10 +455,7 @@ export class SessionCompositionBox extends React.Component<Props, State> { return <></>; } // we try to match the first link found in the current message - const links = window.Signal.LinkPreviews.findLinks( - this.state.message, - undefined - ); + const links = window.Signal.LinkPreviews.findLinks(this.state.message, undefined); if (!links || links.length === 0 || ignoredLink === links[0]) { return <></>; } @@ -500,13 +474,7 @@ export class SessionCompositionBox extends React.Component<Props, State> { return <></>; } - const { - isLoaded, - title, - description, - domain, - image, - } = this.state.stagedLinkPreview; + const { isLoaded, title, description, domain, image } = this.state.stagedLinkPreview; return ( <SessionStagedLinkPreview @@ -564,19 +532,14 @@ export class SessionCompositionBox extends React.Component<Props, State> { } // we finished loading the preview, and checking the abortConrtoller, we are still not aborted. // => update the staged preview - if ( - this.linkPreviewAbortController && - !this.linkPreviewAbortController.signal.aborted - ) { + if (this.linkPreviewAbortController && !this.linkPreviewAbortController.signal.aborted) { this.setState({ stagedLinkPreview: { isLoaded: true, title: ret?.title || null, description: ret?.description || '', url: ret?.url || null, - domain: - (ret?.url && window.Signal.LinkPreviews.getDomain(ret.url)) || - '', + domain: (ret?.url && window.Signal.LinkPreviews.getDomain(ret.url)) || '', image, }, }); @@ -764,27 +727,19 @@ export class SessionCompositionBox extends React.Component<Props, State> { let replacedMentions = text; (matches || []).forEach(match => { const replacedMention = match.substring(2, match.indexOf(':')); - replacedMentions = replacedMentions.replace( - match, - `@${replacedMention}` - ); + replacedMentions = replacedMentions.replace(match, `@${replacedMention}`); }); return replacedMentions; }; - const messagePlaintext = cleanMentions( - this.parseEmojis(this.state.message) - ); + const messagePlaintext = cleanMentions(this.parseEmojis(this.state.message)); const { isBlocked, isPrivate, left, isKickedFromGroup } = this.props; // deny sending of message if our app version is expired if (window.extension.expiredStatus() === true) { - ToastUtils.pushToastError( - 'expiredWarning', - window.i18n('expiredWarning') - ); + ToastUtils.pushToastError('expiredWarning', window.i18n('expiredWarning')); return; } @@ -842,9 +797,7 @@ export class SessionCompositionBox extends React.Component<Props, State> { const linkPreviews = (stagedLinkPreview && stagedLinkPreview.isLoaded && - stagedLinkPreview.title?.length && [ - _.pick(stagedLinkPreview, 'url', 'image', 'title'), - ]) || + stagedLinkPreview.title?.length && [_.pick(stagedLinkPreview, 'url', 'image', 'title')]) || []; try { diff --git a/ts/components/session/conversation/SessionConversation.tsx b/ts/components/session/conversation/SessionConversation.tsx index 430a107cb16ec249fded2eb61988d3a3b4f81047..4553890c15a3b5fd4285d567926b736c3d4c2274 100644 --- a/ts/components/session/conversation/SessionConversation.tsx +++ b/ts/components/session/conversation/SessionConversation.tsx @@ -4,10 +4,7 @@ import React from 'react'; import classNames from 'classnames'; -import { - SessionCompositionBox, - StagedAttachmentType, -} from './SessionCompositionBox'; +import { SessionCompositionBox, StagedAttachmentType } from './SessionCompositionBox'; import { Constants } from '../../../session'; import _ from 'lodash'; @@ -29,10 +26,7 @@ import { MessageView } from '../../MainViewController'; import { pushUnblockToSend } from '../../../session/utils/Toast'; import { MessageDetail } from '../../conversation/MessageDetail'; import { ConversationController } from '../../../session/conversations'; -import { - getMessageById, - getPubkeysInPublicConversation, -} from '../../../data/data'; +import { getMessageById, getPubkeysInPublicConversation } from '../../../data/data'; import autoBind from 'auto-bind'; import { getDecryptedMediaUrl } from '../../../session/crypto/DecryptedAttachmentsManager'; @@ -121,11 +115,7 @@ export class SessionConversation extends React.Component<Props, State> { const { selectedConversationKey: oldConversationKey } = prevProps; // if the convo is valid, and it changed, register for drag events - if ( - newConversationKey && - newConversation && - newConversationKey !== oldConversationKey - ) { + if (newConversationKey && newConversation && newConversationKey !== oldConversationKey) { // Pause thread to wait for rendering to complete setTimeout(() => { const div = this.messageContainerRef.current; @@ -145,10 +135,7 @@ export class SessionConversation extends React.Component<Props, State> { if (newConversation.isPublic) { // TODO use abort controller to stop those requests too void this.updateMemberList(); - this.publicMembersRefreshTimeout = global.setInterval( - this.updateMemberList, - 10000 - ); + this.publicMembersRefreshTimeout = global.setInterval(this.updateMemberList, 10000); } } // if we do not have a model, unregister for events @@ -205,20 +192,13 @@ export class SessionConversation extends React.Component<Props, State> { } = this.state; const selectionMode = !!selectedMessages.length; - const { - selectedConversation, - selectedConversationKey, - messages, - actions, - } = this.props; + const { selectedConversation, selectedConversationKey, messages, actions } = this.props; if (!selectedConversation || !messages) { // return an empty message view return <MessageView />; } - const conversationModel = ConversationController.getInstance().get( - selectedConversationKey - ); + const conversationModel = ConversationController.getInstance().get(selectedConversationKey); // TODO VINCE: OPTIMISE FOR NEW SENDING??? const sendMessageFn = ( body: any, @@ -230,13 +210,7 @@ export class SessionConversation extends React.Component<Props, State> { if (!conversationModel) { return; } - void conversationModel.sendMessage( - body, - attachments, - quote, - preview, - groupInvitation - ); + void conversationModel.sendMessage(body, attachments, quote, preview, groupInvitation); if (this.messageContainerRef.current) { // force scrolling to bottom on message sent // this will mark all messages as read, and reset the conversation unreadCount @@ -263,23 +237,13 @@ export class SessionConversation extends React.Component<Props, State> { <div // if you change the classname, also update it on onKeyDown - className={classNames( - 'conversation-content', - selectionMode && 'selection-mode' - )} + className={classNames('conversation-content', selectionMode && 'selection-mode')} tabIndex={0} onKeyDown={this.onKeyDown} role="navigation" > - <div - className={classNames( - 'conversation-info-panel', - showMessageDetails && 'show' - )} - > - {showMessageDetails && ( - <MessageDetail {...messageDetailShowProps} /> - )} + <div className={classNames('conversation-info-panel', showMessageDetails && 'show')}> + {showMessageDetails && <MessageDetail {...messageDetailShowProps} />} </div> {lightBoxOptions?.media && this.renderLightBox(lightBoxOptions)} @@ -287,9 +251,7 @@ export class SessionConversation extends React.Component<Props, State> { <div className="conversation-messages"> <SessionMessagesList {...this.getMessagesListProps()} /> - {showRecordingView && ( - <div className="conversation-messages__blocking-overlay" /> - )} + {showRecordingView && <div className="conversation-messages__blocking-overlay" />} {isDraggingFile && <SessionFileDropzone />} </div> @@ -322,12 +284,7 @@ export class SessionConversation extends React.Component<Props, State> { /> </div> - <div - className={classNames( - 'conversation-item__options-pane', - showOptionsPane && 'show' - )} - > + <div className={classNames('conversation-item__options-pane', showOptionsPane && 'show')}> <SessionRightPanelWithDetails {...this.getRightPanelProps()} /> </div> </SessionTheme> @@ -349,9 +306,7 @@ export class SessionConversation extends React.Component<Props, State> { if (!selectedConversation) { return; } - const conversationModel = ConversationController.getInstance().get( - selectedConversationKey - ); + const conversationModel = ConversationController.getInstance().get(selectedConversationKey); const unreadCount = await conversationModel.getUnreadCount(); const messagesToFetch = Math.max( Constants.CONVERSATION.DEFAULT_MESSAGE_FETCH_COUNT, @@ -366,9 +321,7 @@ export class SessionConversation extends React.Component<Props, State> { public getHeaderProps() { const { selectedConversationKey, ourNumber } = this.props; const { selectedMessages, messageDetailShowProps } = this.state; - const conversation = ConversationController.getInstance().getOrThrow( - selectedConversationKey - ); + const conversation = ConversationController.getInstance().getOrThrow(selectedConversationKey); const expireTimer = conversation.get('expireTimer'); const expirationSettingName = expireTimer ? window.Whisper.ExpirationTimerOptions.getName(expireTimer || 0) @@ -487,9 +440,7 @@ export class SessionConversation extends React.Component<Props, State> { public getRightPanelProps() { const { selectedConversationKey } = this.props; - const conversation = ConversationController.getInstance().getOrThrow( - selectedConversationKey - ); + const conversation = ConversationController.getInstance().getOrThrow(selectedConversationKey); const ourPrimary = window.storage.get('primaryDevicePubKey'); const members = conversation.get('members') || []; @@ -602,16 +553,9 @@ export class SessionConversation extends React.Component<Props, State> { this.updateSendingProgress(100, -1); } - public async deleteMessagesById( - messageIds: Array<string>, - askUserForConfirmation: boolean - ) { + public async deleteMessagesById(messageIds: Array<string>, askUserForConfirmation: boolean) { // Get message objects - const { - selectedConversationKey, - selectedConversation, - messages, - } = this.props; + const { selectedConversationKey, selectedConversation, messages } = this.props; const conversationModel = ConversationController.getInstance().getOrThrow( selectedConversationKey @@ -637,9 +581,7 @@ export class SessionConversation extends React.Component<Props, State> { ? window.i18n('deleteMultiplePublicWarning') : window.i18n('deletePublicWarning'); } - return multiple - ? window.i18n('deleteMultipleWarning') - : window.i18n('deleteWarning'); + return multiple ? window.i18n('deleteMultipleWarning') : window.i18n('deleteWarning'); })(); const doDelete = async () => { @@ -666,9 +608,7 @@ export class SessionConversation extends React.Component<Props, State> { return; } - toDeleteLocally = await conversationModel.deletePublicMessages( - selectedMessages - ); + toDeleteLocally = await conversationModel.deletePublicMessages(selectedMessages); if (toDeleteLocally.length === 0) { // Message failed to delete from server, show error? return; @@ -690,14 +630,10 @@ export class SessionConversation extends React.Component<Props, State> { // If removable from server, we "Unsend" - otherwise "Delete" const pluralSuffix = multiple ? 's' : ''; const title = window.i18n( - isServerDeletable - ? `deleteMessage${pluralSuffix}ForEveryone` - : `deleteMessage${pluralSuffix}` + isServerDeletable ? `deleteMessage${pluralSuffix}ForEveryone` : `deleteMessage${pluralSuffix}` ); - const okText = window.i18n( - isServerDeletable ? 'deleteForEveryone' : 'delete' - ); + const okText = window.i18n(isServerDeletable ? 'deleteForEveryone' : 'delete'); if (askUserForConfirmation) { window.confirmationDialog({ title, @@ -728,10 +664,7 @@ export class SessionConversation extends React.Component<Props, State> { } public deleteMessage(messageId: string) { - this.setState( - { selectedMessages: [messageId] }, - this.deleteSelectedMessages - ); + this.setState({ selectedMessages: [messageId] }, this.deleteSelectedMessages); } public resetSelection() { @@ -770,16 +703,12 @@ export class SessionConversation extends React.Component<Props, State> { let quotedMessageProps = null; if (quotedMessageTimestamp) { - const quotedMessage = messages.find( - m => m.attributes.sent_at === quotedMessageTimestamp - ); + const quotedMessage = messages.find(m => m.attributes.sent_at === quotedMessageTimestamp); if (quotedMessage) { const quotedMessageModel = await getMessageById(quotedMessage.id); if (quotedMessageModel) { - quotedMessageProps = await conversationModel.makeQuote( - quotedMessageModel - ); + quotedMessageProps = await conversationModel.makeQuote(quotedMessageModel); } } } @@ -886,10 +815,7 @@ export class SessionConversation extends React.Component<Props, State> { const { stagedAttachments } = this.state; let newAttachmentsFiltered: Array<StagedAttachmentType> = []; if (newAttachments?.length > 0) { - if ( - newAttachments.some(a => a.isVoiceMessage) && - stagedAttachments.length > 0 - ) { + if (newAttachments.some(a => a.isVoiceMessage) && stagedAttachments.length > 0) { throw new Error('A voice note cannot be sent with other attachments'); } // do not add already added attachments @@ -903,19 +829,10 @@ export class SessionConversation extends React.Component<Props, State> { }); } - private renderLightBox({ - media, - attachment, - }: { - media: Array<MediaItemType>; - attachment: any; - }) { + private renderLightBox({ media, attachment }: { media: Array<MediaItemType>; attachment: any }) { const selectedIndex = media.length > 1 - ? media.findIndex( - (mediaMessage: any) => - mediaMessage.attachment.path === attachment.path - ) + ? media.findIndex((mediaMessage: any) => mediaMessage.attachment.path === attachment.path) : 0; return ( <LightboxGallery @@ -940,10 +857,7 @@ export class SessionConversation extends React.Component<Props, State> { index?: number; }) { const { getAbsoluteAttachmentPath } = window.Signal.Migrations; - attachment.url = await getDecryptedMediaUrl( - attachment.url, - attachment.contentType - ); + attachment.url = await getDecryptedMediaUrl(attachment.url, attachment.contentType); save({ attachment, document, @@ -1073,12 +987,8 @@ export class SessionConversation extends React.Component<Props, State> { file, }); - if ( - blob.file.size >= Constants.CONVERSATION.MAX_ATTACHMENT_FILESIZE_BYTES - ) { - ToastUtils.pushFileSizeErrorAsByte( - Constants.CONVERSATION.MAX_ATTACHMENT_FILESIZE_BYTES - ); + if (blob.file.size >= Constants.CONVERSATION.MAX_ATTACHMENT_FILESIZE_BYTES) { + ToastUtils.pushFileSizeErrorAsByte(Constants.CONVERSATION.MAX_ATTACHMENT_FILESIZE_BYTES); return; } } catch (error) { @@ -1167,9 +1077,7 @@ export class SessionConversation extends React.Component<Props, State> { } private async updateMemberList() { - const allPubKeys = await getPubkeysInPublicConversation( - this.props.selectedConversationKey - ); + const allPubKeys = await getPubkeysInPublicConversation(this.props.selectedConversationKey); const allMembers = allPubKeys.map((pubKey: string) => { const conv = ConversationController.getInstance().get(pubKey); diff --git a/ts/components/session/conversation/SessionFileDropzone.tsx b/ts/components/session/conversation/SessionFileDropzone.tsx index 3b15c5b9b4baef30fd6dc6bff6bc96df6b87d4a1..55fefb3ef4fc1a4a9ffe892b3760313212cde92b 100644 --- a/ts/components/session/conversation/SessionFileDropzone.tsx +++ b/ts/components/session/conversation/SessionFileDropzone.tsx @@ -33,12 +33,7 @@ export const SessionFileDropzone = () => { return ( <DropZoneContainer> <DropZoneWithBorder> - <Flex - container={true} - justifyContent="space-around" - height="100%" - alignItems="center" - > + <Flex container={true} justifyContent="space-around" height="100%" alignItems="center"> <SessionIcon iconSize={SessionIconSize.Max} iconType={SessionIconType.CirclePlus} diff --git a/ts/components/session/conversation/SessionLastSeenIndicator.tsx b/ts/components/session/conversation/SessionLastSeenIndicator.tsx index 59ad74ed118c0dc3054101f0f9d9429d4b96be8b..f5cf60266cb7afb71f2b0697ab2ad5a740de7c52 100644 --- a/ts/components/session/conversation/SessionLastSeenIndicator.tsx +++ b/ts/components/session/conversation/SessionLastSeenIndicator.tsx @@ -31,16 +31,9 @@ const LastSeenText = styled.div` color: ${props => props.theme.colors.lastSeenIndicatorTextColor}; `; -export const SessionLastSeenIndicator = ({ - count, - show, -}: { - count: number; - show: boolean; -}) => { +export const SessionLastSeenIndicator = ({ count, show }: { count: number; show: boolean }) => { const { i18n } = window; - const text = - count > 1 ? i18n('unreadMessages', count) : i18n('unreadMessage', count); + const text = count > 1 ? i18n('unreadMessages', count) : i18n('unreadMessage', count); return ( <LastSeenBarContainer show={show}> <LastSeenBar> diff --git a/ts/components/session/conversation/SessionMessagesList.tsx b/ts/components/session/conversation/SessionMessagesList.tsx index 64d9ebab1fec3753cdac218d599955ff63d7f48c..f936a0b39f82fcca8daeadd160a2870da16c68ee 100644 --- a/ts/components/session/conversation/SessionMessagesList.tsx +++ b/ts/components/session/conversation/SessionMessagesList.tsx @@ -82,14 +82,9 @@ export class SessionMessagesList extends React.Component<Props, State> { } public componentDidUpdate(prevProps: Props, _prevState: State) { - const isSameConvo = - prevProps.conversationKey === this.props.conversationKey; - const messageLengthChanged = - prevProps.messages.length !== this.props.messages.length; - if ( - !isSameConvo || - (prevProps.messages.length === 0 && this.props.messages.length !== 0) - ) { + const isSameConvo = prevProps.conversationKey === this.props.conversationKey; + const messageLengthChanged = prevProps.messages.length !== this.props.messages.length; + if (!isSameConvo || (prevProps.messages.length === 0 && this.props.messages.length !== 0)) { // displayed conversation changed. We have a bit of cleaning to do here this.scrollOffsetBottomPx = Number.MAX_VALUE; this.ignoreScrollEvents = true; @@ -114,8 +109,7 @@ export class SessionMessagesList extends React.Component<Props, State> { const scrollHeight = messageContainer.scrollHeight; const clientHeight = messageContainer.clientHeight; this.ignoreScrollEvents = true; - messageContainer.scrollTop = - scrollHeight - clientHeight - this.scrollOffsetBottomPx; + messageContainer.scrollTop = scrollHeight - clientHeight - this.scrollOffsetBottomPx; this.ignoreScrollEvents = false; } } @@ -149,10 +143,7 @@ export class SessionMessagesList extends React.Component<Props, State> { {this.renderMessages(messages)} - <SessionScrollButton - show={showScrollButton} - onClick={this.scrollToBottom} - /> + <SessionScrollButton show={showScrollButton} onClick={this.scrollToBottom} /> </div> ); } @@ -178,10 +169,7 @@ export class SessionMessagesList extends React.Component<Props, State> { if (message.attributes.type === 'incoming') { incomingMessagesSoFar++; // message.attributes.unread is !== undefined if the message is unread. - if ( - message.attributes.unread !== undefined && - incomingMessagesSoFar >= unreadCount - ) { + if (message.attributes.unread !== undefined && incomingMessagesSoFar >= unreadCount) { findFirstUnreadIndex = index; break; } @@ -232,10 +220,7 @@ export class SessionMessagesList extends React.Component<Props, State> { if (groupNotificationProps) { return ( <> - <GroupNotification - {...groupNotificationProps} - key={message.id} - /> + <GroupNotification {...groupNotificationProps} key={message.id} /> {unreadIndicator} </> ); @@ -244,10 +229,7 @@ export class SessionMessagesList extends React.Component<Props, State> { if (propsForGroupInvitation) { return ( <> - <GroupInvitation - {...propsForGroupInvitation} - key={message.id} - /> + <GroupInvitation {...propsForGroupInvitation} key={message.id} /> {unreadIndicator} </> ); @@ -266,9 +248,7 @@ export class SessionMessagesList extends React.Component<Props, State> { } if (messageProps.conversationType === 'group') { - messageProps.weAreAdmin = conversation.groupAdmins?.includes( - ourPrimary - ); + messageProps.weAreAdmin = conversation.groupAdmins?.includes(ourPrimary); } // a message is deletable if // either we sent it, @@ -280,9 +260,7 @@ export class SessionMessagesList extends React.Component<Props, State> { (conversation.isPublic && !!messageProps.weAreAdmin); messageProps.isDeletable = isDeletable; - messageProps.isAdmin = conversation.groupAdmins?.includes( - messageProps.authorPhoneNumber - ); + messageProps.isAdmin = conversation.groupAdmins?.includes(messageProps.authorPhoneNumber); // firstMessageOfSeries tells us to render the avatar only for the first message // in a series of messages from the same user @@ -308,9 +286,7 @@ export class SessionMessagesList extends React.Component<Props, State> { multiSelectMode: boolean, message: MessageModel ) { - const selected = - !!messageProps?.id && - this.props.selectedMessages.includes(messageProps.id); + const selected = !!messageProps?.id && this.props.selectedMessages.includes(messageProps.id); messageProps.selected = selected; messageProps.firstMessageOfSeries = firstMessageOfSeries; @@ -331,8 +307,7 @@ export class SessionMessagesList extends React.Component<Props, State> { this.props.onDownloadAttachment({ attachment }); }; - messageProps.isQuotedMessageToAnimate = - messageProps.id === this.state.animateQuotedMessageId; + messageProps.isQuotedMessageToAnimate = messageProps.id === this.state.animateQuotedMessageId; if (messageProps.quote) { messageProps.quote.onClick = (options: { @@ -357,9 +332,7 @@ export class SessionMessagesList extends React.Component<Props, State> { return; } - const conversation = ConversationController.getInstance().getOrThrow( - conversationKey - ); + const conversation = ConversationController.getInstance().getOrThrow(conversationKey); if (conversation.isBlocked()) { return; @@ -400,17 +373,11 @@ export class SessionMessagesList extends React.Component<Props, State> { const scrollOffsetPc = this.scrollOffsetBottomPx / clientHeight; // Scroll button appears if you're more than 75% scrolled up - if ( - scrollOffsetPc > scrollButtonViewShowLimit && - !this.state.showScrollButton - ) { + if (scrollOffsetPc > scrollButtonViewShowLimit && !this.state.showScrollButton) { this.setState({ showScrollButton: true }); } // Scroll button disappears if you're more less than 40% scrolled up - if ( - scrollOffsetPc < scrollButtonViewHideLimit && - this.state.showScrollButton - ) { + if (scrollOffsetPc < scrollButtonViewHideLimit && this.state.showScrollButton) { this.setState({ showScrollButton: false }); } @@ -422,14 +389,12 @@ export class SessionMessagesList extends React.Component<Props, State> { } // Fetch more messages when nearing the top of the message list - const shouldFetchMoreMessages = - scrollTop <= Constants.UI.MESSAGE_CONTAINER_BUFFER_OFFSET_PX; + const shouldFetchMoreMessages = scrollTop <= Constants.UI.MESSAGE_CONTAINER_BUFFER_OFFSET_PX; if (shouldFetchMoreMessages) { const { messages } = this.props; const numMessages = - this.props.messages.length + - Constants.CONVERSATION.DEFAULT_MESSAGE_FETCH_COUNT; + this.props.messages.length + Constants.CONVERSATION.DEFAULT_MESSAGE_FETCH_COUNT; const oldLen = messages.length; const previousTopMessage = messages[oldLen - 1]?.id; @@ -519,8 +484,7 @@ export class SessionMessagesList extends React.Component<Props, State> { if (!messageContainer) { return; } - messageContainer.scrollTop = - messageContainer.scrollHeight - messageContainer.clientHeight; + messageContainer.scrollTop = messageContainer.scrollHeight - messageContainer.clientHeight; this.updateReadMessages(); } diff --git a/ts/components/session/conversation/SessionQuotedMessageComposition.tsx b/ts/components/session/conversation/SessionQuotedMessageComposition.tsx index 5b66d26c79386fca294bc7667075caa570b41773..8cedb7eb343cc9143b956fdcf87f2a4eb1d482e2 100644 --- a/ts/components/session/conversation/SessionQuotedMessageComposition.tsx +++ b/ts/components/session/conversation/SessionQuotedMessageComposition.tsx @@ -61,9 +61,7 @@ export const SessionQuotedMessageComposition = (props: Props) => { /> </Flex> <QuotedMessageCompositionReply> - <Subtle> - {(hasAttachments && window.i18n('mediaMessage')) || body} - </Subtle> + <Subtle>{(hasAttachments && window.i18n('mediaMessage')) || body}</Subtle> </QuotedMessageCompositionReply> </QuotedMessageComposition> ); diff --git a/ts/components/session/conversation/SessionRecording.tsx b/ts/components/session/conversation/SessionRecording.tsx index c3ac7372fe7b3902b791129acc81c16b3e0136b9..b554eac58887a38d0f12e0359378f929e6233cee 100644 --- a/ts/components/session/conversation/SessionRecording.tsx +++ b/ts/components/session/conversation/SessionRecording.tsx @@ -3,11 +3,7 @@ import classNames from 'classnames'; import moment from 'moment'; import { SessionIconButton, SessionIconSize, SessionIconType } from '../icon'; -import { - SessionButton, - SessionButtonColor, - SessionButtonType, -} from '../SessionButton'; +import { SessionButton, SessionButtonColor, SessionButtonType } from '../SessionButton'; import { Constants } from '../../../session'; import { ToastUtils } from '../../../session/utils'; import { DefaultTheme, withTheme } from 'styled-components'; @@ -102,8 +98,7 @@ class SessionRecordingInner extends React.Component<Props, State> { const actionStopRecording = actionHover && isRecording; const actionPlayAudio = !isRecording && !isPlaying; const actionPauseAudio = !isRecording && !isPaused && isPlaying; - const actionDefault = - !actionStopRecording && !actionPlayAudio && !actionPauseAudio; + const actionDefault = !actionStopRecording && !actionPlayAudio && !actionPauseAudio; // if we are recording, we base the time recording on our state values // if we are playing ( audioElement?.currentTime is !== 0, use that instead) @@ -112,23 +107,15 @@ class SessionRecordingInner extends React.Component<Props, State> { const displayTimeMs = isRecording ? (nowTimestamp - startTimestamp) * 1000 : (this.audioElement && - (this.audioElement?.currentTime * 1000 || - this.audioElement?.duration)) || + (this.audioElement?.currentTime * 1000 || this.audioElement?.duration)) || 0; const displayTimeString = moment.utc(displayTimeMs).format('m:ss'); - const actionPauseFn = isPlaying - ? this.pauseAudio - : this.stopRecordingStream; + const actionPauseFn = isPlaying ? this.pauseAudio : this.stopRecordingStream; return ( - <div - role="main" - className="session-recording" - tabIndex={0} - onKeyDown={this.onKeyDown} - > + <div role="main" className="session-recording" tabIndex={0} onKeyDown={this.onKeyDown}> <div className="session-recording--actions" onMouseEnter={this.handleHoverActions} @@ -169,20 +156,12 @@ class SessionRecordingInner extends React.Component<Props, State> { )} </div> - <div - className="session-recording--visualisation" - ref={this.visualisationRef} - > + <div className="session-recording--visualisation" ref={this.visualisationRef}> {!isRecording && <canvas ref={this.playbackCanvas} />} {isRecording && <canvas ref={this.visualisationCanvas} />} </div> - <div - className={classNames( - 'session-recording--timer', - !isRecording && 'playback-timer' - )} - > + <div className={classNames('session-recording--timer', !isRecording && 'playback-timer')}> {displayTimeString} {isRecording && <div className="session-recording--timer-light" />} </div> @@ -278,11 +257,7 @@ class SessionRecordingInner extends React.Component<Props, State> { this.audioElement.oncanplaythrough = async () => { const duration = recordDuration; - if ( - duration && - this.audioElement && - this.audioElement.currentTime < duration - ) { + if (duration && this.audioElement && this.audioElement.currentTime < duration) { await this.audioElement?.play(); } }; @@ -322,13 +297,8 @@ class SessionRecordingInner extends React.Component<Props, State> { } // Is the audio file > attachment filesize limit - if ( - this.audioBlobMp3.size > - Constants.CONVERSATION.MAX_ATTACHMENT_FILESIZE_BYTES - ) { - ToastUtils.pushFileSizeErrorAsByte( - Constants.CONVERSATION.MAX_ATTACHMENT_FILESIZE_BYTES - ); + if (this.audioBlobMp3.size > Constants.CONVERSATION.MAX_ATTACHMENT_FILESIZE_BYTES) { + ToastUtils.pushFileSizeErrorAsByte(Constants.CONVERSATION.MAX_ATTACHMENT_FILESIZE_BYTES); return; } diff --git a/ts/components/session/conversation/SessionRightPanel.tsx b/ts/components/session/conversation/SessionRightPanel.tsx index 6ebaab2baa89670af625970fcce05c99599a2bd6..27a883ef7eebb0f715b01e93ef48f5034a0cc832 100644 --- a/ts/components/session/conversation/SessionRightPanel.tsx +++ b/ts/components/session/conversation/SessionRightPanel.tsx @@ -1,11 +1,7 @@ import React from 'react'; import { SessionIconButton, SessionIconSize, SessionIconType } from '../icon'; import { Avatar, AvatarSize } from '../../Avatar'; -import { - SessionButton, - SessionButtonColor, - SessionButtonType, -} from '../SessionButton'; +import { SessionButton, SessionButtonColor, SessionButtonType } from '../SessionButton'; import { SessionDropdown } from '../SessionDropdown'; import { MediaGallery } from '../../conversation/media-gallery/MediaGallery'; import _ from 'lodash'; @@ -70,36 +66,29 @@ class SessionRightPanel extends React.Component<Props, State> { } public componentWillMount() { - void this.getMediaGalleryProps().then( - ({ documents, media, onItemClick }) => { - this.setState({ - documents, - media, - onItemClick, - }); - } - ); + void this.getMediaGalleryProps().then(({ documents, media, onItemClick }) => { + this.setState({ + documents, + media, + onItemClick, + }); + }); } public componentDidUpdate() { const mediaScanInterval = 1000; setTimeout(() => { - void this.getMediaGalleryProps().then( - ({ documents, media, onItemClick }) => { - const { documents: oldDocs, media: oldMedias } = this.state; - if ( - oldDocs.length !== documents.length || - oldMedias.length !== media.length - ) { - this.setState({ - documents, - media, - onItemClick, - }); - } + void this.getMediaGalleryProps().then(({ documents, media, onItemClick }) => { + const { documents: oldDocs, media: oldMedias } = this.state; + if (oldDocs.length !== documents.length || oldMedias.length !== media.length) { + this.setState({ + documents, + media, + onItemClick, + }); } - ); + }); }, mediaScanInterval); } @@ -111,12 +100,9 @@ class SessionRightPanel extends React.Component<Props, State> { // We fetch more documents than media as they don’t require to be loaded // into memory right away. Revisit this once we have infinite scrolling: const conversationId = this.props.id; - const rawMedia = await getMessagesWithVisualMediaAttachments( - conversationId, - { - limit: Constants.CONVERSATION.DEFAULT_MEDIA_FETCH_COUNT, - } - ); + const rawMedia = await getMessagesWithVisualMediaAttachments(conversationId, { + limit: Constants.CONVERSATION.DEFAULT_MEDIA_FETCH_COUNT, + }); const rawDocuments = await getMessagesWithFileAttachments(conversationId, { limit: Constants.CONVERSATION.DEFAULT_DOCUMENTS_FETCH_COUNT, }); @@ -130,9 +116,7 @@ class SessionRightPanel extends React.Component<Props, State> { if (schemaVersion < message.VERSION_NEEDED_FOR_DISPLAY) { // Yep, we really do want to wait for each of these // eslint-disable-next-line no-await-in-loop - rawMedia[i] = await window.Signal.Migrations.upgradeMessageSchema( - message - ); + rawMedia[i] = await window.Signal.Migrations.upgradeMessageSchema(message); // eslint-disable-next-line no-await-in-loop await rawMedia[i].commit(); } @@ -147,59 +131,45 @@ class SessionRightPanel extends React.Component<Props, State> { (attachment: { thumbnail: any; pending: any; error: any }) => attachment.thumbnail && !attachment.pending && !attachment.error ) - .map( - ( - attachment: { path?: any; contentType?: any; thumbnail?: any }, - index: any - ) => { - const { thumbnail } = attachment; - - return { - objectURL: window.Signal.Migrations.getAbsoluteAttachmentPath( - attachment.path - ), - thumbnailObjectUrl: thumbnail - ? window.Signal.Migrations.getAbsoluteAttachmentPath( - thumbnail.path - ) - : null, - contentType: attachment.contentType, - index, - attachment, - message, - }; - } - ); + .map((attachment: { path?: any; contentType?: any; thumbnail?: any }, index: any) => { + const { thumbnail } = attachment; + + return { + objectURL: window.Signal.Migrations.getAbsoluteAttachmentPath(attachment.path), + thumbnailObjectUrl: thumbnail + ? window.Signal.Migrations.getAbsoluteAttachmentPath(thumbnail.path) + : null, + contentType: attachment.contentType, + index, + attachment, + message, + }; + }); }) ); // Unlike visual media, only one non-image attachment is supported - const documents = rawDocuments.map( - (message: { attachments: Array<any> }) => { - // this is to not fail if the attachment is invalid (could be a Long Attachment type which is not supported) - if (!message.attachments?.length) { - // window.log.info( - // 'Got a message with an empty list of attachment. Skipping...' - // ); - return null; - } - const attachment = message.attachments[0]; - - return { - contentType: attachment.contentType, - index: 0, - attachment, - message, - }; + const documents = rawDocuments.map((message: { attachments: Array<any> }) => { + // this is to not fail if the attachment is invalid (could be a Long Attachment type which is not supported) + if (!message.attachments?.length) { + // window.log.info( + // 'Got a message with an empty list of attachment. Skipping...' + // ); + return null; } - ); + const attachment = message.attachments[0]; + + return { + contentType: attachment.contentType, + index: 0, + attachment, + message, + }; + }); const saveAttachment = async ({ attachment, message }: any = {}) => { const timestamp = message.received_at; - attachment.url = await getDecryptedMediaUrl( - attachment.url, - attachment.contentType - ); + attachment.url = await getDecryptedMediaUrl(attachment.url, attachment.contentType); save({ attachment, document, @@ -295,26 +265,15 @@ class SessionRightPanel extends React.Component<Props, State> { <div className="spacer-lg" /> </> )} - <input - className="description" - placeholder={window.i18n('description')} - /> + <input className="description" placeholder={window.i18n('description')} /> {showUpdateGroupNameButton && ( - <div - className="group-settings-item" - role="button" - onClick={this.props.onUpdateGroupName} - > + <div className="group-settings-item" role="button" onClick={this.props.onUpdateGroupName}> {isPublic ? window.i18n('editGroup') : window.i18n('editGroupName')} </div> )} {showAddRemoveModeratorsButton && ( <> - <div - className="group-settings-item" - role="button" - onClick={this.props.onAddModerators} - > + <div className="group-settings-item" role="button" onClick={this.props.onAddModerators}> {window.i18n('addModerators')} </div> <div @@ -344,11 +303,7 @@ class SessionRightPanel extends React.Component<Props, State> { /> )} - <MediaGallery - documents={documents} - media={media} - onItemClick={onItemClick} - /> + <MediaGallery documents={documents} media={media} onItemClick={onItemClick} /> {isGroup && ( <SessionButton text={leaveGroupString} @@ -379,8 +334,7 @@ class SessionRightPanel extends React.Component<Props, State> { left, } = this.props; - const showInviteContacts = - (isPublic || isAdmin) && !isKickedFromGroup && !isBlocked && !left; + const showInviteContacts = (isPublic || isAdmin) && !isKickedFromGroup && !isBlocked && !left; const userName = name || profileName || phoneNumber; return ( diff --git a/ts/components/session/conversation/SessionStagedLinkPreview.tsx b/ts/components/session/conversation/SessionStagedLinkPreview.tsx index b11c0bf847358c26cf72a86d362e1f8d2a91abf0..3d96e4fe8edd9bb99be936554074cd0786e04637 100644 --- a/ts/components/session/conversation/SessionStagedLinkPreview.tsx +++ b/ts/components/session/conversation/SessionStagedLinkPreview.tsx @@ -55,11 +55,7 @@ export const getPreview = async ( try { window.log.info('insecureNodeFetch => plaintext for getPreview()'); - const fullSizeImage = await fetchLinkPreviewImage( - insecureNodeFetch, - imageHref, - abortSignal - ); + const fullSizeImage = await fetchLinkPreviewImage(insecureNodeFetch, imageHref, abortSignal); if (!fullSizeImage) { throw new Error('Failed to fetch link preview image'); } @@ -79,12 +75,10 @@ export const getPreview = async ( const data = await arrayBufferFromFile(withBlob.file); objectUrl = URL.createObjectURL(withBlob.file); - const dimensions = await window.Signal.Types.VisualAttachment.getImageDimensions( - { - objectUrl, - logger: window.log, - } - ); + const dimensions = await window.Signal.Types.VisualAttachment.getImageDimensions({ + objectUrl, + logger: window.log, + }); image = { data, @@ -94,10 +88,7 @@ export const getPreview = async ( }; } catch (error) { // We still want to show the preview if we failed to get an image - window.log.error( - 'getPreview failed to get image for link preview:', - error.message - ); + window.log.error('getPreview failed to get image for link preview:', error.message); } finally { if (objectUrl) { URL.revokeObjectURL(objectUrl); diff --git a/ts/components/session/icon/SessionIconButton.tsx b/ts/components/session/icon/SessionIconButton.tsx index 454adc2b66879803d54dfa6664afd0151249351d..121e0fb05dc919d3a04cd34db7fcc056e2557b9e 100644 --- a/ts/components/session/icon/SessionIconButton.tsx +++ b/ts/components/session/icon/SessionIconButton.tsx @@ -30,11 +30,7 @@ export const SessionIconButton = (props: SProps) => { return ( <div - className={classNames( - 'session-icon-button', - iconSize, - isSelected ? 'no-opacity' : '' - )} + className={classNames('session-icon-button', iconSize, isSelected ? 'no-opacity' : '')} role="button" onClick={clickHandler} > @@ -45,9 +41,7 @@ export const SessionIconButton = (props: SProps) => { iconRotation={iconRotation} theme={theme} /> - {Boolean(notificationCount) && ( - <SessionNotificationCount count={notificationCount} /> - )} + {Boolean(notificationCount) && <SessionNotificationCount count={notificationCount} />} </div> ); }; diff --git a/ts/components/session/menu/ConversationHeaderMenu.tsx b/ts/components/session/menu/ConversationHeaderMenu.tsx index 84cc3e9503c2c8256dcbf4145a8a016a4e0eb1ec..5ace0b1d7d6ea8f6ddbae9e50940af2506ab6f13 100644 --- a/ts/components/session/menu/ConversationHeaderMenu.tsx +++ b/ts/components/session/menu/ConversationHeaderMenu.tsx @@ -79,52 +79,17 @@ export const ConversationHeaderMenu = (props: PropsConversationHeaderMenu) => { onSetDisappearingMessages, window.i18n )} - {getBlockMenuItem( - isMe, - isPrivate, - isBlocked, - onBlockUser, - onUnblockUser, - window.i18n - )} + {getBlockMenuItem(isMe, isPrivate, isBlocked, onBlockUser, onUnblockUser, window.i18n)} {getCopyMenuItem(isPublic, isGroup, onCopyPublicKey, window.i18n)} {getMarkAllReadMenuItem(onMarkAllRead, window.i18n)} {getDeleteMessagesMenuItem(isPublic, onDeleteMessages, window.i18n)} - {getAddModeratorsMenuItem( - isAdmin, - isKickedFromGroup, - onAddModerators, - window.i18n - )} - {getRemoveModeratorsMenuItem( - isAdmin, - isKickedFromGroup, - onRemoveModerators, - window.i18n - )} - {getUpdateGroupNameMenuItem( - isAdmin, - isKickedFromGroup, - left, - onUpdateGroupName, - window.i18n - )} - {getLeaveGroupMenuItem( - isKickedFromGroup, - left, - isGroup, - isPublic, - onLeaveGroup, - window.i18n - )} + {getAddModeratorsMenuItem(isAdmin, isKickedFromGroup, onAddModerators, window.i18n)} + {getRemoveModeratorsMenuItem(isAdmin, isKickedFromGroup, onRemoveModerators, window.i18n)} + {getUpdateGroupNameMenuItem(isAdmin, isKickedFromGroup, left, onUpdateGroupName, window.i18n)} + {getLeaveGroupMenuItem(isKickedFromGroup, left, isGroup, isPublic, onLeaveGroup, window.i18n)} {/* TODO: add delete group */} - {getInviteContactMenuItem( - isGroup, - isPublic, - onInviteContacts, - window.i18n - )} + {getInviteContactMenuItem(isGroup, isPublic, onInviteContacts, window.i18n)} {getDeleteContactMenuItem( isMe, isGroup, diff --git a/ts/components/session/menu/ConversationListItemContextMenu.tsx b/ts/components/session/menu/ConversationListItemContextMenu.tsx index a8db5274b3b9f09a6685eb557d64df26964b5a80..da775084e5465387fca72c7722458340638bcda0 100644 --- a/ts/components/session/menu/ConversationListItemContextMenu.tsx +++ b/ts/components/session/menu/ConversationListItemContextMenu.tsx @@ -33,9 +33,7 @@ export type PropsContextConversationItem = { onClearNickname?: () => void; }; -export const ConversationListItemContextMenu = ( - props: PropsContextConversationItem -) => { +export const ConversationListItemContextMenu = (props: PropsContextConversationItem) => { const { triggerId, isBlocked, @@ -71,28 +69,12 @@ export const ConversationListItemContextMenu = ( {i18n('changeNickname')} </Item> ) : null} */} - {getClearNicknameMenuItem( - isPublic, - isMe, - hasNickname, - onClearNickname, - window.i18n - )} - {getCopyMenuItem( - isPublic, - type === 'group', - onCopyPublicKey, - window.i18n - )} + {getClearNicknameMenuItem(isPublic, isMe, hasNickname, onClearNickname, window.i18n)} + {getCopyMenuItem(isPublic, type === 'group', onCopyPublicKey, window.i18n)} {getMarkAllReadMenuItem(onMarkAllRead, window.i18n)} {getDeleteMessagesMenuItem(isPublic, onDeleteMessages, window.i18n)} - {getInviteContactMenuItem( - type === 'group', - isPublic, - onInviteContacts, - window.i18n - )} + {getInviteContactMenuItem(type === 'group', isPublic, onInviteContacts, window.i18n)} {getDeleteContactMenuItem( isMe, type === 'group', diff --git a/ts/components/session/menu/Menu.tsx b/ts/components/session/menu/Menu.tsx index 11ce15e1e7e186517d2a54d7872f65aab7e7a8d7..077da45d5fa98a926bfc6a023663a4a1cba3f523 100644 --- a/ts/components/session/menu/Menu.tsx +++ b/ts/components/session/menu/Menu.tsx @@ -20,11 +20,7 @@ function showBlock(isMe: boolean, isPrivate: boolean): boolean { return !isMe && isPrivate; } -function showClearNickname( - isPublic: boolean, - isMe: boolean, - hasNickname: boolean -): boolean { +function showClearNickname(isPublic: boolean, isMe: boolean, hasNickname: boolean): boolean { return !isPublic && !isMe && hasNickname; } @@ -45,31 +41,18 @@ function showDeleteContact( isKickedFromGroup: boolean ): boolean { // you need to have left a closed group first to be able to delete it completely. - return ( - (!isMe && !isGroup) || - (isGroup && (isGroupLeft || isKickedFromGroup || isPublic)) - ); + return (!isMe && !isGroup) || (isGroup && (isGroupLeft || isKickedFromGroup || isPublic)); } -function showAddModerators( - isAdmin: boolean, - isKickedFromGroup: boolean -): boolean { +function showAddModerators(isAdmin: boolean, isKickedFromGroup: boolean): boolean { return !isKickedFromGroup && isAdmin; } -function showRemoveModerators( - isAdmin: boolean, - isKickedFromGroup: boolean -): boolean { +function showRemoveModerators(isAdmin: boolean, isKickedFromGroup: boolean): boolean { return !isKickedFromGroup && isAdmin; } -function showUpdateGroupName( - isAdmin: boolean, - isKickedFromGroup: boolean, - left: boolean -): boolean { +function showUpdateGroupName(isAdmin: boolean, isKickedFromGroup: boolean, left: boolean): boolean { return !isKickedFromGroup && !left && isAdmin; } @@ -135,12 +118,7 @@ export function getLeaveGroupMenuItem( i18n: LocalizerType ): JSX.Element | null { if ( - showLeaveGroup( - Boolean(isKickedFromGroup), - Boolean(left), - Boolean(isGroup), - Boolean(isPublic) - ) + showLeaveGroup(Boolean(isKickedFromGroup), Boolean(left), Boolean(isGroup), Boolean(isPublic)) ) { return <Item onClick={action}>{i18n('leaveGroup')}</Item>; } @@ -154,13 +132,7 @@ export function getUpdateGroupNameMenuItem( action: any, i18n: LocalizerType ): JSX.Element | null { - if ( - showUpdateGroupName( - Boolean(isAdmin), - Boolean(isKickedFromGroup), - Boolean(left) - ) - ) { + if (showUpdateGroupName(Boolean(isAdmin), Boolean(isKickedFromGroup), Boolean(left))) { return <Item onClick={action}>{i18n('editGroup')}</Item>; } return null; @@ -197,18 +169,13 @@ export function getCopyMenuItem( i18n: LocalizerType ): JSX.Element | null { if (showCopyId(Boolean(isPublic), Boolean(isGroup))) { - const copyIdLabel = isPublic - ? i18n('copyOpenGroupURL') - : i18n('copySessionID'); + const copyIdLabel = isPublic ? i18n('copyOpenGroupURL') : i18n('copySessionID'); return <Item onClick={action}>{copyIdLabel}</Item>; } return null; } -export function getMarkAllReadMenuItem( - action: any, - i18n: LocalizerType -): JSX.Element | null { +export function getMarkAllReadMenuItem(action: any, i18n: LocalizerType): JSX.Element | null { return <Item onClick={action}>{i18n('markAllAsRead')}</Item>; } @@ -291,9 +258,7 @@ export function getClearNicknameMenuItem( action: any, i18n: LocalizerType ): JSX.Element | null { - if ( - showClearNickname(Boolean(isPublic), Boolean(isMe), Boolean(hasNickname)) - ) { + if (showClearNickname(Boolean(isPublic), Boolean(isMe), Boolean(hasNickname))) { return <Item onClick={action}>{i18n('clearNickname')}</Item>; } return null; diff --git a/ts/components/session/registration/RegistrationTabs.tsx b/ts/components/session/registration/RegistrationTabs.tsx index ec7bd850072150d3610aea84641fd0b24787ef47..283c6b45c35fbecef54240f86026e4f24be33085 100644 --- a/ts/components/session/registration/RegistrationTabs.tsx +++ b/ts/components/session/registration/RegistrationTabs.tsx @@ -1,11 +1,6 @@ import React from 'react'; -import { - PromiseUtils, - StringUtils, - ToastUtils, - UserUtils, -} from '../../../session/utils'; +import { PromiseUtils, StringUtils, ToastUtils, UserUtils } from '../../../session/utils'; import { ConversationController } from '../../../session/conversations'; import { createOrUpdateItem, removeAll } from '../../../data/data'; import { SignUpTab } from './SignUpTab'; @@ -76,18 +71,12 @@ const passwordsAreValid = (password: string, verifyPassword: string) => { const passwordErrors = validatePassword(password, verifyPassword); if (passwordErrors.passwordErrorString) { window.log.warn('invalid password for registration'); - ToastUtils.pushToastError( - 'invalidPassword', - window.i18n('invalidPassword') - ); + ToastUtils.pushToastError('invalidPassword', window.i18n('invalidPassword')); return false; } if (!!password && !passwordErrors.passwordFieldsMatch) { window.log.warn('passwords does not match for registration'); - ToastUtils.pushToastError( - 'invalidPassword', - window.i18n('passwordsDoNotMatch') - ); + ToastUtils.pushToastError('invalidPassword', window.i18n('passwordsDoNotMatch')); return false; } @@ -104,10 +93,7 @@ const displayNameIsValid = (displayName: string): undefined | string => { if (!trimName) { window.log.warn('invalid trimmed name for registration'); - ToastUtils.pushToastError( - 'invalidDisplayName', - window.i18n('displayNameEmpty') - ); + ToastUtils.pushToastError('invalidDisplayName', window.i18n('displayNameEmpty')); return undefined; } return trimName; @@ -119,12 +105,7 @@ export async function signUp(signUpDetails: { password: string; verifyPassword: string; }) { - const { - displayName, - password, - verifyPassword, - generatedRecoveryPhrase, - } = signUpDetails; + const { displayName, password, verifyPassword, generatedRecoveryPhrase } = signUpDetails; window.log.info('SIGNING UP'); const trimName = displayNameIsValid(displayName); @@ -150,10 +131,7 @@ export async function signUp(signUpDetails: { } catch (e) { await resetRegistration(); - ToastUtils.pushToastError( - 'registrationError', - `Error: ${e.message || 'Something went wrong'}` - ); + ToastUtils.pushToastError('registrationError', `Error: ${e.message || 'Something went wrong'}`); window.log.warn('exception during registration:', e); } } @@ -169,12 +147,7 @@ export async function signInWithRecovery(signInDetails: { password: string; verifyPassword: string; }) { - const { - displayName, - password, - verifyPassword, - userRecoveryPhrase, - } = signInDetails; + const { displayName, password, verifyPassword, userRecoveryPhrase } = signInDetails; window.log.info('RESTORING FROM SEED'); const trimName = displayNameIsValid(displayName); // shows toast to user about the error @@ -194,10 +167,7 @@ export async function signInWithRecovery(signInDetails: { trigger('openInbox'); } catch (e) { await resetRegistration(); - ToastUtils.pushToastError( - 'registrationError', - `Error: ${e.message || 'Something went wrong'}` - ); + ToastUtils.pushToastError('registrationError', `Error: ${e.message || 'Something went wrong'}`); window.log.warn('exception during registration:', e); } } @@ -225,27 +195,20 @@ export async function signInWithLinking(signInDetails: { let displayNameFromNetwork = ''; await PromiseUtils.waitForTask(done => { - window.Whisper.events.on( - 'configurationMessageReceived', - (displayName: string) => { - window.Whisper.events.off('configurationMessageReceived'); - UserUtils.setSignInByLinking(false); - done(displayName); - - displayNameFromNetwork = displayName; - } - ); + window.Whisper.events.on('configurationMessageReceived', (displayName: string) => { + window.Whisper.events.off('configurationMessageReceived'); + UserUtils.setSignInByLinking(false); + done(displayName); + + displayNameFromNetwork = displayName; + }); }, 60000); if (displayNameFromNetwork.length) { // display name, avatars, groups and contacts should already be handled when this event was triggered. window.log.info('We got a displayName from network: '); } else { - window.log.info( - 'Got a config message from network but without a displayName...' - ); - throw new Error( - 'Got a config message from network but without a displayName...' - ); + window.log.info('Got a config message from network but without a displayName...'); + throw new Error('Got a config message from network but without a displayName...'); } // Do not set the lastProfileUpdateTimestamp. // We expect to get a display name from a configuration message while we are loading messages of this user @@ -332,11 +295,7 @@ export class RegistrationTabs extends React.Component<any, State> { }; private renderSections() { - const { - selectedTab, - generatedRecoveryPhrase, - hexGeneratedPubKey, - } = this.state; + const { selectedTab, generatedRecoveryPhrase, hexGeneratedPubKey } = this.state; if (selectedTab === TabType.SignUp) { return ( <SignUpTab diff --git a/ts/components/session/registration/RegistrationUserDetails.tsx b/ts/components/session/registration/RegistrationUserDetails.tsx index 709852ac216e75e8f0d89a6ee3fc32bf2ddf71a3..b7237ca4a1daefa27a6de694e2c6b9766106ec8a 100644 --- a/ts/components/session/registration/RegistrationUserDetails.tsx +++ b/ts/components/session/registration/RegistrationUserDetails.tsx @@ -56,9 +56,7 @@ const PasswordAndVerifyPasswordFields = (props: { }) => { const { password, passwordFieldsMatch, passwordErrorString } = props; const passwordsDoNotMatch = - !passwordFieldsMatch && password - ? window.i18n('passwordsDoNotMatch') - : undefined; + !passwordFieldsMatch && password ? window.i18n('passwordsDoNotMatch') : undefined; return ( <> @@ -105,10 +103,7 @@ export interface Props { } export const RegistrationUserDetails = (props: Props) => { - if ( - props.showSeedField && - (props.recoveryPhrase === undefined || !props.onSeedChanged) - ) { + if (props.showSeedField && (props.recoveryPhrase === undefined || !props.onSeedChanged)) { throw new Error('if show seed is true, we need callback + value'); } return ( diff --git a/ts/components/session/registration/SignInTab.tsx b/ts/components/session/registration/SignInTab.tsx index d700c5152f6d7633c9e5ac5b7ff8b9ee1480d683..64c21b91c4b89c06a5820f260c3ed91675fe25a5 100644 --- a/ts/components/session/registration/SignInTab.tsx +++ b/ts/components/session/registration/SignInTab.tsx @@ -1,16 +1,8 @@ import React, { useState } from 'react'; import { Flex } from '../Flex'; -import { - SessionButton, - SessionButtonColor, - SessionButtonType, -} from '../SessionButton'; +import { SessionButton, SessionButtonColor, SessionButtonType } from '../SessionButton'; import { SessionSpinner } from '../SessionSpinner'; -import { - signInWithLinking, - signInWithRecovery, - validatePassword, -} from './RegistrationTabs'; +import { signInWithLinking, signInWithRecovery, validatePassword } from './RegistrationTabs'; import { RegistrationUserDetails } from './RegistrationUserDetails'; import { TermsAndConditions } from './TermsAndConditions'; @@ -33,9 +25,7 @@ const LinkDeviceButton = (props: { onLinkDeviceButtonClicked: () => any }) => { ); }; -const RestoreUsingRecoveryPhraseButton = (props: { - onRecoveryButtonClicked: () => any; -}) => { +const RestoreUsingRecoveryPhraseButton = (props: { onRecoveryButtonClicked: () => any }) => { return ( <SessionButton onClick={props.onRecoveryButtonClicked} @@ -87,15 +77,11 @@ const SignInButtons = (props: { } return ( <div> - <RestoreUsingRecoveryPhraseButton - onRecoveryButtonClicked={props.onRecoveryButtonClicked} - /> + <RestoreUsingRecoveryPhraseButton onRecoveryButtonClicked={props.onRecoveryButtonClicked} /> <div className="spacer-lg" /> <div className="or">{window.i18n('or')}</div> <div className="spacer-lg" /> - <LinkDeviceButton - onLinkDeviceButtonClicked={props.onLinkDeviceButtonClicked} - /> + <LinkDeviceButton onLinkDeviceButtonClicked={props.onLinkDeviceButtonClicked} /> </div> ); }; @@ -103,9 +89,7 @@ const SignInButtons = (props: { export const SignInTab = () => { const [signInMode, setSignInMode] = useState(SignInMode.Default); const [recoveryPhrase, setRecoveryPhrase] = useState(''); - const [recoveryPhraseError, setRecoveryPhraseError] = useState( - undefined as string | undefined - ); + const [recoveryPhraseError, setRecoveryPhraseError] = useState(undefined as string | undefined); const [displayName, setDisplayName] = useState(''); const [displayNameError, setDisplayNameError] = useState(''); const [password, setPassword] = useState(''); @@ -124,17 +108,14 @@ export const SignInTab = () => { const showDisplayNameField = isRecovery; // Display name is required only on isRecoveryMode - const displayNameOK = - (isRecovery && !displayNameError && !!displayName) || isLinking; + const displayNameOK = (isRecovery && !displayNameError && !!displayName) || isLinking; // Password is valid if empty, or if no error and fields are matching - const passwordsOK = - !password || (!passwordErrorString && passwordFieldsMatch); + const passwordsOK = !password || (!passwordErrorString && passwordFieldsMatch); // Seed is mandatory no matter which mode const seedOK = recoveryPhrase && !recoveryPhraseError; - const activateContinueButton = - seedOK && displayNameOK && passwordsOK && !loading; + const activateContinueButton = seedOK && displayNameOK && passwordsOK && !loading; const continueYourSession = async () => { if (isRecovery) { @@ -167,9 +148,7 @@ export const SignInTab = () => { const sanitizedName = name.replace(window.displayNameRegex, ''); const trimName = sanitizedName.trim(); setDisplayName(sanitizedName); - setDisplayNameError( - !trimName ? window.i18n('displayNameEmpty') : undefined - ); + setDisplayNameError(!trimName ? window.i18n('displayNameEmpty') : undefined); }} onPasswordChanged={(val: string) => { setPassword(val); @@ -192,9 +171,7 @@ export const SignInTab = () => { }} onSeedChanged={(seed: string) => { setRecoveryPhrase(seed); - setRecoveryPhraseError( - !seed ? window.i18n('recoveryPhraseEmpty') : undefined - ); + setRecoveryPhraseError(!seed ? window.i18n('recoveryPhraseEmpty') : undefined); }} password={password} passwordErrorString={passwordErrorString} diff --git a/ts/components/session/registration/SignUpTab.tsx b/ts/components/session/registration/SignUpTab.tsx index 93248f8416a95ddf93d842aa8257c87bff2ad538..494205c6a5fbb57c4614964bff5cba641eaf9f1c 100644 --- a/ts/components/session/registration/SignUpTab.tsx +++ b/ts/components/session/registration/SignUpTab.tsx @@ -1,9 +1,5 @@ import React, { useEffect, useState } from 'react'; -import { - SessionButton, - SessionButtonColor, - SessionButtonType, -} from '../SessionButton'; +import { SessionButton, SessionButtonColor, SessionButtonType } from '../SessionButton'; import { SessionIdEditable } from '../SessionIdEditable'; import { signUp, validatePassword } from './RegistrationTabs'; import { RegistrationUserDetails } from './RegistrationUserDetails'; @@ -21,11 +17,7 @@ export interface Props { hexGeneratedPubKey: string; } -const CreateSessionIdButton = ({ - createSessionID, -}: { - createSessionID: any; -}) => { +const CreateSessionIdButton = ({ createSessionID }: { createSessionID: any }) => { return ( <SessionButton onClick={createSessionID} @@ -112,8 +104,7 @@ export const SignUpTab = (props: Props) => { // Display name is required const displayNameOK = !displayNameError && !!displayName; // Password is valid if empty, or if no error and fields are matching - const passwordsOK = - !password || (!passwordErrorString && passwordFieldsMatch); + const passwordsOK = !password || (!passwordErrorString && passwordFieldsMatch); const enableCompleteSignUp = displayNameOK && passwordsOK; const signUpWithDetails = async () => { @@ -140,9 +131,7 @@ export const SignUpTab = (props: Props) => { const sanitizedName = name.replace(window.displayNameRegex, ''); const trimName = sanitizedName.trim(); setDisplayName(sanitizedName); - setDisplayNameError( - !trimName ? window.i18n('displayNameEmpty') : undefined - ); + setDisplayNameError(!trimName ? window.i18n('displayNameEmpty') : undefined); }} onPasswordChanged={(val: string) => { setPassword(val); diff --git a/ts/components/session/registration/TabLabel.tsx b/ts/components/session/registration/TabLabel.tsx index bb2548f4333b6b860f916a0f2e78f448801b42a9..0e37f5dafda7457493df28915e14542ad9d35d98 100644 --- a/ts/components/session/registration/TabLabel.tsx +++ b/ts/components/session/registration/TabLabel.tsx @@ -21,10 +21,7 @@ export const TabLabel = ({ } : undefined; - const label = - type === TabType.SignUp - ? window.i18n('createAccount') - : window.i18n('signIn'); + const label = type === TabType.SignUp ? window.i18n('createAccount') : window.i18n('signIn'); return ( <div diff --git a/ts/components/session/settings/SessionSettingListItem.tsx b/ts/components/session/settings/SessionSettingListItem.tsx index a5b3218ca649981a4ee257ebcce19fd56da4409d..c638027f0c4cb0e43f547923cfdca6723a6ce334 100644 --- a/ts/components/session/settings/SessionSettingListItem.tsx +++ b/ts/components/session/settings/SessionSettingListItem.tsx @@ -41,8 +41,7 @@ export class SessionSettingListItem extends React.Component<Props, State> { public render(): JSX.Element { const { title, description, type, value, content } = this.props; const inline = - !!type && - ![SessionSettingType.Options, SessionSettingType.Slider].includes(type); + !!type && ![SessionSettingType.Options, SessionSettingType.Slider].includes(type); const currentSliderValue = type === SessionSettingType.Slider && (this.state.sliderValue || value); @@ -52,11 +51,7 @@ export class SessionSettingListItem extends React.Component<Props, State> { <div className="session-settings-item__info"> <div className="session-settings-item__title">{title}</div> - {description && ( - <div className="session-settings-item__description"> - {description} - </div> - )} + {description && <div className="session-settings-item__description">{description}</div>} </div> <div className="session-settings-item__content"> diff --git a/ts/components/session/settings/SessionSettings.tsx b/ts/components/session/settings/SessionSettings.tsx index 63d005cbd97b1ee5bbffb65d320a04dbfb3a8717..691780177a82c8c1760bade857a1ff7adeef2ec9 100644 --- a/ts/components/session/settings/SessionSettings.tsx +++ b/ts/components/session/settings/SessionSettings.tsx @@ -2,20 +2,13 @@ import React from 'react'; import { SettingsHeader } from './SessionSettingsHeader'; import { SessionSettingListItem } from './SessionSettingListItem'; -import { - SessionButton, - SessionButtonColor, - SessionButtonType, -} from '../SessionButton'; +import { SessionButton, SessionButtonColor, SessionButtonType } from '../SessionButton'; import { BlockedNumberController, PasswordUtil } from '../../../util'; import { ToastUtils } from '../../../session/utils'; import { ConversationLookupType } from '../../../state/ducks/conversations'; import { StateType } from '../../../state/reducer'; import { ConversationController } from '../../../session/conversations'; -import { - getConversationLookup, - getConversations, -} from '../../../state/selectors/conversations'; +import { getConversationLookup, getConversations } from '../../../state/selectors/conversations'; import { connect } from 'react-redux'; import { getPasswordHash } from '../../../../ts/data/data'; @@ -122,10 +115,7 @@ class SettingsViewInner extends React.Component<SettingsViewProps, State> { const description = setting.description || ''; const comparisonValue = setting.comparisonValue || null; - const storedSetting = window.getSettingValue( - setting.id, - comparisonValue - ); + const storedSetting = window.getSettingValue(setting.id, comparisonValue); const value = storedSetting !== undefined ? storedSetting @@ -133,8 +123,7 @@ class SettingsViewInner extends React.Component<SettingsViewProps, State> { const sliderFn = setting.type === SessionSettingType.Slider - ? (settingValue: any) => - window.setSettingValue(setting.id, settingValue) + ? (settingValue: any) => window.setSettingValue(setting.id, settingValue) : () => null; const onClickFn = @@ -169,20 +158,13 @@ class SettingsViewInner extends React.Component<SettingsViewProps, State> { <div className="session-settings__password-lock"> <div className="session-settings__password-lock-box"> <h3>{window.i18n('password')}</h3> - <input - type="password" - id="password-lock-input" - defaultValue="" - placeholder="Password" - /> + <input type="password" id="password-lock-input" defaultValue="" placeholder="Password" /> <div className="spacer-xs" /> {this.state.pwdLockError && ( <> - <div className="session-label warning"> - {this.state.pwdLockError} - </div> + <div className="session-label warning">{this.state.pwdLockError}</div> <div className="spacer-lg" /> </> )} @@ -230,8 +212,7 @@ class SettingsViewInner extends React.Component<SettingsViewProps, State> { public render() { const { category } = this.props; - const shouldRenderPasswordLock = - this.state.shouldLockSettings && this.state.hasPassword; + const shouldRenderPasswordLock = this.state.shouldLockSettings && this.state.hasPassword; return ( <div className="session-settings"> @@ -355,8 +336,7 @@ class SettingsViewInner extends React.Component<SettingsViewProps, State> { comparisonValue: undefined, onClick: undefined, confirmationDialogParams: { - shouldShowConfirm: () => - !window.getSettingValue('link-preview-setting'), + shouldShowConfirm: () => !window.getSettingValue('link-preview-setting'), title: window.i18n('linkPreviewsTitle'), message: window.i18n('linkPreviewsConfirmMessage'), okTheme: 'danger', @@ -377,8 +357,7 @@ class SettingsViewInner extends React.Component<SettingsViewProps, State> { content: { options: { group: 'notification-setting', - initalItem: - window.getSettingValue('notification-setting') || 'message', + initalItem: window.getSettingValue('notification-setting') || 'message', items: [ { label: window.i18n('nameAndMessage'), @@ -559,14 +538,9 @@ class SettingsViewInner extends React.Component<SettingsViewProps, State> { for (const blockedNumber of blockedNumbers) { let title: string; - const currentModel = ConversationController.getInstance().get( - blockedNumber - ); + const currentModel = ConversationController.getInstance().get(blockedNumber); if (currentModel) { - title = - currentModel.getProfileName() || - currentModel.getName() || - window.i18n('anonymous'); + title = currentModel.getProfileName() || currentModel.getName() || window.i18n('anonymous'); } else { title = window.i18n('anonymous'); } @@ -619,9 +593,7 @@ class SettingsViewInner extends React.Component<SettingsViewProps, State> { } private async onKeyUp(event: any) { - const lockPasswordFocussed = ($('#password-lock-input') as any).is( - ':focus' - ); + const lockPasswordFocussed = ($('#password-lock-input') as any).is(':focus'); if (event.key === 'Enter' && lockPasswordFocussed) { await this.validatePasswordLock(); diff --git a/ts/components/session/usingClosedConversationDetails.tsx b/ts/components/session/usingClosedConversationDetails.tsx index ccdabc82dea4d26ea19d06a0df4bd0e32bf42e78..d25d10f4f00b758e9ab26ffa66df611a1afd2ea9 100644 --- a/ts/components/session/usingClosedConversationDetails.tsx +++ b/ts/components/session/usingClosedConversationDetails.tsx @@ -33,28 +33,13 @@ export function usingClosedConversationDetails(WrappedComponent: any) { } public render() { - return ( - <WrappedComponent - memberAvatars={this.state.memberAvatars} - {...this.props} - /> - ); + return <WrappedComponent memberAvatars={this.state.memberAvatars} {...this.props} />; } private async fetchClosedConversationDetails() { - const { - isPublic, - type, - conversationType, - isGroup, - phoneNumber, - id, - } = this.props; + const { isPublic, type, conversationType, isGroup, phoneNumber, id } = this.props; - if ( - !isPublic && - (conversationType === 'group' || type === 'group' || isGroup) - ) { + if (!isPublic && (conversationType === 'group' || type === 'group' || isGroup)) { const groupId = id || phoneNumber; const ourPrimary = UserUtils.getOurPubKeyFromCache(); let members = await GroupUtils.getGroupMembers(PubKey.cast(groupId)); @@ -70,10 +55,7 @@ export function usingClosedConversationDetails(WrappedComponent: any) { members = members.slice(0, 2); const memberConvos = await Promise.all( members.map(async m => - ConversationController.getInstance().getOrCreateAndWait( - m.key, - ConversationType.PRIVATE - ) + ConversationController.getInstance().getOrCreateAndWait(m.key, ConversationType.PRIVATE) ) ); const memberAvatars = memberConvos.map(m => { diff --git a/ts/data/data.ts b/ts/data/data.ts index 5343f2f15389a1da95b369df4244ac83792b2520..ec624b997561cdced7cfc0c4064391967eee1270 100644 --- a/ts/data/data.ts +++ b/ts/data/data.ts @@ -4,19 +4,13 @@ const { ipcRenderer } = Electron; // tslint:disable: function-name no-require-imports no-var-requires one-variable-per-declaration no-void-expression import _ from 'lodash'; -import { - ConversationCollection, - ConversationModel, -} from '../models/conversation'; +import { ConversationCollection, ConversationModel } from '../models/conversation'; import { MessageCollection, MessageModel } from '../models/message'; import { MessageAttributes } from '../models/messageType'; import { HexKeyPair } from '../receiver/keypairs'; import { getSodium } from '../session/crypto'; import { PubKey } from '../session/types'; -import { - fromArrayBufferToBase64, - fromBase64ToArrayBuffer, -} from '../session/utils/String'; +import { fromArrayBufferToBase64, fromBase64ToArrayBuffer } from '../session/utils/String'; import { ConversationType } from '../state/ducks/conversations'; import { channels } from './channels'; import { channelsToMake as channelstoMakeOpenGroupV2 } from './opengroups'; @@ -65,8 +59,7 @@ export type ServerToken = { token: string; }; -export const hasSyncedInitialConfigurationItem = - 'hasSyncedInitialConfigurationItem'; +export const hasSyncedInitialConfigurationItem = 'hasSyncedInitialConfigurationItem'; const channelsToMake = { shutdown, @@ -183,29 +176,24 @@ export function init() { } }); - ipcRenderer.on( - `${SQL_CHANNEL_KEY}-done`, - (event, jobId, errorForDisplay, result) => { - const job = _getJob(jobId); - if (!job) { - throw new Error( - `Received SQL channel reply to job ${jobId}, but did not have it in our registry!` - ); - } + ipcRenderer.on(`${SQL_CHANNEL_KEY}-done`, (event, jobId, errorForDisplay, result) => { + const job = _getJob(jobId); + if (!job) { + throw new Error( + `Received SQL channel reply to job ${jobId}, but did not have it in our registry!` + ); + } - const { resolve, reject, fnName } = job; + const { resolve, reject, fnName } = job; - if (errorForDisplay) { - return reject( - new Error( - `Error received from SQL channel job ${jobId} (${fnName}): ${errorForDisplay}` - ) - ); - } - - return resolve(result); + if (errorForDisplay) { + return reject( + new Error(`Error received from SQL channel job ${jobId} (${fnName}): ${errorForDisplay}`) + ); } - ); + + return resolve(result); + }); } // When IPC arguments are prepared for the cross-process send, they are JSON.stringified. @@ -249,9 +237,7 @@ async function _shutdown() { _shuttingDown = true; const jobKeys = Object.keys(_jobs); - window.log.info( - `data.shutdown: starting process. ${jobKeys.length} jobs outstanding` - ); + window.log.info(`data.shutdown: starting process. ${jobKeys.length} jobs outstanding`); // No outstanding jobs, return immediately if (jobKeys.length === 0) { @@ -275,9 +261,7 @@ async function _shutdown() { function _makeJob(fnName: string) { if (_shuttingDown && fnName !== 'close') { - throw new Error( - `Rejecting SQL channel job (${fnName}); application is shutting down` - ); + throw new Error(`Rejecting SQL channel job (${fnName}); application is shutting down`); } _jobCounter += 1; @@ -315,9 +299,7 @@ function _updateJob(id: number, data: any) { reject: (error: any) => { _removeJob(id); const end = Date.now(); - window.log.warn( - `SQL channel job ${id} (${fnName}) failed in ${end - start}ms` - ); + window.log.warn(`SQL channel job ${id} (${fnName}) failed in ${end - start}ms`); return reject(error); }, }; @@ -363,8 +345,7 @@ function makeChannel(fnName: string) { }); _jobs[jobId].timer = setTimeout( - () => - reject(new Error(`SQL channel job ${jobId} (${fnName}) timed out`)), + () => reject(new Error(`SQL channel job ${jobId} (${fnName}) timed out`)), DATABASE_UPDATE_TIMEOUT ); }); @@ -429,9 +410,7 @@ const IDENTITY_KEY_KEYS = ['publicKey']; // TODO: identity key has different shape depending on how it is called, // so we need to come up with a way to make TS work with all of them -export async function getIdentityKeyById( - id: string -): Promise<IdentityKey | null> { +export async function getIdentityKeyById(id: string): Promise<IdentityKey | null> { const data = await channels.getIdentityKeyById(id); return keysToArrayBuffer(IDENTITY_KEY_KEYS, data); } @@ -468,9 +447,7 @@ const ITEM_KEYS: Object = { export async function createOrUpdateItem(data: StorageItem): Promise<void> { const { id } = data; if (!id) { - throw new Error( - 'createOrUpdateItem: Provided data did not have a truthy id' - ); + throw new Error('createOrUpdateItem: Provided data did not have a truthy id'); } const keys = (ITEM_KEYS as any)[id]; @@ -478,9 +455,7 @@ export async function createOrUpdateItem(data: StorageItem): Promise<void> { await channels.createOrUpdateItem(updated); } -export async function getItemById( - id: string -): Promise<StorageItem | undefined> { +export async function getItemById(id: string): Promise<StorageItem | undefined> { const keys = (ITEM_KEYS as any)[id]; const data = await channels.getItemById(id); @@ -497,10 +472,7 @@ export async function generateAttachmentKeyIfEmpty() { value: encryptingKey, }); // be sure to write the new key to the cache. so we can access it straight away - window.textsecure.storage.put( - 'local_attachment_encrypted_key', - encryptingKey - ); + window.textsecure.storage.put('local_attachment_encrypted_key', encryptingKey); } } @@ -521,9 +493,7 @@ export async function removeAllSessions(): Promise<void> { } // Swarm nodes -export async function getSwarmNodesForPubkey( - pubkey: string -): Promise<Array<string>> { +export async function getSwarmNodesForPubkey(pubkey: string): Promise<Array<string>> { return channels.getSwarmNodesForPubkey(pubkey); } @@ -578,9 +548,7 @@ export async function saveConversation(data: ConversationType): Promise<void> { await channels.saveConversation(cleaned); } -export async function getConversationById( - id: string -): Promise<ConversationModel | undefined> { +export async function getConversationById(id: string): Promise<ConversationModel | undefined> { const data = await channels.getConversationById(id); if (data) { return new ConversationModel(data); @@ -588,9 +556,7 @@ export async function getConversationById( return undefined; } -export async function updateConversation( - data: ConversationType -): Promise<void> { +export async function updateConversation(data: ConversationType): Promise<void> { await channels.updateConversation(data); } @@ -618,9 +584,7 @@ export async function getAllConversationIds(): Promise<Array<string>> { return ids; } -export async function getAllPublicConversations(): Promise< - ConversationCollection -> { +export async function getAllPublicConversations(): Promise<ConversationCollection> { const conversations = await channels.getAllPublicConversations(); const collection = new ConversationCollection(); @@ -628,9 +592,7 @@ export async function getAllPublicConversations(): Promise< return collection; } -export async function getPubkeysInPublicConversation( - id: string -): Promise<Array<string>> { +export async function getPubkeysInPublicConversation(id: string): Promise<Array<string>> { return channels.getPubkeysInPublicConversation(id); } @@ -640,15 +602,11 @@ export async function savePublicServerToken(data: ServerToken): Promise<void> { } // open groups v1 only -export async function getPublicServerTokenByServerUrl( - serverUrl: string -): Promise<string> { +export async function getPublicServerTokenByServerUrl(serverUrl: string): Promise<string> { const token = await channels.getPublicServerTokenByServerUrl(serverUrl); return token; } -export async function getAllGroupsInvolvingId( - id: string -): Promise<ConversationCollection> { +export async function getAllGroupsInvolvingId(id: string): Promise<ConversationCollection> { const conversations = await channels.getAllGroupsInvolvingId(id); const collection = new ConversationCollection(); @@ -661,10 +619,7 @@ export async function searchConversations(query: string): Promise<Array<any>> { return conversations; } -export async function searchMessages( - query: string, - { limit }: any = {} -): Promise<Array<any>> { +export async function searchMessages(query: string, { limit }: any = {}): Promise<Array<any>> { const messages = await channels.searchMessages(query, { limit }); return messages; } @@ -677,11 +632,9 @@ export async function searchMessagesInConversation( conversationId: string, options: { limit: number } | undefined ): Promise<Object> { - const messages = await channels.searchMessagesInConversation( - query, - conversationId, - { limit: options?.limit } - ); + const messages = await channels.searchMessagesInConversation(query, conversationId, { + limit: options?.limit, + }); return messages; } @@ -720,9 +673,7 @@ export async function saveMessage(data: MessageAttributes): Promise<string> { return id; } -export async function saveMessages( - arrayOfMessages: Array<MessageAttributes> -): Promise<void> { +export async function saveMessages(arrayOfMessages: Array<MessageAttributes>): Promise<void> { await channels.saveMessages(_cleanData(arrayOfMessages)); } @@ -742,10 +693,7 @@ export async function _removeMessages(ids: Array<string>): Promise<void> { await channels.removeMessage(ids); } -export async function getMessageIdsFromServerIds( - serverIds: Array<string>, - conversationId: string -) { +export async function getMessageIdsFromServerIds(serverIds: Array<string>, conversationId: string) { return channels.getMessageIdsFromServerIds(serverIds, conversationId); } @@ -771,11 +719,7 @@ export async function getAllMessageIds(): Promise<Array<string>> { export async function getMessageBySender( // eslint-disable-next-line camelcase - { - source, - sourceDevice, - sent_at, - }: { source: string; sourceDevice: number; sent_at: number } + { source, sourceDevice, sent_at }: { source: string; sourceDevice: number; sent_at: number } ): Promise<MessageModel | null> { const messages = await channels.getMessageBySender({ source, @@ -789,17 +733,13 @@ export async function getMessageBySender( return new MessageModel(messages[0]); } -export async function getUnreadByConversation( - conversationId: string -): Promise<MessageCollection> { +export async function getUnreadByConversation(conversationId: string): Promise<MessageCollection> { const messages = await channels.getUnreadByConversation(conversationId); return new MessageCollection(messages); } // might throw -export async function getUnreadCountByConversation( - conversationId: string -): Promise<number> { +export async function getUnreadCountByConversation(conversationId: string): Promise<number> { return channels.getUnreadCountByConversation(conversationId); } @@ -815,22 +755,15 @@ export async function getMessagesByConversation( return new MessageCollection(messages); } -export async function getLastHashBySnode( - convoId: string, - snode: string -): Promise<string> { +export async function getLastHashBySnode(convoId: string, snode: string): Promise<string> { return channels.getLastHashBySnode(convoId, snode); } -export async function getSeenMessagesByHashList( - hashes: Array<string> -): Promise<any> { +export async function getSeenMessagesByHashList(hashes: Array<string>): Promise<any> { return channels.getSeenMessagesByHashList(hashes); } -export async function removeAllMessagesInConversation( - conversationId: string -): Promise<void> { +export async function removeAllMessagesInConversation(conversationId: string): Promise<void> { let messages; do { // Yes, we really want the await in the loop. We're deleting 100 at a @@ -856,9 +789,7 @@ export async function removeAllMessagesInConversation( } while (messages.length > 0); } -export async function getMessagesBySentAt( - sentAt: number -): Promise<MessageCollection> { +export async function getMessagesBySentAt(sentAt: number): Promise<MessageCollection> { const messages = await channels.getMessagesBySentAt(sentAt); return new MessageCollection(messages); } @@ -868,9 +799,7 @@ export async function getExpiredMessages(): Promise<MessageCollection> { return new MessageCollection(messages); } -export async function getOutgoingWithoutExpiresAt(): Promise< - MessageCollection -> { +export async function getOutgoingWithoutExpiresAt(): Promise<MessageCollection> { const messages = await channels.getOutgoingWithoutExpiresAt(); return new MessageCollection(messages); } @@ -903,23 +832,15 @@ export type UnprocessedParameter = { senderIdentity?: string; }; -export async function saveUnprocessed( - data: UnprocessedParameter -): Promise<string> { +export async function saveUnprocessed(data: UnprocessedParameter): Promise<string> { const id = await channels.saveUnprocessed(_cleanData(data)); return id; } -export async function updateUnprocessedAttempts( - id: string, - attempts: number -): Promise<void> { +export async function updateUnprocessedAttempts(id: string, attempts: number): Promise<void> { await channels.updateUnprocessedAttempts(id, attempts); } -export async function updateUnprocessedWithData( - id: string, - data: any -): Promise<void> { +export async function updateUnprocessedWithData(id: string, data: any): Promise<void> { await channels.updateUnprocessedWithData(id, data); } @@ -933,18 +854,13 @@ export async function removeAllUnprocessed(): Promise<void> { // Attachment downloads -export async function getNextAttachmentDownloadJobs( - limit: number -): Promise<any> { +export async function getNextAttachmentDownloadJobs(limit: number): Promise<any> { return channels.getNextAttachmentDownloadJobs(limit); } export async function saveAttachmentDownloadJob(job: any): Promise<void> { await channels.saveAttachmentDownloadJob(job); } -export async function setAttachmentDownloadJobPending( - id: string, - pending: boolean -): Promise<void> { +export async function setAttachmentDownloadJobPending(id: string, pending: boolean): Promise<void> { await channels.setAttachmentDownloadJobPending(id, pending); } export async function resetAttachmentDownloadPending(): Promise<void> { @@ -973,10 +889,7 @@ export async function cleanupOrphanedAttachments(): Promise<void> { // Note: will need to restart the app after calling this, to set up afresh export async function removeOtherData(): Promise<void> { - await Promise.all([ - callChannel(ERASE_SQL_KEY), - callChannel(ERASE_ATTACHMENTS_KEY), - ]); + await Promise.all([callChannel(ERASE_SQL_KEY), callChannel(ERASE_ATTACHMENTS_KEY)]); } async function callChannel(name: string): Promise<any> { diff --git a/ts/data/opengroups.ts b/ts/data/opengroups.ts index b835f6d10e6c6f860d28914f70a6b38feb981a96..1d02d7ad85ad8e1c0b31d6a553331345af61b388 100644 --- a/ts/data/opengroups.ts +++ b/ts/data/opengroups.ts @@ -13,13 +13,9 @@ export type OpenGroupV2Room = { token?: string; // currently, the token is on a per room basis }; -export async function getAllV2OpenGroupRooms(): Promise< - Map<string, OpenGroupV2Room> | undefined -> { +export async function getAllV2OpenGroupRooms(): Promise<Map<string, OpenGroupV2Room> | undefined> { // TODO sql - const opengroupsv2Rooms = (await channels.getAllV2OpenGroupRooms()) as Array< - OpenGroupV2Room - >; + const opengroupsv2Rooms = (await channels.getAllV2OpenGroupRooms()) as Array<OpenGroupV2Room>; if (!opengroupsv2Rooms) { return undefined; @@ -51,10 +47,7 @@ export async function getV2OpenGroupRoom( export async function getV2OpenGroupRoomByRoomId( roomInfos: OpenGroupRequestCommonType ): Promise<OpenGroupV2Room | undefined> { - const room = await channels.getV2OpenGroupRoomByRoomId( - roomInfos.serverUrl, - roomInfos.roomId - ); + const room = await channels.getV2OpenGroupRoomByRoomId(roomInfos.serverUrl, roomInfos.roomId); if (!room) { return undefined; @@ -63,9 +56,7 @@ export async function getV2OpenGroupRoomByRoomId( return room; } -export async function saveV2OpenGroupRoom( - opengroupsv2Room: OpenGroupV2Room -): Promise<void> { +export async function saveV2OpenGroupRoom(opengroupsv2Room: OpenGroupV2Room): Promise<void> { if ( !opengroupsv2Room.conversationId || !opengroupsv2Room.roomId || @@ -79,9 +70,7 @@ export async function saveV2OpenGroupRoom( await channels.saveV2OpenGroupRoom(opengroupsv2Room); } -export async function removeV2OpenGroupRoom( - conversationId: string -): Promise<void> { +export async function removeV2OpenGroupRoom(conversationId: string): Promise<void> { console.warn('removing roomInfo', conversationId); await channels.removeV2OpenGroupRoom(conversationId); diff --git a/ts/models/conversation.ts b/ts/models/conversation.ts index 2a7b2c750124e4bb46bb776390af0d1e424e1ff0..daf1b8f83cc2e1fa20989003b469017c797dcdc4 100644 --- a/ts/models/conversation.ts +++ b/ts/models/conversation.ts @@ -21,10 +21,7 @@ import { saveMessages, updateConversation, } from '../../ts/data/data'; -import { - fromArrayBufferToBase64, - fromBase64ToArrayBuffer, -} from '../session/utils/String'; +import { fromArrayBufferToBase64, fromBase64ToArrayBuffer } from '../session/utils/String'; import { actions as conversationActions, ConversationType as ReduxConversationType, @@ -166,24 +163,17 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> { autoBind(this); this.throttledBumpTyping = _.throttle(this.bumpTyping, 300); - this.updateLastMessage = _.throttle( - this.bouncyUpdateLastMessage.bind(this), - 1000 - ); + this.updateLastMessage = _.throttle(this.bouncyUpdateLastMessage.bind(this), 1000); this.throttledNotify = _.debounce(this.notify, 500, { maxWait: 1000 }); //start right away the function is called, and wait 1sec before calling it again this.markRead = _.debounce(this.markReadBouncy, 1000, { leading: true }); // Listening for out-of-band data updates - this.on('ourAvatarChanged', avatar => - this.updateAvatarOnPublicChat(avatar) - ); + this.on('ourAvatarChanged', avatar => this.updateAvatarOnPublicChat(avatar)); this.typingRefreshTimer = null; this.typingPauseTimer = null; - window.inboxStore?.dispatch( - conversationActions.conversationChanged(this.id, this.getProps()) - ); + window.inboxStore?.dispatch(conversationActions.conversationChanged(this.id, this.getProps())); } public idForLogging() { @@ -283,10 +273,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> { if (this.typingRefreshTimer) { clearTimeout(this.typingRefreshTimer); } - this.typingRefreshTimer = global.setTimeout( - this.onTypingRefreshTimeout.bind(this), - 10 * 1000 - ); + this.typingRefreshTimer = global.setTimeout(this.onTypingRefreshTimeout.bind(this), 10 * 1000); } public onTypingRefreshTimeout() { @@ -301,10 +288,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> { if (this.typingPauseTimer) { clearTimeout(this.typingPauseTimer); } - this.typingPauseTimer = global.setTimeout( - this.onTypingPauseTimeout.bind(this), - 10 * 1000 - ); + this.typingPauseTimer = global.setTimeout(this.onTypingPauseTimeout.bind(this), 10 * 1000); } public onTypingPauseTimeout() { @@ -358,12 +342,9 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> { public async cleanup() { const { deleteAttachmentData } = window.Signal.Migrations; - await window.Signal.Types.Conversation.deleteExternalFiles( - this.attributes, - { - deleteAttachmentData, - } - ); + await window.Signal.Types.Conversation.deleteExternalFiles(this.attributes, { + deleteAttachmentData, + }); window.profileImages.removeImage(this.id); } @@ -391,8 +372,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> { public getProps(): ReduxConversationType { const groupAdmins = this.getGroupAdmins(); - const members = - this.isGroup() && !this.isPublic() ? this.get('members') : undefined; + const members = this.isGroup() && !this.isPublic() ? this.get('members') : undefined; // isSelected is overriden by redux return { @@ -514,20 +494,14 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> { } public async getQuoteAttachment(attachments: any, preview: any) { - const { - loadAttachmentData, - getAbsoluteAttachmentPath, - } = window.Signal.Migrations; + const { loadAttachmentData, getAbsoluteAttachmentPath } = window.Signal.Migrations; if (attachments && attachments.length) { return Promise.all( attachments .filter( (attachment: any) => - attachment && - attachment.contentType && - !attachment.pending && - !attachment.error + attachment && attachment.contentType && !attachment.pending && !attachment.error ) .slice(0, 1) .map(async (attachment: any) => { @@ -586,13 +560,8 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> { const body = quotedMessage.get('body'); const embeddedContact = quotedMessage.get('contact'); const embeddedContactName = - embeddedContact && embeddedContact.length > 0 - ? getName(embeddedContact[0]) - : ''; - const quotedAttachments = await this.getQuoteAttachment( - attachments, - preview - ); + embeddedContact && embeddedContact.length > 0 ? getName(embeddedContact[0]) : ''; + const quotedAttachments = await this.getQuoteAttachment(attachments, preview); return { author: contact.id, id: quotedMessage.get('sent_at'), @@ -612,10 +581,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> { conversationId: this.id, }); } - public async sendMessageJob( - message: MessageModel, - expireTimer: number | undefined - ) { + public async sendMessageJob(message: MessageModel, expireTimer: number | undefined) { try { const uploads = await message.uploadData(); const { id } = message; @@ -676,18 +642,12 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> { expireTimer: this.get('expireTimer'), }); // we need the return await so that errors are caught in the catch {} - await getMessageQueue().sendToPubKey( - destinationPubkey, - groupInvitMessage - ); + await getMessageQueue().sendToPubKey(destinationPubkey, groupInvitMessage); return; } const chatMessagePrivate = new VisibleMessage(chatMessageParams); - await getMessageQueue().sendToPubKey( - destinationPubkey, - chatMessagePrivate - ); + await getMessageQueue().sendToPubKey(destinationPubkey, chatMessagePrivate); return; } @@ -704,9 +664,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> { } if (this.isClosedGroup()) { - throw new Error( - 'Legacy group are not supported anymore. You need to recreate this group.' - ); + throw new Error('Legacy group are not supported anymore. You need to recreate this group.'); } throw new TypeError(`Invalid conversation type: '${this.get('type')}'`); @@ -731,12 +689,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> { const now = Date.now(); - window.log.info( - 'Sending message to conversation', - this.idForLogging(), - 'with timestamp', - now - ); + window.log.info('Sending message to conversation', this.idForLogging(), 'with timestamp', now); // be sure an empty quote is marked as undefined rather than being empty // otherwise upgradeMessageSchema() will return an object with an empty array // and this.get('quote') will be true, even if there is no quote. @@ -805,9 +758,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> { // tslint:disable-next-line: no-parameter-reassignment profileKey = fromArrayBufferToBase64(profileKey); } - const serverAPI = await window.lokiPublicChatAPI.findOrCreateServer( - this.get('server') - ); + const serverAPI = await window.lokiPublicChatAPI.findOrCreateServer(this.get('server')); if (!serverAPI) { return; } @@ -829,16 +780,12 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> { const lastMessageStatusModel = lastMessageModel ? lastMessageModel.getMessagePropStatus() : null; - const lastMessageUpdate = window.Signal.Types.Conversation.createLastMessageUpdate( - { - currentTimestamp: this.get('active_at') || null, - lastMessage: lastMessageJSON, - lastMessageStatus: lastMessageStatusModel, - lastMessageNotificationText: lastMessageModel - ? lastMessageModel.getNotificationText() - : null, - } - ); + const lastMessageUpdate = window.Signal.Types.Conversation.createLastMessageUpdate({ + currentTimestamp: this.get('active_at') || null, + lastMessage: lastMessageJSON, + lastMessageStatus: lastMessageStatusModel, + lastMessageNotificationText: lastMessageModel ? lastMessageModel.getNotificationText() : null, + }); // Because we're no longer using Backbone-integrated saves, we need to manually // clear the changed fields here so our hasChanged() check below is useful. (this as any).changed = {}; @@ -864,10 +811,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> { if (!expireTimer) { expireTimer = null; } - if ( - this.get('expireTimer') === expireTimer || - (!expireTimer && !this.get('expireTimer')) - ) { + if (this.get('expireTimer') === expireTimer || (!expireTimer && !this.get('expireTimer'))) { return null; } @@ -927,30 +871,22 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> { } if (this.isMe()) { - const expirationTimerMessage = new ExpirationTimerUpdateMessage( - expireUpdate - ); + const expirationTimerMessage = new ExpirationTimerUpdateMessage(expireUpdate); return message.sendSyncMessageOnly(expirationTimerMessage); } if (this.isPrivate()) { - const expirationTimerMessage = new ExpirationTimerUpdateMessage( - expireUpdate - ); + const expirationTimerMessage = new ExpirationTimerUpdateMessage(expireUpdate); const pubkey = new PubKey(this.get('id')); await getMessageQueue().sendToPubKey(pubkey, expirationTimerMessage); } else { - window.log.warn( - 'TODO: Expiration update for closed groups are to be updated' - ); + window.log.warn('TODO: Expiration update for closed groups are to be updated'); const expireUpdateForGroup = { ...expireUpdate, groupId: this.get('id'), }; - const expirationTimerMessage = new ExpirationTimerUpdateMessage( - expireUpdateForGroup - ); + const expirationTimerMessage = new ExpirationTimerUpdateMessage(expireUpdateForGroup); await getMessageQueue().sendToGroup(expirationTimerMessage); } @@ -968,10 +904,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> { ); } - public async addSingleMessage( - messageAttributes: MessageAttributesOptionals, - setToExpire = true - ) { + public async addSingleMessage(messageAttributes: MessageAttributesOptionals, setToExpire = true) { const model = new MessageModel(messageAttributes); const messageId = await model.commit(); @@ -1002,10 +935,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> { } } - public async markReadBouncy( - newestUnreadDate: number, - providedOptions: any = {} - ) { + public async markReadBouncy(newestUnreadDate: number, providedOptions: any = {}) { const options = providedOptions || {}; _.defaults(options, { sendReadReceipts: true }); @@ -1042,9 +972,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> { for (const nowRead of oldUnreadNowRead) { nowRead.generateProps(false); } - window.inboxStore?.dispatch( - conversationActions.messagesChanged(oldUnreadNowRead) - ); + window.inboxStore?.dispatch(conversationActions.messagesChanged(oldUnreadNowRead)); // Some messages we're marking read are local notifications with no sender read = _.filter(read, m => Boolean(m.sender)); @@ -1061,9 +989,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> { return; } - allUnreadMessagesInConvo = allUnreadMessagesInConvo.filter((m: any) => - Boolean(m.isIncoming()) - ); + allUnreadMessagesInConvo = allUnreadMessagesInConvo.filter((m: any) => Boolean(m.isIncoming())); this.set({ unreadCount: realUnreadCount }); @@ -1102,9 +1028,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> { if (window.storage.get('read-receipt-setting')) { await Promise.all( _.map(_.groupBy(read, 'sender'), async (receipts, sender) => { - const timestamps = _.map(receipts, 'timestamp').filter( - t => !!t - ) as Array<number>; + const timestamps = _.map(receipts, 'timestamp').filter(t => !!t) as Array<number>; const receiptMessage = new ReadReceiptMessage({ timestamp: Date.now(), timestamps, @@ -1130,10 +1054,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> { await this.updateProfileName(); } - public async setLokiProfile(newProfile: { - displayName?: string | null; - avatar?: string; - }) { + public async setLokiProfile(newProfile: { displayName?: string | null; avatar?: string }) { if (!_.isEqual(this.get('profile'), newProfile)) { this.set({ profile: newProfile }); await this.commit(); @@ -1165,15 +1086,10 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> { // maybe "Backend" instead of "Source"? public async setPublicSource(newServer: any, newChannelId: any) { if (!this.isPublic()) { - window.log.warn( - `trying to setPublicSource on non public chat conversation ${this.id}` - ); + window.log.warn(`trying to setPublicSource on non public chat conversation ${this.id}`); return; } - if ( - this.get('server') !== newServer || - this.get('channelId') !== newChannelId - ) { + if (this.get('server') !== newServer || this.get('channelId') !== newChannelId) { // mark active so it's not in the contacts list but in the conversation list this.set({ server: newServer, @@ -1185,9 +1101,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> { } public getPublicSource() { if (!this.isPublic()) { - window.log.warn( - `trying to getPublicSource on non public chat conversation ${this.id}` - ); + window.log.warn(`trying to getPublicSource on non public chat conversation ${this.id}`); return null; } return { @@ -1321,9 +1235,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> { try { const profileKeyBuffer = fromBase64ToArrayBuffer(profileKey); - const accessKeyBuffer = await window.Signal.Crypto.deriveAccessKey( - profileKeyBuffer - ); + const accessKeyBuffer = await window.Signal.Crypto.deriveAccessKey(profileKeyBuffer); const accessKey = fromArrayBufferToBase64(accessKeyBuffer); this.set({ accessKey }); } catch (e) { @@ -1338,9 +1250,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> { const { attributes } = message; const { schemaVersion } = attributes; - if ( - schemaVersion < window.Signal.Types.Message.VERSION_NEEDED_FOR_DISPLAY - ) { + if (schemaVersion < window.Signal.Types.Message.VERSION_NEEDED_FOR_DISPLAY) { // Yep, we really do want to wait for each of these // eslint-disable-next-line no-await-in-loop const { upgradeMessageSchema } = window.Signal.Migrations; @@ -1418,10 +1328,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> { ignoredServerIds = result.ignoredIds; } - const toDeleteLocallyServerIds = _.union( - deletedServerIds, - ignoredServerIds - ); + const toDeleteLocallyServerIds = _.union(deletedServerIds, ignoredServerIds); let toDeleteLocally = messages.filter(m => toDeleteLocallyServerIds.includes(m.attributes.serverId) ); @@ -1453,9 +1360,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> { public deleteMessages() { let params; if (this.isPublic()) { - throw new Error( - 'Called deleteMessages() on an open group. Only leave group is supported.' - ); + throw new Error('Called deleteMessages() on an open group. Only leave group is supported.'); } else { params = { title: window.i18n('deleteMessages'), @@ -1497,9 +1402,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> { if (this.isPrivate()) { const profileName = this.getProfileName(); const number = this.getNumber(); - const name = profileName - ? `${profileName} (${PubKey.shorten(number)})` - : number; + const name = profileName ? `${profileName} (${PubKey.shorten(number)})` : number; return this.get('name') || name; } @@ -1690,9 +1593,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> { } } -export class ConversationCollection extends Backbone.Collection< - ConversationModel -> { +export class ConversationCollection extends Backbone.Collection<ConversationModel> { constructor(models?: Array<ConversationModel>) { super(models); this.comparator = (m: ConversationModel) => { diff --git a/ts/models/message.ts b/ts/models/message.ts index fb9b02bb546df816c456444a6503aafdedecef86..c05a4bf0480fb0f39e1570451307351c993123d9 100644 --- a/ts/models/message.ts +++ b/ts/models/message.ts @@ -6,10 +6,7 @@ import { SignalService } from '../../ts/protobuf'; import { getMessageQueue, Types, Utils } from '../../ts/session'; import { ConversationController } from '../../ts/session/conversations'; import { MessageController } from '../../ts/session/messages'; -import { - DataMessage, - OpenGroupMessage, -} from '../../ts/session/messages/outgoing'; +import { DataMessage, OpenGroupMessage } from '../../ts/session/messages/outgoing'; import { ClosedGroupVisibleMessage } from '../session/messages/outgoing/visibleMessage/ClosedGroupVisibleMessage'; import { PubKey } from '../../ts/session/types'; import { ToastUtils, UserUtils } from '../../ts/session/utils'; @@ -83,8 +80,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> { } public isExpirationTimerUpdate() { - const expirationTimerFlag = - SignalService.DataMessage.Flags.EXPIRATION_TIMER_UPDATE; + const expirationTimerFlag = SignalService.DataMessage.Flags.EXPIRATION_TIMER_UPDATE; const flags = this.get('flags'); if (!flags) { return false; @@ -154,15 +150,11 @@ export class MessageModel extends Backbone.Model<MessageAttributes> { } if (groupUpdate.joined && groupUpdate.joined.length) { const names = groupUpdate.joined.map((pubKey: string) => - ConversationController.getInstance().getContactProfileNameOrFullPubKey( - pubKey - ) + ConversationController.getInstance().getContactProfileNameOrFullPubKey(pubKey) ); if (names.length > 1) { - messages.push( - window.i18n('multipleJoinedTheGroup', names.join(', ')) - ); + messages.push(window.i18n('multipleJoinedTheGroup', names.join(', '))); } else { messages.push(window.i18n('joinedTheGroup', names[0])); } @@ -171,14 +163,11 @@ export class MessageModel extends Backbone.Model<MessageAttributes> { if (groupUpdate.kicked && groupUpdate.kicked.length) { const names = _.map( groupUpdate.kicked, - ConversationController.getInstance() - .getContactProfileNameOrShortenedPubKey + ConversationController.getInstance().getContactProfileNameOrShortenedPubKey ); if (names.length > 1) { - messages.push( - window.i18n('multipleKickedFromTheGroup', names.join(', ')) - ); + messages.push(window.i18n('multipleKickedFromTheGroup', names.join(', '))); } else { messages.push(window.i18n('kickedFromTheGroup', names[0])); } @@ -225,9 +214,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> { return window.i18n( 'timerSetTo', - window.Whisper.ExpirationTimerOptions.getAbbreviated( - expireTimerUpdate.expireTimer || 0 - ) + window.Whisper.ExpirationTimerOptions.getAbbreviated(expireTimerUpdate.expireTimer || 0) ); } const contacts = this.get('contact'); @@ -254,9 +241,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> { } const { expireTimer, fromSync, source } = timerUpdate; - const timespan = window.Whisper.ExpirationTimerOptions.getName( - expireTimer || 0 - ); + const timespan = window.Whisper.ExpirationTimerOptions.getName(expireTimer || 0); const disabled = !expireTimer; const basicProps = { @@ -340,9 +325,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> { changes.push({ type: 'add', contacts: _.map( - Array.isArray(groupUpdate.joined) - ? groupUpdate.joined - : [groupUpdate.joined], + Array.isArray(groupUpdate.joined) ? groupUpdate.joined : [groupUpdate.joined], phoneNumber => this.findAndFormatContact(phoneNumber) ), }); @@ -357,9 +340,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> { changes.push({ type: 'kicked', contacts: _.map( - Array.isArray(groupUpdate.kicked) - ? groupUpdate.kicked - : [groupUpdate.kicked], + Array.isArray(groupUpdate.kicked) ? groupUpdate.kicked : [groupUpdate.kicked], phoneNumber => this.findAndFormatContact(phoneNumber) ), }); @@ -384,9 +365,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> { changes.push({ type: 'remove', contacts: _.map( - Array.isArray(groupUpdate.left) - ? groupUpdate.left - : [groupUpdate.left], + Array.isArray(groupUpdate.left) ? groupUpdate.left : [groupUpdate.left], phoneNumber => this.findAndFormatContact(phoneNumber) ), }); @@ -473,9 +452,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> { const expirationLength = this.get('expireTimer') * 1000; const expireTimerStart = this.get('expirationStartTimestamp'); const expirationTimestamp = - expirationLength && expireTimerStart - ? expireTimerStart + expirationLength - : null; + expirationLength && expireTimerStart ? expireTimerStart + expirationLength : null; // TODO: investigate why conversation is undefined // for the public group chat @@ -533,9 +510,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> { const regex = /(\S)( +)(\S+\s*)$/; return text.replace(regex, (_match, start, spaces, end) => { const newSpaces = - end.length < 12 - ? _.reduce(spaces, accumulator => accumulator + nbsp, '') - : spaces; + end.length < 12 ? _.reduce(spaces, accumulator => accumulator + nbsp, '') : spaces; return `${start}${newSpaces}${end}`; }); } @@ -601,9 +576,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> { const contact = author && ConversationController.getInstance().get(author); const authorName = contact ? contact.getName() : null; - const isFromMe = contact - ? contact.id === UserUtils.getOurPubKeyStrFromCache() - : false; + const isFromMe = contact ? contact.id === UserUtils.getOurPubKeyStrFromCache() : false; const onClick = noClick ? null : (event: any) => { @@ -619,9 +592,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> { return { text: this.createNonBreakingLastSeparator(quote.text), - attachment: firstAttachment - ? this.processQuoteAttachment(firstAttachment) - : null, + attachment: firstAttachment ? this.processQuoteAttachment(firstAttachment) : null, isFromMe, authorPhoneNumber: author, messageId: id, @@ -647,23 +618,17 @@ export class MessageModel extends Backbone.Model<MessageAttributes> { // tslint:disable-next-line: no-bitwise flags & SignalService.AttachmentPointer.Flags.VOICE_MESSAGE, pending, - url: path - ? window.Signal.Migrations.getAbsoluteAttachmentPath(path) - : null, + url: path ? window.Signal.Migrations.getAbsoluteAttachmentPath(path) : null, screenshot: screenshot ? { ...screenshot, - url: window.Signal.Migrations.getAbsoluteAttachmentPath( - screenshot.path - ), + url: window.Signal.Migrations.getAbsoluteAttachmentPath(screenshot.path), } : null, thumbnail: thumbnail ? { ...thumbnail, - url: window.Signal.Migrations.getAbsoluteAttachmentPath( - thumbnail.path - ), + url: window.Signal.Migrations.getAbsoluteAttachmentPath(thumbnail.path), } : null, }; @@ -677,9 +642,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> { ? [this.get('source')] : _.union( this.get('sent_to') || [], - this.get('recipients') || - this.getConversation()?.getRecipients() || - [] + this.get('recipients') || this.getConversation()?.getRecipients() || [] ); // This will make the error message for outgoing key errors a bit nicer @@ -749,17 +712,13 @@ export class MessageModel extends Backbone.Model<MessageAttributes> { const source = this.get('source'); const conversation = this.getConversation(); if (!conversation) { - window.log.info( - 'cannot ban user, the corresponding conversation was not found.' - ); + window.log.info('cannot ban user, the corresponding conversation was not found.'); return; } const channelAPI = await conversation.getPublicSendData(); if (!channelAPI) { - window.log.info( - 'cannot ban user, the corresponding channelAPI was not found.' - ); + window.log.info('cannot ban user, the corresponding channelAPI was not found.'); return; } const success = await channelAPI.banUser(source); @@ -789,41 +748,29 @@ export class MessageModel extends Backbone.Model<MessageAttributes> { // This way we don't upload duplicated data. const attachmentsWithData = await Promise.all( - (this.get('attachments') || []).map( - window.Signal.Migrations.loadAttachmentData - ) + (this.get('attachments') || []).map(window.Signal.Migrations.loadAttachmentData) ); const body = this.get('body'); const finalAttachments = attachmentsWithData; - const filenameOverridenAttachments = finalAttachments.map( - (attachment: any) => ({ - ...attachment, - fileName: getSuggestedFilenameSending({ - attachment, - timestamp: Date.now(), - }), - }) - ); + const filenameOverridenAttachments = finalAttachments.map((attachment: any) => ({ + ...attachment, + fileName: getSuggestedFilenameSending({ + attachment, + timestamp: Date.now(), + }), + })); - const quoteWithData = await window.Signal.Migrations.loadQuoteData( - this.get('quote') - ); - const previewWithData = await window.Signal.Migrations.loadPreviewData( - this.get('preview') - ); + const quoteWithData = await window.Signal.Migrations.loadQuoteData(this.get('quote')); + const previewWithData = await window.Signal.Migrations.loadPreviewData(this.get('preview')); const conversation = this.getConversation(); const openGroup = - (conversation && conversation.isPublic() && conversation.toOpenGroup()) || - undefined; + (conversation && conversation.isPublic() && conversation.toOpenGroup()) || undefined; const { AttachmentUtils } = Utils; const [attachments, preview, quote] = await Promise.all([ - AttachmentUtils.uploadAttachments( - filenameOverridenAttachments, - openGroup - ), + AttachmentUtils.uploadAttachments(filenameOverridenAttachments, openGroup), AttachmentUtils.uploadLinkPreviews(previewWithData, openGroup), AttachmentUtils.uploadQuoteThumbnails(quoteWithData, openGroup), ]); @@ -846,13 +793,9 @@ export class MessageModel extends Backbone.Model<MessageAttributes> { this.set({ errors: null }); await this.commit(); try { - const conversation: - | ConversationModel - | undefined = this.getConversation(); + const conversation: ConversationModel | undefined = this.getConversation(); if (!conversation) { - window.log.info( - 'cannot retry send message, the corresponding conversation was not found.' - ); + window.log.info('cannot retry send message, the corresponding conversation was not found.'); return; } @@ -898,10 +841,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> { } if (conversation.isPrivate()) { - return getMessageQueue().sendToPubKey( - PubKey.cast(conversation.id), - chatMessage - ); + return getMessageQueue().sendToPubKey(PubKey.cast(conversation.id), chatMessage); } // Here, the convo is neither an open group, a private convo or ourself. It can only be a medium group. @@ -939,9 +879,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> { // This needs to be an unsafe call, because this method is called during // initial module setup. We may be in the middle of the initial fetch to // the database. - return ConversationController.getInstance().getUnsafe( - this.get('conversationId') - ); + return ConversationController.getInstance().getUnsafe(this.get('conversationId')); } public getQuoteContact() { @@ -972,10 +910,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> { return null; } - return ConversationController.getInstance().getOrCreate( - source, - ConversationType.PRIVATE - ); + return ConversationController.getInstance().getOrCreate(source, ConversationType.PRIVATE); } public isOutgoing() { @@ -1013,17 +948,11 @@ export class MessageModel extends Backbone.Model<MessageAttributes> { await this.commit(); - const data = - dataMessage instanceof DataMessage - ? dataMessage.dataProto() - : dataMessage; + const data = dataMessage instanceof DataMessage ? dataMessage.dataProto() : dataMessage; await this.sendSyncMessage(data, now); } - public async sendSyncMessage( - dataMessage: SignalService.DataMessage, - sentTimestamp: number - ) { + public async sendSyncMessage(dataMessage: SignalService.DataMessage, sentTimestamp: number) { if (this.get('synced') || this.get('sentSync')) { return; } @@ -1032,19 +961,13 @@ export class MessageModel extends Backbone.Model<MessageAttributes> { if ( (dataMessage.body && dataMessage.body.length) || dataMessage.attachments.length || - dataMessage.flags === - SignalService.DataMessage.Flags.EXPIRATION_TIMER_UPDATE + dataMessage.flags === SignalService.DataMessage.Flags.EXPIRATION_TIMER_UPDATE ) { const conversation = this.getConversation(); if (!conversation) { throw new Error('Cannot trigger syncMessage with unknown convo.'); } - const syncMessage = buildSyncMessage( - this.id, - dataMessage, - conversation.id, - sentTimestamp - ); + const syncMessage = buildSyncMessage(this.id, dataMessage, conversation.id, sentTimestamp); await getMessageQueue().sendSyncMessage(syncMessage); } this.set({ sentSync: true }); @@ -1111,10 +1034,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> { this.set({ unread: 0 }); if (this.get('expireTimer') && !this.get('expirationStartTimestamp')) { - const expirationStartTimestamp = Math.min( - Date.now(), - readAt || Date.now() - ); + const expirationStartTimestamp = Math.min(Date.now(), readAt || Date.now()); this.set({ expirationStartTimestamp }); } diff --git a/ts/models/messageType.ts b/ts/models/messageType.ts index bc0249e2daf24a7751394867f887b2cd8732935d..c17589704a0292e95fbe081b468af6bbf137d12a 100644 --- a/ts/models/messageType.ts +++ b/ts/models/messageType.ts @@ -6,12 +6,7 @@ import { AttachmentType } from '../types/Attachment'; import { Contact } from '../types/Contact'; export type MessageModelType = 'incoming' | 'outgoing'; -export type MessageDeliveryStatus = - | 'sending' - | 'sent' - | 'delivered' - | 'read' - | 'error'; +export type MessageDeliveryStatus = 'sending' | 'sent' | 'delivered' | 'read' | 'error'; export interface MessageAttributes { // the id of the message diff --git a/ts/notifications/getStatus.ts b/ts/notifications/getStatus.ts index 7c693435c4952cd2e0955ff2ad4d9a4e699ddfb4..c837b132a274ac132e3fe179e8f008e900c65890 100644 --- a/ts/notifications/getStatus.ts +++ b/ts/notifications/getStatus.ts @@ -16,12 +16,7 @@ interface Status { type UserSetting = 'off' | 'count' | 'name' | 'message'; -type Type = - | 'ok' - | 'disabled' - | 'appIsFocused' - | 'noNotifications' - | 'userSetting'; +type Type = 'ok' | 'disabled' | 'appIsFocused' | 'noNotifications' | 'userSetting'; export const getStatus = ({ isAppFocused, @@ -52,8 +47,7 @@ export const getStatus = ({ return 'ok'; })(); - const shouldPlayNotificationSound = - isAudioNotificationSupported && isAudioNotificationEnabled; + const shouldPlayNotificationSound = isAudioNotificationSupported && isAudioNotificationEnabled; const shouldShowNotifications = type === 'ok'; const shouldClearNotifications = type === 'appIsFocused'; diff --git a/ts/opengroup/opengroupV1/OpenGroup.ts b/ts/opengroup/opengroupV1/OpenGroup.ts index 3ff2847692d84c79e98d10442d43d00df90961d9..a975a147d398c975fa9496b13603e8fbced513de 100644 --- a/ts/opengroup/opengroupV1/OpenGroup.ts +++ b/ts/opengroup/opengroupV1/OpenGroup.ts @@ -59,9 +59,7 @@ export class OpenGroup { const convos = ConversationController.getInstance().getConversations(); return convos .filter(c => !!c.get('active_at') && c.isPublic() && !c.get('left')) - .map(c => c.id.substring((c.id as string).lastIndexOf('@') + 1)) as Array< - string - >; + .map(c => c.id.substring((c.id as string).lastIndexOf('@') + 1)) as Array<string>; } /** @@ -107,10 +105,7 @@ export class OpenGroup { * @param onLoading Callback function to be called once server begins connecting * @returns `OpenGroup` if connection success or if already connected */ - public static async join( - server: string, - fromSyncMessage: boolean = false - ): Promise<void> { + public static async join(server: string, fromSyncMessage: boolean = false): Promise<void> { const prefixedServer = prefixify(server); if (!OpenGroup.validate(server)) { return; @@ -160,9 +155,7 @@ export class OpenGroup { if (!OpenGroup.validate(server)) { return; } - const rawServerURL = server - .replace(/^https?:\/\//i, '') - .replace(/[/\\]+$/i, ''); + const rawServerURL = server.replace(/^https?:\/\//i, '').replace(/[/\\]+$/i, ''); const channelId = 1; const conversationId = `publicChat:${channelId}@${rawServerURL}`; @@ -182,22 +175,15 @@ export class OpenGroup { } const prefixedServer = prefixify(server); - return Boolean( - await window.lokiPublicChatAPI.findOrCreateServer(prefixedServer) - ); + return Boolean(await window.lokiPublicChatAPI.findOrCreateServer(prefixedServer)); } - private static getServer( - groupId: string, - hasSSL: boolean - ): string | undefined { + private static getServer(groupId: string, hasSSL: boolean): string | undefined { const isValid = this.groupIdRegex.test(groupId); const strippedServer = isValid ? groupId.split('@')[1] : undefined; // We don't know for sure if the server is https or http when taken from the groupId. Preifx accordingly. - return strippedServer - ? prefixify(strippedServer.toLowerCase(), hasSSL) - : undefined; + return strippedServer ? prefixify(strippedServer.toLowerCase(), hasSSL) : undefined; } private static getChannel(groupId: string): number | undefined { @@ -254,16 +240,12 @@ export class OpenGroup { // Add http or https prefix to server completeServerURL = prefixify(completeServerURL); - const rawServerURL = serverUrl - .replace(/^https?:\/\//i, '') - .replace(/[/\\]+$/i, ''); + const rawServerURL = serverUrl.replace(/^https?:\/\//i, '').replace(/[/\\]+$/i, ''); const conversationId = `publicChat:${channelId}@${rawServerURL}`; // Quickly peak to make sure we don't already have it - const conversationExists = ConversationController.getInstance().get( - conversationId - ); + const conversationExists = ConversationController.getInstance().get(conversationId); if (conversationExists) { // We are already a member of this public chat return new Promise((_resolve, reject) => { @@ -272,9 +254,7 @@ export class OpenGroup { } // Get server - const serverAPI = await window.lokiPublicChatAPI.findOrCreateServer( - completeServerURL - ); + const serverAPI = await window.lokiPublicChatAPI.findOrCreateServer(completeServerURL); // SSL certificate failure or offline if (!serverAPI) { // Url incorrect or server not compatible diff --git a/ts/opengroup/opengroupV2/ApiUtil.ts b/ts/opengroup/opengroupV2/ApiUtil.ts index 8b75f23a92e4fbaf343bbefd69181b46fbd8f083..773378cb94fcdd0e807c05db651e0fec8028794b 100644 --- a/ts/opengroup/opengroupV2/ApiUtil.ts +++ b/ts/opengroup/opengroupV2/ApiUtil.ts @@ -53,9 +53,7 @@ export const buildUrl = (request: OpenGroupV2Request): URL | null => { const entries = Object.entries(request.queryParams || {}); if (entries.length) { - const queryString = entries - .map(([key, value]) => `${key}=${value}`) - .join('&'); + const queryString = entries.map(([key, value]) => `${key}=${value}`).join('&'); rawURL += `?${queryString}`; } } @@ -70,10 +68,7 @@ export const buildUrl = (request: OpenGroupV2Request): URL | null => { /** * Map of serverUrl to roomId to list of moderators as a Set */ -export const cachedModerators: Map< - string, - Map<string, Set<string>> -> = new Map(); +export const cachedModerators: Map<string, Map<string, Set<string>>> = new Map(); export const setCachedModerators = ( serverUrl: string, @@ -115,15 +110,9 @@ export const parseMessages = async ( return null; } // Validate the message signature - const senderPubKey = PubKey.cast( - opengroupMessage.sender - ).withoutPrefix(); - const signature = fromBase64ToArrayBuffer( - opengroupMessage.base64EncodedSignature - ); - const messageData = fromBase64ToArrayBuffer( - opengroupMessage.base64EncodedData - ); + const senderPubKey = PubKey.cast(opengroupMessage.sender).withoutPrefix(); + const signature = fromBase64ToArrayBuffer(opengroupMessage.base64EncodedSignature); + const messageData = fromBase64ToArrayBuffer(opengroupMessage.base64EncodedData); // throws if signature failed await window.libsignal.Curve.async.verifySignature( fromHex(senderPubKey), @@ -132,10 +121,7 @@ export const parseMessages = async ( ); return opengroupMessage; } catch (e) { - window.log.error( - 'An error happened while fetching getMessages output:', - e - ); + window.log.error('An error happened while fetching getMessages output:', e); return null; } }) diff --git a/ts/opengroup/opengroupV2/JoinOpenGroupV2.ts b/ts/opengroup/opengroupV2/JoinOpenGroupV2.ts index 40cb713687cfaf705c05704baf449b65ff671f9b..0d800daad1e97069666456db65928fb75ee6ad2c 100644 --- a/ts/opengroup/opengroupV2/JoinOpenGroupV2.ts +++ b/ts/opengroup/opengroupV2/JoinOpenGroupV2.ts @@ -6,10 +6,7 @@ import { import { ConversationController } from '../../session/conversations'; import { PromiseUtils } from '../../session/utils'; import { forceSyncConfigurationNowIfNeeded } from '../../session/utils/syncUtils'; -import { - getOpenGroupV2ConversationId, - prefixify, -} from '../utils/OpenGroupUtils'; +import { getOpenGroupV2ConversationId, prefixify } from '../utils/OpenGroupUtils'; import { attemptConnectionV2OneAtATime } from './OpenGroupManagerV2'; const protocolRegex = '(https?://)?'; @@ -34,9 +31,7 @@ const openGroupV2CompleteURLRegex = new RegExp( // https://143.198.213.225:443/main?public_key=658d29b91892a2389505596b135e76a53db6e11d613a51dbd3d0816adffb231c // 143.198.213.255:80/main?public_key=658d29b91892a2389505596b135e76a53db6e11d613a51dbd3d0816adffb231c -export function parseOpenGroupV2( - urlWithPubkey: string -): OpenGroupV2Room | undefined { +export function parseOpenGroupV2(urlWithPubkey: string): OpenGroupV2Room | undefined { const lowerCased = urlWithPubkey.toLowerCase(); try { if (!openGroupV2CompleteURLRegex.test(lowerCased)) { @@ -77,12 +72,7 @@ export async function joinOpenGroupV2( room: OpenGroupV2Room, fromSyncMessage: boolean = false ): Promise<void> { - if ( - !room.serverUrl || - !room.roomId || - room.roomId.length < 2 || - !room.serverPublicKey - ) { + if (!room.serverUrl || !room.roomId || room.roomId.length < 2 || !room.serverPublicKey) { return; } @@ -93,9 +83,7 @@ export async function joinOpenGroupV2( const alreadyExist = await getV2OpenGroupRoomByRoomId({ serverUrl, roomId }); const conversationId = getOpenGroupV2ConversationId(serverUrl, roomId); - const existingConvo = ConversationController.getInstance().get( - conversationId - ); + const existingConvo = ConversationController.getInstance().get(conversationId); if (alreadyExist && existingConvo) { window.log.warn('Skipping join opengroupv2: already exists'); diff --git a/ts/opengroup/opengroupV2/OpenGroupAPIV2.ts b/ts/opengroup/opengroupV2/OpenGroupAPIV2.ts index ccb17463c517d3596f67ffead5784f1c725fce98..193b9fe68d324edabbd993f6267f32b659b2f19a 100644 --- a/ts/opengroup/opengroupV2/OpenGroupAPIV2.ts +++ b/ts/opengroup/opengroupV2/OpenGroupAPIV2.ts @@ -1,8 +1,5 @@ import _ from 'lodash'; -import { - getV2OpenGroupRoomByRoomId, - saveV2OpenGroupRoom, -} from '../../data/opengroups'; +import { getV2OpenGroupRoomByRoomId, saveV2OpenGroupRoom } from '../../data/opengroups'; import { ConversationController } from '../../session/conversations'; import { sendViaOnion } from '../../session/onions/onionSend'; import { allowOnlyOneAtATime } from '../../session/utils/Promise'; @@ -11,10 +8,7 @@ import { fromBase64ToArrayBuffer, toHex, } from '../../session/utils/String'; -import { - getIdentityKeyPair, - getOurPubKeyStrFromCache, -} from '../../session/utils/User'; +import { getIdentityKeyPair, getOurPubKeyStrFromCache } from '../../session/utils/User'; import { getOpenGroupV2ConversationId } from '../utils/OpenGroupUtils'; import { buildUrl, @@ -38,9 +32,7 @@ import { OpenGroupMessageV2 } from './OpenGroupMessageV2'; * download and upload of attachments for instance, but most of the logic happens in * the compact_poll endpoint */ -async function sendOpenGroupV2Request( - request: OpenGroupV2Request -): Promise<Object | null> { +async function sendOpenGroupV2Request(request: OpenGroupV2Request): Promise<Object | null> { const builtUrl = buildUrl(request); if (!builtUrl) { @@ -91,10 +83,7 @@ async function sendOpenGroupV2Request( const statusCode = parseStatusCodeFromOnionRequest(res); if (!statusCode) { - window.log.warn( - 'sendOpenGroupV2Request Got unknown status code; res:', - res - ); + window.log.warn('sendOpenGroupV2Request Got unknown status code; res:', res); return res as object; } // A 401 means that we didn't provide a (valid) auth token for a route that required one. We use this as an @@ -155,19 +144,14 @@ export async function requestNewAuthToken({ return null; } const ciphertext = fromBase64ToArrayBuffer(base64EncodedCiphertext); - const ephemeralPublicKey = fromBase64ToArrayBuffer( - base64EncodedEphemeralPublicKey - ); + const ephemeralPublicKey = fromBase64ToArrayBuffer(base64EncodedEphemeralPublicKey); try { const symmetricKey = await window.libloki.crypto.deriveSymmetricKey( ephemeralPublicKey, userKeyPair.privKey ); - const plaintextBuffer = await window.libloki.crypto.DecryptAESGCM( - symmetricKey, - ciphertext - ); + const plaintextBuffer = await window.libloki.crypto.DecryptAESGCM(symmetricKey, ciphertext); const token = toHex(plaintextBuffer); @@ -255,28 +239,25 @@ export async function getAuthToken({ return roomDetails?.token; } - await allowOnlyOneAtATime( - `getAuthTokenV2${serverUrl}:${roomId}`, - async () => { - try { - const token = await requestNewAuthToken({ serverUrl, roomId }); - if (!token) { - window.log.warn('invalid new auth token', token); - return; - } - const claimedToken = await claimAuthToken(token, serverUrl, roomId); - if (!claimedToken) { - window.log.warn('invalid claimed token', claimedToken); - } - // still save it to the db. just to mark it as to be refreshed later - roomDetails.token = claimedToken || ''; - await saveV2OpenGroupRoom(roomDetails); - } catch (e) { - window.log.error('Failed to getAuthToken', e); - throw e; + await allowOnlyOneAtATime(`getAuthTokenV2${serverUrl}:${roomId}`, async () => { + try { + const token = await requestNewAuthToken({ serverUrl, roomId }); + if (!token) { + window.log.warn('invalid new auth token', token); + return; + } + const claimedToken = await claimAuthToken(token, serverUrl, roomId); + if (!claimedToken) { + window.log.warn('invalid claimed token', claimedToken); } + // still save it to the db. just to mark it as to be refreshed later + roomDetails.token = claimedToken || ''; + await saveV2OpenGroupRoom(roomDetails); + } catch (e) { + window.log.error('Failed to getAuthToken', e); + throw e; } - ); + }); const refreshedRoomDetails = await getV2OpenGroupRoomByRoomId({ serverUrl, @@ -292,10 +273,7 @@ export async function getAuthToken({ return null; } -export const deleteAuthToken = async ({ - serverUrl, - roomId, -}: OpenGroupRequestCommonType) => { +export const deleteAuthToken = async ({ serverUrl, roomId }: OpenGroupRequestCommonType) => { const request: OpenGroupV2Request = { method: 'DELETE', room: roomId, @@ -340,9 +318,7 @@ export const getMessages = async ({ } // we have a 200 - const rawMessages = (result as any)?.result?.messages as Array< - Record<string, any> - >; + const rawMessages = (result as any)?.result?.messages as Array<Record<string, any>>; const validMessages = await parseMessages(rawMessages); console.warn('validMessages', validMessages); return validMessages; @@ -406,9 +382,7 @@ export const getModerators = async ({ const moderators = parseModerators(result); if (moderators === undefined) { // if moderators is undefined, do not update the cached moderator list - window.log.warn( - 'Could not getModerators, got no moderatorsGot at all in json.' - ); + window.log.warn('Could not getModerators, got no moderatorsGot at all in json.'); return []; } setCachedModerators(serverUrl, roomId, moderators || []); @@ -457,9 +431,7 @@ export const unbanUser = async ( await sendOpenGroupV2Request(request); }; -export const getAllRoomInfos = async ( - roomInfos: OpenGroupRequestCommonType -) => { +export const getAllRoomInfos = async (roomInfos: OpenGroupRequestCommonType) => { // room should not be required here const request: OpenGroupV2Request = { method: 'GET', @@ -479,9 +451,7 @@ export const getAllRoomInfos = async ( return parseRooms(result); }; -export const getMemberCount = async ( - roomInfos: OpenGroupRequestCommonType -): Promise<void> => { +export const getMemberCount = async (roomInfos: OpenGroupRequestCommonType): Promise<void> => { const request: OpenGroupV2Request = { method: 'GET', room: roomInfos.roomId, @@ -500,16 +470,11 @@ export const getMemberCount = async ( return; } - const conversationId = getOpenGroupV2ConversationId( - roomInfos.serverUrl, - roomInfos.roomId - ); + const conversationId = getOpenGroupV2ConversationId(roomInfos.serverUrl, roomInfos.roomId); const convo = ConversationController.getInstance().get(conversationId); if (!convo) { - window.log.warn( - 'cannot update conversation memberCount as it does not exist' - ); + window.log.warn('cannot update conversation memberCount as it does not exist'); return; } if (convo.get('subscriberCount') !== count) { diff --git a/ts/opengroup/opengroupV2/OpenGroupAPIV2CompactPoll.ts b/ts/opengroup/opengroupV2/OpenGroupAPIV2CompactPoll.ts index e0cd8dca9a24f45f107adff6cb7ece8a0a403e60..85dde8563a42a57b4b1580aaec1dbb41673a34ed 100644 --- a/ts/opengroup/opengroupV2/OpenGroupAPIV2CompactPoll.ts +++ b/ts/opengroup/opengroupV2/OpenGroupAPIV2CompactPoll.ts @@ -1,7 +1,4 @@ -import { - getV2OpenGroupRoomByRoomId, - saveV2OpenGroupRoom, -} from '../../data/opengroups'; +import { getV2OpenGroupRoomByRoomId, saveV2OpenGroupRoom } from '../../data/opengroups'; import { OpenGroupRequestCommonType, OpenGroupV2CompactPollRequest, @@ -27,10 +24,7 @@ export const compactFetchEverything = async ( return null; } - const result = await sendOpenGroupV2RequestCompactPoll( - compactPollRequest, - abortSignal - ); + const result = await sendOpenGroupV2RequestCompactPoll(compactPollRequest, abortSignal); const statusCode = parseStatusCodeFromOnionRequest(result); if (statusCode !== 200) { return null; @@ -140,10 +134,7 @@ async function sendOpenGroupV2RequestCompactPoll( const statusCode = parseStatusCodeFromOnionRequest(res); if (!statusCode) { - window.log.warn( - 'sendOpenGroupV2Request Got unknown status code; res:', - res - ); + window.log.warn('sendOpenGroupV2Request Got unknown status code; res:', res); return null; } @@ -153,9 +144,7 @@ async function sendOpenGroupV2RequestCompactPoll( return null; } // get all roomIds which needs a refreshed token - const roomTokensToRefresh = results - .filter(ret => ret.statusCode === 401) - .map(r => r.roomId); + const roomTokensToRefresh = results.filter(ret => ret.statusCode === 401).map(r => r.roomId); if (roomTokensToRefresh) { await Promise.all( @@ -230,12 +219,7 @@ const parseCompactPollResult = async ( const parseCompactPollResults = async ( res: any ): Promise<Array<ParsedRoomCompactPollResults> | null> => { - if ( - !res || - !res.result || - !res.result.results || - !res.result.results.length - ) { + if (!res || !res.result || !res.result.results || !res.result.results.length) { return null; } const arrayOfResults = res.result.results as Array<any>; diff --git a/ts/opengroup/opengroupV2/OpenGroupAPIV2Parser.ts b/ts/opengroup/opengroupV2/OpenGroupAPIV2Parser.ts index 80bb4f17224f6df2bdc34ff24ae91964e84aac0c..2d169519efc046306419eb951c89c2ccf32c89f0 100644 --- a/ts/opengroup/opengroupV2/OpenGroupAPIV2Parser.ts +++ b/ts/opengroup/opengroupV2/OpenGroupAPIV2Parser.ts @@ -8,9 +8,7 @@ import _ from 'lodash'; * This utility function just extract the status code and returns it. * If the status code is not found, this function returns undefined; */ -export const parseStatusCodeFromOnionRequest = ( - onionResult: any -): number | undefined => { +export const parseStatusCodeFromOnionRequest = (onionResult: any): number | undefined => { if (!onionResult) { return undefined; } @@ -32,9 +30,7 @@ export const parseMemberCount = (onionResult: any): number | undefined => { return undefined; }; -export const parseRooms = ( - onionResult: any -): undefined | Array<OpenGroupV2Info> => { +export const parseRooms = (onionResult: any): undefined | Array<OpenGroupV2Info> => { if (!onionResult) { return undefined; } @@ -57,11 +53,7 @@ export const parseRooms = ( ); }; -export const parseModerators = ( - onionResult: any -): Array<string> | undefined => { - const moderatorsGot = onionResult?.result?.moderators as - | Array<string> - | undefined; +export const parseModerators = (onionResult: any): Array<string> | undefined => { + const moderatorsGot = onionResult?.result?.moderators as Array<string> | undefined; return moderatorsGot; }; diff --git a/ts/opengroup/opengroupV2/OpenGroupManagerV2.ts b/ts/opengroup/opengroupV2/OpenGroupManagerV2.ts index 4b055374d379e88aff62b3e48e6cb43b216b01f6..5798c295cef1db446f5199f9172a1135924c1ea3 100644 --- a/ts/opengroup/opengroupV2/OpenGroupManagerV2.ts +++ b/ts/opengroup/opengroupV2/OpenGroupManagerV2.ts @@ -1,8 +1,4 @@ -import { - OpenGroupV2Room, - removeV2OpenGroupRoom, - saveV2OpenGroupRoom, -} from '../../data/opengroups'; +import { OpenGroupV2Room, removeV2OpenGroupRoom, saveV2OpenGroupRoom } from '../../data/opengroups'; import { ConversationModel, ConversationType } from '../../models/conversation'; import { ConversationController } from '../../session/conversations'; import { allowOnlyOneAtATime } from '../../session/utils/Promise'; diff --git a/ts/opengroup/opengroupV2/OpenGroupServerPoller.ts b/ts/opengroup/opengroupV2/OpenGroupServerPoller.ts index 492344e202fbc0e473f049845942f7508b922349..280839455e22a367c43d624ab95e6e70a139089a 100644 --- a/ts/opengroup/opengroupV2/OpenGroupServerPoller.ts +++ b/ts/opengroup/opengroupV2/OpenGroupServerPoller.ts @@ -41,10 +41,7 @@ export class OpenGroupServerPoller { }); this.abortController = new AbortController(); - this.pollForEverythingTimer = global.setInterval( - this.compactPoll, - pollForEverythingInterval - ); + this.pollForEverythingTimer = global.setInterval(this.compactPoll, pollForEverythingInterval); // first verify the rooms we got are all from on the same server } @@ -71,9 +68,7 @@ export class OpenGroupServerPoller { return; } if (this.roomIdsToPoll.has(room.roomId)) { - window.log.info( - `Removing ${room.roomId} from polling for ${this.serverUrl}` - ); + window.log.info(`Removing ${room.roomId} from polling for ${this.serverUrl}`); this.roomIdsToPoll.delete(room.roomId); } else { window.log.info( @@ -99,9 +94,7 @@ export class OpenGroupServerPoller { private async compactPoll() { if (this.wasStopped) { - window.log.error( - 'serverpoller was stopped. CompactPoll should not happen' - ); + window.log.error('serverpoller was stopped. CompactPoll should not happen'); return; } if (!this.roomIdsToPoll.size) { @@ -138,10 +131,7 @@ export class OpenGroupServerPoller { compactFetchResults = compactFetchResults.filter(result => this.roomIdsToPoll.has(result.roomId) ); - window.log.warn( - `compactFetchResults for ${this.serverUrl}:`, - compactFetchResults - ); + window.log.warn(`compactFetchResults for ${this.serverUrl}:`, compactFetchResults); } catch (e) { window.log.warn('Got error while compact fetch:', e); } finally { diff --git a/ts/opengroup/utils/OpenGroupUtils.ts b/ts/opengroup/utils/OpenGroupUtils.ts index 5e2425c5d04aee660bdb508cbe58483ab3e5b4a0..88fd5b6cad1251bd108f38c7395e3d9655b145a4 100644 --- a/ts/opengroup/utils/OpenGroupUtils.ts +++ b/ts/opengroup/utils/OpenGroupUtils.ts @@ -47,18 +47,10 @@ export const validOpenGroupServer = async (serverUrl: string) => { // we got the public key of the server we are trying to add. // decode it. const obj = JSON.parse(result.response.data); - const pubKey = window.dcodeIO.ByteBuffer.wrap( - obj.data, - 'base64' - ).toArrayBuffer(); + const pubKey = window.dcodeIO.ByteBuffer.wrap(obj.data, 'base64').toArrayBuffer(); // verify we can make an onion routed call to that open group with the decoded public key // get around the FILESERVER_HOSTS filter by not using serverRequest - const res = await sendViaOnion( - pubKey, - url, - { method: 'GET' }, - { noJson: true } - ); + const res = await sendViaOnion(pubKey, url, { method: 'GET' }, { noJson: true }); if (res && res.result && res.result.status === 200) { window.log.info( `loki_public_chat::validOpenGroupServer - onion routing enabled on ${url.toString()}` @@ -104,10 +96,7 @@ export function prefixify(server: string, hasSSL: boolean = true): string { * No sql access. Just how our open groupv2 url looks like * @returns `publicChat:${roomId}@${serverUrl}` */ -export function getOpenGroupV2ConversationId( - serverUrl: string, - roomId: string -) { +export function getOpenGroupV2ConversationId(serverUrl: string, roomId: string) { if (roomId.length < 2) { throw new Error('Invalid roomId: too short'); } diff --git a/ts/receiver/attachments.ts b/ts/receiver/attachments.ts index 598436decaf9beefd03985b85796ed07ed5a045c..9e5677bcc74d19baea0eb0b4b657a67c4656f48f 100644 --- a/ts/receiver/attachments.ts +++ b/ts/receiver/attachments.ts @@ -18,9 +18,7 @@ export async function downloadAttachment(attachment: any) { // TODO: we need attachments to remember which API should be used to retrieve them if (!defaultFileserver) { - const serverAPI = await window.lokiPublicChatAPI.findOrCreateServer( - serverUrl - ); + const serverAPI = await window.lokiPublicChatAPI.findOrCreateServer(serverUrl); if (serverAPI) { res = await serverAPI.downloadAttachment(attachment.url); @@ -34,9 +32,7 @@ export async function downloadAttachment(attachment: any) { if (res.byteLength === 0) { window.log.error('Failed to download attachment. Length is 0'); - throw new Error( - `Failed to download attachment. Length is 0 for ${attachment.url}` - ); + throw new Error(`Failed to download attachment. Length is 0 for ${attachment.url}`); } // FIXME "178" test to remove once this is fixed server side. @@ -45,9 +41,7 @@ export async function downloadAttachment(attachment: any) { window.log.error( 'Data of 178 length corresponds of a 404 returned as 200 by file.getsession.org.' ); - throw new Error( - `downloadAttachment: invalid response for ${attachment.url}` - ); + throw new Error(`downloadAttachment: invalid response for ${attachment.url}`); } } else { // if useFileOnionRequestsV2 is true, we expect an ArrayBuffer not empty @@ -59,9 +53,7 @@ export async function downloadAttachment(attachment: any) { const { key, digest, size } = attachment; if (!key || !digest) { - throw new Error( - 'Attachment is not raw but we do not have a key to decode it' - ); + throw new Error('Attachment is not raw but we do not have a key to decode it'); } data = await window.textsecure.crypto.decryptAttachment( @@ -147,14 +139,11 @@ async function processAvatars(message: MessageModel): Promise<number> { addedCount += 1; - const avatarJob = await window.Signal.AttachmentDownloads.addJob( - item.avatar.avatar, - { - messaeId: message.id, - type: 'contact', - index, - } - ); + const avatarJob = await window.Signal.AttachmentDownloads.addJob(item.avatar.avatar, { + messaeId: message.id, + type: 'contact', + index, + }); return { ...item, @@ -190,14 +179,11 @@ async function processQuoteAttachments(message: MessageModel): Promise<number> { addedCount += 1; - const thumbnail = await window.Signal.AttachmentDownloads.addJob( - item.thumbnail, - { - messageId: message.id, - type: 'quote', - index, - } - ); + const thumbnail = await window.Signal.AttachmentDownloads.addJob(item.thumbnail, { + messageId: message.id, + type: 'quote', + index, + }); return { ...item, thumbnail }; }) @@ -229,15 +215,10 @@ async function processGroupAvatar(message: MessageModel): Promise<boolean> { return true; } -export async function queueAttachmentDownloads( - message: MessageModel -): Promise<void> { +export async function queueAttachmentDownloads(message: MessageModel): Promise<void> { let count = 0; - count += await processNormalAttachments( - message, - message.get('attachments') || [] - ); + count += await processNormalAttachments(message, message.get('attachments') || []); count += await processPreviews(message); diff --git a/ts/receiver/cache.ts b/ts/receiver/cache.ts index bce0cddee741dc916c45fa61b4159f9a03f1541d..b6973e8fb5a23b01fb0a529e9c01ca9be1df3cae 100644 --- a/ts/receiver/cache.ts +++ b/ts/receiver/cache.ts @@ -20,10 +20,7 @@ export async function removeFromCache(envelope: EnvelopePlus) { return removeUnprocessed(id); } -export async function addToCache( - envelope: EnvelopePlus, - plaintext: ArrayBuffer -) { +export async function addToCache(envelope: EnvelopePlus, plaintext: ArrayBuffer) { const { id } = envelope; window.log.info(`adding to cache envelope: ${id}`); @@ -47,9 +44,7 @@ async function fetchAllFromCache(): Promise<Array<any>> { if (count > 1500) { await removeAllUnprocessed(); - window.log.warn( - `There were ${count} messages in cache. Deleted all instead of reprocessing` - ); + window.log.warn(`There were ${count} messages in cache. Deleted all instead of reprocessing`); return []; } @@ -69,10 +64,7 @@ export async function getAllFromCache() { try { if (attempts >= 10) { - window.log.warn( - 'getAllFromCache final attempt for envelope', - item.id - ); + window.log.warn('getAllFromCache final attempt for envelope', item.id); await removeUnprocessed(item.id); } else { await updateUnprocessedAttempts(item.id, attempts); @@ -97,11 +89,7 @@ export async function getAllFromCacheForSource(source: string) { item => !!item.senderIdentity || item.senderIdentity === source ); - window.log.info( - 'getAllFromCacheForSource loaded', - itemsFromSource.length, - 'saved envelopes' - ); + window.log.info('getAllFromCacheForSource loaded', itemsFromSource.length, 'saved envelopes'); return Promise.all( _.map(items, async (item: any) => { @@ -109,10 +97,7 @@ export async function getAllFromCacheForSource(source: string) { try { if (attempts >= 10) { - window.log.warn( - 'getAllFromCache final attempt for envelope', - item.id - ); + window.log.warn('getAllFromCache final attempt for envelope', item.id); await removeUnprocessed(item.id); } else { await updateUnprocessedAttempts(item.id, attempts); @@ -129,10 +114,7 @@ export async function getAllFromCacheForSource(source: string) { ); } -export async function updateCache( - envelope: EnvelopePlus, - plaintext: ArrayBuffer -): Promise<void> { +export async function updateCache(envelope: EnvelopePlus, plaintext: ArrayBuffer): Promise<void> { const { id } = envelope; const item = await getUnprocessedById(id); if (!item) { diff --git a/ts/receiver/closedGroups.ts b/ts/receiver/closedGroups.ts index fd631b5a78854f798367e90943d1b77a46595590..a4fdd15554ce1f1b99642bffe0ced3030830392f 100644 --- a/ts/receiver/closedGroups.ts +++ b/ts/receiver/closedGroups.ts @@ -34,10 +34,7 @@ import { ClosedGroupEncryptionPairReplyMessage } from '../session/messages/outgo import { queueAllCachedFromSource } from './receiver'; import { actions as conversationActions } from '../state/ducks/conversations'; -export const distributingClosedGroupEncryptionKeyPairs = new Map< - string, - ECKeyPair ->(); +export const distributingClosedGroupEncryptionKeyPairs = new Map<string, ECKeyPair>(); export async function handleClosedGroupControlMessage( envelope: EnvelopePlus, @@ -58,11 +55,7 @@ export async function handleClosedGroupControlMessage( if (type === Type.ENCRYPTION_KEY_PAIR) { const isComingFromGroupPubkey = envelope.type === SignalService.Envelope.Type.CLOSED_GROUP_CIPHERTEXT; - await handleClosedGroupEncryptionKeyPair( - envelope, - groupUpdate, - isComingFromGroupPubkey - ); + await handleClosedGroupEncryptionKeyPair(envelope, groupUpdate, isComingFromGroupPubkey); } else if (type === Type.NEW) { await handleNewClosedGroup(envelope, groupUpdate); } else if ( @@ -103,10 +96,7 @@ function sanityCheckNewGroup( const hexGroupPublicKey = toHex(publicKey); if (!PubKey.from(hexGroupPublicKey)) { - log.warn( - 'groupUpdate: publicKey is not recognized as a valid pubkey', - hexGroupPublicKey - ); + log.warn('groupUpdate: publicKey is not recognized as a valid pubkey', hexGroupPublicKey); return false; } @@ -148,10 +138,7 @@ export async function handleNewClosedGroup( ) { const { log } = window; - if ( - groupUpdate.type !== - SignalService.DataMessage.ClosedGroupControlMessage.Type.NEW - ) { + if (groupUpdate.type !== SignalService.DataMessage.ClosedGroupControlMessage.Type.NEW) { return; } if (!sanityCheckNewGroup(groupUpdate)) { @@ -162,9 +149,7 @@ export async function handleNewClosedGroup( const ourNumber = UserUtils.getOurPubKeyFromCache(); if (envelope.senderIdentity === ourNumber.key) { - window.log.warn( - 'Dropping new closed group updatemessage from our other device.' - ); + window.log.warn('Dropping new closed group updatemessage from our other device.'); return removeFromCache(envelope); } @@ -181,9 +166,7 @@ export async function handleNewClosedGroup( const admins = adminsAsData.map(toHex); if (!members.includes(ourNumber.key)) { - log.info( - 'Got a new group message but apparently we are not a member of it. Dropping it.' - ); + log.info('Got a new group message but apparently we are not a member of it. Dropping it.'); await removeFromCache(envelope); return; } @@ -194,10 +177,7 @@ export async function handleNewClosedGroup( const groupExists = !!maybeConvo; if (groupExists) { - if ( - maybeConvo && - (maybeConvo.get('isKickedFromGroup') || maybeConvo.get('left')) - ) { + if (maybeConvo && (maybeConvo.get('isKickedFromGroup') || maybeConvo.get('left'))) { // TODO: indicate that we've been re-invited // to the group if that is the case @@ -206,9 +186,7 @@ export async function handleNewClosedGroup( maybeConvo.set('left', false); maybeConvo.set('lastJoinedTimestamp', _.toNumber(envelope.timestamp)); } else { - log.warn( - 'Ignoring a closed group message of type NEW: the conversation already exists' - ); + log.warn('Ignoring a closed group message of type NEW: the conversation already exists'); await removeFromCache(envelope); return; } @@ -253,10 +231,7 @@ export async function handleNewClosedGroup( await convo.commit(); // sanity checks validate this // tslint:disable: no-non-null-assertion - const ecKeyPair = new ECKeyPair( - encryptionKeyPair!.publicKey, - encryptionKeyPair!.privateKey - ); + const ecKeyPair = new ECKeyPair(encryptionKeyPair!.publicKey, encryptionKeyPair!.privateKey); window.log.info(`Received a the encryptionKeyPair for new group ${groupId}`); await addClosedGroupEncryptionKeyPair(groupId, ecKeyPair.toHexKeyPair()); @@ -294,9 +269,7 @@ async function handleUpdateClosedGroup( if (wasCurrentUserRemoved) { if (isCurrentUserAdmin) { // cannot remove the admin from a closed group - log.info( - 'Dropping message trying to remove the admin (us) from a closed group' - ); + log.info('Dropping message trying to remove the admin (us) from a closed group'); await removeFromCache(envelope); return; } @@ -315,30 +288,17 @@ async function handleUpdateClosedGroup( } // Generate and distribute a new encryption key pair if needed - const wasAnyUserRemoved = - diff.leavingMembers && diff.leavingMembers.length > 0; + const wasAnyUserRemoved = diff.leavingMembers && diff.leavingMembers.length > 0; if (wasAnyUserRemoved && isCurrentUserAdmin) { window.log.info( 'Handling group update: A user was removed and we are the admin. Generating and sending a new ECKeyPair' ); - await ClosedGroup.generateAndSendNewEncryptionKeyPair( - groupPublicKey, - members - ); + await ClosedGroup.generateAndSendNewEncryptionKeyPair(groupPublicKey, members); } // Only add update message if we have something to show - if ( - diff.joiningMembers?.length || - diff.leavingMembers?.length || - diff.newName - ) { - await ClosedGroup.addUpdateMessage( - convo, - diff, - 'incoming', - _.toNumber(envelope.timestamp) - ); + if (diff.joiningMembers?.length || diff.leavingMembers?.length || diff.newName) { + await ClosedGroup.addUpdateMessage(convo, diff, 'incoming', _.toNumber(envelope.timestamp)); } convo.set('name', name); @@ -372,12 +332,8 @@ async function handleClosedGroupEncryptionKeyPair( // in the case of an encryption key pair coming as a reply to a request we made // senderIdentity will be unset as the message is not encoded for medium groups - const sender = isComingFromGroupPubkey - ? envelope.senderIdentity - : envelope.source; - window.log.info( - `Got a group update for group ${groupPublicKey}, type: ENCRYPTION_KEY_PAIR` - ); + const sender = isComingFromGroupPubkey ? envelope.senderIdentity : envelope.source; + window.log.info(`Got a group update for group ${groupPublicKey}, type: ENCRYPTION_KEY_PAIR`); const ourKeyPair = await UserUtils.getIdentityKeyPair(); if (!ourKeyPair) { @@ -410,9 +366,7 @@ async function handleClosedGroupEncryptionKeyPair( } // Find our wrapper and decrypt it if possible - const ourWrapper = groupUpdate.wrappers.find( - w => toHex(w.publicKey) === ourNumber.key - ); + const ourWrapper = groupUpdate.wrappers.find(w => toHex(w.publicKey) === ourNumber.key); if (!ourWrapper) { window.log.warn( `Couldn\'t find our wrapper in the encryption keypairs wrappers for group ${groupPublicKey}` @@ -441,11 +395,7 @@ async function handleClosedGroupEncryptionKeyPair( let proto: SignalService.KeyPair; try { proto = SignalService.KeyPair.decode(plaintext); - if ( - !proto || - proto.privateKey.length === 0 || - proto.publicKey.length === 0 - ) { + if (!proto || proto.privateKey.length === 0 || proto.publicKey.length === 0) { throw new Error(); } } catch (e) { @@ -462,22 +412,15 @@ async function handleClosedGroupEncryptionKeyPair( await removeFromCache(envelope); return; } - window.log.info( - `Received a new encryptionKeyPair for group ${groupPublicKey}` - ); + window.log.info(`Received a new encryptionKeyPair for group ${groupPublicKey}`); // Store it if needed const newKeyPairInHex = keyPair.toHexKeyPair(); - const isKeyPairAlreadyHere = await isKeyPairAlreadySaved( - groupPublicKey, - newKeyPairInHex - ); + const isKeyPairAlreadyHere = await isKeyPairAlreadySaved(groupPublicKey, newKeyPairInHex); if (isKeyPairAlreadyHere) { - const existingKeyPairs = await getAllEncryptionKeyPairsForGroup( - groupPublicKey - ); + const existingKeyPairs = await getAllEncryptionKeyPairsForGroup(groupPublicKey); window.log.info('Dropping already saved keypair for group', groupPublicKey); await removeFromCache(envelope); return; @@ -506,9 +449,7 @@ async function performIfValid( } if (!convo) { - window.log.warn( - 'Ignoring a closed group update message (INFO) for a non-existing group' - ); + window.log.warn('Ignoring a closed group update message (INFO) for a non-existing group'); return removeFromCache(envelope); } @@ -542,9 +483,7 @@ async function performIfValid( } if (groupUpdate.type === Type.UPDATE) { - window.log.warn( - 'Received a groupUpdate non explicit. This should not happen anymore.' - ); + window.log.warn('Received a groupUpdate non explicit. This should not happen anymore.'); await handleUpdateClosedGroup(envelope, groupUpdate, convo); } else if (groupUpdate.type === Type.NAME_CHANGE) { await handleClosedGroupNameChanged(envelope, groupUpdate, convo); @@ -556,11 +495,7 @@ async function performIfValid( await handleClosedGroupMemberLeft(envelope, groupUpdate, convo); } else if (groupUpdate.type === Type.ENCRYPTION_KEY_PAIR_REQUEST) { if (window.lokiFeatureFlags.useRequestEncryptionKeyPair) { - await handleClosedGroupEncryptionKeyPairRequest( - envelope, - groupUpdate, - convo - ); + await handleClosedGroupEncryptionKeyPairRequest(envelope, groupUpdate, convo); } else { window.log.warn( 'Received ENCRYPTION_KEY_PAIR_REQUEST message but it is not enabled for now.' @@ -580,9 +515,7 @@ async function handleClosedGroupNameChanged( ) { // Only add update message if we have something to show const newName = groupUpdate.name; - window.log.info( - `Got a group update for group ${envelope.source}, type: NAME_CHANGED` - ); + window.log.info(`Got a group update for group ${envelope.source}, type: NAME_CHANGED`); if (newName !== convo.get('name')) { const groupDiff: ClosedGroup.GroupDiff = { @@ -610,12 +543,8 @@ async function handleClosedGroupMembersAdded( const { members: addedMembersBinary } = groupUpdate; const addedMembers = (addedMembersBinary || []).map(toHex); const oldMembers = convo.get('members') || []; - const membersNotAlreadyPresent = addedMembers.filter( - m => !oldMembers.includes(m) - ); - window.log.info( - `Got a group update for group ${envelope.source}, type: MEMBERS_ADDED` - ); + const membersNotAlreadyPresent = addedMembers.filter(m => !oldMembers.includes(m)); + window.log.info(`Got a group update for group ${envelope.source}, type: MEMBERS_ADDED`); if (membersNotAlreadyPresent.length === 0) { window.log.info( @@ -626,12 +555,7 @@ async function handleClosedGroupMembersAdded( } if (await areWeAdmin(convo)) { - await sendLatestKeyPairToUsers( - envelope, - convo, - convo.id, - membersNotAlreadyPresent - ); + await sendLatestKeyPairToUsers(envelope, convo, convo.id, membersNotAlreadyPresent); } const members = [...oldMembers, ...membersNotAlreadyPresent]; @@ -640,12 +564,7 @@ async function handleClosedGroupMembersAdded( const groupDiff: ClosedGroup.GroupDiff = { joiningMembers: membersNotAlreadyPresent, }; - await ClosedGroup.addUpdateMessage( - convo, - groupDiff, - 'incoming', - _.toNumber(envelope.timestamp) - ); + await ClosedGroup.addUpdateMessage(convo, groupDiff, 'incoming', _.toNumber(envelope.timestamp)); convo.set({ members }); convo.updateLastMessage(); @@ -674,13 +593,9 @@ async function handleClosedGroupMembersRemoved( const removedMembers = groupUpdate.members.map(toHex); // effectivelyRemovedMembers are the members which where effectively on this group before the update // and is used for the group update message only - const effectivelyRemovedMembers = removedMembers.filter(m => - currentMembers.includes(m) - ); + const effectivelyRemovedMembers = removedMembers.filter(m => currentMembers.includes(m)); const groupPubKey = envelope.source; - window.log.info( - `Got a group update for group ${envelope.source}, type: MEMBERS_REMOVED` - ); + window.log.info(`Got a group update for group ${envelope.source}, type: MEMBERS_REMOVED`); const membersAfterUpdate = _.difference(currentMembers, removedMembers); const groupAdmins = convo.get('groupAdmins'); @@ -690,9 +605,7 @@ async function handleClosedGroupMembersRemoved( const firstAdmin = groupAdmins[0]; if (removedMembers.includes(firstAdmin)) { - window.log.warn( - 'Ignoring invalid closed group update: trying to remove the admin.' - ); + window.log.warn('Ignoring invalid closed group update: trying to remove the admin.'); await removeFromCache(envelope); return; } @@ -711,10 +624,7 @@ async function handleClosedGroupMembersRemoved( // Generate and distribute a new encryption key pair if needed if (await areWeAdmin(convo)) { try { - await ClosedGroup.generateAndSendNewEncryptionKeyPair( - groupPubKey, - membersAfterUpdate - ); + await ClosedGroup.generateAndSendNewEncryptionKeyPair(groupPubKey, membersAfterUpdate); } catch (e) { window.log.warn('Could not distribute new encryption keypair.'); } @@ -762,13 +672,9 @@ async function handleClosedGroupMemberLeft( const ourPubkey = UserUtils.getOurPubKeyStrFromCache(); // Generate and distribute a new encryption key pair if needed - const isCurrentUserAdmin = - convo.get('groupAdmins')?.includes(ourPubkey) || false; + const isCurrentUserAdmin = convo.get('groupAdmins')?.includes(ourPubkey) || false; if (isCurrentUserAdmin && !!members.length) { - await ClosedGroup.generateAndSendNewEncryptionKeyPair( - groupPublicKey, - members - ); + await ClosedGroup.generateAndSendNewEncryptionKeyPair(groupPublicKey, members); } if (didAdminLeave) { @@ -820,40 +726,28 @@ async function sendLatestKeyPairToUsers( targetUsers: Array<string> ) { // use the inMemory keypair if found - const inMemoryKeyPair = distributingClosedGroupEncryptionKeyPairs.get( - groupPubKey - ); + const inMemoryKeyPair = distributingClosedGroupEncryptionKeyPairs.get(groupPubKey); // Get the latest encryption key pair - const latestKeyPair = await getLatestClosedGroupEncryptionKeyPair( - groupPubKey - ); + const latestKeyPair = await getLatestClosedGroupEncryptionKeyPair(groupPubKey); if (!inMemoryKeyPair && !latestKeyPair) { - window.log.info( - 'We do not have the keypair ourself, so dropping this message.' - ); + window.log.info('We do not have the keypair ourself, so dropping this message.'); return; } - const keyPairToUse = - inMemoryKeyPair || ECKeyPair.fromHexKeyPair(latestKeyPair as HexKeyPair); + const keyPairToUse = inMemoryKeyPair || ECKeyPair.fromHexKeyPair(latestKeyPair as HexKeyPair); const expireTimer = groupConvo.get('expireTimer') || 0; await Promise.all( targetUsers.map(async member => { - window.log.info( - `Sending latest closed group encryption key pair to: ${member}` - ); + window.log.info(`Sending latest closed group encryption key pair to: ${member}`); await ConversationController.getInstance().getOrCreateAndWait( member, ConversationType.PRIVATE ); - const wrappers = await ClosedGroup.buildEncryptionKeyPairWrappers( - [member], - keyPairToUse - ); + const wrappers = await ClosedGroup.buildEncryptionKeyPairWrappers([member], keyPairToUse); const keypairsMessage = new ClosedGroupEncryptionPairReplyMessage({ groupId: groupPubKey, @@ -863,10 +757,7 @@ async function sendLatestKeyPairToUsers( }); // the encryption keypair is sent using established channels - await getMessageQueue().sendToPubKey( - PubKey.cast(member), - keypairsMessage - ); + await getMessageQueue().sendToPubKey(PubKey.cast(member), keypairsMessage); }) ); } @@ -883,22 +774,15 @@ async function handleClosedGroupEncryptionKeyPairRequest( const groupPublicKey = envelope.source; // Guard against self-sends if (UserUtils.isUsFromCache(sender)) { - window.log.info( - 'Dropping self send message of type ENCRYPTION_KEYPAIR_REQUEST' - ); + window.log.info('Dropping self send message of type ENCRYPTION_KEYPAIR_REQUEST'); await removeFromCache(envelope); return; } - await sendLatestKeyPairToUsers(envelope, groupConvo, groupPublicKey, [ - sender, - ]); + await sendLatestKeyPairToUsers(envelope, groupConvo, groupPublicKey, [sender]); return removeFromCache(envelope); } -export async function createClosedGroup( - groupName: string, - members: Array<string> -) { +export async function createClosedGroup(groupName: string, members: Array<string>) { const setOfMembers = new Set(members); const ourNumber = UserUtils.getOurPubKeyFromCache(); @@ -937,12 +821,7 @@ export async function createClosedGroup( joiningMembers: listOfMembers, }; - const dbMessage = await ClosedGroup.addUpdateMessage( - convo, - groupDiff, - 'outgoing', - Date.now() - ); + const dbMessage = await ClosedGroup.addUpdateMessage(convo, groupDiff, 'outgoing', Date.now()); MessageController.getInstance().register(dbMessage.id, dbMessage); // be sure to call this before sending the message. @@ -964,14 +843,9 @@ export async function createClosedGroup( expireTimer: 0, }; const message = new ClosedGroupNewMessage(messageParams); - window.log.info( - `Creating a new group and an encryptionKeyPair for group ${groupPublicKey}` - ); + window.log.info(`Creating a new group and an encryptionKeyPair for group ${groupPublicKey}`); // tslint:disable-next-line: no-non-null-assertion - await addClosedGroupEncryptionKeyPair( - groupPublicKey, - encryptionKeyPair.toHexKeyPair() - ); + await addClosedGroupEncryptionKeyPair(groupPublicKey, encryptionKeyPair.toHexKeyPair()); return getMessageQueue().sendToPubKey(PubKey.cast(m), message); }); @@ -982,7 +856,5 @@ export async function createClosedGroup( await forceSyncConfigurationNowIfNeeded(); - window.inboxStore?.dispatch( - conversationActions.openConversationExternal(groupPublicKey) - ); + window.inboxStore?.dispatch(conversationActions.openConversationExternal(groupPublicKey)); } diff --git a/ts/receiver/common.ts b/ts/receiver/common.ts index 5f7280c0bbfa78db5e22a40199496ae62bd523bf..b2976622d42b5eb8c9ac4aa7fd9a4f431a3a0fd1 100644 --- a/ts/receiver/common.ts +++ b/ts/receiver/common.ts @@ -3,9 +3,7 @@ import { EnvelopePlus } from './types'; export function getEnvelopeId(envelope: EnvelopePlus) { if (envelope.source) { - return `${envelope.source} ${toNumber(envelope.timestamp)} (${ - envelope.id - })`; + return `${envelope.source} ${toNumber(envelope.timestamp)} (${envelope.id})`; } return envelope.id; diff --git a/ts/receiver/configMessage.ts b/ts/receiver/configMessage.ts index c14e88c0643d49aeef4418782020d7d789c25476..204eca347860e43fb2370c39cd22176ba08da37a 100644 --- a/ts/receiver/configMessage.ts +++ b/ts/receiver/configMessage.ts @@ -1,9 +1,5 @@ import _ from 'lodash'; -import { - createOrUpdateItem, - getItemById, - hasSyncedInitialConfigurationItem, -} from '../data/data'; +import { createOrUpdateItem, getItemById, hasSyncedInitialConfigurationItem } from '../data/data'; import { ConversationType } from '../models/conversation'; import { OpenGroup } from '../opengroup/opengroupV1/OpenGroup'; import { SignalService } from '../protobuf'; @@ -49,9 +45,7 @@ async function handleOurProfileUpdate( if (displayName) { trigger(configurationMessageReceived, displayName); } else { - window.log.warn( - 'Got a configuration message but the display name is empty' - ); + window.log.warn('Got a configuration message but the display name is empty'); } } } @@ -81,22 +75,18 @@ async function handleGroupsAndContactsFromConfigMessage( await Promise.all( configMessage.closedGroups.map(async c => { - const groupUpdate = new SignalService.DataMessage.ClosedGroupControlMessage( - { - type: SignalService.DataMessage.ClosedGroupControlMessage.Type.NEW, - encryptionKeyPair: c.encryptionKeyPair, - name: c.name, - admins: c.admins, - members: c.members, - publicKey: c.publicKey, - } - ); + const groupUpdate = new SignalService.DataMessage.ClosedGroupControlMessage({ + type: SignalService.DataMessage.ClosedGroupControlMessage.Type.NEW, + encryptionKeyPair: c.encryptionKeyPair, + name: c.name, + admins: c.admins, + members: c.members, + publicKey: c.publicKey, + }); try { await handleNewClosedGroup(envelope, groupUpdate); } catch (e) { - window?.log?.warn( - 'failed to handle a new closed group from configuration message' - ); + window?.log?.warn('failed to handle a new closed group from configuration message'); } }) ); @@ -109,9 +99,7 @@ async function handleGroupsAndContactsFromConfigMessage( for (let i = 0; i < numberOpenGroup; i++) { const current = configMessage.openGroups[i]; if (!allOpenGroups.includes(current)) { - window?.log?.info( - `triggering join of public chat '${current}' from ConfigurationMessage` - ); + window?.log?.info(`triggering join of public chat '${current}' from ConfigurationMessage`); void OpenGroup.join(current); } } @@ -135,9 +123,7 @@ async function handleGroupsAndContactsFromConfigMessage( await updateProfile(contactConvo, profile, c.profileKey); } catch (e) { - window?.log?.warn( - 'failed to handle a new closed group from configuration message' - ); + window?.log?.warn('failed to handle a new closed group from configuration message'); } }) ); @@ -154,22 +140,13 @@ export async function handleConfigurationMessage( } if (envelope.source !== ourPubkey) { - window?.log?.info( - 'Dropping configuration change from someone else than us.' - ); + window?.log?.info('Dropping configuration change from someone else than us.'); return removeFromCache(envelope); } - await handleOurProfileUpdate( - envelope.timestamp, - configurationMessage, - ourPubkey - ); + await handleOurProfileUpdate(envelope.timestamp, configurationMessage, ourPubkey); - await handleGroupsAndContactsFromConfigMessage( - envelope, - configurationMessage - ); + await handleGroupsAndContactsFromConfigMessage(envelope, configurationMessage); await removeFromCache(envelope); } diff --git a/ts/receiver/contentMessage.ts b/ts/receiver/contentMessage.ts index aa78ce2aa54a56be57bf8f8a7bee2cc20a9e88a0..db4fa6e2a679acbeb24d88a8851dc6d9421ecf5a 100644 --- a/ts/receiver/contentMessage.ts +++ b/ts/receiver/contentMessage.ts @@ -34,28 +34,19 @@ export async function handleContentMessage(envelope: EnvelopePlus) { } } -async function decryptForClosedGroup( - envelope: EnvelopePlus, - ciphertext: ArrayBuffer -) { +async function decryptForClosedGroup(envelope: EnvelopePlus, ciphertext: ArrayBuffer) { // case .closedGroupCiphertext: for ios window.log.info('received closed group message'); try { const hexEncodedGroupPublicKey = envelope.source; if (!GroupUtils.isMediumGroup(PubKey.cast(hexEncodedGroupPublicKey))) { - window.log.warn( - 'received medium group message but not for an existing medium group' - ); + window.log.warn('received medium group message but not for an existing medium group'); throw new Error('Invalid group public key'); // invalidGroupPublicKey } - const encryptionKeyPairs = await getAllEncryptionKeyPairsForGroup( - hexEncodedGroupPublicKey - ); + const encryptionKeyPairs = await getAllEncryptionKeyPairsForGroup(hexEncodedGroupPublicKey); const encryptionKeyPairsCount = encryptionKeyPairs?.length; if (!encryptionKeyPairs?.length) { - throw new Error( - `No group keypairs for group ${hexEncodedGroupPublicKey}` - ); // noGroupKeyPair + throw new Error(`No group keypairs for group ${hexEncodedGroupPublicKey}`); // noGroupKeyPair } // Loop through all known group key pairs in reverse order (i.e. try the latest key pair first (which'll more than // likely be the one we want) but try older ones in case that didn't work) @@ -72,9 +63,7 @@ async function decryptForClosedGroup( if (!hexEncryptionKeyPair) { throw new Error('No more encryption keypairs to try for message.'); } - const encryptionKeyPair = ECKeyPair.fromHexKeyPair( - hexEncryptionKeyPair - ); + const encryptionKeyPair = ECKeyPair.fromHexKeyPair(hexEncryptionKeyPair); decryptedContent = await decryptWithSessionProtocol( envelope, @@ -103,10 +92,7 @@ async function decryptForClosedGroup( 'Decrypted a closed group message with not the latest encryptionkeypair we have' ); } - window.log.info( - 'ClosedGroup Message decrypted successfully with keyIndex:', - keyIndex - ); + window.log.info('ClosedGroup Message decrypted successfully with keyIndex:', keyIndex); return unpad(decryptedContent); } catch (e) { @@ -117,10 +103,7 @@ async function decryptForClosedGroup( * */ - window.log.warn( - 'decryptWithSessionProtocol for medium group message throw:', - e - ); + window.log.warn('decryptWithSessionProtocol for medium group message throw:', e); const groupPubKey = PubKey.cast(envelope.source); // To enable back if we decide to enable encryption key pair request work again @@ -170,35 +153,23 @@ export async function decryptWithSessionProtocol( fromHexToArray(recipientX25519PublicKey), new Uint8Array(recipientX25519PrivateKey) ); - if ( - plaintextWithMetadata.byteLength <= - signatureSize + ed25519PublicKeySize - ) { + if (plaintextWithMetadata.byteLength <= signatureSize + ed25519PublicKeySize) { throw new Error('Decryption failed.'); // throw Error.decryptionFailed; } // 2. ) Get the message parts const signatureStart = plaintextWithMetadata.byteLength - signatureSize; const signature = plaintextWithMetadata.subarray(signatureStart); - const pubkeyStart = - plaintextWithMetadata.byteLength - (signatureSize + ed25519PublicKeySize); + const pubkeyStart = plaintextWithMetadata.byteLength - (signatureSize + ed25519PublicKeySize); const pubkeyEnd = plaintextWithMetadata.byteLength - signatureSize; - const senderED25519PublicKey = plaintextWithMetadata.subarray( - pubkeyStart, - pubkeyEnd - ); - const plainTextEnd = - plaintextWithMetadata.byteLength - (signatureSize + ed25519PublicKeySize); + const senderED25519PublicKey = plaintextWithMetadata.subarray(pubkeyStart, pubkeyEnd); + const plainTextEnd = plaintextWithMetadata.byteLength - (signatureSize + ed25519PublicKeySize); const plaintext = plaintextWithMetadata.subarray(0, plainTextEnd); // 3. ) Verify the signature const isValid = sodium.crypto_sign_verify_detached( signature, - concatUInt8Array( - plaintext, - senderED25519PublicKey, - fromHexToArray(recipientX25519PublicKey) - ), + concatUInt8Array(plaintext, senderED25519PublicKey, fromHexToArray(recipientX25519PublicKey)), senderED25519PublicKey ); @@ -206,9 +177,7 @@ export async function decryptWithSessionProtocol( throw new Error('Invalid message signature.'); //throw Error.invalidSignature } // 4. ) Get the sender's X25519 public key - const senderX25519PublicKey = sodium.crypto_sign_ed25519_pk_to_curve25519( - senderED25519PublicKey - ); + const senderX25519PublicKey = sodium.crypto_sign_ed25519_pk_to_curve25519(senderED25519PublicKey); if (!senderX25519PublicKey) { throw new Error('Decryption failed.'); // Error.decryptionFailed } @@ -257,17 +226,10 @@ async function decryptUnidentifiedSender( userX25519KeyPair.privKey ); // keep the await so the try catch works as expected - const retSessionProtocol = await decryptWithSessionProtocol( - envelope, - ciphertext, - ecKeyPair - ); + const retSessionProtocol = await decryptWithSessionProtocol(envelope, ciphertext, ecKeyPair); return unpad(retSessionProtocol); } catch (e) { - window.log.warn( - 'decryptWithSessionProtocol for unidentified message throw:', - e - ); + window.log.warn('decryptWithSessionProtocol for unidentified message throw:', e); return null; } } @@ -293,10 +255,7 @@ async function doDecrypt( } // tslint:disable-next-line: max-func-body-length -async function decrypt( - envelope: EnvelopePlus, - ciphertext: ArrayBuffer -): Promise<any> { +async function decrypt(envelope: EnvelopePlus, ciphertext: ArrayBuffer): Promise<any> { try { const plaintext = await doDecrypt(envelope, ciphertext); @@ -376,9 +335,7 @@ export async function innerHandleContentMessage( window.log.info('Dropping blocked user message'); return; } else { - window.log.info( - 'Allowing group-control message only from blocked user' - ); + window.log.info('Allowing group-control message only from blocked user'); } } @@ -388,10 +345,7 @@ export async function innerHandleContentMessage( ); if (content.dataMessage) { - if ( - content.dataMessage.profileKey && - content.dataMessage.profileKey.length === 0 - ) { + if (content.dataMessage.profileKey && content.dataMessage.profileKey.length === 0) { content.dataMessage.profileKey = null; } await handleDataMessage(envelope, content.dataMessage); diff --git a/ts/receiver/dataMessage.ts b/ts/receiver/dataMessage.ts index 5cbd9093737c8c3b4d8f3b71f335e4df8dfb07cd..530ac1a0d99706e5fc9b37af1ce65e8734ecac00 100644 --- a/ts/receiver/dataMessage.ts +++ b/ts/receiver/dataMessage.ts @@ -32,8 +32,7 @@ export async function updateProfile( // TODO: may need to allow users to reset their avatars to null if (profile.profilePicture) { const prevPointer = conversation.get('avatarPointer'); - const needsUpdate = - !prevPointer || !_.isEqual(prevPointer, profile.profilePicture); + const needsUpdate = !prevPointer || !_.isEqual(prevPointer, profile.profilePicture); if (needsUpdate) { const downloaded = await downloadAttachment({ @@ -221,16 +220,7 @@ export async function processDecrypted( } export function isMessageEmpty(message: SignalService.DataMessage) { - const { - flags, - body, - attachments, - group, - quote, - contact, - preview, - groupInvitation, - } = message; + const { flags, body, attachments, group, quote, contact, preview, groupInvitation } = message; return ( !flags && @@ -282,9 +272,7 @@ export async function handleDataMessage( window.log.info(`Handle dataMessage from ${source} `); if (isSyncMessage && !isMe) { - window.log.warn( - 'Got a sync message from someone else than me. Dropping it.' - ); + window.log.warn('Got a sync message from someone else than me. Dropping it.'); return removeFromCache(envelope); } else if (isSyncMessage && dataMessage.syncTarget) { // override the envelope source @@ -298,11 +286,7 @@ export async function handleDataMessage( // Check if we need to update any profile names if (!isMe && senderConversation && message.profile) { - await updateProfile( - senderConversation, - message.profile, - message.profileKey - ); + await updateProfile(senderConversation, message.profile, message.profileKey); } if (isMessageEmpty(message)) { window.log.warn(`Message ${getEnvelopeId(envelope)} ignored; it was empty`); @@ -346,12 +330,7 @@ interface MessageId { } const PUBLICCHAT_MIN_TIME_BETWEEN_DUPLICATE_MESSAGES = 10 * 1000; // 10s -async function isMessageDuplicate({ - source, - sourceDevice, - timestamp, - message, -}: MessageId) { +async function isMessageDuplicate({ source, sourceDevice, timestamp, message }: MessageId) { const { Errors } = window.Signal.Types; try { @@ -364,12 +343,8 @@ async function isMessageDuplicate({ if (!result) { return false; } - const filteredResult = [result].filter( - (m: any) => m.attributes.body === message.body - ); - const isSimilar = filteredResult.some((m: any) => - isDuplicate(m, message, source) - ); + const filteredResult = [result].filter((m: any) => m.attributes.body === message.body); + const isSimilar = filteredResult.some((m: any) => isDuplicate(m, message, source)); return isSimilar; } catch (error) { window.log.error('isMessageDuplicate error:', Errors.toLogFormat(error)); @@ -381,8 +356,7 @@ export const isDuplicate = (m: any, testedMessage: any, source: string) => { // The username in this case is the users pubKey const sameUsername = m.attributes.source === source; const sameServerId = - m.attributes.serverId !== undefined && - testedMessage.id === m.attributes.serverId; + m.attributes.serverId !== undefined && testedMessage.id === m.attributes.serverId; const sameText = m.attributes.body === testedMessage.body; // Don't filter out messages that are too far apart from each other const timestampsSimilar = @@ -450,8 +424,7 @@ export function initIncomingMessage(data: MessageCreationData): MessageModel { } = data; const messageGroupId = message?.group?.id; - let groupId = - messageGroupId && messageGroupId.length > 0 ? messageGroupId : null; + let groupId = messageGroupId && messageGroupId.length > 0 ? messageGroupId : null; if (groupId) { groupId = PubKey.removeTextSecurePrefixIfNeeded(groupId); @@ -492,15 +465,11 @@ function createSentMessage(data: MessageCreationData): MessageModel { const sentSpecificFields = { sent_to: [], sent: true, - expirationStartTimestamp: Math.min( - expirationStartTimestamp || data.timestamp || now, - now - ), + expirationStartTimestamp: Math.min(expirationStartTimestamp || data.timestamp || now, now), }; const messageGroupId = message?.group?.id; - let groupId = - messageGroupId && messageGroupId.length > 0 ? messageGroupId : null; + let groupId = messageGroupId && messageGroupId.length > 0 ? messageGroupId : null; if (groupId) { groupId = PubKey.removeTextSecurePrefixIfNeeded(groupId); @@ -522,10 +491,7 @@ function createSentMessage(data: MessageCreationData): MessageModel { return new MessageModel(messageData); } -function createMessage( - data: MessageCreationData, - isIncoming: boolean -): MessageModel { +function createMessage(data: MessageCreationData, isIncoming: boolean): MessageModel { if (isIncoming) { return initIncomingMessage(data); } else { @@ -566,9 +532,7 @@ export async function handleMessageEvent(event: MessageEvent): Promise<void> { const isGroupMessage = Boolean(message.group); - const type = isGroupMessage - ? ConversationType.GROUP - : ConversationType.PRIVATE; + const type = isGroupMessage ? ConversationType.GROUP : ConversationType.PRIVATE; let conversationId = isIncoming ? source : destination || source; // for synced message if (!conversationId) { @@ -577,12 +541,7 @@ export async function handleMessageEvent(event: MessageEvent): Promise<void> { return; } if (message.profileKey?.length) { - await handleProfileUpdate( - message.profileKey, - conversationId, - type, - isIncoming - ); + await handleProfileUpdate(message.profileKey, conversationId, type, isIncoming); } const msg = createMessage(data, isIncoming); @@ -616,10 +575,7 @@ export async function handleMessageEvent(event: MessageEvent): Promise<void> { } if (!conversationId) { - window.log.warn( - 'Invalid conversation id for incoming message', - conversationId - ); + window.log.warn('Invalid conversation id for incoming message', conversationId); } const ourNumber = UserUtils.getOurPubKeyStrFromCache(); @@ -641,13 +597,6 @@ export async function handleMessageEvent(event: MessageEvent): Promise<void> { } conversation.queueJob(async () => { - await handleMessageJob( - msg, - conversation, - message, - ourNumber, - confirm, - source - ); + await handleMessageJob(msg, conversation, message, ourNumber, confirm, source); }); } diff --git a/ts/receiver/errors.ts b/ts/receiver/errors.ts index 8e043e30a32d333c8473691cc9957980809d5fb6..ed98fc399ff1558560c185ec7425c5208a038404 100644 --- a/ts/receiver/errors.ts +++ b/ts/receiver/errors.ts @@ -7,10 +7,7 @@ import { ConversationType } from '../models/conversation'; export async function onError(ev: any) { const { error } = ev; - window.log.error( - 'background onError:', - window.Signal.Errors.toLogFormat(error) - ); + window.log.error('background onError:', window.Signal.Errors.toLogFormat(error)); if (ev.proto) { const envelope = ev.proto; diff --git a/ts/receiver/keypairs.ts b/ts/receiver/keypairs.ts index 1af3b814dd0d0e5b7ac939eaaf2c022547f55ff5..c8693469366eccb92b100e35c229891d77c80e2e 100644 --- a/ts/receiver/keypairs.ts +++ b/ts/receiver/keypairs.ts @@ -20,17 +20,11 @@ export class ECKeyPair { } public static fromKeyPair(pair: KeyPair) { - return new ECKeyPair( - new Uint8Array(pair.pubKey), - new Uint8Array(pair.privKey) - ); + return new ECKeyPair(new Uint8Array(pair.pubKey), new Uint8Array(pair.privKey)); } public static fromHexKeyPair(pair: HexKeyPair) { - return new ECKeyPair( - fromHexToArray(pair.publicHex), - fromHexToArray(pair.privateHex) - ); + return new ECKeyPair(fromHexToArray(pair.publicHex), fromHexToArray(pair.privateHex)); } public toString() { diff --git a/ts/receiver/openGroups.ts b/ts/receiver/openGroups.ts index dd7014c8e8e2c14c3f7ee466d5e5c4babc3f9c06..0315920ce3a8bc51f662574551e3be8b94bc1ecc 100644 --- a/ts/receiver/openGroups.ts +++ b/ts/receiver/openGroups.ts @@ -1,8 +1,4 @@ -export async function updateOpenGroup( - convo: any, - groupName: string, - avatar: any -) { +export async function updateOpenGroup(convo: any, groupName: string, avatar: any) { const API = await convo.getPublicSendData(); if (avatar) { @@ -37,9 +33,7 @@ export async function updateOpenGroup( maxSize: 1000 * 1024, } ); - const dataResized = await window.Signal.Types.Attachment.arrayBufferFromFile( - withBlob.file - ); + const dataResized = await window.Signal.Types.Attachment.arrayBufferFromFile(withBlob.file); // const tempUrl = window.URL.createObjectURL(avatar); // Get file onto public chat server diff --git a/ts/receiver/queuedJob.ts b/ts/receiver/queuedJob.ts index ede6347fe67e42731cd05afc17d59989e0453a35..b7ce205d1392319a593c78f35f9965b8d6aaead1 100644 --- a/ts/receiver/queuedJob.ts +++ b/ts/receiver/queuedJob.ts @@ -34,8 +34,7 @@ async function handleGroups( attributes.name = group.name; attributes.members = group.members; - groupUpdate = - conversation.changedAttributes(_.pick(group, 'name', 'avatar')) || {}; + groupUpdate = conversation.changedAttributes(_.pick(group, 'name', 'avatar')) || {}; const addedMembers = _.difference(attributes.members, oldMembers); if (addedMembers.length > 0) { @@ -55,9 +54,7 @@ async function handleGroups( // Check if anyone got kicked: const removedMembers = _.difference(oldMembers, attributes.members); - const ourDeviceWasRemoved = removedMembers.some(member => - UserUtils.isUsFromCache(member) - ); + const ourDeviceWasRemoved = removedMembers.some(member => UserUtils.isUsFromCache(member)); if (ourDeviceWasRemoved) { groupUpdate.kicked = 'You'; @@ -111,15 +108,11 @@ async function copyFromQuotedMessage( // Exponential backoff, giving up after 5 attempts: if (attemptCount < 5) { setTimeout(() => { - window.log.info( - `Looking for the message id : ${id}, attempt: ${attemptCount + 1}` - ); + window.log.info(`Looking for the message id : ${id}, attempt: ${attemptCount + 1}`); void copyFromQuotedMessage(msg, quote, attemptCount + 1); }, attemptCount * attemptCount * 500); } else { - window.log.warn( - `We did not found quoted message ${id} after ${attemptCount} attempts.` - ); + window.log.warn(`We did not found quoted message ${id} after ${attemptCount} attempts.`); } quote.referencedMessageNotFound = true; @@ -129,10 +122,7 @@ async function copyFromQuotedMessage( window.log.info(`Found quoted message id: ${id}`); quote.referencedMessageNotFound = false; - const queryMessage = MessageController.getInstance().register( - found.id, - found - ); + const queryMessage = MessageController.getInstance().register(found.id, found); quote.text = queryMessage.get('body') || ''; if (attemptCount > 1) { @@ -150,13 +140,8 @@ async function copyFromQuotedMessage( firstAttachment.thumbnail = null; try { - if ( - (queryMessage.get('schemaVersion') || 0) < - TypedMessage.VERSION_NEEDED_FOR_DISPLAY - ) { - const upgradedMessage = await upgradeMessageSchema( - queryMessage.attributes - ); + if ((queryMessage.get('schemaVersion') || 0) < TypedMessage.VERSION_NEEDED_FOR_DISPLAY) { + const upgradedMessage = await upgradeMessageSchema(queryMessage.attributes); queryMessage.set(upgradedMessage); await upgradedMessage.commit(); } @@ -196,11 +181,7 @@ async function copyFromQuotedMessage( } } -function handleLinkPreviews( - messageBody: string, - messagePreview: any, - message: MessageModel -) { +function handleLinkPreviews(messageBody: string, messagePreview: any, message: MessageModel) { const urls = window.Signal.LinkPreviews.findLinks(messageBody); const incomingPreview = messagePreview || []; const preview = incomingPreview.filter( @@ -241,10 +222,7 @@ function handleMentions( } } -function updateReadStatus( - message: MessageModel, - conversation: ConversationModel -) { +function updateReadStatus(message: MessageModel, conversation: ConversationModel) { const readSync = window.Whisper.ReadSyncs.forMessage(message); if (readSync) { const shouldExpire = message.get('expireTimer'); @@ -265,14 +243,8 @@ function updateReadStatus( } } -function handleSyncedReceipts( - message: MessageModel, - conversation: ConversationModel -) { - const readReceipts = window.Whisper.ReadReceipts.forMessage( - conversation, - message - ); +function handleSyncedReceipts(message: MessageModel, conversation: ConversationModel) { + const readReceipts = window.Whisper.ReadReceipts.forMessage(conversation, message); if (readReceipts.length) { const readBy = readReceipts.map((receipt: any) => receipt.get('reader')); message.set({ @@ -280,10 +252,7 @@ function handleSyncedReceipts( }); } - const deliveryReceipts = window.Whisper.DeliveryReceipts.forMessage( - conversation, - message - ); + const deliveryReceipts = window.Whisper.DeliveryReceipts.forMessage(conversation, message); if (deliveryReceipts.length) { handleSyncDeliveryReceipts(message, deliveryReceipts); @@ -335,11 +304,7 @@ async function handleRegularMessage( // Medium groups might have `group` set even if with group chat messages... if (dataMessage.group && !conversation.isMediumGroup()) { // This is not necessarily a group update message, it could also be a regular group message - const groupUpdate = await handleGroups( - conversation, - dataMessage.group, - source - ); + const groupUpdate = await handleGroups(conversation, dataMessage.group, source); if (groupUpdate !== null) { message.set({ group_update: groupUpdate }); } @@ -389,10 +354,7 @@ async function handleRegularMessage( } const conversationActiveAt = conversation.get('active_at'); - if ( - !conversationActiveAt || - (message.get('sent_at') || 0) > conversationActiveAt - ) { + if (!conversationActiveAt || (message.get('sent_at') || 0) > conversationActiveAt) { conversation.set({ active_at: message.get('sent_at'), lastMessage: message.getNotificationText(), @@ -442,11 +404,7 @@ async function handleExpirationTimerUpdate( source: 'handleDataMessage', }); - await conversation.updateExpirationTimer( - expireTimer, - source, - message.get('received_at') - ); + await conversation.updateExpirationTimer(expireTimer, source, message.get('received_at')); } export async function handleMessageJob( @@ -470,25 +428,12 @@ export async function handleMessageJob( if (confirm) { confirm(); } - window.log.info( - 'Dropping ExpireTimerUpdate message as we already have the same one set.' - ); + window.log.info('Dropping ExpireTimerUpdate message as we already have the same one set.'); return; } - await handleExpirationTimerUpdate( - conversation, - message, - source, - expireTimer - ); + await handleExpirationTimerUpdate(conversation, message, source, expireTimer); } else { - await handleRegularMessage( - conversation, - message, - initialMessage, - source, - ourNumber - ); + await handleRegularMessage(conversation, message, initialMessage, source, ourNumber); } const id = await message.commit(); @@ -530,8 +475,7 @@ export async function handleMessageJob( if (previousUnread !== message.get('unread')) { window.log.warn( - 'Caught race condition on new message read state! ' + - 'Manually starting timers.' + 'Caught race condition on new message read state! ' + 'Manually starting timers.' ); // We call markRead() even though the message is already // marked read because we need to start expiration @@ -539,11 +483,7 @@ export async function handleMessageJob( await message.markRead(Date.now()); } } catch (error) { - window.log.warn( - 'handleDataMessage: Message', - message.idForLogging(), - 'was deleted' - ); + window.log.warn('handleDataMessage: Message', message.idForLogging(), 'was deleted'); } if (message.get('unread')) { @@ -555,12 +495,7 @@ export async function handleMessageJob( } } catch (error) { const errorForLog = error && error.stack ? error.stack : error; - window.log.error( - 'handleDataMessage', - message.idForLogging(), - 'error:', - errorForLog - ); + window.log.error('handleDataMessage', message.idForLogging(), 'error:', errorForLog); throw error; } diff --git a/ts/receiver/receiver.ts b/ts/receiver/receiver.ts index 47fff475bf4af52f607b549cc84deb5308924578..d17f90e96338b69e6ee48c46a06e1c0129204da3 100644 --- a/ts/receiver/receiver.ts +++ b/ts/receiver/receiver.ts @@ -4,20 +4,12 @@ import { EnvelopePlus } from './types'; export { downloadAttachment } from './attachments'; import { v4 as uuidv4 } from 'uuid'; -import { - addToCache, - getAllFromCache, - getAllFromCacheForSource, - removeFromCache, -} from './cache'; +import { addToCache, getAllFromCache, getAllFromCacheForSource, removeFromCache } from './cache'; import { processMessage } from '../session/snode_api/swarmPolling'; import { onError } from './errors'; // innerHandleContentMessage is only needed because of code duplication in handleDecryptedEnvelope... -import { - handleContentMessage, - innerHandleContentMessage, -} from './contentMessage'; +import { handleContentMessage, innerHandleContentMessage } from './contentMessage'; import _ from 'lodash'; export { processMessage }; @@ -65,10 +57,7 @@ class EnvelopeQueue { const promise = this.pending.then(task, task); this.pending = promise; - this.pending.then( - this.cleanup.bind(this, promise), - this.cleanup.bind(this, promise) - ); + this.pending.then(this.cleanup.bind(this, promise), this.cleanup.bind(this, promise)); } private cleanup(promise: Promise<any>) { @@ -88,10 +77,7 @@ function queueEnvelope(envelope: EnvelopePlus) { window.log.info('queueing envelope', id); const task = handleEnvelope.bind(null, envelope); - const taskWithTimeout = window.textsecure.createTaskWithTimeout( - task, - `queueEnvelope ${id}` - ); + const taskWithTimeout = window.textsecure.createTaskWithTimeout(task, `queueEnvelope ${id}`); try { envelopeQueue.add(taskWithTimeout); @@ -134,9 +120,7 @@ async function handleRequestDetail( } envelope.id = envelope.serverGuid || uuidv4(); - envelope.serverTimestamp = envelope.serverTimestamp - ? envelope.serverTimestamp.toNumber() - : null; + envelope.serverTimestamp = envelope.serverTimestamp ? envelope.serverTimestamp.toNumber() : null; try { // NOTE: Annoyngly we add plaintext to the cache @@ -167,16 +151,11 @@ export function handleRequest(body: any, options: ReqOptions): void { const plaintext = body; - const promise = handleRequestDetail(plaintext, options, lastPromise).catch( - e => { - window.log.error( - 'Error handling incoming message:', - e && e.stack ? e.stack : e - ); + const promise = handleRequestDetail(plaintext, options, lastPromise).catch(e => { + window.log.error('Error handling incoming message:', e && e.stack ? e.stack : e); - void onError(e); - } - ); + void onError(e); + }); incomingMessagePromises.push(promise); } @@ -267,10 +246,7 @@ function queueDecryptedEnvelope(envelope: any, plaintext: ArrayBuffer) { } } -async function handleDecryptedEnvelope( - envelope: EnvelopePlus, - plaintext: ArrayBuffer -) { +async function handleDecryptedEnvelope(envelope: EnvelopePlus, plaintext: ArrayBuffer) { // if (this.stoppingProcessing) { // return Promise.resolve(); // } @@ -296,13 +272,10 @@ export async function handlePublicMessage(messageData: any) { await updateProfile(conversation, profile, profileKey); } - const isPublicVisibleMessage = - group && group.id && !!group.id.match(/^publicChat:/); + const isPublicVisibleMessage = group && group.id && !!group.id.match(/^publicChat:/); if (!isPublicVisibleMessage) { - throw new Error( - 'handlePublicMessage Should only be called with public message groups' - ); + throw new Error('handlePublicMessage Should only be called with public message groups'); } const ev = { diff --git a/ts/session/conversations/index.ts b/ts/session/conversations/index.ts index 9755df781f4db78dc8837dd2e52e91c822fa24bc..c506fcfcb36424117792af97b29aa166f36b7f4d 100644 --- a/ts/session/conversations/index.ts +++ b/ts/session/conversations/index.ts @@ -36,9 +36,7 @@ export class ConversationController { // FIXME this could return | undefined public get(id: string): ConversationModel { if (!this._initialFetchComplete) { - throw new Error( - 'ConversationController.get() needs complete initial fetch' - ); + throw new Error('ConversationController.get() needs complete initial fetch'); } return this.conversations.get(id); @@ -46,9 +44,7 @@ export class ConversationController { public getOrThrow(id: string): ConversationModel { if (!this._initialFetchComplete) { - throw new Error( - 'ConversationController.get() needs complete initial fetch' - ); + throw new Error('ConversationController.get() needs complete initial fetch'); } const convo = this.conversations.get(id); @@ -56,9 +52,7 @@ export class ConversationController { if (convo) { return convo; } - throw new Error( - `Conversation ${id} does not exist on ConversationController.get()` - ); + throw new Error(`Conversation ${id} does not exist on ConversationController.get()`); } // Needed for some model setup which happens during the initial fetch() call below public getUnsafe(id: string): ConversationModel | undefined { @@ -79,15 +73,11 @@ export class ConversationController { type !== ConversationType.GROUP && type !== ConversationType.OPEN_GROUP ) { - throw new TypeError( - `'type' must be 'private' or 'group' or 'opengroup; got: '${type}'` - ); + throw new TypeError(`'type' must be 'private' or 'group' or 'opengroup; got: '${type}'`); } if (!this._initialFetchComplete) { - throw new Error( - 'ConversationController.get() needs complete initial fetch' - ); + throw new Error('ConversationController.get() needs complete initial fetch'); } let conversation = this.conversations.get(id); @@ -122,10 +112,7 @@ export class ConversationController { conversation.initialPromise.then(async () => { if (window.inboxStore) { window.inboxStore?.dispatch( - conversationActions.conversationAdded( - conversation.id, - conversation.getProps() - ) + conversationActions.conversationAdded(conversation.id, conversation.getProps()) ); } if (!conversation.isPublic()) { @@ -169,14 +156,10 @@ export class ConversationController { type: ConversationType ): Promise<ConversationModel> { const initialPromise = - this._initialPromise !== undefined - ? this._initialPromise - : Promise.resolve(); + this._initialPromise !== undefined ? this._initialPromise : Promise.resolve(); return initialPromise.then(() => { if (!id) { - return Promise.reject( - new Error('getOrCreateAndWait: invalid id passed.') - ); + return Promise.reject(new Error('getOrCreateAndWait: invalid id passed.')); } const pubkey = id && (id as any).key ? (id as any).key : id; const conversation = this.getOrCreate(pubkey, type); @@ -185,9 +168,7 @@ export class ConversationController { return conversation.initialPromise.then(() => conversation); } - return Promise.reject( - new Error('getOrCreateAndWait: did not get conversation') - ); + return Promise.reject(new Error('getOrCreateAndWait: did not get conversation')); }); } @@ -202,9 +183,7 @@ export class ConversationController { } if (!this._initialFetchComplete) { - throw new Error( - 'ConversationController.get() needs complete initial fetch' - ); + throw new Error('ConversationController.get() needs complete initial fetch'); } const conversation = this.conversations.get(id); @@ -231,9 +210,7 @@ export class ConversationController { await removeConversation(id); this.conversations.remove(conversation); if (window.inboxStore) { - window.inboxStore?.dispatch( - conversationActions.conversationRemoved(conversation.id) - ); + window.inboxStore?.dispatch(conversationActions.conversationRemoved(conversation.id)); } } @@ -262,18 +239,13 @@ export class ConversationController { promises.push(conversation.updateLastMessage()); } - promises.concat([ - conversation.updateProfileName(), - conversation.updateProfileAvatar(), - ]); + promises.concat([conversation.updateProfileName(), conversation.updateProfileAvatar()]); }); await Promise.all(promises); // Remove any unused images - window.profileImages.removeImagesNotInArray( - this.conversations.map((c: any) => c.id) - ); + window.profileImages.removeImagesNotInArray(this.conversations.map((c: any) => c.id)); window.log.info('ConversationController: done with initial fetch'); } catch (error) { window.log.error( diff --git a/ts/session/crypto/DecryptedAttachmentsManager.ts b/ts/session/crypto/DecryptedAttachmentsManager.ts index 563b8c1d5312c1d9c973c5f1f4e93eac186983ec..71113878500609558b3f25e4e5def138e6cb9a28 100644 --- a/ts/session/crypto/DecryptedAttachmentsManager.ts +++ b/ts/session/crypto/DecryptedAttachmentsManager.ts @@ -14,10 +14,7 @@ import { HOURS } from '../utils/Number'; // FIXME. // add a way to remove the blob when the attachment file path is removed (message removed?) // do not hardcode the password -const urlToDecryptedBlobMap = new Map< - string, - { decrypted: string; lastAccessTimestamp: number } ->(); +const urlToDecryptedBlobMap = new Map<string, { decrypted: string; lastAccessTimestamp: number }>(); export const cleanUpOldDecryptedMedias = () => { const currentTimestamp = Date.now(); @@ -34,15 +31,10 @@ export const cleanUpOldDecryptedMedias = () => { countKept++; } } - window.log.info( - `Clean medias blobs: cleaned/kept: ${countCleaned}:${countKept}` - ); + window.log.info(`Clean medias blobs: cleaned/kept: ${countCleaned}:${countKept}`); }; -export const getDecryptedMediaUrl = async ( - url: string, - contentType: string -): Promise<string> => { +export const getDecryptedMediaUrl = async (url: string, contentType: string): Promise<string> => { if (!url) { return url; } @@ -57,8 +49,7 @@ export const getDecryptedMediaUrl = async ( // if it's not, the hook caller has to fallback to setting the img src as an url to the file instead and load it if (urlToDecryptedBlobMap.has(url)) { // refresh the last access timestamp so we keep the one being currently in use - const existingObjUrl = urlToDecryptedBlobMap.get(url) - ?.decrypted as string; + const existingObjUrl = urlToDecryptedBlobMap.get(url)?.decrypted as string; urlToDecryptedBlobMap.set(url, { decrypted: existingObjUrl, @@ -69,9 +60,7 @@ export const getDecryptedMediaUrl = async ( return existingObjUrl; } else { const encryptedFileContent = await fse.readFile(url); - const decryptedContent = await decryptAttachmentBuffer( - toArrayBuffer(encryptedFileContent) - ); + const decryptedContent = await decryptAttachmentBuffer(toArrayBuffer(encryptedFileContent)); if (decryptedContent?.length) { const arrayBuffer = decryptedContent.buffer; const { makeObjectUrl } = window.Signal.Types.VisualAttachment; diff --git a/ts/session/crypto/MessageEncrypter.ts b/ts/session/crypto/MessageEncrypter.ts index e0823f0d79342ee1115b435d8b23bf6523537e0c..a3cf2a988fff47666e4378414ae991950c013903 100644 --- a/ts/session/crypto/MessageEncrypter.ts +++ b/ts/session/crypto/MessageEncrypter.ts @@ -12,9 +12,7 @@ import { UserUtils } from '../utils'; * @param messageBuffer The buffer to add padding to. */ export function padPlainTextBuffer(messageBuffer: Uint8Array): Uint8Array { - const plaintext = new Uint8Array( - getPaddedMessageLength(messageBuffer.byteLength + 1) - 1 - ); + const plaintext = new Uint8Array(getPaddedMessageLength(messageBuffer.byteLength + 1) - 1); plaintext.set(new Uint8Array(messageBuffer)); plaintext[messageBuffer.byteLength] = 0x80; @@ -50,14 +48,8 @@ export async function encrypt( plainTextBuffer: Uint8Array, encryptionType: EncryptionType ): Promise<EncryptResult> { - const { - CLOSED_GROUP_CIPHERTEXT, - UNIDENTIFIED_SENDER, - } = SignalService.Envelope.Type; - if ( - encryptionType !== EncryptionType.ClosedGroup && - encryptionType !== EncryptionType.Fallback - ) { + const { CLOSED_GROUP_CIPHERTEXT, UNIDENTIFIED_SENDER } = SignalService.Envelope.Type; + if (encryptionType !== EncryptionType.ClosedGroup && encryptionType !== EncryptionType.Fallback) { throw new Error(`Invalid encryption type:${encryptionType}`); } const encryptForClosedGroup = encryptionType === EncryptionType.ClosedGroup; @@ -67,13 +59,9 @@ export async function encrypt( window?.log?.info( 'Encrypting message with SessionProtocol and envelope type is CLOSED_GROUP_CIPHERTEXT' ); - const hexEncryptionKeyPair = await getLatestClosedGroupEncryptionKeyPair( - device.key - ); + const hexEncryptionKeyPair = await getLatestClosedGroupEncryptionKeyPair(device.key); if (!hexEncryptionKeyPair) { - window?.log?.warn( - "Couldn't get key pair for closed group during encryption" - ); + window?.log?.warn("Couldn't get key pair for closed group during encryption"); throw new Error("Couldn't get key pair for closed group"); } const hexPubFromECKeyPair = PubKey.cast(hexEncryptionKeyPair.publicHex); @@ -91,10 +79,7 @@ export async function encrypt( }; } - const cipherText = await exports.encryptUsingSessionProtocol( - device, - plainText - ); + const cipherText = await exports.encryptUsingSessionProtocol(device, plainText); return { envelopeType: UNIDENTIFIED_SENDER, cipherText }; } @@ -112,16 +97,11 @@ export async function encryptUsingSessionProtocol( } const sodium = await getSodium(); - window?.log?.info( - 'encryptUsingSessionProtocol for ', - recipientHexEncodedX25519PublicKey.key - ); + window?.log?.info('encryptUsingSessionProtocol for ', recipientHexEncodedX25519PublicKey.key); const recipientX25519PublicKey = recipientHexEncodedX25519PublicKey.withoutPrefixToArray(); const userED25519PubKeyBytes = fromHexToArray(userED25519KeyPairHex.pubKey); - const userED25519SecretKeyBytes = fromHexToArray( - userED25519KeyPairHex.privKey - ); + const userED25519SecretKeyBytes = fromHexToArray(userED25519KeyPairHex.privKey); // merge all arrays into one const verificationData = concatUInt8Array( @@ -130,24 +110,14 @@ export async function encryptUsingSessionProtocol( recipientX25519PublicKey ); - const signature = sodium.crypto_sign_detached( - verificationData, - userED25519SecretKeyBytes - ); + const signature = sodium.crypto_sign_detached(verificationData, userED25519SecretKeyBytes); if (!signature || signature.length === 0) { throw new Error("Couldn't sign message"); } - const plaintextWithMetadata = concatUInt8Array( - plaintext, - userED25519PubKeyBytes, - signature - ); + const plaintextWithMetadata = concatUInt8Array(plaintext, userED25519PubKeyBytes, signature); - const ciphertext = sodium.crypto_box_seal( - plaintextWithMetadata, - recipientX25519PublicKey - ); + const ciphertext = sodium.crypto_box_seal(plaintextWithMetadata, recipientX25519PublicKey); if (!ciphertext) { throw new Error("Couldn't encrypt message."); } diff --git a/ts/session/crypto/index.ts b/ts/session/crypto/index.ts index 7b66ba36fd48225ccd7a6f4fff87ece74d9cba54..aabd76279f0fec00f0c207d828a0ca05a6557ba3 100644 --- a/ts/session/crypto/index.ts +++ b/ts/session/crypto/index.ts @@ -36,9 +36,7 @@ export async function generateClosedGroupPublicKey() { const sodium = await getSodium(); const ed25519KeyPair = sodium.crypto_sign_keypair(); - const x25519PublicKey = sodium.crypto_sign_ed25519_pk_to_curve25519( - ed25519KeyPair.publicKey - ); + const x25519PublicKey = sodium.crypto_sign_ed25519_pk_to_curve25519(ed25519KeyPair.publicKey); // prepend version byte (coming from `processKeys(raw_keys)`) const origPub = new Uint8Array(x25519PublicKey); const prependedX25519PublicKey = new Uint8Array(33); @@ -56,12 +54,8 @@ export async function generateCurve25519KeyPairWithoutPrefix(): Promise<ECKeyPai try { const ed25519KeyPair = sodium.crypto_sign_keypair(); - const x25519PublicKey = sodium.crypto_sign_ed25519_pk_to_curve25519( - ed25519KeyPair.publicKey - ); - const x25519SecretKey = sodium.crypto_sign_ed25519_sk_to_curve25519( - ed25519KeyPair.privateKey - ); + const x25519PublicKey = sodium.crypto_sign_ed25519_pk_to_curve25519(ed25519KeyPair.publicKey); + const x25519SecretKey = sodium.crypto_sign_ed25519_sk_to_curve25519(ed25519KeyPair.privateKey); return new ECKeyPair(x25519PublicKey, x25519SecretKey); } catch (err) { diff --git a/ts/session/crypto/mnemonic.ts b/ts/session/crypto/mnemonic.ts index daf174b7d0023ea45f879ff98fc81ea3836bab94..ec1dc88835ff55f33fecc8dfaf263352e6454d97 100644 --- a/ts/session/crypto/mnemonic.ts +++ b/ts/session/crypto/mnemonic.ts @@ -23,19 +23,14 @@ function mn_get_checksum_index(words: Array<string>, prefixLen: number) { return index; } -export function mn_encode( - str: string, - wordsetName: string = MN_DEFAULT_WORDSET -): string { +export function mn_encode(str: string, wordsetName: string = MN_DEFAULT_WORDSET): string { const wordset = mnWords[wordsetName]; let out = [] as Array<any>; const n = wordset.words.length; let strCopy = str; for (let j = 0; j < strCopy.length; j += 8) { strCopy = - strCopy.slice(0, j) + - mn_swap_endian_4byte(strCopy.slice(j, j + 8)) + - strCopy.slice(j + 8); + strCopy.slice(0, j) + mn_swap_endian_4byte(strCopy.slice(j, j + 8)) + strCopy.slice(j + 8); } for (let i = 0; i < strCopy.length; i += 8) { const x = parseInt(strCopy.substr(i, 8), 16); @@ -57,10 +52,7 @@ function mn_swap_endian_4byte(str: string) { return str.slice(6, 8) + str.slice(4, 6) + str.slice(2, 4) + str.slice(0, 2); } -export function mn_decode( - str: string, - wordsetName: string = MN_DEFAULT_WORDSET -): string { +export function mn_decode(str: string, wordsetName: string = MN_DEFAULT_WORDSET): string { const wordset = mnWords[wordsetName]; let out = ''; const n = wordset.words.length; @@ -114,8 +106,7 @@ export function mn_decode( const index = mn_get_checksum_index(wlist, wordset.prefixLen); const expectedChecksumWord = wlist[index]; if ( - expectedChecksumWord.slice(0, wordset.prefixLen) !== - checksumWord.slice(0, wordset.prefixLen) + expectedChecksumWord.slice(0, wordset.prefixLen) !== checksumWord.slice(0, wordset.prefixLen) ) { throw new MnemonicError( 'Your private key could not be verified, please verify the checksum word' @@ -170,9 +161,7 @@ for (const i in mnWords) { continue; } for (let j = 0; j < mnWords[i].words.length; ++j) { - mnWords[i].truncWords.push( - mnWords[i].words[j].slice(0, mnWords[i].prefixLen) - ); + mnWords[i].truncWords.push(mnWords[i].words[j].slice(0, mnWords[i].prefixLen)); } } } diff --git a/ts/session/group/index.ts b/ts/session/group/index.ts index a3733f9856f7022894b5712e90009fee93a9ee04..d3aa22415f1e63c8d8ea24438a70220d913644d3 100644 --- a/ts/session/group/index.ts +++ b/ts/session/group/index.ts @@ -69,9 +69,7 @@ export async function getGroupSecretKey(groupId: string): Promise<Uint8Array> { const secretKey = groupIdentity.secretKey; if (!secretKey) { - throw new Error( - `Secret key not found in identity key record for group ${groupId}` - ); + throw new Error(`Secret key not found in identity key record for group ${groupId}`); } return new Uint8Array(fromHex(secretKey)); @@ -125,52 +123,24 @@ export async function initiateGroupUpdate( if (diff.newName?.length) { const nameOnlyDiff: GroupDiff = { newName: diff.newName }; - const dbMessageName = await addUpdateMessage( - convo, - nameOnlyDiff, - 'outgoing', - Date.now() - ); + const dbMessageName = await addUpdateMessage(convo, nameOnlyDiff, 'outgoing', Date.now()); MessageController.getInstance().register(dbMessageName.id, dbMessageName); await sendNewName(convo, diff.newName, dbMessageName.id); } if (diff.joiningMembers?.length) { const joiningOnlyDiff: GroupDiff = { joiningMembers: diff.joiningMembers }; - const dbMessageAdded = await addUpdateMessage( - convo, - joiningOnlyDiff, - 'outgoing', - Date.now() - ); + const dbMessageAdded = await addUpdateMessage(convo, joiningOnlyDiff, 'outgoing', Date.now()); MessageController.getInstance().register(dbMessageAdded.id, dbMessageAdded); - await sendAddedMembers( - convo, - diff.joiningMembers, - dbMessageAdded.id, - updateObj - ); + await sendAddedMembers(convo, diff.joiningMembers, dbMessageAdded.id, updateObj); } if (diff.leavingMembers?.length) { const leavingOnlyDiff: GroupDiff = { leavingMembers: diff.leavingMembers }; - const dbMessageLeaving = await addUpdateMessage( - convo, - leavingOnlyDiff, - 'outgoing', - Date.now() - ); - MessageController.getInstance().register( - dbMessageLeaving.id, - dbMessageLeaving - ); + const dbMessageLeaving = await addUpdateMessage(convo, leavingOnlyDiff, 'outgoing', Date.now()); + MessageController.getInstance().register(dbMessageLeaving.id, dbMessageLeaving); const stillMembers = members; - await sendRemovedMembers( - convo, - diff.leavingMembers, - dbMessageLeaving.id, - stillMembers - ); + await sendRemovedMembers(convo, diff.leavingMembers, dbMessageLeaving.id, stillMembers); } } @@ -220,10 +190,7 @@ export async function addUpdateMessage( return message; } -export function buildGroupDiff( - convo: ConversationModel, - update: UpdatableGroupState -): GroupDiff { +export function buildGroupDiff(convo: ConversationModel, update: UpdatableGroupState): GroupDiff { const groupDiff: GroupDiff = {}; if (convo.get('name') !== update.name) { @@ -271,9 +238,7 @@ export async function updateOrCreateClosedGroup(details: GroupInfo) { updates.timestamp = updates.active_at; } updates.left = false; - updates.lastJoinedTimestamp = weWereJustAdded - ? Date.now() - : updates.active_at; + updates.lastJoinedTimestamp = weWereJustAdded ? Date.now() : updates.active_at; } else { updates.left = true; } @@ -339,9 +304,7 @@ export async function leaveClosedGroup(groupId: string) { } else { // otherwise, just the exclude ourself from the members and trigger an update with this convo.set({ left: true }); - members = (convo.get('members') || []).filter( - (m: string) => m !== ourNumber.key - ); + members = (convo.get('members') || []).filter((m: string) => m !== ourNumber.key); admins = convo.get('groupAdmins') || []; } convo.set({ members }); @@ -366,24 +329,16 @@ export async function leaveClosedGroup(groupId: string) { expireTimer: existingExpireTimer, }); - window.log.info( - `We are leaving the group ${groupId}. Sending our leaving message.` - ); + window.log.info(`We are leaving the group ${groupId}. Sending our leaving message.`); // sent the message to the group and once done, remove everything related to this group window.SwarmPolling.removePubkey(groupId); await getMessageQueue().sendToGroup(ourLeavingMessage, async () => { - window.log.info( - `Leaving message sent ${groupId}. Removing everything related to this group.` - ); + window.log.info(`Leaving message sent ${groupId}. Removing everything related to this group.`); await removeAllClosedGroupEncryptionKeyPairs(groupId); }); } -async function sendNewName( - convo: ConversationModel, - name: string, - messageId: string -) { +async function sendNewName(convo: ConversationModel, name: string, messageId: string) { if (name.length === 0) { window.log.warn('No name given for group update. Skipping'); return; @@ -417,9 +372,7 @@ async function sendAddedMembers( const admins = groupUpdate.admins || []; // Check preconditions - const hexEncryptionKeyPair = await getLatestClosedGroupEncryptionKeyPair( - groupId - ); + const hexEncryptionKeyPair = await getLatestClosedGroupEncryptionKeyPair(groupId); if (!hexEncryptionKeyPair) { throw new Error("Couldn't get key pair for closed group"); } @@ -450,10 +403,7 @@ async function sendAddedMembers( }); const promises = addedMembers.map(async m => { - await ConversationController.getInstance().getOrCreateAndWait( - m, - ConversationType.PRIVATE - ); + await ConversationController.getInstance().getOrCreateAndWait(m, ConversationType.PRIVATE); const memberPubKey = PubKey.cast(m); await getMessageQueue().sendToPubKey(memberPubKey, newClosedGroupUpdate); }); @@ -477,14 +427,10 @@ async function sendRemovedMembers( const isCurrentUserAdmin = admins.includes(ourNumber.key); const isUserLeaving = removedMembers.includes(ourNumber.key); if (isUserLeaving) { - throw new Error( - 'Cannot remove members and leave the group at the same time' - ); + throw new Error('Cannot remove members and leave the group at the same time'); } if (removedMembers.includes(admins[0]) && stillMembers.length !== 0) { - throw new Error( - "Can't remove admin from closed group without removing everyone." - ); + throw new Error("Can't remove admin from closed group without removing everyone."); } const expireTimer = convo.get('expireTimer') || 0; @@ -497,19 +443,16 @@ async function sendRemovedMembers( expireTimer, }); // Send the group update, and only once sent, generate and distribute a new encryption key pair if needed - await getMessageQueue().sendToGroup( - mainClosedGroupControlMessage, - async () => { - if (isCurrentUserAdmin) { - // we send the new encryption key only to members already here before the update - window.log.info( - `Sending group update: A user was removed from ${groupId} and we are the admin. Generating and sending a new EncryptionKeyPair` - ); - - await generateAndSendNewEncryptionKeyPair(groupId, stillMembers); - } + await getMessageQueue().sendToGroup(mainClosedGroupControlMessage, async () => { + if (isCurrentUserAdmin) { + // we send the new encryption key only to members already here before the update + window.log.info( + `Sending group update: A user was removed from ${groupId} and we are the admin. Generating and sending a new EncryptionKeyPair` + ); + + await generateAndSendNewEncryptionKeyPair(groupId, stillMembers); } - ); + }); } export async function generateAndSendNewEncryptionKeyPair( @@ -520,10 +463,7 @@ export async function generateAndSendNewEncryptionKeyPair( const groupId = fromHexToArray(groupPublicKey); if (!groupConvo) { - window.log.warn( - 'generateAndSendNewEncryptionKeyPair: conversation not found', - groupPublicKey - ); + window.log.warn('generateAndSendNewEncryptionKeyPair: conversation not found', groupPublicKey); return; } if (!groupConvo.isMediumGroup()) { @@ -536,9 +476,7 @@ export async function generateAndSendNewEncryptionKeyPair( const ourNumber = UserUtils.getOurPubKeyFromCache(); if (!groupConvo.get('groupAdmins')?.includes(ourNumber.key)) { - window.log.warn( - 'generateAndSendNewEncryptionKeyPair: cannot send it as a non admin' - ); + window.log.warn('generateAndSendNewEncryptionKeyPair: cannot send it as a non admin'); return; } @@ -546,16 +484,11 @@ export async function generateAndSendNewEncryptionKeyPair( const newKeyPair = await generateCurve25519KeyPairWithoutPrefix(); if (!newKeyPair) { - window.log.warn( - 'generateAndSendNewEncryptionKeyPair: failed to generate new keypair' - ); + window.log.warn('generateAndSendNewEncryptionKeyPair: failed to generate new keypair'); return; } // Distribute it - const wrappers = await buildEncryptionKeyPairWrappers( - targetMembers, - newKeyPair - ); + const wrappers = await buildEncryptionKeyPairWrappers(targetMembers, newKeyPair); const expireTimer = groupConvo.get('expireTimer') || 0; @@ -575,10 +508,7 @@ export async function generateAndSendNewEncryptionKeyPair( distributingClosedGroupEncryptionKeyPairs.delete(toHex(groupId)); - await addClosedGroupEncryptionKeyPair( - toHex(groupId), - newKeyPair.toHexKeyPair() - ); + await addClosedGroupEncryptionKeyPair(toHex(groupId), newKeyPair.toHexKeyPair()); }; // this is to be sent to the group pubkey adress await getMessageQueue().sendToGroup(keypairsMessage, messageSentCallback); @@ -593,9 +523,7 @@ export async function buildEncryptionKeyPairWrappers( !encryptionKeyPair.publicKeyData.length || !encryptionKeyPair.privateKeyData.length ) { - throw new Error( - 'buildEncryptionKeyPairWrappers() needs a valid encryptionKeyPair set' - ); + throw new Error('buildEncryptionKeyPairWrappers() needs a valid encryptionKeyPair set'); } const proto = new SignalService.KeyPair({ @@ -606,31 +534,22 @@ export async function buildEncryptionKeyPairWrappers( const wrappers = await Promise.all( targetMembers.map(async pubkey => { - const ciphertext = await encryptUsingSessionProtocol( - PubKey.cast(pubkey), - plaintext - ); - return new SignalService.DataMessage.ClosedGroupControlMessage.KeyPairWrapper( - { - encryptedKeyPair: ciphertext, - publicKey: fromHexToArray(pubkey), - } - ); + const ciphertext = await encryptUsingSessionProtocol(PubKey.cast(pubkey), plaintext); + return new SignalService.DataMessage.ClosedGroupControlMessage.KeyPairWrapper({ + encryptedKeyPair: ciphertext, + publicKey: fromHexToArray(pubkey), + }); }) ); return wrappers; } -export async function requestEncryptionKeyPair( - groupPublicKey: string | PubKey -) { +export async function requestEncryptionKeyPair(groupPublicKey: string | PubKey) { if (!window.lokiFeatureFlags.useRequestEncryptionKeyPair) { throw new Error('useRequestEncryptionKeyPair is disabled'); } - const groupConvo = ConversationController.getInstance().get( - PubKey.cast(groupPublicKey).key - ); + const groupConvo = ConversationController.getInstance().get(PubKey.cast(groupPublicKey).key); if (!groupConvo) { window.log.warn( @@ -641,9 +560,7 @@ export async function requestEncryptionKeyPair( const ourNumber = UserUtils.getOurPubKeyFromCache(); if (!groupConvo.get('members').includes(ourNumber.key)) { - window.log.info( - 'requestEncryptionKeyPair: We are not a member of this group.' - ); + window.log.info('requestEncryptionKeyPair: We are not a member of this group.'); return; } const expireTimer = groupConvo.get('expireTimer') || 0; diff --git a/ts/session/index.ts b/ts/session/index.ts index 37486ad13ecb284fa48a98f0c39e76bc66793dc9..0a74aa255c757144c3d3649f79ff2f9bc6c0d831 100644 --- a/ts/session/index.ts +++ b/ts/session/index.ts @@ -8,13 +8,4 @@ import * as ClosedGroup from './group'; const getMessageQueue = Sending.getMessageQueue; -export { - Conversations, - Messages, - Utils, - Types, - Sending, - Constants, - ClosedGroup, - getMessageQueue, -}; +export { Conversations, Messages, Utils, Types, Sending, Constants, ClosedGroup, getMessageQueue }; diff --git a/ts/session/messages/MessageController.ts b/ts/session/messages/MessageController.ts index 66a84e494f0c47156f5e049919c9ff07fcc76ae3..779926084b366720fdc8a33fc3c357ca340420b6 100644 --- a/ts/session/messages/MessageController.ts +++ b/ts/session/messages/MessageController.ts @@ -31,9 +31,7 @@ export class MessageController { public register(id: string, message: MessageModel) { if (!(message instanceof MessageModel)) { - throw new Error( - 'Only MessageModels can be registered to the MessageController.' - ); + throw new Error('Only MessageModels can be registered to the MessageController.'); } const existing = this.messageLookup.get(id); if (existing) { @@ -57,9 +55,7 @@ export class MessageController { } public cleanup() { - window.log.warn( - 'Cleaning up MessageController singleton oldest messages...' - ); + window.log.warn('Cleaning up MessageController singleton oldest messages...'); const now = Date.now(); (this.messageLookup || []).forEach(messageEntry => { diff --git a/ts/session/messages/outgoing/OpenGroupMessage.ts b/ts/session/messages/outgoing/OpenGroupMessage.ts index 11ece2cf82494951031235ab0f60904301a6a486..125444aaa05507f932e9939fdc07f22d5e81335c 100644 --- a/ts/session/messages/outgoing/OpenGroupMessage.ts +++ b/ts/session/messages/outgoing/OpenGroupMessage.ts @@ -1,10 +1,6 @@ import { Message, MessageParams } from './Message'; import { OpenGroup } from '../../../opengroup/opengroupV1/OpenGroup'; -import { - AttachmentPointer, - Preview, - Quote, -} from './visibleMessage/VisibleMessage'; +import { AttachmentPointer, Preview, Quote } from './visibleMessage/VisibleMessage'; interface OpenGroupMessageParams extends MessageParams { group: OpenGroup; diff --git a/ts/session/messages/outgoing/controlMessage/ConfigurationMessage.ts b/ts/session/messages/outgoing/controlMessage/ConfigurationMessage.ts index 44f271c400850293386fbb393216439dec4c8051..4c4db54eb86d0057e62f13c7300d4cc801e23405 100644 --- a/ts/session/messages/outgoing/controlMessage/ConfigurationMessage.ts +++ b/ts/session/messages/outgoing/controlMessage/ConfigurationMessage.ts @@ -122,10 +122,7 @@ export class ConfigurationMessageContact { throw new Error('displayName must be set or undefined'); } - if ( - this.profilePictureURL !== undefined && - this.profilePictureURL?.length === 0 - ) { + if (this.profilePictureURL !== undefined && this.profilePictureURL?.length === 0) { throw new Error('profilePictureURL must either undefined or not empty'); } if (this.profileKey !== undefined && this.profileKey?.length === 0) { diff --git a/ts/session/messages/outgoing/controlMessage/ExpirationTimerUpdateMessage.ts b/ts/session/messages/outgoing/controlMessage/ExpirationTimerUpdateMessage.ts index 72aff13ae0dc7e062ff85501e0a04d54b49325b9..c2c989ea85812eacd5c646db2bfdf26c0bc09304 100644 --- a/ts/session/messages/outgoing/controlMessage/ExpirationTimerUpdateMessage.ts +++ b/ts/session/messages/outgoing/controlMessage/ExpirationTimerUpdateMessage.ts @@ -38,9 +38,7 @@ export class ExpirationTimerUpdateMessage extends DataMessage { // the envelope stores the groupId for a closed group already. if (this.groupId) { const groupMessage = new SignalService.GroupContext(); - const groupIdWithPrefix = PubKey.addTextSecurePrefixIfNeeded( - this.groupId.key - ); + const groupIdWithPrefix = PubKey.addTextSecurePrefixIfNeeded(this.groupId.key); const encoded = StringUtils.encode(groupIdWithPrefix, 'utf8'); const id = new Uint8Array(encoded); groupMessage.id = id; diff --git a/ts/session/messages/outgoing/controlMessage/group/ClosedGroupAddedMembersMessage.ts b/ts/session/messages/outgoing/controlMessage/group/ClosedGroupAddedMembersMessage.ts index 5b0063bac11909fcdc4f4c691ae3b1d4df1745de..25ac6f5d23cb7e7cbaabdb2676638cf8b0a83783 100644 --- a/ts/session/messages/outgoing/controlMessage/group/ClosedGroupAddedMembersMessage.ts +++ b/ts/session/messages/outgoing/controlMessage/group/ClosedGroupAddedMembersMessage.ts @@ -2,13 +2,9 @@ import { fromHex } from 'bytebuffer'; import { Constants } from '../../../..'; import { SignalService } from '../../../../../protobuf'; import { fromHexToArray } from '../../../../utils/String'; -import { - ClosedGroupMessage, - ClosedGroupMessageParams, -} from './ClosedGroupMessage'; +import { ClosedGroupMessage, ClosedGroupMessageParams } from './ClosedGroupMessage'; -interface ClosedGroupAddedMembersMessageParams - extends ClosedGroupMessageParams { +interface ClosedGroupAddedMembersMessageParams extends ClosedGroupMessageParams { addedMembers: Array<string>; } @@ -34,9 +30,7 @@ export class ClosedGroupAddedMembersMessage extends ClosedGroupMessage { // tslint:disable: no-non-null-assertion dataMessage.closedGroupControlMessage!.type = SignalService.DataMessage.ClosedGroupControlMessage.Type.MEMBERS_ADDED; - dataMessage.closedGroupControlMessage!.members = this.addedMembers.map( - fromHexToArray - ); + dataMessage.closedGroupControlMessage!.members = this.addedMembers.map(fromHexToArray); return dataMessage; } diff --git a/ts/session/messages/outgoing/controlMessage/group/ClosedGroupEncryptionPairMessage.ts b/ts/session/messages/outgoing/controlMessage/group/ClosedGroupEncryptionPairMessage.ts index 8c4275068e5573aeecc9d122b78e0b2d64363c72..4942b5d612be9b16d8c89cf3a6fd560682d6def9 100644 --- a/ts/session/messages/outgoing/controlMessage/group/ClosedGroupEncryptionPairMessage.ts +++ b/ts/session/messages/outgoing/controlMessage/group/ClosedGroupEncryptionPairMessage.ts @@ -1,15 +1,9 @@ import { Constants } from '../../../..'; import { SignalService } from '../../../../../protobuf'; -import { - ClosedGroupMessage, - ClosedGroupMessageParams, -} from './ClosedGroupMessage'; +import { ClosedGroupMessage, ClosedGroupMessageParams } from './ClosedGroupMessage'; -export interface ClosedGroupEncryptionPairMessageParams - extends ClosedGroupMessageParams { - encryptedKeyPairs: Array< - SignalService.DataMessage.ClosedGroupControlMessage.KeyPairWrapper - >; +export interface ClosedGroupEncryptionPairMessageParams extends ClosedGroupMessageParams { + encryptedKeyPairs: Array<SignalService.DataMessage.ClosedGroupControlMessage.KeyPairWrapper>; } export class ClosedGroupEncryptionPairMessage extends ClosedGroupMessage { @@ -36,15 +30,13 @@ export class ClosedGroupEncryptionPairMessage extends ClosedGroupMessage { // tslint:disable: no-non-null-assertion dataMessage.closedGroupControlMessage!.type = SignalService.DataMessage.ClosedGroupControlMessage.Type.ENCRYPTION_KEY_PAIR; - dataMessage.closedGroupControlMessage!.wrappers = this.encryptedKeyPairs.map( - w => { - const { publicKey, encryptedKeyPair } = w; - return { - publicKey: publicKey, - encryptedKeyPair, - }; - } - ); + dataMessage.closedGroupControlMessage!.wrappers = this.encryptedKeyPairs.map(w => { + const { publicKey, encryptedKeyPair } = w; + return { + publicKey: publicKey, + encryptedKeyPair, + }; + }); return dataMessage; } diff --git a/ts/session/messages/outgoing/controlMessage/group/ClosedGroupEncryptionPairReplyMessage.ts b/ts/session/messages/outgoing/controlMessage/group/ClosedGroupEncryptionPairReplyMessage.ts index bde11186ca1fd97a0bc337a09c0c7747467e94d5..5455337b54cfdddd2105e101c48415f1aa2bdfaa 100644 --- a/ts/session/messages/outgoing/controlMessage/group/ClosedGroupEncryptionPairReplyMessage.ts +++ b/ts/session/messages/outgoing/controlMessage/group/ClosedGroupEncryptionPairReplyMessage.ts @@ -16,9 +16,7 @@ export class ClosedGroupEncryptionPairReplyMessage extends ClosedGroupEncryption public dataProto(): SignalService.DataMessage { const dataMessage = super.dataProto(); // tslint:disable: no-non-null-assertion - dataMessage.closedGroupControlMessage!.publicKey = fromHexToArray( - this.groupId.key - ); + dataMessage.closedGroupControlMessage!.publicKey = fromHexToArray(this.groupId.key); return dataMessage; } diff --git a/ts/session/messages/outgoing/controlMessage/group/ClosedGroupEncryptionPairRequestMessage.ts b/ts/session/messages/outgoing/controlMessage/group/ClosedGroupEncryptionPairRequestMessage.ts index 3b670f4353f0a1d088e222a74634079e14414cd8..057986f051c3558b5a56987e3bccf88b01f4ea69 100644 --- a/ts/session/messages/outgoing/controlMessage/group/ClosedGroupEncryptionPairRequestMessage.ts +++ b/ts/session/messages/outgoing/controlMessage/group/ClosedGroupEncryptionPairRequestMessage.ts @@ -4,9 +4,7 @@ import { ClosedGroupMessage } from './ClosedGroupMessage'; export class ClosedGroupEncryptionPairRequestMessage extends ClosedGroupMessage { public dataProto(): SignalService.DataMessage { - throw new Error( - 'ClosedGroupEncryptionPairRequestMessage: This is unused for now ' - ); + throw new Error('ClosedGroupEncryptionPairRequestMessage: This is unused for now '); const dataMessage = super.dataProto(); // tslint:disable: no-non-null-assertion diff --git a/ts/session/messages/outgoing/controlMessage/group/ClosedGroupMessage.ts b/ts/session/messages/outgoing/controlMessage/group/ClosedGroupMessage.ts index 9c353f52e772a9a29a889b96da4ad8fab36760ca..955d42286b375bd9e2c6153901b4fb82ddad0d58 100644 --- a/ts/session/messages/outgoing/controlMessage/group/ClosedGroupMessage.ts +++ b/ts/session/messages/outgoing/controlMessage/group/ClosedGroupMessage.ts @@ -25,10 +25,7 @@ export abstract class ClosedGroupMessage extends DataMessage { } } - public static areAdminsMembers( - admins: Array<string>, - members: Array<string> - ) { + public static areAdminsMembers(admins: Array<string>, members: Array<string>) { return admins.every(a => members.includes(a)); } diff --git a/ts/session/messages/outgoing/controlMessage/group/ClosedGroupNameChangeMessage.ts b/ts/session/messages/outgoing/controlMessage/group/ClosedGroupNameChangeMessage.ts index ea70d6085a56d18f7b20caf0f7c152ad438c8fab..d5de53624ceaae5d133ec12d2b1e5ed3ffc4ff07 100644 --- a/ts/session/messages/outgoing/controlMessage/group/ClosedGroupNameChangeMessage.ts +++ b/ts/session/messages/outgoing/controlMessage/group/ClosedGroupNameChangeMessage.ts @@ -1,9 +1,6 @@ import { Constants } from '../../../..'; import { SignalService } from '../../../../../protobuf'; -import { - ClosedGroupMessage, - ClosedGroupMessageParams, -} from './ClosedGroupMessage'; +import { ClosedGroupMessage, ClosedGroupMessageParams } from './ClosedGroupMessage'; interface ClosedGroupNameChangeMessageParams extends ClosedGroupMessageParams { name: string; diff --git a/ts/session/messages/outgoing/controlMessage/group/ClosedGroupNewMessage.ts b/ts/session/messages/outgoing/controlMessage/group/ClosedGroupNewMessage.ts index b57ff533c8475b6c0ed62f22e8b1ace72084e19c..79fcc692e63bcac799460d503fd03e1c4ed1aa92 100644 --- a/ts/session/messages/outgoing/controlMessage/group/ClosedGroupNewMessage.ts +++ b/ts/session/messages/outgoing/controlMessage/group/ClosedGroupNewMessage.ts @@ -1,8 +1,5 @@ import { SignalService } from '../../../../../protobuf'; -import { - ClosedGroupMessage, - ClosedGroupMessageParams, -} from './ClosedGroupMessage'; +import { ClosedGroupMessage, ClosedGroupMessageParams } from './ClosedGroupMessage'; import { fromHexToArray } from '../../../../utils/String'; import { ECKeyPair } from '../../../../../receiver/keypairs'; @@ -61,17 +58,11 @@ export class ClosedGroupNewMessage extends ClosedGroupMessage { dataMessage.closedGroupControlMessage.type = SignalService.DataMessage.ClosedGroupControlMessage.Type.NEW; - dataMessage.closedGroupControlMessage.publicKey = fromHexToArray( - this.groupId.key - ); + dataMessage.closedGroupControlMessage.publicKey = fromHexToArray(this.groupId.key); dataMessage.closedGroupControlMessage.name = this.name; - dataMessage.closedGroupControlMessage.admins = this.admins.map( - fromHexToArray - ); - dataMessage.closedGroupControlMessage.members = this.members.map( - fromHexToArray - ); + dataMessage.closedGroupControlMessage.admins = this.admins.map(fromHexToArray); + dataMessage.closedGroupControlMessage.members = this.members.map(fromHexToArray); try { dataMessage.closedGroupControlMessage.encryptionKeyPair = new SignalService.KeyPair(); dataMessage.closedGroupControlMessage.encryptionKeyPair.privateKey = new Uint8Array( diff --git a/ts/session/messages/outgoing/controlMessage/group/ClosedGroupRemovedMembersMessage.ts b/ts/session/messages/outgoing/controlMessage/group/ClosedGroupRemovedMembersMessage.ts index 8a2eb0f5ba3863af3664f9fa694bc0efc81a34ea..0087d4fab864f04e3922bf4aaada37bcf0b05a9b 100644 --- a/ts/session/messages/outgoing/controlMessage/group/ClosedGroupRemovedMembersMessage.ts +++ b/ts/session/messages/outgoing/controlMessage/group/ClosedGroupRemovedMembersMessage.ts @@ -1,13 +1,9 @@ import { Constants } from '../../../..'; import { SignalService } from '../../../../../protobuf'; import { fromHexToArray } from '../../../../utils/String'; -import { - ClosedGroupMessage, - ClosedGroupMessageParams, -} from './ClosedGroupMessage'; +import { ClosedGroupMessage, ClosedGroupMessageParams } from './ClosedGroupMessage'; -interface ClosedGroupRemovedMembersMessageParams - extends ClosedGroupMessageParams { +interface ClosedGroupRemovedMembersMessageParams extends ClosedGroupMessageParams { removedMembers: Array<string>; } @@ -33,9 +29,7 @@ export class ClosedGroupRemovedMembersMessage extends ClosedGroupMessage { // tslint:disable: no-non-null-assertion dataMessage.closedGroupControlMessage!.type = SignalService.DataMessage.ClosedGroupControlMessage.Type.MEMBERS_REMOVED; - dataMessage.closedGroupControlMessage!.members = this.removedMembers.map( - fromHexToArray - ); + dataMessage.closedGroupControlMessage!.members = this.removedMembers.map(fromHexToArray); return dataMessage; } diff --git a/ts/session/messages/outgoing/visibleMessage/ClosedGroupVisibleMessage.ts b/ts/session/messages/outgoing/visibleMessage/ClosedGroupVisibleMessage.ts index ffc6f7eab636f2afe4fec1066d8a54b8c65105ca..0c6eff1babee0afd7fe2166e8f295edcbb46c294 100644 --- a/ts/session/messages/outgoing/visibleMessage/ClosedGroupVisibleMessage.ts +++ b/ts/session/messages/outgoing/visibleMessage/ClosedGroupVisibleMessage.ts @@ -33,9 +33,7 @@ export class ClosedGroupVisibleMessage extends ClosedGroupMessage { if (this.groupId) { const groupMessage = new SignalService.GroupContext(); - const groupIdWithPrefix = PubKey.addTextSecurePrefixIfNeeded( - this.groupId.key - ); + const groupIdWithPrefix = PubKey.addTextSecurePrefixIfNeeded(this.groupId.key); const encoded = StringUtils.encode(groupIdWithPrefix, 'utf8'); const id = new Uint8Array(encoded); groupMessage.id = id; diff --git a/ts/session/messages/outgoing/visibleMessage/VisibleMessage.ts b/ts/session/messages/outgoing/visibleMessage/VisibleMessage.ts index 311ded641bd18b5052332435e55cb1b9f664f855..bb962bbb9dc06e31b1badb7041b282d73a466a9e 100644 --- a/ts/session/messages/outgoing/visibleMessage/VisibleMessage.ts +++ b/ts/session/messages/outgoing/visibleMessage/VisibleMessage.ts @@ -179,9 +179,6 @@ export class VisibleMessage extends DataMessage { } public isEqual(comparator: VisibleMessage): boolean { - return ( - this.identifier === comparator.identifier && - this.timestamp === comparator.timestamp - ); + return this.identifier === comparator.identifier && this.timestamp === comparator.timestamp; } } diff --git a/ts/session/onions/index.ts b/ts/session/onions/index.ts index 73542d0a57f5cb0502863b30e8f92ca547662d2e..ae974161d939f9eeb55cfba1bd0e4d327a7140f4 100644 --- a/ts/session/onions/index.ts +++ b/ts/session/onions/index.ts @@ -40,9 +40,7 @@ export class OnionPaths { }); } - public async getOnionPath(toExclude?: { - pubkey_ed25519: string; - }): Promise<Array<Snode>> { + public async getOnionPath(toExclude?: { pubkey_ed25519: string }): Promise<Array<Snode>> { const { log, CONSTANTS } = window; let goodPaths = this.onionPaths.filter(x => !x.bad); @@ -76,11 +74,7 @@ export class OnionPaths { // Select a path that doesn't contain `toExclude` const otherPaths = paths.filter( - path => - !_.some( - path.path, - node => node.pubkey_ed25519 === toExclude.pubkey_ed25519 - ) + path => !_.some(path.path, node => node.pubkey_ed25519 === toExclude.pubkey_ed25519) ); if (otherPaths.length === 0) { @@ -102,10 +96,7 @@ export class OnionPaths { } if (!otherPaths[0].path) { - log.error( - 'LokiSnodeAPI::getOnionPath - otherPaths no path in', - otherPaths[0] - ); + log.error('LokiSnodeAPI::getOnionPath - otherPaths no path in', otherPaths[0]); } return otherPaths[0].path; @@ -188,10 +179,7 @@ export class OnionPaths { // `getRandomSnodePool` is expected to refresh itself on low nodes const nodePool = await SnodePool.getRandomSnodePool(); if (nodePool.length < CONSTANTS.DESIRED_GUARD_COUNT) { - log.error( - 'Could not select guard nodes. Not enough nodes in the pool: ', - nodePool.length - ); + log.error('Could not select guard nodes. Not enough nodes in the pool: ', nodePool.length); return []; } @@ -212,9 +200,7 @@ export class OnionPaths { // Test all three nodes at once // eslint-disable-next-line no-await-in-loop - const idxOk = await Promise.all( - candidateNodes.map(n => this.testGuardNode(n)) - ); + const idxOk = await Promise.all(candidateNodes.map(n => this.testGuardNode(n))); const goodNodes = _.zip(idxOk, candidateNodes) .filter(x => x[0]) @@ -224,9 +210,7 @@ export class OnionPaths { } if (guardNodes.length < CONSTANTS.DESIRED_GUARD_COUNT) { - log.error( - `COULD NOT get enough guard nodes, only have: ${guardNodes.length}` - ); + log.error(`COULD NOT get enough guard nodes, only have: ${guardNodes.length}`); } log.info('new guard nodes: ', guardNodes); @@ -256,9 +240,7 @@ export class OnionPaths { } else { // We only store the nodes' keys, need to find full entries: const edKeys = nodes.map(x => x.ed25519PubKey); - this.guardNodes = allNodes.filter( - x => edKeys.indexOf(x.pubkey_ed25519) !== -1 - ); + this.guardNodes = allNodes.filter(x => edKeys.indexOf(x.pubkey_ed25519) !== -1); if (this.guardNodes.length < edKeys.length) { log.warn( @@ -296,9 +278,7 @@ export class OnionPaths { const maxPath = Math.floor( Math.min( guards.length, - nodesNeededPerPaths - ? otherNodes.length / nodesNeededPerPaths - : otherNodes.length + nodesNeededPerPaths ? otherNodes.length / nodesNeededPerPaths : otherNodes.length ) ); diff --git a/ts/session/onions/onionSend.ts b/ts/session/onions/onionSend.ts index 5428456bd3204c3fe4a31da4477be3e5c57f4082..c765a59af7d4b756919108a8ba70dc50471742e2 100644 --- a/ts/session/onions/onionSend.ts +++ b/ts/session/onions/onionSend.ts @@ -49,9 +49,7 @@ const handleSendViaOnionRetry = async ( ); if (options.retry && options.retry >= MAX_SEND_ONION_RETRIES) { - window.log.error( - `sendViaOnion too many retries: ${options.retry}. Stopping retries.` - ); + window.log.error(`sendViaOnion too many retries: ${options.retry}. Stopping retries.`); return null; } else { // handle error/retries, this is a RequestError @@ -73,10 +71,7 @@ const handleSendViaOnionRetry = async ( ); }; -const buildSendViaOnionPayload = ( - url: URL, - fetchOptions: OnionFetchOptions -) => { +const buildSendViaOnionPayload = (url: URL, fetchOptions: OnionFetchOptions) => { let tempHeaders = fetchOptions.headers || {}; const payloadObj = { method: fetchOptions.method || 'GET', @@ -114,14 +109,10 @@ export const getOnionPathForSending = async (requestNumber: number) => { try { pathNodes = await OnionPaths.getInstance().getOnionPath(); } catch (e) { - window.log.error( - `sendViaOnion #${requestNumber} - getOnionPath Error ${e.code} ${e.message}` - ); + window.log.error(`sendViaOnion #${requestNumber} - getOnionPath Error ${e.code} ${e.message}`); } if (!pathNodes || !pathNodes.length) { - window.log.warn( - `sendViaOnion #${requestNumber} - failing, no path available` - ); + window.log.warn(`sendViaOnion #${requestNumber} - failing, no path available`); // should we retry? return null; } @@ -159,9 +150,7 @@ export const sendViaOnion = async ( const defaultedOptions = initOptionsWithDefaults(options); const payloadObj = buildSendViaOnionPayload(url, fetchOptions); - const pathNodes = await getOnionPathForSending( - defaultedOptions.requestNumber - ); + const pathNodes = await getOnionPathForSending(defaultedOptions.requestNumber); if (!pathNodes) { return null; } @@ -302,11 +291,7 @@ export const serverRequest = async ( fetchOptions.agent = snodeHttpsAgent; } } catch (e) { - window.log.error( - 'loki_app_dot_net:::serverRequest - set up error:', - e.code, - e.message - ); + window.log.error('loki_app_dot_net:::serverRequest - set up error:', e.code, e.message); return { err: e, ok: false, @@ -320,38 +305,21 @@ export const serverRequest = async ( try { const host = url.host.toLowerCase(); // log.info('host', host, FILESERVER_HOSTS); - if ( - window.lokiFeatureFlags.useFileOnionRequests && - FILESERVER_HOSTS.includes(host) - ) { + if (window.lokiFeatureFlags.useFileOnionRequests && FILESERVER_HOSTS.includes(host)) { mode = 'sendViaOnion'; if (!srvPubKey) { - throw new Error( - 'useFileOnionRequests=true but we do not have a server pubkey set.' - ); + throw new Error('useFileOnionRequests=true but we do not have a server pubkey set.'); } - const onionResponse = await sendViaOnion( - srvPubKey, - url, - fetchOptions, - options - ); + const onionResponse = await sendViaOnion(srvPubKey, url, fetchOptions, options); if (onionResponse) { ({ response, txtResponse, result } = onionResponse); } } else if (window.lokiFeatureFlags.useFileOnionRequests) { if (!srvPubKey) { - throw new Error( - 'useFileOnionRequests=true but we do not have a server pubkey set.' - ); + throw new Error('useFileOnionRequests=true but we do not have a server pubkey set.'); } mode = 'sendViaOnionOG'; - const onionResponse = await sendViaOnion( - srvPubKey, - url, - fetchOptions, - options - ); + const onionResponse = await sendViaOnion(srvPubKey, url, fetchOptions, options); if (onionResponse) { ({ response, txtResponse, result } = onionResponse); } diff --git a/ts/session/sending/MessageQueue.ts b/ts/session/sending/MessageQueue.ts index e79c1efaa81f190d0c36b205578bb10fff043581..ee418c49af59e1bff0104d2e53172880ffd4b412 100644 --- a/ts/session/sending/MessageQueue.ts +++ b/ts/session/sending/MessageQueue.ts @@ -44,10 +44,7 @@ export class MessageQueue { message: ContentMessage, sentCb?: (message: RawMessage) => Promise<void> ): Promise<void> { - if ( - message instanceof ConfigurationMessage || - !!(message as any).syncTarget - ) { + if (message instanceof ConfigurationMessage || !!(message as any).syncTarget) { throw new Error('SyncMessage needs to be sent with sendSyncMessage'); } await this.process(user, message, sentCb); @@ -77,10 +74,7 @@ export class MessageQueue { void MessageSentHandler.handlePublicMessageSentSuccess(message, result); } } catch (e) { - window?.log?.warn( - `Failed to send message to open group: ${message.group.server}`, - e - ); + window?.log?.warn(`Failed to send message to open group: ${message.group.server}`, e); void MessageSentHandler.handleMessageSentFailure(message, error); } } @@ -94,10 +88,7 @@ export class MessageQueue { sentCb?: (message: RawMessage) => Promise<void> ): Promise<void> { let groupId: PubKey | undefined; - if ( - message instanceof ExpirationTimerUpdateMessage || - message instanceof ClosedGroupMessage - ) { + if (message instanceof ExpirationTimerUpdateMessage || message instanceof ClosedGroupMessage) { groupId = message.groupId; } @@ -115,10 +106,7 @@ export class MessageQueue { if (!message) { return; } - if ( - !(message instanceof ConfigurationMessage) && - !(message as any)?.syncTarget - ) { + if (!(message instanceof ConfigurationMessage) && !(message as any)?.syncTarget) { throw new Error('Invalid message given to sendSyncMessage'); } @@ -139,14 +127,9 @@ export class MessageQueue { const job = async () => { try { const wrappedEnvelope = await MessageSender.send(message); - await MessageSentHandler.handleMessageSentSuccess( - message, - wrappedEnvelope - ); - - const cb = this.pendingMessageCache.callbacks.get( - message.identifier - ); + await MessageSentHandler.handleMessageSentSuccess(message, wrappedEnvelope); + + const cb = this.pendingMessageCache.callbacks.get(message.identifier); if (cb) { await cb(message); diff --git a/ts/session/sending/MessageSender.ts b/ts/session/sending/MessageSender.ts index 24c3807704f3c63e480770930947890cdc293ce7..36c2bdc6c5d5b7923ea5930b362103d1b8bdf579 100644 --- a/ts/session/sending/MessageSender.ts +++ b/ts/session/sending/MessageSender.ts @@ -40,12 +40,7 @@ export async function send( plainTextBuffer, encryption ); - const envelope = await buildEnvelope( - envelopeType, - device.key, - timestamp, - cipherText - ); + const envelope = await buildEnvelope(envelopeType, device.key, timestamp, cipherText); window?.log?.debug('Sending envelope', envelope, ' to ', device.key); const data = wrapEnvelope(envelope); diff --git a/ts/session/sending/MessageSentHandler.ts b/ts/session/sending/MessageSentHandler.ts index e7c7bb9200603a50c2888b4cf05d465aaf29f93f..b42290eed0d61c7bf599d64e9d943c49a2a778fe 100644 --- a/ts/session/sending/MessageSentHandler.ts +++ b/ts/session/sending/MessageSentHandler.ts @@ -15,9 +15,7 @@ export class MessageSentHandler { ) { const { serverId, serverTimestamp } = result; try { - const foundMessage = await MessageSentHandler.fetchHandleMessageSentData( - sentMessage - ); + const foundMessage = await MessageSentHandler.fetchHandleMessageSentData(sentMessage); if (!foundMessage) { throw new Error( @@ -47,9 +45,7 @@ export class MessageSentHandler { wrappedEnvelope?: Uint8Array ) { // The wrappedEnvelope will be set only if the message is not one of OpenGroupMessage type. - const fetchedMessage = await MessageSentHandler.fetchHandleMessageSentData( - sentMessage - ); + const fetchedMessage = await MessageSentHandler.fetchHandleMessageSentData(sentMessage); if (!fetchedMessage) { return; } @@ -63,8 +59,7 @@ export class MessageSentHandler { // FIXME this is not correct and will cause issues with syncing // At this point the only way to check for medium // group is by comparing the encryption type - const isClosedGroupMessage = - sentMessage.encryption === EncryptionType.ClosedGroup; + const isClosedGroupMessage = sentMessage.encryption === EncryptionType.ClosedGroup; // We trigger a sync message only when the message is not to one of our devices, AND // the message is not for an open group (there is no sync for opengroups, each device pulls all messages), AND @@ -77,12 +72,9 @@ export class MessageSentHandler { // A message is synced if we triggered a sync message (sentSync) // and the current message was sent to our device (so a sync message) - const shouldMarkMessageAsSynced = - isOurDevice && fetchedMessage.get('sentSync'); + const shouldMarkMessageAsSynced = isOurDevice && fetchedMessage.get('sentSync'); - const contentDecoded = SignalService.Content.decode( - sentMessage.plainTextBuffer - ); + const contentDecoded = SignalService.Content.decode(sentMessage.plainTextBuffer); const { dataMessage } = contentDecoded; /** @@ -92,8 +84,7 @@ export class MessageSentHandler { */ const hasBodyOrAttachments = Boolean( dataMessage && - (dataMessage.body || - (dataMessage.attachments && dataMessage.attachments.length)) + (dataMessage.body || (dataMessage.attachments && dataMessage.attachments.length)) ); const shouldNotifyPushServer = hasBodyOrAttachments && !isOurDevice; @@ -106,10 +97,7 @@ export class MessageSentHandler { window.LokiPushNotificationServer = new window.LokiPushNotificationServerApi(); } - window.LokiPushNotificationServer.notify( - wrappedEnvelope, - sentMessage.device - ); + window.LokiPushNotificationServer.notify(wrappedEnvelope, sentMessage.device); } } @@ -146,9 +134,7 @@ export class MessageSentHandler { sentMessage: RawMessage | OpenGroupMessage, error: any ) { - const fetchedMessage = await MessageSentHandler.fetchHandleMessageSentData( - sentMessage - ); + const fetchedMessage = await MessageSentHandler.fetchHandleMessageSentData(sentMessage); if (!fetchedMessage) { return; } @@ -190,9 +176,7 @@ export class MessageSentHandler { * In this case, this function will look for it in the database and return it. * If the message is found on the db, it will also register it to the MessageController so our subsequent calls are quicker. */ - private static async fetchHandleMessageSentData( - m: RawMessage | OpenGroupMessage - ) { + private static async fetchHandleMessageSentData(m: RawMessage | OpenGroupMessage) { // if a message was sent and this message was sent after the last app restart, // this message is still in memory in the MessageController const msg = MessageController.getInstance().get(m.identifier); diff --git a/ts/session/sending/PendingMessageCache.ts b/ts/session/sending/PendingMessageCache.ts index fd67424788a51a147bd84f0ef8cb0bc61f81b348..55e659ca921abf14546eab9e3c6281510e76dc1c 100644 --- a/ts/session/sending/PendingMessageCache.ts +++ b/ts/session/sending/PendingMessageCache.ts @@ -13,10 +13,7 @@ import { MessageUtils } from '../utils'; // memory and sync its state with the database on modification (add or remove). export class PendingMessageCache { - public callbacks: Map< - string, - (message: RawMessage) => Promise<void> - > = new Map(); + public callbacks: Map<string, (message: RawMessage) => Promise<void>> = new Map(); protected loadPromise: Promise<void> | undefined; protected cache: Array<RawMessage> = []; @@ -63,9 +60,7 @@ export class PendingMessageCache { return rawMessage; } - public async remove( - message: RawMessage - ): Promise<Array<RawMessage> | undefined> { + public async remove(message: RawMessage): Promise<Array<RawMessage> | undefined> { await this.loadFromDBIfNeeded(); // Should only be called after message is processed @@ -76,11 +71,7 @@ export class PendingMessageCache { // Remove item from cache and sync with database const updatedCache = this.cache.filter( - cached => - !( - cached.device === message.device && - cached.timestamp === message.timestamp - ) + cached => !(cached.device === message.device && cached.timestamp === message.timestamp) ); this.cache = updatedCache; this.callbacks.delete(message.identifier); @@ -91,9 +82,7 @@ export class PendingMessageCache { public find(message: RawMessage): RawMessage | undefined { // Find a message in the cache - return this.cache.find( - m => m.device === message.device && m.timestamp === message.timestamp - ); + return this.cache.find(m => m.device === message.device && m.timestamp === message.timestamp); } public async clear() { @@ -122,9 +111,7 @@ export class PendingMessageCache { return []; } - const barePending = JSON.parse(String(data.value)) as Array< - PartialRawMessage - >; + const barePending = JSON.parse(String(data.value)) as Array<PartialRawMessage>; // Rebuild plainTextBuffer return barePending.map((message: PartialRawMessage) => { diff --git a/ts/session/snode_api/onions.ts b/ts/session/snode_api/onions.ts index 7b3dd7c2c195ebf448085854c5350f3f9cafb79d..7d1f8125723a7db4decaa6b344c24bc3747749bf 100644 --- a/ts/session/snode_api/onions.ts +++ b/ts/session/snode_api/onions.ts @@ -26,10 +26,7 @@ export interface SnodeResponse { // Returns the actual ciphertext, symmetric key that will be used // for decryption, and an ephemeral_key to send to the next hop -async function encryptForPubKey( - pubKeyX25519hex: string, - reqObj: any -): Promise<DestinationContext> { +async function encryptForPubKey(pubKeyX25519hex: string, reqObj: any): Promise<DestinationContext> { const reqStr = JSON.stringify(reqObj); const textEncoder = new TextEncoder(); @@ -39,11 +36,7 @@ async function encryptForPubKey( } // `ctx` holds info used by `node` to relay further -async function encryptForRelay( - relayX25519hex: string, - destination: any, - ctx: any -) { +async function encryptForRelay(relayX25519hex: string, destination: any, ctx: any) { const { log, StringView } = window; // ctx contains: ciphertext, symmetricKey, ephemeralKey @@ -63,11 +56,7 @@ async function encryptForRelay( } // `ctx` holds info used by `node` to relay further -async function encryptForRelayV2( - relayX25519hex: string, - destination: any, - ctx: any -) { +async function encryptForRelayV2(relayX25519hex: string, destination: any, ctx: any) { const { log, StringView } = window; if (!destination.host && !destination.destination) { @@ -100,10 +89,7 @@ function makeGuardPayload(guardCtx: any): Uint8Array { } /// Encode ciphertext as (len || binary) and append payloadJson as utf8 -function encodeCiphertextPlusJson( - ciphertext: any, - payloadJson: any -): Uint8Array { +function encodeCiphertextPlusJson(ciphertext: any, payloadJson: any): Uint8Array { const payloadStr = JSON.stringify(payloadJson); const bufferJson = ByteBuffer.wrap(payloadStr, 'utf8'); @@ -197,18 +183,10 @@ async function buildOnionCtxs( try { const encryptFn = useV2 ? encryptForRelayV2 : encryptForRelay; // eslint-disable-next-line no-await-in-loop - const ctx = await encryptFn( - nodePath[i].pubkey_x25519, - dest, - ctxes[ctxes.length - 1] - ); + const ctx = await encryptFn(nodePath[i].pubkey_x25519, dest, ctxes[ctxes.length - 1]); ctxes.push(ctx); } catch (e) { - log.error( - `loki_rpc:::makeOnionRequest ${id} - encryptForRelay failure`, - e.code, - e.message - ); + log.error(`loki_rpc:::makeOnionRequest ${id} - encryptForRelay failure`, e.code, e.message); throw e; } } @@ -238,9 +216,7 @@ async function makeOnionRequest( const guardCtx = ctxes[ctxes.length - 1]; // last ctx - const payload = useV2 - ? makeGuardPayloadV2(guardCtx) - : makeGuardPayload(guardCtx); + const payload = useV2 ? makeGuardPayloadV2(guardCtx) : makeGuardPayload(guardCtx); // all these requests should use AesGcm return payload; @@ -271,7 +247,7 @@ const processOnionResponse = async ( return RequestError.BAD_PATH; } - + // detect SNode is not ready (not in swarm; not done syncing) if (response.status === 503) { log.warn(`(${reqIdx}) [path] Got 503: snode not ready`); @@ -306,10 +282,7 @@ const processOnionResponse = async ( return RequestError.OTHER; } if (debug) { - log.debug( - `(${reqIdx}) [path] lokiRpc::processOnionResponse - ciphertext`, - ciphertext - ); + log.debug(`(${reqIdx}) [path] lokiRpc::processOnionResponse - ciphertext`, ciphertext); } let plaintext; @@ -322,10 +295,7 @@ const processOnionResponse = async ( // just try to get a json object from what is inside (for PN requests), if it fails, continue () } try { - ciphertextBuffer = dcodeIO.ByteBuffer.wrap( - ciphertext, - 'base64' - ).toArrayBuffer(); + ciphertextBuffer = dcodeIO.ByteBuffer.wrap(ciphertext, 'base64').toArrayBuffer(); if (debug) { log.debug( @@ -334,23 +304,14 @@ const processOnionResponse = async ( ); } - const plaintextBuffer = await libloki.crypto.DecryptAESGCM( - sharedKey, - ciphertextBuffer - ); + const plaintextBuffer = await libloki.crypto.DecryptAESGCM(sharedKey, ciphertextBuffer); if (debug) { - log.debug( - 'lokiRpc::processOnionResponse - plaintextBuffer', - plaintextBuffer.toString() - ); + log.debug('lokiRpc::processOnionResponse - plaintextBuffer', plaintextBuffer.toString()); } plaintext = new TextDecoder().decode(plaintextBuffer); } catch (e) { - log.error( - `(${reqIdx}) [path] lokiRpc::processOnionResponse - decode error`, - e - ); + log.error(`(${reqIdx}) [path] lokiRpc::processOnionResponse - decode error`, e); log.error( `(${reqIdx}) [path] lokiRpc::processOnionResponse - symKey`, StringView.arrayBufferToHex(sharedKey) @@ -477,10 +438,7 @@ const sendOnionRequest = async ( const bodyEncoded = textEncoder.encode(body); const plaintext = encodeCiphertextPlusJson(bodyEncoded, options); - destCtx = await window.libloki.crypto.encryptForPubkey( - destX25519hex, - plaintext - ); + destCtx = await window.libloki.crypto.encryptForPubkey(destX25519hex, plaintext); } else { destCtx = await encryptForPubKey(destX25519hex, options); } @@ -524,13 +482,7 @@ const sendOnionRequest = async ( const response = await insecureNodeFetch(guardUrl, guardFetchOptions); - return processOnionResponse( - reqIdx, - response, - destCtx.symmetricKey, - false, - abortSignal - ); + return processOnionResponse(reqIdx, response, destCtx.symmetricKey, false, abortSignal); }; async function sendOnionRequestSnodeDest( @@ -595,18 +547,11 @@ export async function lokiOnionFetch( // At this point I only care about BAD_PATH // eslint-disable-next-line no-await-in-loop - const result = await sendOnionRequestSnodeDest( - thisIdx, - path, - targetNode, - body - ); + const result = await sendOnionRequestSnodeDest(thisIdx, path, targetNode, body); if (result === RequestError.BAD_PATH) { log.error( - `[path] Error on the path: ${getPathString(path)} to ${targetNode.ip}:${ - targetNode.port - }` + `[path] Error on the path: ${getPathString(path)} to ${targetNode.ip}:${targetNode.port}` ); OnionPaths.getInstance().markPathAsBad(path); return false; @@ -616,9 +561,9 @@ export async function lokiOnionFetch( // or can't decrypt // it's not a bad_path, so we don't need to mark the path as bad log.error( - `[path] sendOnionRequest gave false for path: ${getPathString( - path - )} to ${targetNode.ip}:${targetNode.port}` + `[path] sendOnionRequest gave false for path: ${getPathString(path)} to ${targetNode.ip}:${ + targetNode.port + }` ); return false; } else if (result === RequestError.ABORTED) { @@ -627,9 +572,9 @@ export async function lokiOnionFetch( // or can't decrypt // it's not a bad_path, so we don't need to mark the path as bad log.error( - `[path] sendOnionRequest gave aborted for path: ${getPathString( - path - )} to ${targetNode.ip}:${targetNode.port}` + `[path] sendOnionRequest gave aborted for path: ${getPathString(path)} to ${ + targetNode.ip + }:${targetNode.port}` ); return false; } else { diff --git a/ts/session/snode_api/serviceNodeAPI.ts b/ts/session/snode_api/serviceNodeAPI.ts index edb05bc6643fbb140ffd0acb81ebc3553c268e4d..1eaad91319739a325dcaf6cea5ad3459ab44dca2 100644 --- a/ts/session/snode_api/serviceNodeAPI.ts +++ b/ts/session/snode_api/serviceNodeAPI.ts @@ -11,44 +11,29 @@ import Electron from 'electron'; const { remote } = Electron; import { snodeRpc } from './lokiRpc'; -import { - sendOnionRequestLsrpcDest, - snodeHttpsAgent, - SnodeResponse, -} from './onions'; +import { sendOnionRequestLsrpcDest, snodeHttpsAgent, SnodeResponse } from './onions'; import { sleepFor } from '../../../js/modules/loki_primitives'; export { sendOnionRequestLsrpcDest }; -import { - getRandomSnodeAddress, - markNodeUnreachable, - Snode, - updateSnodesFor, -} from './snodePool'; +import { getRandomSnodeAddress, markNodeUnreachable, Snode, updateSnodesFor } from './snodePool'; import { Constants } from '..'; /** * Currently unused. If we need it again, be sure to update it to onion routing rather * than using a plain nodeFetch */ -export async function getVersion( - node: Snode, - retries: number = 0 -): Promise<string | boolean> { +export async function getVersion(node: Snode, retries: number = 0): Promise<string | boolean> { const SNODE_VERSION_RETRIES = 3; const { log } = window; try { window.log.warn('insecureNodeFetch => plaintext for getVersion'); - const result = await insecureNodeFetch( - `https://${node.ip}:${node.port}/get_stats/v1`, - { - agent: snodeHttpsAgent, - } - ); + const result = await insecureNodeFetch(`https://${node.ip}:${node.port}/get_stats/v1`, { + agent: snodeHttpsAgent, + }); const data = await result.json(); if (data.version) { return data.version; @@ -63,9 +48,7 @@ export async function getVersion( if (e.code === 'ECONNREFUSED') { markNodeUnreachable(node); // clean up these error messages to be a little neater - log.warn( - `LokiSnodeAPI::_getVersion - ${node.ip}:${node.port} is offline, removing` - ); + log.warn(`LokiSnodeAPI::_getVersion - ${node.ip}:${node.port} is offline, removing`); // if not ECONNREFUSED, it's mostly ECONNRESETs // ENOTFOUND could mean no internet or hiccup } else if (retries < SNODE_VERSION_RETRIES) { @@ -79,9 +62,7 @@ export async function getVersion( return getVersion(node, retries + 1); } else { markNodeUnreachable(node); - log.warn( - `LokiSnodeAPI::_getVersion - failing to get version for ${node.ip}:${node.port}` - ); + log.warn(`LokiSnodeAPI::_getVersion - failing to get version for ${node.ip}:${node.port}`); } // maybe throw? return false; @@ -131,10 +112,7 @@ const getSslAgentForSeedNode = (seedNodeHost: string, isSsl = false) => { // tslint:disable: non-literal-fs-path // read the cert each time. We only run this request once for each seed node nevertheless. const appPath = remote.app.getAppPath(); - const crt = fs.readFileSync( - path.join(appPath, `/certificates/${filePrefix}.crt`), - 'utf-8' - ); + const crt = fs.readFileSync(path.join(appPath, `/certificates/${filePrefix}.crt`), 'utf-8'); // debugger; const sslOptions = { // as the seed nodes are using a self signed certificate, we have to provide it here. @@ -247,9 +225,7 @@ export async function getSnodesFromSeedUrl(urlObj: URL): Promise<Array<any>> { return []; } // Filter 0.0.0.0 nodes which haven't submitted uptime proofs - return result.service_node_states.filter( - (snode: any) => snode.public_ip !== '0.0.0.0' - ); + return result.service_node_states.filter((snode: any) => snode.public_ip !== '0.0.0.0'); } catch (e) { log.error('Invalid json response'); return []; @@ -265,9 +241,7 @@ interface SendParams { } // get snodes for pubkey from random snode. Uses an existing snode -export async function requestSnodesForPubkey( - pubKey: string -): Promise<Array<Snode>> { +export async function requestSnodesForPubkey(pubKey: string): Promise<Array<Snode>> { const { log } = window; let snode; @@ -308,20 +282,14 @@ export async function requestSnodesForPubkey( return []; } - const snodes = json.snodes.filter( - (tSnode: any) => tSnode.ip !== '0.0.0.0' - ); + const snodes = json.snodes.filter((tSnode: any) => tSnode.ip !== '0.0.0.0'); return snodes; } catch (e) { log.warn('Invalid json'); return []; } } catch (e) { - log.error( - 'LokiSnodeAPI::requestSnodesForPubkey - error', - e.code, - e.message - ); + log.error('LokiSnodeAPI::requestSnodesForPubkey - error', e.code, e.message); if (snode) { markNodeUnreachable(snode); @@ -374,10 +342,7 @@ function checkResponse(response: SnodeResponse): void { } } -export async function storeOnNode( - targetNode: Snode, - params: SendParams -): Promise<boolean> { +export async function storeOnNode(targetNode: Snode, params: SendParams): Promise<boolean> { const { log, textsecure } = window; let successiveFailures = 0; @@ -418,11 +383,7 @@ export async function storeOnNode( const json = JSON.parse(snodeRes.body); // Make sure we aren't doing too much PoW const currentDifficulty = window.storage.get('PoWDifficulty', null); - if ( - json && - json.difficulty && - json.difficulty !== parseInt(currentDifficulty, 10) - ) { + if (json && json.difficulty && json.difficulty !== parseInt(currentDifficulty, 10)) { window.storage.put('PoWDifficulty', json.difficulty); } return true; @@ -441,9 +402,7 @@ export async function storeOnNode( const { newDifficulty } = e; // difficulty of 100 happens when a snode restarts. We have to exit the loop and markNodeUnreachable() if (newDifficulty === 100) { - log.warn( - 'loki_message:::storeOnNode - invalid new difficulty:100. Marking node as bad.' - ); + log.warn('loki_message:::storeOnNode - invalid new difficulty:100. Marking node as bad.'); successiveFailures = MAX_ACCEPTABLE_FAILURES; continue; } @@ -499,11 +458,7 @@ export async function retrieveNextMessages( try { checkResponse(res); } catch (e) { - window.log.warn( - 'loki_message:::retrieveNextMessages - send error:', - e.code, - e.message - ); + window.log.warn('loki_message:::retrieveNextMessages - send error:', e.code, e.message); if (e instanceof window.textsecure.WrongSwarmError) { const { newSwarm } = e; await updateSnodesFor(params.pubKey, newSwarm); diff --git a/ts/session/snode_api/snodePool.ts b/ts/session/snode_api/snodePool.ts index df97229660156349e8bf9585f9680d71bf0a7ba8..ca3c459d470b88a62d526e797e6c5e691b4f3401 100644 --- a/ts/session/snode_api/snodePool.ts +++ b/ts/session/snode_api/snodePool.ts @@ -5,10 +5,7 @@ import { abortableIterator } from '../../../js/modules/loki_primitives'; import { getSnodesFromSeedUrl, requestSnodesForPubkey } from './serviceNodeAPI'; -import { - getSwarmNodesForPubkey, - updateSwarmNodesForPubkey, -} from '../../../ts/data/data'; +import { getSwarmNodesForPubkey, updateSwarmNodesForPubkey } from '../../../ts/data/data'; export type SnodeEdKey = string; import { allowOnlyOneAtATime } from '../utils/Promise'; @@ -37,9 +34,7 @@ async function tryGetSnodeListFromLokidSeednode( const { log } = window; if (!seedNodes.length) { - log.info( - 'loki_snode_api::tryGetSnodeListFromLokidSeednode - seedNodes are empty' - ); + log.info('loki_snode_api::tryGetSnodeListFromLokidSeednode - seedNodes are empty'); return []; } @@ -70,9 +65,7 @@ async function tryGetSnodeListFromLokidSeednode( `loki_snode_api::tryGetSnodeListFromLokidSeednode - ${seedNode.ip_url} did not return any snodes` ); // does this error message need to be exactly this? - throw new window.textsecure.SeedNodeError( - 'Failed to contact seed node' - ); + throw new window.textsecure.SeedNodeError('Failed to contact seed node'); } } if (snodes.length) { @@ -150,16 +143,12 @@ async function requestVersion(node: any): Promise<void> { const version = result as string; - const foundNodeIdx = randomSnodePool.findIndex((n: any) => - compareSnodes(n, node) - ); + const foundNodeIdx = randomSnodePool.findIndex((n: any) => compareSnodes(n, node)); if (foundNodeIdx !== -1) { randomSnodePool[foundNodeIdx].version = version; } else { // maybe already marked bad... - log.debug( - `LokiSnodeAPI::_getVersion - can't find ${node.ip}:${node.port} in randomSnodePool` - ); + log.debug(`LokiSnodeAPI::_getVersion - can't find ${node.ip}:${node.port} in randomSnodePool`); } } @@ -172,9 +161,7 @@ export async function getRandomSnodePool(): Promise<Array<Snode>> { // not cacheable because we write to this.randomSnodePool elsewhere export function getNodesMinVersion(minVersion: string): Array<Snode> { - return randomSnodePool.filter( - (node: any) => node.version && semver.gt(node.version, minVersion) - ); + return randomSnodePool.filter((node: any) => node.version && semver.gt(node.version, minVersion)); } /** @@ -195,11 +182,7 @@ export async function getAllVersionsForRandomSnodePool(): Promise<void> { try { await requestVersion(node); } catch (e) { - log.error( - 'LokiSnodeAPI::_getAllVersionsForRandomSnodePool - error', - e.code, - e.message - ); + log.error('LokiSnodeAPI::_getAllVersionsForRandomSnodePool - error', e.code, e.message); throw e; } }); @@ -229,20 +212,14 @@ async function getSnodeListFromLokidSeednode( const { log } = window; if (!seedNodes.length) { - log.info( - 'loki_snode_api::getSnodeListFromLokidSeednode - seedNodes are empty' - ); + log.info('loki_snode_api::getSnodeListFromLokidSeednode - seedNodes are empty'); return []; } let snodes: Array<Snode> = []; try { snodes = await tryGetSnodeListFromLokidSeednode(seedNodes); } catch (e) { - log.warn( - 'loki_snode_api::getSnodeListFromLokidSeednode - error', - e.code, - e.message - ); + log.warn('loki_snode_api::getSnodeListFromLokidSeednode - error', e.code, e.message); // handle retries in case of temporary hiccups if (retries < SEED_NODE_RETRIES) { setTimeout(() => { @@ -310,9 +287,7 @@ export async function refreshRandomPool(seedNodes?: Array<any>): Promise<void> { if (!seedNodes || !seedNodes.length) { if (!window.seedNodeList || !window.seedNodeList.length) { - log.error( - 'LokiSnodeAPI:::refreshRandomPool - seedNodeList has not been loaded yet' - ); + log.error('LokiSnodeAPI:::refreshRandomPool - seedNodeList has not been loaded yet'); return; } // tslint:disable-next-line:no-parameter-reassignment @@ -326,10 +301,7 @@ export async function refreshRandomPool(seedNodes?: Array<any>): Promise<void> { }); } -export async function updateSnodesFor( - pubkey: string, - snodes: Array<Snode> -): Promise<void> { +export async function updateSnodesFor(pubkey: string, snodes: Array<Snode>): Promise<void> { const edkeys = snodes.map((sn: Snode) => sn.pubkey_ed25519); await internalUpdateSnodesFor(pubkey, edkeys); } @@ -353,9 +325,7 @@ export async function getSnodesFor(pubkey: string): Promise<Array<Snode>> { } // See how many are actually still reachable - const goodNodes = randomSnodePool.filter( - (n: Snode) => nodes.indexOf(n.pubkey_ed25519) !== -1 - ); + const goodNodes = randomSnodePool.filter((n: Snode) => nodes.indexOf(n.pubkey_ed25519) !== -1); if (goodNodes.length < MIN_NODES) { // Request new node list from the network diff --git a/ts/session/snode_api/swarmPolling.ts b/ts/session/snode_api/swarmPolling.ts index e65e2bca713517bbf30417fa04540b4bf37258c4..8a798a4b6e641ac26307c328f5cc92d0eb70e487 100644 --- a/ts/session/snode_api/swarmPolling.ts +++ b/ts/session/snode_api/swarmPolling.ts @@ -72,10 +72,7 @@ export class SwarmPolling { public removePubkey(pk: PubKey | string) { const pubkey = PubKey.cast(pk); - window.log.info( - 'Swarm removePubkey: removing pubkey from polling', - pubkey.key - ); + window.log.info('Swarm removePubkey: removing pubkey from polling', pubkey.key); this.pubkeys = this.pubkeys.filter(key => !pubkey.isEqual(key)); this.groupPubkeys = this.groupPubkeys.filter(key => !pubkey.isEqual(key)); @@ -89,9 +86,7 @@ export class SwarmPolling { const snodes = await getSnodesFor(pkStr); // Select nodes for which we already have lastHashes - const alreadyPolled = snodes.filter( - (n: Snode) => this.lastHashes[n.pubkey_ed25519] - ); + const alreadyPolled = snodes.filter((n: Snode) => this.lastHashes[n.pubkey_ed25519]); // If we need more nodes, select randomly from the remaining nodes: @@ -129,10 +124,7 @@ export class SwarmPolling { // Fetches messages for `pubkey` from `node` potentially updating // the lash hash record - protected async pollNodeForKey( - node: Snode, - pubkey: PubKey - ): Promise<Array<any>> { + protected async pollNodeForKey(node: Snode, pubkey: PubKey): Promise<Array<any>> { const edkey = node.pubkey_ed25519; const pkStr = pubkey.key; @@ -147,12 +139,7 @@ export class SwarmPolling { const lastMessage = _.last(messages); - await this.updateLastHash( - edkey, - pubkey, - lastMessage.hash, - lastMessage.expiration - ); + await this.updateLastHash(edkey, pubkey, lastMessage.hash, lastMessage.expiration); return messages; } @@ -163,10 +150,7 @@ export class SwarmPolling { const mediumGroupsOnly = convos.filter( (c: ConversationModel) => - c.isMediumGroup() && - !c.isBlocked() && - !c.get('isKickedFromGroup') && - !c.get('left') + c.isMediumGroup() && !c.isBlocked() && !c.get('isKickedFromGroup') && !c.get('left') ); mediumGroupsOnly.forEach((c: any) => { @@ -175,9 +159,7 @@ export class SwarmPolling { }); } - private async handleSeenMessages( - messages: Array<Message> - ): Promise<Array<Message>> { + private async handleSeenMessages(messages: Array<Message>): Promise<Array<Message>> { if (!messages.length) { return []; } @@ -185,9 +167,7 @@ export class SwarmPolling { const incomingHashes = messages.map((m: Message) => m.hash); const dupHashes = await getSeenMessagesByHashList(incomingHashes); - const newMessages = messages.filter( - (m: Message) => !dupHashes.includes(m.hash) - ); + const newMessages = messages.filter((m: Message) => !dupHashes.includes(m.hash)); if (newMessages.length) { const newHashes = newMessages.map((m: Message) => ({ @@ -242,10 +222,7 @@ export class SwarmPolling { this.lastHashes[edkey][pkStr] = hash; } - private async getLastHash( - nodeEdKey: string, - pubkey: string - ): Promise<string> { + private async getLastHash(nodeEdKey: string, pubkey: string): Promise<string> { // TODO: always retrieve from the database? const nodeRecords = this.lastHashes[nodeEdKey]; diff --git a/ts/session/snode_api/swarmPollingStub.ts b/ts/session/snode_api/swarmPollingStub.ts index ae55a0c8bc1642e79972c68e5b1417a3f1638965..c05ab8c48acb21ecfeb55a7bd63c5e7853c66313 100644 --- a/ts/session/snode_api/swarmPollingStub.ts +++ b/ts/session/snode_api/swarmPollingStub.ts @@ -13,10 +13,7 @@ export class SwarmPollingStub extends SwarmPolling { }; // insecureNodeFetch but this is a stub - const res = await insecureNodeFetch( - `${this.baseUrl}/messages?pubkey=${pubkeyStr}`, - get - ); + const res = await insecureNodeFetch(`${this.baseUrl}/messages?pubkey=${pubkeyStr}`, get); try { const json = await res.json(); diff --git a/ts/session/types/PubKey.ts b/ts/session/types/PubKey.ts index 7d62c6c429a53b84c772d0fccfd3ca4014364514..49f4ac3b6afa965899a9ebdd017f22a8c931d104 100644 --- a/ts/session/types/PubKey.ts +++ b/ts/session/types/PubKey.ts @@ -60,9 +60,7 @@ export class PubKey { const pk = value instanceof PubKey ? valAny.key : value; if (!pk) { - throw new Error( - 'PubkKey.shorten was given an invalid PubKey to shorten.' - ); + throw new Error('PubkKey.shorten was given an invalid PubKey to shorten.'); } return `(...${pk.substring(pk.length - 6)})`; @@ -125,10 +123,7 @@ export class PubKey { * @param keyWithOrWithoutPrefix the key with or without the prefix */ public static remove05PrefixIfNeeded(keyWithOrWithoutPrefix: string): string { - if ( - keyWithOrWithoutPrefix.length === 66 && - keyWithOrWithoutPrefix.startsWith('05') - ) { + if (keyWithOrWithoutPrefix.length === 66 && keyWithOrWithoutPrefix.startsWith('05')) { return keyWithOrWithoutPrefix.substr(2); } return keyWithOrWithoutPrefix; @@ -138,9 +133,7 @@ export class PubKey { * This adds the `__textsecure_group__!` prefix to a pubkey if this pubkey does not already have it * @param keyWithOrWithoutPrefix the key to use as base */ - public static addTextSecurePrefixIfNeeded( - keyWithOrWithoutPrefix: string | PubKey - ): string { + public static addTextSecurePrefixIfNeeded(keyWithOrWithoutPrefix: string | PubKey): string { const key = keyWithOrWithoutPrefix instanceof PubKey ? keyWithOrWithoutPrefix.key @@ -155,9 +148,7 @@ export class PubKey { * This removes the `__textsecure_group__!` prefix from a pubkey if this pubkey have one * @param keyWithOrWithoutPrefix the key to use as base */ - public static removeTextSecurePrefixIfNeeded( - keyWithOrWithoutPrefix: string | PubKey - ): string { + public static removeTextSecurePrefixIfNeeded(keyWithOrWithoutPrefix: string | PubKey): string { const key = keyWithOrWithoutPrefix instanceof PubKey ? keyWithOrWithoutPrefix.key diff --git a/ts/session/utils/Attachments.ts b/ts/session/utils/Attachments.ts index 9423320089c772611c444d7349b19f8f17818574..d7504198a1ade67047abfe9f632283f56ae3399f 100644 --- a/ts/session/utils/Attachments.ts +++ b/ts/session/utils/Attachments.ts @@ -48,13 +48,7 @@ export class AttachmentUtils { } public static async upload(params: UploadParams): Promise<AttachmentPointer> { - const { - attachment, - openGroup, - isAvatar = false, - isRaw = false, - shouldPad = false, - } = params; + const { attachment, openGroup, isAvatar = false, isRaw = false, shouldPad = false } = params; if (typeof attachment !== 'object' || attachment == null) { throw new Error('Invalid attachment passed.'); } @@ -67,13 +61,9 @@ export class AttachmentUtils { let server = this.getDefaultServer(); if (openGroup) { - const openGroupServer = await window.lokiPublicChatAPI.findOrCreateServer( - openGroup.server - ); + const openGroupServer = await window.lokiPublicChatAPI.findOrCreateServer(openGroup.server); if (!openGroupServer) { - throw new Error( - `Failed to get open group server: ${openGroup.server}.` - ); + throw new Error(`Failed to get open group server: ${openGroup.server}.`); } server = openGroupServer; } @@ -221,12 +211,7 @@ export class AttachmentUtils { const paddedSize = Math.max( 541, - Math.floor( - Math.pow( - 1.05, - Math.ceil(Math.log(originalUInt.length) / Math.log(1.05)) - ) - ) + Math.floor(Math.pow(1.05, Math.ceil(Math.log(originalUInt.length) / Math.log(1.05)))) ); const paddedData = new ArrayBuffer(paddedSize); const paddedUInt = new Uint8Array(paddedData); diff --git a/ts/session/utils/Groups.ts b/ts/session/utils/Groups.ts index 27f535300492c2eb23140b5308eea42a43b34521..3922351da9f3894cf609818761c0b157f9e661b2 100644 --- a/ts/session/utils/Groups.ts +++ b/ts/session/utils/Groups.ts @@ -4,12 +4,8 @@ import { ConversationController } from '../conversations'; import { fromHexToArray } from './String'; export async function getGroupMembers(groupId: PubKey): Promise<Array<PubKey>> { - const groupConversation = ConversationController.getInstance().get( - groupId.key - ); - const groupMembers = groupConversation - ? groupConversation.get('members') - : undefined; + const groupConversation = ConversationController.getInstance().get(groupId.key); + const groupMembers = groupConversation ? groupConversation.get('members') : undefined; if (!groupMembers) { return []; diff --git a/ts/session/utils/JobQueue.ts b/ts/session/utils/JobQueue.ts index b774e25dbfb905d02f99a3a670d3d0382c8a0875..6ac05223a47007150d11015d2727e0e93b01a550 100644 --- a/ts/session/utils/JobQueue.ts +++ b/ts/session/utils/JobQueue.ts @@ -17,10 +17,7 @@ export class JobQueue { return this.addWithId(id, job); } - public async addWithId<Result>( - id: string, - job: Job<Result> - ): Promise<Result> { + public async addWithId<Result>(id: string, job: Job<Result>): Promise<Result> { if (this.jobs.has(id)) { return this.jobs.get(id) as Promise<Result>; } diff --git a/ts/session/utils/Messages.ts b/ts/session/utils/Messages.ts index a68969e82c7a2c58ab3e210e9cb3f3d010653ea7..89d774828b86bd5a642ef42abfc325a68c713ce2 100644 --- a/ts/session/utils/Messages.ts +++ b/ts/session/utils/Messages.ts @@ -8,9 +8,7 @@ import { ClosedGroupEncryptionPairReplyMessage } from '../messages/outgoing/cont import { ContentMessage } from '../messages/outgoing'; import { ExpirationTimerUpdateMessage } from '../messages/outgoing/controlMessage/ExpirationTimerUpdateMessage'; -function getEncryptionTypeFromMessageType( - message: ContentMessage -): EncryptionType { +function getEncryptionTypeFromMessageType(message: ContentMessage): EncryptionType { // ClosedGroupNewMessage is sent using established channels, so using fallback if ( message instanceof ClosedGroupNewMessage || @@ -31,10 +29,7 @@ function getEncryptionTypeFromMessageType( } } -export async function toRawMessage( - device: PubKey, - message: ContentMessage -): Promise<RawMessage> { +export async function toRawMessage(device: PubKey, message: ContentMessage): Promise<RawMessage> { const timestamp = message.timestamp; const ttl = message.ttl(); // window?.log?.debug('toRawMessage proto:', message.contentProto()); diff --git a/ts/session/utils/Promise.ts b/ts/session/utils/Promise.ts index 00b598c5290356873c1f44f14ce703d97df571dd..ea3214748e27c3a6c391f515ede9025ab78bac7b 100644 --- a/ts/session/utils/Promise.ts +++ b/ts/session/utils/Promise.ts @@ -15,11 +15,7 @@ export class TaskTimedOutError extends Error { // one action resolves all const snodeGlobalLocks: any = {}; -export async function allowOnlyOneAtATime( - name: string, - process: any, - timeoutMs?: number -) { +export async function allowOnlyOneAtATime(name: string, process: any, timeoutMs?: number) { // if currently not in progress if (snodeGlobalLocks[name] === undefined) { // set lock @@ -28,9 +24,7 @@ export async function allowOnlyOneAtATime( let timeoutTimer = null; if (timeoutMs) { timeoutTimer = setTimeout(() => { - window.log.warn( - `loki_primitives:::allowOnlyOneAtATime - TIMEDOUT after ${timeoutMs}s` - ); + window.log.warn(`loki_primitives:::allowOnlyOneAtATime - TIMEDOUT after ${timeoutMs}s`); // tslint:disable-next-line: no-dynamic-delete delete snodeGlobalLocks[name]; // clear lock reject(); @@ -42,13 +36,9 @@ export async function allowOnlyOneAtATime( innerRetVal = await process(); } catch (e) { if (typeof e === 'string') { - window.log.error( - `loki_primitives:::allowOnlyOneAtATime - error ${e}` - ); + window.log.error(`loki_primitives:::allowOnlyOneAtATime - error ${e}`); } else { - window.log.error( - `loki_primitives:::allowOnlyOneAtATime - error ${e.code} ${e.message}` - ); + window.log.error(`loki_primitives:::allowOnlyOneAtATime - error ${e.code} ${e.message}`); } // clear timeout timer @@ -172,10 +162,7 @@ export async function poll( * @param check The boolean check. * @param timeout The time before an error is thrown. */ -export async function waitUntil( - check: () => Return<boolean>, - timeoutMs: number = 2000 -) { +export async function waitUntil(check: () => Return<boolean>, timeoutMs: number = 2000) { // This is causing unhandled promise rejection somewhere in MessageQueue tests return poll( async done => { @@ -191,10 +178,7 @@ export async function waitUntil( ); } -export async function timeout<T>( - promise: Promise<T>, - timeoutMs: number = 2000 -): Promise<T> { +export async function timeout<T>(promise: Promise<T>, timeoutMs: number = 2000): Promise<T> { const timeoutPromise = new Promise<T>((_, rej) => { const wait = setTimeout(() => { clearTimeout(wait); diff --git a/ts/session/utils/Protobuf.ts b/ts/session/utils/Protobuf.ts index 5a7470b2f4b5115d3ee5691c81178a88a2ce0520..a800ee2dd49e60d627c20642025e0dc8670282bb 100644 --- a/ts/session/utils/Protobuf.ts +++ b/ts/session/utils/Protobuf.ts @@ -10,11 +10,7 @@ export function convertToTS(object: any): any { // No idea why js `ByteBuffer` and ts `ByteBuffer` differ ... if (object instanceof Uint8Array) { return object; - } else if ( - object && - object.constructor && - object.constructor.name === 'ByteBuffer' - ) { + } else if (object && object.constructor && object.constructor.name === 'ByteBuffer') { return new Uint8Array(object.toArrayBuffer()); } else if ( object instanceof ByteBuffer || diff --git a/ts/session/utils/String.ts b/ts/session/utils/String.ts index 9b8b30140c8918d5573c60d813392ea52e2567e4..7745921cde87276beaefddb0728383034de03aab 100644 --- a/ts/session/utils/String.ts +++ b/ts/session/utils/String.ts @@ -36,8 +36,7 @@ export const fromHex = (d: string) => encode(d, 'hex'); export const fromHexToArray = (d: string) => new Uint8Array(encode(d, 'hex')); export const fromBase64ToArrayBuffer = (d: string) => encode(d, 'base64'); -export const fromBase64ToArray = (d: string) => - new Uint8Array(encode(d, 'base64')); +export const fromBase64ToArray = (d: string) => new Uint8Array(encode(d, 'base64')); export const fromArrayBufferToBase64 = (d: BufferType) => decode(d, 'base64'); export const fromUInt8ArrayToBase64 = (d: Uint8Array) => decode(d, 'base64'); diff --git a/ts/session/utils/Toast.tsx b/ts/session/utils/Toast.tsx index 2a93e097076c69ce7076c9391a742efc80cba402..15f616fb1c28d166e9591bc34ce984481c0638c6 100644 --- a/ts/session/utils/Toast.tsx +++ b/ts/session/utils/Toast.tsx @@ -1,37 +1,18 @@ import React from 'react'; import { toast } from 'react-toastify'; import { SessionIconType } from '../../components/session/icon'; -import { - SessionToast, - SessionToastType, -} from '../../components/session/SessionToast'; +import { SessionToast, SessionToastType } from '../../components/session/SessionToast'; // if you push a toast manually with toast...() be sure to set the type attribute of the SessionToast component -export function pushToastError( - id: string, - title: string, - description?: string -) { +export function pushToastError(id: string, title: string, description?: string) { toast.error( - <SessionToast - title={title} - description={description} - type={SessionToastType.Error} - /> + <SessionToast title={title} description={description} type={SessionToastType.Error} /> ); } -export function pushToastWarning( - id: string, - title: string, - description?: string -) { +export function pushToastWarning(id: string, title: string, description?: string) { toast.warning( - <SessionToast - title={title} - description={description} - type={SessionToastType.Warning} - /> + <SessionToast title={title} description={description} type={SessionToastType.Warning} /> ); } @@ -69,15 +50,9 @@ export function pushToastSuccess( export function pushLoadAttachmentFailure(message?: string) { if (message) { - pushToastError( - 'unableToLoadAttachment', - `${window.i18n('unableToLoadAttachment')} ${message}` - ); + pushToastError('unableToLoadAttachment', `${window.i18n('unableToLoadAttachment')} ${message}`); } else { - pushToastError( - 'unableToLoadAttachment', - window.i18n('unableToLoadAttachment') - ); + pushToastError('unableToLoadAttachment', window.i18n('unableToLoadAttachment')); } } @@ -86,11 +61,7 @@ export function pushDangerousFileError() { } export function pushFileSizeError(limit: number, units: string) { - pushToastError( - 'fileSizeWarning', - window.i18n('fileSizeWarning'), - `Max size: ${limit} ${units}` - ); + pushToastError('fileSizeWarning', window.i18n('fileSizeWarning'), `Max size: ${limit} ${units}`); } export function pushFileSizeErrorAsByte(bytesCount: number) { @@ -112,10 +83,7 @@ export function pushMultipleNonImageError() { } export function pushCannotMixError() { - pushToastError( - 'oneNonImageAtATimeToast', - window.i18n('oneNonImageAtATimeToast') - ); + pushToastError('oneNonImageAtATimeToast', window.i18n('oneNonImageAtATimeToast')); } export function pushMaximumAttachmentsError() { @@ -151,10 +119,7 @@ export function pushUserBanFailure() { } export function pushMessageDeleteForbidden() { - pushToastError( - 'messageDeletionForbidden', - window.i18n('messageDeletionForbidden') - ); + pushToastError('messageDeletionForbidden', window.i18n('messageDeletionForbidden')); } export function pushAudioPermissionNeeded(onClicked: () => void) { @@ -167,24 +132,15 @@ export function pushAudioPermissionNeeded(onClicked: () => void) { } export function pushOriginalNotFound() { - pushToastError( - 'originalMessageNotFound', - window.i18n('originalMessageNotFound') - ); + pushToastError('originalMessageNotFound', window.i18n('originalMessageNotFound')); } export function pushOriginalNoLongerAvailable() { - pushToastError( - 'originalMessageNotAvailable', - window.i18n('originalMessageNotAvailable') - ); + pushToastError('originalMessageNotAvailable', window.i18n('originalMessageNotAvailable')); } export function pushFoundButNotLoaded() { - pushToastError( - 'messageFoundButNotLoaded', - window.i18n('messageFoundButNotLoaded') - ); + pushToastError('messageFoundButNotLoaded', window.i18n('messageFoundButNotLoaded')); } export function pushTooManyMembers() { @@ -208,12 +164,7 @@ export function pushYouLeftTheGroup() { } export function pushDeleted() { - pushToastSuccess( - 'deleted', - window.i18n('deleted'), - undefined, - SessionIconType.Check - ); + pushToastSuccess('deleted', window.i18n('deleted'), undefined, SessionIconType.Check); } export function pushCannotRemoveCreatorFromGroup() { @@ -233,17 +184,11 @@ export function pushUserNeedsToHaveJoined() { } export function pushUserAddedToModerators() { - pushToastSuccess( - 'userAddedToModerators', - window.i18n('userAddedToModerators') - ); + pushToastSuccess('userAddedToModerators', window.i18n('userAddedToModerators')); } export function pushUserRemovedToModerators() { - pushToastSuccess( - 'userRemovedFromModerators', - window.i18n('userRemovedFromModerators') - ); + pushToastSuccess('userRemovedFromModerators', window.i18n('userRemovedFromModerators')); } export function pushInvalidPubKey() { diff --git a/ts/session/utils/TypedEmitter.ts b/ts/session/utils/TypedEmitter.ts index ec66bfdfdbcb8c90ac48935a82ff04b5f37a9ed2..a834ff6c647765c8f698cc5835a495a5e7e483d6 100644 --- a/ts/session/utils/TypedEmitter.ts +++ b/ts/session/utils/TypedEmitter.ts @@ -1,10 +1,6 @@ // Code from https://github.com/andywer/typed-emitter -type Arguments<T> = [T] extends [(...args: infer U) => any] - ? U - : [T] extends [void] - ? [] - : [T]; +type Arguments<T> = [T] extends [(...args: infer U) => any] ? U : [T] extends [void] ? [] : [T]; /** * Type-safe event emitter. @@ -33,19 +29,13 @@ export interface TypedEventEmitter<Events> { on<E extends keyof Events>(event: E, listener: Events[E]): this; once<E extends keyof Events>(event: E, listener: Events[E]): this; prependListener<E extends keyof Events>(event: E, listener: Events[E]): this; - prependOnceListener<E extends keyof Events>( - event: E, - listener: Events[E] - ): this; + prependOnceListener<E extends keyof Events>(event: E, listener: Events[E]): this; off<E extends keyof Events>(event: E, listener: Events[E]): this; removeAllListeners<E extends keyof Events>(event?: E): this; removeListener<E extends keyof Events>(event: E, listener: Events[E]): this; - emit<E extends keyof Events>( - event: E, - ...args: Arguments<Events[E]> - ): boolean; + emit<E extends keyof Events>(event: E, ...args: Arguments<Events[E]>): boolean; eventNames(): Array<keyof Events | string | symbol>; listeners<E extends keyof Events>(event: E): Array<Function>; listenerCount<E extends keyof Events>(event: E): number; diff --git a/ts/session/utils/User.ts b/ts/session/utils/User.ts index fdef310202d537fb32b37613856d19dde57b540a..595e521d559f2292edeed076ea6971f191cd4778 100644 --- a/ts/session/utils/User.ts +++ b/ts/session/utils/User.ts @@ -111,9 +111,7 @@ export function getLastProfileUpdateTimestamp(): number | undefined { } export function setLastProfileUpdateTimestamp(lastUpdateTimestamp: number) { - return window.textsecure.storage.user.setLastProfileUpdateTimestamp( - lastUpdateTimestamp - ); + return window.textsecure.storage.user.setLastProfileUpdateTimestamp(lastUpdateTimestamp); } export function getCurrentRecoveryPhrase() { diff --git a/ts/session/utils/syncUtils.ts b/ts/session/utils/syncUtils.ts index fcc22fd64b5374643e68ca0ff0278c0ff19b0d93..2f72a0377742df7f3461a29d3c0563a87b8f5236 100644 --- a/ts/session/utils/syncUtils.ts +++ b/ts/session/utils/syncUtils.ts @@ -15,11 +15,7 @@ import { ConfigurationMessageContact, } from '../messages/outgoing/controlMessage/ConfigurationMessage'; import { ConversationModel } from '../../models/conversation'; -import { - fromBase64ToArray, - fromBase64ToArrayBuffer, - fromHexToArray, -} from './String'; +import { fromBase64ToArray, fromBase64ToArrayBuffer, fromHexToArray } from './String'; import { fromBase64 } from 'bytebuffer'; import { SignalService } from '../../protobuf'; import _ from 'lodash'; @@ -55,10 +51,7 @@ export const syncConfigurationIfNeeded = async () => { await getMessageQueue().sendSyncMessage(configMessage); } catch (e) { - window.log.warn( - 'Caught an error while sending our ConfigurationMessage:', - e - ); + window.log.warn('Caught an error while sending our ConfigurationMessage:', e); // we do return early so that next time we use the old timestamp again // and so try again to trigger a sync return; @@ -66,9 +59,7 @@ export const syncConfigurationIfNeeded = async () => { await writeLastSyncTimestampToDb(now); }; -export const forceSyncConfigurationNowIfNeeded = async ( - waitForMessageSent = false -) => +export const forceSyncConfigurationNowIfNeeded = async (waitForMessageSent = false) => new Promise(resolve => { const allConvos = ConversationController.getInstance().getConversations(); @@ -92,26 +83,19 @@ export const forceSyncConfigurationNowIfNeeded = async ( } }) .catch(e => { - window.log.warn( - 'Caught an error while building our ConfigurationMessage:', - e - ); + window.log.warn('Caught an error while building our ConfigurationMessage:', e); resolve(false); }); }); -export const getCurrentConfigurationMessage = async ( - convos: Array<ConversationModel> -) => { +export const getCurrentConfigurationMessage = async (convos: Array<ConversationModel>) => { const ourPubKey = UserUtils.getOurPubKeyStrFromCache(); const ourConvo = convos.find(convo => convo.id === ourPubKey); // Filter open groups const openGroupsIds = convos .filter(c => !!c.get('active_at') && c.isPublic() && !c.get('left')) - .map(c => c.id.substring((c.id as string).lastIndexOf('@') + 1)) as Array< - string - >; + .map(c => c.id.substring((c.id as string).lastIndexOf('@') + 1)) as Array<string>; // Filter Closed/Medium groups const closedGroupModels = convos.filter( @@ -128,9 +112,7 @@ export const getCurrentConfigurationMessage = async ( const closedGroups = await Promise.all( closedGroupModels.map(async c => { const groupPubKey = c.get('id'); - const fetchEncryptionKeyPair = await getLatestClosedGroupEncryptionKeyPair( - groupPubKey - ); + const fetchEncryptionKeyPair = await getLatestClosedGroupEncryptionKeyPair(groupPubKey); if (!fetchEncryptionKeyPair) { return null; } @@ -151,11 +133,7 @@ export const getCurrentConfigurationMessage = async ( // Filter contacts const contactsModels = convos.filter( - c => - !!c.get('active_at') && - c.getLokiProfile()?.displayName && - c.isPrivate() && - !c.isBlocked() + c => !!c.get('active_at') && c.getLokiProfile()?.displayName && c.isPrivate() && !c.isBlocked() ); const contacts = contactsModels.map(c => { @@ -172,14 +150,10 @@ export const getCurrentConfigurationMessage = async ( }); if (!ourConvo) { - window.log.error( - 'Could not find our convo while building a configuration message.' - ); + window.log.error('Could not find our convo while building a configuration message.'); } const profileKeyFromStorage = window.storage.get('profileKey'); - const profileKey = profileKeyFromStorage - ? new Uint8Array(profileKeyFromStorage) - : undefined; + const profileKey = profileKeyFromStorage ? new Uint8Array(profileKeyFromStorage) : undefined; const profilePicture = ourConvo?.get('avatarPointer') || undefined; const displayName = ourConvo?.getLokiProfile()?.displayName || undefined; @@ -256,10 +230,7 @@ const buildSyncExpireTimerMessage = ( }); }; -export type SyncMessageType = - | VisibleMessage - | ExpirationTimerUpdateMessage - | ConfigurationMessage; +export type SyncMessageType = VisibleMessage | ExpirationTimerUpdateMessage | ConfigurationMessage; export const buildSyncMessage = ( identifier: string, @@ -279,21 +250,8 @@ export const buildSyncMessage = ( } // don't include our profileKey on syncing message. This is to be done by a ConfigurationMessage now const timestamp = _.toNumber(sentTimestamp); - if ( - dataMessage.flags === - SignalService.DataMessage.Flags.EXPIRATION_TIMER_UPDATE - ) { - return buildSyncExpireTimerMessage( - identifier, - dataMessage, - timestamp, - syncTarget - ); + if (dataMessage.flags === SignalService.DataMessage.Flags.EXPIRATION_TIMER_UPDATE) { + return buildSyncExpireTimerMessage(identifier, dataMessage, timestamp, syncTarget); } - return buildSyncVisibleMessage( - identifier, - dataMessage, - timestamp, - syncTarget - ); + return buildSyncVisibleMessage(identifier, dataMessage, timestamp, syncTarget); }; diff --git a/ts/state/createStore.ts b/ts/state/createStore.ts index d4df8451acb27df34e98313aa426fcc60652a8dd..8f936c93a6d2f6f2ee60a46b89913b863a2da2af 100644 --- a/ts/state/createStore.ts +++ b/ts/state/createStore.ts @@ -30,6 +30,5 @@ export const createStore = (initialState: any) => configureStore({ reducer: allReducers, preloadedState: initialState, - middleware: (getDefaultMiddleware: any) => - getDefaultMiddleware().concat(middlewareList), + middleware: (getDefaultMiddleware: any) => getDefaultMiddleware().concat(middlewareList), }); diff --git a/ts/state/ducks/SessionTheme.tsx b/ts/state/ducks/SessionTheme.tsx index f5db120dfe5bcfcbce851f4bac04e24b05f1a78c..7b43e06dc304fe44af862023a75779e1473c0c62 100644 --- a/ts/state/ducks/SessionTheme.tsx +++ b/ts/state/ducks/SessionTheme.tsx @@ -129,8 +129,7 @@ export const darkTheme = { clickableHovered: '#414347', sessionBorder: `1px solid ${borderDarkTheme}`, sessionUnreadBorder: `4px solid ${accentDarkTheme}`, - leftpaneOverlayBackground: - 'linear-gradient(180deg, #171717 0%, #121212 100%)', + leftpaneOverlayBackground: 'linear-gradient(180deg, #171717 0%, #121212 100%)', // scrollbars scrollBarTrack: '#1b1b1b', scrollBarThumb: '#474646', @@ -157,13 +156,9 @@ export const inversedTheme = (theme: DefaultTheme): DefaultTheme => { }; }; -export const SessionTheme = ({ - children, - theme, -}: { - children: any; - theme: DefaultTheme; -}) => <ThemeProvider theme={theme}>{children}</ThemeProvider>; +export const SessionTheme = ({ children, theme }: { children: any; theme: DefaultTheme }) => ( + <ThemeProvider theme={theme}>{children}</ThemeProvider> +); window.lightTheme = lightTheme; window.darkTheme = darkTheme; diff --git a/ts/state/ducks/conversations.ts b/ts/state/ducks/conversations.ts index aadf704eb29290e9eeecc9beeee37f634d8be722..c7951d749a0c9efa0d855a4e4964ba04b5e2e9c1 100644 --- a/ts/state/ducks/conversations.ts +++ b/ts/state/ducks/conversations.ts @@ -49,13 +49,7 @@ export type MessageTypeInConvo = { getPropsForMessageDetail(): Promise<any>; }; -export type LastMessageStatusType = - | 'error' - | 'sending' - | 'sent' - | 'delivered' - | 'read' - | null; +export type LastMessageStatusType = 'error' | 'sending' | 'sent' | 'delivered' | 'read' | null; export type LastMessageType = { status: LastMessageStatusType; @@ -113,9 +107,7 @@ async function getMessages( conversationKey: string, numMessages: number ): Promise<Array<MessageTypeInConvo>> { - const conversation = ConversationController.getInstance().get( - conversationKey - ); + const conversation = ConversationController.getInstance().get(conversationKey); if (!conversation) { // no valid conversation, early return window.log.error('Failed to get convo on reducer.'); @@ -123,8 +115,7 @@ async function getMessages( } const unreadCount = await conversation.getUnreadCount(); let msgCount = - numMessages || - Number(Constants.CONVERSATION.DEFAULT_MESSAGE_FETCH_COUNT) + unreadCount; + numMessages || Number(Constants.CONVERSATION.DEFAULT_MESSAGE_FETCH_COUNT) + unreadCount; msgCount = msgCount > Constants.CONVERSATION.MAX_MESSAGE_FETCH_COUNT ? Constants.CONVERSATION.MAX_MESSAGE_FETCH_COUNT @@ -169,9 +160,7 @@ const updateFirstMessageOfSeries = (messageModels: Array<any>) => { firstMessageOfSeries = false; } if (messageModels[i].propsForMessage) { - messageModels[ - i - ].propsForMessage.firstMessageOfSeries = firstMessageOfSeries; + messageModels[i].propsForMessage.firstMessageOfSeries = firstMessageOfSeries; } } return messageModels; @@ -179,21 +168,13 @@ const updateFirstMessageOfSeries = (messageModels: Array<any>) => { const fetchMessagesForConversation = createAsyncThunk( 'messages/fetchByConversationKey', - async ({ - conversationKey, - count, - }: { - conversationKey: string; - count: number; - }) => { + async ({ conversationKey, count }: { conversationKey: string; count: number }) => { const beforeTimestamp = Date.now(); const messages = await getMessages(conversationKey, count); const afterTimestamp = Date.now(); const time = afterTimestamp - beforeTimestamp; - window.log.info( - `Loading ${messages.length} messages took ${time}ms to load.` - ); + window.log.info(`Loading ${messages.length} messages took ${time}ms to load.`); return { conversationKey, @@ -311,10 +292,7 @@ export const actions = { openConversationExternal, }; -function conversationAdded( - id: string, - data: ConversationType -): ConversationAddedActionType { +function conversationAdded(id: string, data: ConversationType): ConversationAddedActionType { return { type: 'CONVERSATION_ADDED', payload: { @@ -323,10 +301,7 @@ function conversationAdded( }, }; } -function conversationChanged( - id: string, - data: ConversationType -): ConversationChangedActionType { +function conversationChanged(id: string, data: ConversationType): ConversationChangedActionType { return { type: 'CONVERSATION_CHANGED', payload: { @@ -373,9 +348,7 @@ function messageChanged(messageModel: MessageModel): MessageChangedActionType { }; } -function messagesChanged( - messageModels: Array<MessageModel> -): MessagesChangedActionType { +function messagesChanged(messageModels: Array<MessageModel>): MessagesChangedActionType { return { type: 'MESSAGES_CHANGED', payload: messageModels, @@ -486,8 +459,7 @@ function sortMessages( // be sure to update the sorting order to fetch messages from the DB too at getMessagesByConversation if (isPublic) { return messages.sort( - (a: any, b: any) => - b.attributes.serverTimestamp - a.attributes.serverTimestamp + (a: any, b: any) => b.attributes.serverTimestamp - a.attributes.serverTimestamp ); } if (messages.some(n => !n.attributes.sent_at && !n.attributes.received_at)) { @@ -505,10 +477,7 @@ function sortMessages( return messagesSorted; } -function handleMessageAdded( - state: ConversationsStateType, - action: MessageAddedActionType -) { +function handleMessageAdded(state: ConversationsStateType, action: MessageAddedActionType) { const { messages } = state; const { conversationKey, messageModel } = action.payload; if (conversationKey === state.selectedConversation) { @@ -519,9 +488,7 @@ function handleMessageAdded( if (convo) { const sortedMessage = sortMessages(messagesWithNewMessage, isPublic); - const updatedWithFirstMessageOfSeries = updateFirstMessageOfSeries( - sortedMessage - ); + const updatedWithFirstMessageOfSeries = updateFirstMessageOfSeries(sortedMessage); return { ...state, @@ -532,20 +499,12 @@ function handleMessageAdded( return state; } -function handleMessageChanged( - state: ConversationsStateType, - action: MessageChangedActionType -) { +function handleMessageChanged(state: ConversationsStateType, action: MessageChangedActionType) { const { payload } = action; - const messageInStoreIndex = state?.messages?.findIndex( - m => m.id === payload.id - ); + const messageInStoreIndex = state?.messages?.findIndex(m => m.id === payload.id); if (messageInStoreIndex >= 0) { - const changedMessage = _.pick( - payload as any, - toPickFromMessageModel - ) as MessageTypeInConvo; + const changedMessage = _.pick(payload as any, toPickFromMessageModel) as MessageTypeInConvo; // we cannot edit the array directly, so slice the first part, insert our edited message, and slice the second part const editedMessages = [ ...state.messages.slice(0, messageInStoreIndex), @@ -557,9 +516,7 @@ function handleMessageChanged( const isPublic = convo?.isPublic || false; // reorder the messages depending on the timestamp (we might have an updated serverTimestamp now) const sortedMessage = sortMessages(editedMessages, isPublic); - const updatedWithFirstMessageOfSeries = updateFirstMessageOfSeries( - sortedMessage - ); + const updatedWithFirstMessageOfSeries = updateFirstMessageOfSeries(sortedMessage); return { ...state, @@ -570,10 +527,7 @@ function handleMessageChanged( return state; } -function handleMessagesChanged( - state: ConversationsStateType, - action: MessagesChangedActionType -) { +function handleMessagesChanged(state: ConversationsStateType, action: MessagesChangedActionType) { const { payload } = action; payload.forEach(element => { @@ -595,9 +549,7 @@ function handleMessageExpiredOrDeleted( if (conversationKey === state.selectedConversation) { // search if we find this message id. // we might have not loaded yet, so this case might not happen - const messageInStoreIndex = state?.messages.findIndex( - m => m.id === messageId - ); + const messageInStoreIndex = state?.messages.findIndex(m => m.id === messageId); if (messageInStoreIndex >= 0) { // we cannot edit the array directly, so slice the first part, and slice the second part, // keeping the index removed out @@ -606,9 +558,7 @@ function handleMessageExpiredOrDeleted( ...state.messages.slice(messageInStoreIndex + 1), ]; - const updatedWithFirstMessageOfSeries = updateFirstMessageOfSeries( - editedMessages - ); + const updatedWithFirstMessageOfSeries = updateFirstMessageOfSeries(editedMessages); // FIXME two other thing we have to do: // * update the last message text if the message deleted was the last one @@ -686,8 +636,7 @@ export function reducer( return { ...state, conversationLookup: omit(conversationLookup, [id]), - selectedConversation: - selectedConversation === id ? undefined : selectedConversation, + selectedConversation: selectedConversation === id ? undefined : selectedConversation, }; } if (action.type === 'CONVERSATIONS_REMOVE_ALL') { @@ -719,9 +668,9 @@ export function reducer( const { messages, conversationKey } = action.payload as any; // double check that this update is for the shown convo if (conversationKey === state.selectedConversation) { - const lightMessages = messages.map((m: any) => - _.pick(m, toPickFromMessageModel) - ) as Array<MessageTypeInConvo>; + const lightMessages = messages.map((m: any) => _.pick(m, toPickFromMessageModel)) as Array< + MessageTypeInConvo + >; return { ...state, messages: lightMessages, diff --git a/ts/state/ducks/search.ts b/ts/state/ducks/search.ts index 6faaf564bd470839ffe0e3464f5ed7699c8b7fe5..842b7b92c09be95c6360840ae9f8b4f1d78718f2 100644 --- a/ts/state/ducks/search.ts +++ b/ts/state/ducks/search.ts @@ -76,20 +76,14 @@ export const actions = { updateSearchTerm, }; -export function search( - query: string, - options: SearchOptions -): SearchResultsKickoffActionType { +export function search(query: string, options: SearchOptions): SearchResultsKickoffActionType { return { type: 'SEARCH_RESULTS', payload: doSearch(query, options), }; } -async function doSearch( - query: string, - options: SearchOptions -): Promise<SearchResultsPayloadType> { +async function doSearch(query: string, options: SearchOptions): Promise<SearchResultsPayloadType> { const advancedSearchOptions = getAdvancedSearchOptionsFromQuery(query); const processedQuery = advancedSearchOptions.query; const isAdvancedQuery = query !== processedQuery; @@ -110,11 +104,7 @@ async function doSearch( ); senderFilter = senderFilterQuery.contacts; } - filteredMessages = filterMessages( - filteredMessages, - advancedSearchOptions, - senderFilter - ); + filteredMessages = filterMessages(filteredMessages, advancedSearchOptions, senderFilter); } return { @@ -163,14 +153,10 @@ function filterMessages( } } if (filters.before > 0) { - filteredMessages = filteredMessages.filter( - message => message.received_at < filters.before - ); + filteredMessages = filteredMessages.filter(message => message.received_at < filters.before); } if (filters.after > 0) { - filteredMessages = filteredMessages.filter( - message => message.received_at > filters.after - ); + filteredMessages = filteredMessages.filter(message => message.received_at > filters.after); } return filteredMessages; @@ -195,9 +181,7 @@ function getUnixMillisecondsTimestamp(timestamp: string): number { return 0; } -function getAdvancedSearchOptionsFromQuery( - query: string -): AdvancedSearchOptions { +function getAdvancedSearchOptionsFromQuery(query: string): AdvancedSearchOptions { const filterSeperator = ':'; const filters: any = { query: null, @@ -253,16 +237,11 @@ async function queryMessages(query: string) { } } -async function queryConversationsAndContacts( - providedQuery: string, - options: SearchOptions -) { +async function queryConversationsAndContacts(providedQuery: string, options: SearchOptions) { const { ourNumber, noteToSelf } = options; const query = providedQuery.replace(/[+-.()]*/g, ''); - const searchResults: Array<ConversationType> = await searchConversations( - query - ); + const searchResults: Array<ConversationType> = await searchConversations(query); // Split into two groups - active conversations and items just from address book let conversations: Array<string> = []; @@ -310,10 +289,7 @@ function getEmptyState(): SearchStateType { }; } -export function reducer( - state: SearchStateType | undefined, - action: SEARCH_TYPES -): SearchStateType { +export function reducer(state: SearchStateType | undefined, action: SEARCH_TYPES): SearchStateType { if (!state) { return getEmptyState(); } @@ -334,13 +310,7 @@ export function reducer( if (action.type === 'SEARCH_RESULTS_FULFILLED') { const { payload } = action; - const { - query, - messages, - normalizedPhoneNumber, - conversations, - contacts, - } = payload; + const { query, messages, normalizedPhoneNumber, conversations, contacts } = payload; // Reject if the associated query is not the most recent user-provided query if (state.query !== query) { diff --git a/ts/state/ducks/section.tsx b/ts/state/ducks/section.tsx index 8e31e860b35202fe9f81a7a97c884bffed2cbf7d..b32855a21387e35c66920142aca376e4bb7ea1b8 100644 --- a/ts/state/ducks/section.tsx +++ b/ts/state/ducks/section.tsx @@ -14,18 +14,14 @@ type FocusSettingsSectionActionType = { payload: SessionSettingCategory; }; -export function showLeftPaneSection( - section: SectionType -): FocusSectionActionType { +export function showLeftPaneSection(section: SectionType): FocusSectionActionType { return { type: FOCUS_SECTION, payload: section, }; } -type SectionActionTypes = - | FocusSectionActionType - | FocusSettingsSectionActionType; +type SectionActionTypes = FocusSectionActionType | FocusSettingsSectionActionType; export function showSettingsSection( category: SessionSettingCategory diff --git a/ts/state/ducks/user.ts b/ts/state/ducks/user.ts index c4f7dafef325d1873c8f1892588d029474c6a1c2..220db597cb00b5fcfd893b87a97c5e633ff7e6ae 100644 --- a/ts/state/ducks/user.ts +++ b/ts/state/ducks/user.ts @@ -25,10 +25,7 @@ export const actions = { userChanged, }; -function userChanged(attributes: { - ourNumber: string; - ourPrimary: string; -}): UserChangedActionType { +function userChanged(attributes: { ourNumber: string; ourPrimary: string }): UserChangedActionType { return { type: 'USER_CHANGED', payload: attributes, @@ -44,10 +41,7 @@ function getEmptyState(): UserStateType { }; } -export function reducer( - state: UserStateType, - action: UserActionType -): UserStateType { +export function reducer(state: UserStateType, action: UserActionType): UserStateType { if (!state) { return getEmptyState(); } diff --git a/ts/state/reducer.ts b/ts/state/reducer.ts index f6b07979b1a0a60a7b87f5ed836d0a031a22ed39..27cc7842c55410c383980cf7b96565966ca2b694 100644 --- a/ts/state/reducer.ts +++ b/ts/state/reducer.ts @@ -1,10 +1,7 @@ import { combineReducers } from 'redux'; import { reducer as search, SearchStateType } from './ducks/search'; -import { - ConversationsStateType, - reducer as conversations, -} from './ducks/conversations'; +import { ConversationsStateType, reducer as conversations } from './ducks/conversations'; import { reducer as user, UserStateType } from './ducks/user'; import { reducer as theme, ThemeStateType } from './ducks/theme'; import { reducer as section, SectionStateType } from './ducks/section'; diff --git a/ts/state/selectors/conversations.ts b/ts/state/selectors/conversations.ts index d9e28e3a21a74f7646fc1985591441ac7382222e..218cc88d1935090f0b3ff81160eb6dfc3cf5d615 100644 --- a/ts/state/selectors/conversations.ts +++ b/ts/state/selectors/conversations.ts @@ -12,8 +12,7 @@ import { getIntl, getOurNumber } from './user'; import { BlockedNumberController } from '../../util'; import { LocalizerType } from '../../types/Util'; -export const getConversations = (state: StateType): ConversationsStateType => - state.conversations; +export const getConversations = (state: StateType): ConversationsStateType => state.conversations; export const getConversationLookup = createSelector( getConversations, @@ -49,10 +48,7 @@ export const getMessagesOfSelectedConversation = createSelector( (state: ConversationsStateType): Array<MessageTypeInConvo> => state.messages ); -function getConversationTitle( - conversation: ConversationType, - i18n: LocalizerType -): string { +function getConversationTitle(conversation: ConversationType, i18n: LocalizerType): string { if (conversation.name) { return conversation.name; } @@ -78,22 +74,13 @@ export const _getConversationComparator = (i18n: LocalizerType) => { if (leftActiveAt && rightActiveAt && leftActiveAt !== rightActiveAt) { return rightActiveAt - leftActiveAt; } - const leftTitle = getConversationTitle( - left, - i18n || window?.i18n - ).toLowerCase(); - const rightTitle = getConversationTitle( - right, - i18n || window?.i18n - ).toLowerCase(); + const leftTitle = getConversationTitle(left, i18n || window?.i18n).toLowerCase(); + const rightTitle = getConversationTitle(right, i18n || window?.i18n).toLowerCase(); return collator.compare(leftTitle, rightTitle); }; }; -export const getConversationComparator = createSelector( - getIntl, - _getConversationComparator -); +export const getConversationComparator = createSelector(getIntl, _getConversationComparator); // export only because we use it in some of our tests export const _getLeftPaneLists = ( @@ -135,10 +122,7 @@ export const _getLeftPaneLists = ( conversation.index = index; // Add Open Group to list as soon as the name has been set - if ( - conversation.isPublic && - (!conversation.name || conversation.name === 'Unknown group') - ) { + if (conversation.isPublic && (!conversation.name || conversation.name === 'Unknown group')) { continue; } @@ -225,9 +209,6 @@ export const getMe = createSelector( } ); -export const getUnreadMessageCount = createSelector( - getLeftPaneLists, - (state): number => { - return state.unreadCount; - } -); +export const getUnreadMessageCount = createSelector(getLeftPaneLists, (state): number => { + return state.unreadCount; +}); diff --git a/ts/state/selectors/search.ts b/ts/state/selectors/search.ts index 638a6167ecbe84fb6db6fb89fed0739e399dc5ba..7aba2617cb96754de249360eb66a3d47b29338e6 100644 --- a/ts/state/selectors/search.ts +++ b/ts/state/selectors/search.ts @@ -13,32 +13,21 @@ import { ConversationLookupType } from '../ducks/conversations'; export const getSearch = (state: StateType): SearchStateType => state.search; -export const getQuery = createSelector( - getSearch, - (state: SearchStateType): string => state.query -); +export const getQuery = createSelector(getSearch, (state: SearchStateType): string => state.query); export const getSelectedMessage = createSelector( getSearch, (state: SearchStateType): string | undefined => state.selectedMessage ); -export const isSearching = createSelector( - getSearch, - (state: SearchStateType) => { - const { query } = state; +export const isSearching = createSelector(getSearch, (state: SearchStateType) => { + const { query } = state; - return Boolean(query && query.trim().length > 1); - } -); + return Boolean(query && query.trim().length > 1); +}); export const getSearchResults = createSelector( - [ - getSearch, - getConversationLookup, - getSelectedConversationKey, - getSelectedMessage, - ], + [getSearch, getConversationLookup, getSelectedConversationKey, getSelectedMessage], ( state: SearchStateType, lookup: ConversationLookupType, diff --git a/ts/state/selectors/section.ts b/ts/state/selectors/section.ts index 31f580a0888dc3996c955243707e6f99135cb354..35f5df59967ebe216eeb05a289af6b7a9bbde1ad 100644 --- a/ts/state/selectors/section.ts +++ b/ts/state/selectors/section.ts @@ -14,6 +14,5 @@ export const getFocusedSection = createSelector( export const getFocusedSettingsSection = createSelector( getSection, - (state: SectionStateType): SessionSettingCategory | undefined => - state.focusedSettingsSection + (state: SectionStateType): SessionSettingCategory | undefined => state.focusedSettingsSection ); diff --git a/ts/state/selectors/user.ts b/ts/state/selectors/user.ts index e2a2e144c5e2466a342aad379080f52e04924abb..e3468583c50a8aaa6ee0baa9ecfdd3b64ea9d0ed 100644 --- a/ts/state/selectors/user.ts +++ b/ts/state/selectors/user.ts @@ -12,7 +12,4 @@ export const getOurNumber = createSelector( (state: UserStateType): string => state.ourNumber ); -export const getIntl = createSelector( - getUser, - (state: UserStateType): LocalizerType => state.i18n -); +export const getIntl = createSelector(getUser, (state: UserStateType): LocalizerType => state.i18n); diff --git a/ts/test/session/integration/add_contacts_itest.ts b/ts/test/session/integration/add_contacts_itest.ts index 9c1b8429db675be8cb7d2d32836bbe08ea669d56..188bdc729a4844cced1ea8c1fcd22643b75fbb48 100644 --- a/ts/test/session/integration/add_contacts_itest.ts +++ b/ts/test/session/integration/add_contacts_itest.ts @@ -47,14 +47,9 @@ describe('Add contact', function() { await app.client.element(ConversationPage.contactsButtonSection).click(); await app.client.element(ConversationPage.addContactButton).click(); - await app.client.isExisting(ConversationPage.leftPaneOverlay).should - .eventually.be.true; - - await Common.setValueWrapper( - app, - ConversationPage.sessionIDInput, - Common.TEST_PUBKEY2 - ); + await app.client.isExisting(ConversationPage.leftPaneOverlay).should.eventually.be.true; + + await Common.setValueWrapper(app, ConversationPage.sessionIDInput, Common.TEST_PUBKEY2); await app.client .element(ConversationPage.sessionIDInput) .getValue() @@ -64,27 +59,18 @@ describe('Add contact', function() { await app.client.waitForExist(ConversationPage.sendMessageTextarea, 1000); // send a text message to that user - await app.client - .element(ConversationPage.sendMessageTextarea) - .setValue(textMessage); + await app.client.element(ConversationPage.sendMessageTextarea).setValue(textMessage); await app.client.keys('Enter'); - await app.client.waitForExist( - ConversationPage.existingSendMessageText(textMessage), - 1000 - ); + await app.client.waitForExist(ConversationPage.existingSendMessageText(textMessage), 1000); // assure session request message has been sent await Common.timeout(3000); - await app.client.isExisting(ConversationPage.retrySendButton).should - .eventually.be.false; + await app.client.isExisting(ConversationPage.retrySendButton).should.eventually.be.false; await app2.client.waitForExist(ConversationPage.conversationItem, 5000); await app2.client.element(ConversationPage.conversationItem).click(); - await app2.client.waitForExist( - ConversationPage.existingReceivedMessageText(textMessage), - 1000 - ); + await app2.client.waitForExist(ConversationPage.existingReceivedMessageText(textMessage), 1000); }); }); diff --git a/ts/test/session/integration/closed_group_itest.ts b/ts/test/session/integration/closed_group_itest.ts index 4aa17bf8efb42e7858b71cc560f1d81a379ddcea..a24c8378a1cb2ab75efbedff14c6471dad160714 100644 --- a/ts/test/session/integration/closed_group_itest.ts +++ b/ts/test/session/integration/closed_group_itest.ts @@ -35,9 +35,7 @@ describe('Closed groups', function() { // send a message from app and validate it is received on app2 const textMessage = Common.generateSendMessageText(); - await app.client - .element(ConversationPage.sendMessageTextarea) - .setValue(textMessage); + await app.client.element(ConversationPage.sendMessageTextarea).setValue(textMessage); await app.client .element(ConversationPage.sendMessageTextarea) .getValue() @@ -46,15 +44,9 @@ describe('Closed groups', function() { await app.client.keys('Enter'); // validate that the message has been added to the message list view - await app.client.waitForExist( - ConversationPage.existingSendMessageText(textMessage), - 2000 - ); + await app.client.waitForExist(ConversationPage.existingSendMessageText(textMessage), 2000); // validate that the message has been added to the message list view - await app2.client.waitForExist( - ConversationPage.existingReceivedMessageText(textMessage), - 5000 - ); + await app2.client.waitForExist(ConversationPage.existingReceivedMessageText(textMessage), 5000); }); }); diff --git a/ts/test/session/integration/common.ts b/ts/test/session/integration/common.ts index 210b7982a973d371ee6ddebd5fba099bf112ae6c..d8b93e6e7218237b093df72bab4db5f7372a271f 100644 --- a/ts/test/session/integration/common.ts +++ b/ts/test/session/integration/common.ts @@ -76,11 +76,7 @@ export class Common { } // a wrapper to work around electron/spectron bug - public static async setValueWrapper( - app: Application, - selector: any, - value: string - ) { + public static async setValueWrapper(app: Application, selector: any, value: string) { // keys, setValue and addValue hang on certain platforms if (process.platform === 'darwin') { @@ -113,22 +109,11 @@ export class Common { } public static async startApp(environment = 'test-integration-session') { - const env = environment.startsWith('test-integration') - ? 'test-integration' - : environment; + const env = environment.startsWith('test-integration') ? 'test-integration' : environment; const instance = environment.replace('test-integration-', ''); const app1 = new Application({ - path: path.join( - __dirname, - '..', - '..', - '..', - '..', - 'node_modules', - '.bin', - 'electron' - ), + path: path.join(__dirname, '..', '..', '..', '..', 'node_modules', '.bin', 'electron'), args: ['.'], env: { NODE_ENV: env, @@ -183,24 +168,17 @@ export class Common { } public static async startAndAssureCleanedApp2() { - const app2 = await Common.startAndAssureCleanedApp( - 'test-integration-session-2' - ); + const app2 = await Common.startAndAssureCleanedApp('test-integration-session-2'); return app2; } - public static async startAndAssureCleanedApp( - env = 'test-integration-session' - ) { + public static async startAndAssureCleanedApp(env = 'test-integration-session') { const userData = path.join(Common.USER_DATA_ROOT_FOLDER, `Session-${env}`); await Common.rmFolder(userData); const app1 = await Common.startApp(env); - await app1.client.waitForExist( - RegistrationPage.registrationTabSignIn, - 4000 - ); + await app1.client.waitForExist(RegistrationPage.registrationTabSignIn, 4000); return app1; } @@ -243,31 +221,17 @@ export class Common { ) { await app.client.element(RegistrationPage.registrationTabSignIn).click(); await app.client.element(RegistrationPage.restoreFromSeedMode).click(); - await Common.setValueWrapper( - app, - RegistrationPage.recoveryPhraseInput, - recoveryPhrase - ); + await Common.setValueWrapper(app, RegistrationPage.recoveryPhraseInput, recoveryPhrase); - await Common.setValueWrapper( - app, - RegistrationPage.displayNameInput, - displayName - ); + await Common.setValueWrapper(app, RegistrationPage.displayNameInput, displayName); // await app.client.element(RegistrationPage.continueSessionButton).click(); await app.client.keys('Enter'); - await app.client.waitForExist( - RegistrationPage.conversationListContainer, - 4000 - ); + await app.client.waitForExist(RegistrationPage.conversationListContainer, 4000); } - public static async makeFriends( - app1: Application, - client2: [Application, string] - ) { + public static async makeFriends(app1: Application, client2: [Application, string]) { const [_, pubkey2] = client2; /** add each other as friends */ @@ -275,28 +239,14 @@ export class Common { await app1.client.element(ConversationPage.contactsButtonSection).click(); await app1.client.element(ConversationPage.addContactButton).click(); - await Common.setValueWrapper( - app1, - ConversationPage.sessionIDInput, - pubkey2 - ); + await Common.setValueWrapper(app1, ConversationPage.sessionIDInput, pubkey2); await app1.client.element(ConversationPage.nextButton).click(); - await app1.client.waitForExist( - ConversationPage.sendMessageTextareaAndMessage, - 1000 - ); + await app1.client.waitForExist(ConversationPage.sendMessageTextareaAndMessage, 1000); // send a text message to that user (will be a friend request) - await Common.setValueWrapper( - app1, - ConversationPage.sendMessageTextareaAndMessage, - textMessage - ); + await Common.setValueWrapper(app1, ConversationPage.sendMessageTextareaAndMessage, textMessage); await app1.client.keys('Enter'); - await app1.client.waitForExist( - ConversationPage.existingSendMessageText(textMessage), - 1000 - ); + await app1.client.waitForExist(ConversationPage.existingSendMessageText(textMessage), 1000); } public static async startAppsAsFriends() { @@ -325,9 +275,7 @@ export class Common { public static async addFriendToNewClosedGroup(members: Array<Application>) { const [app, ...others] = members; - await app.client - .element(ConversationPage.conversationButtonSection) - .click(); + await app.client.element(ConversationPage.conversationButtonSection).click(); await app.client.element(ConversationPage.createClosedGroupButton).click(); await Common.setValueWrapper( @@ -345,91 +293,63 @@ export class Common { for (let i = 0; i < others.length; i += 1) { // eslint-disable-next-line no-await-in-loop - await app.client - .element(ConversationPage.createClosedGroupMemberItem(i)) - .isVisible().should.eventually.be.true; + await app.client.element(ConversationPage.createClosedGroupMemberItem(i)).isVisible().should + .eventually.be.true; // eslint-disable-next-line no-await-in-loop - await app.client - .element(ConversationPage.createClosedGroupMemberItem(i)) - .click(); + await app.client.element(ConversationPage.createClosedGroupMemberItem(i)).click(); } - await app.client - .element(ConversationPage.createClosedGroupMemberItemSelected) - .isVisible().should.eventually.be.true; + await app.client.element(ConversationPage.createClosedGroupMemberItemSelected).isVisible() + .should.eventually.be.true; // trigger the creation of the group - await app.client - .element(ConversationPage.validateCreationClosedGroupButton) - .click(); + await app.client.element(ConversationPage.validateCreationClosedGroupButton).click(); - await app.client.waitForExist( - ConversationPage.sessionToastGroupCreatedSuccess, - 1000 - ); + await app.client.waitForExist(ConversationPage.sessionToastGroupCreatedSuccess, 1000); await app.client.isExisting( ConversationPage.headerTitleGroupName(Common.VALID_CLOSED_GROUP_NAME1) ).should.eventually.be.true; - await app.client - .element(ConversationPage.headerTitleMembers(members.length)) - .isVisible().should.eventually.be.true; + await app.client.element(ConversationPage.headerTitleMembers(members.length)).isVisible().should + .eventually.be.true; // validate overlay is closed - await app.client - .isExisting(ConversationPage.leftPaneOverlay) - .should.eventually.be.equal(false); + await app.client.isExisting(ConversationPage.leftPaneOverlay).should.eventually.be.equal(false); // move back to the conversation section - await app.client - .element(ConversationPage.conversationButtonSection) - .click(); + await app.client.element(ConversationPage.conversationButtonSection).click(); // validate open chat has been added await app.client.isExisting( - ConversationPage.rowOpenGroupConversationName( - Common.VALID_CLOSED_GROUP_NAME1 - ) + ConversationPage.rowOpenGroupConversationName(Common.VALID_CLOSED_GROUP_NAME1) ).should.eventually.be.true; await Promise.all( others.map(async otherApp => { // next check that other members have been invited and have the group in their conversations await otherApp.client.waitForExist( - ConversationPage.rowOpenGroupConversationName( - Common.VALID_CLOSED_GROUP_NAME1 - ), + ConversationPage.rowOpenGroupConversationName(Common.VALID_CLOSED_GROUP_NAME1), 6000 ); // open the closed group conversation on otherApp - await otherApp.client - .element(ConversationPage.conversationButtonSection) - .click(); + await otherApp.client.element(ConversationPage.conversationButtonSection).click(); await Common.timeout(500); await otherApp.client - .element( - ConversationPage.rowOpenGroupConversationName( - Common.VALID_CLOSED_GROUP_NAME1 - ) - ) + .element(ConversationPage.rowOpenGroupConversationName(Common.VALID_CLOSED_GROUP_NAME1)) .click(); }) ); } - public static async linkApp2ToApp( - app1: Application, - app2: Application, - app1Pubkey: string - ) { + public static async linkApp2ToApp(app1: Application, app2: Application, app1Pubkey: string) { // app needs to be logged in as user1 and app2 needs to be logged out // start the pairing dialog for the first app await app1.client.element(SettingsPage.settingsButtonSection).click(); await app1.client.isVisible(ConversationPage.noPairedDeviceMessage); // we should not find the linkDeviceButtonDisabled button (as DISABLED) - await app1.client.isExisting(ConversationPage.linkDeviceButtonDisabled) - .should.eventually.be.false; + await app1.client.isExisting(ConversationPage.linkDeviceButtonDisabled).should.eventually.be + .false; await app1.client.element(ConversationPage.linkDeviceButton).click(); // validate device pairing dialog is shown and has a qrcode @@ -439,11 +359,7 @@ export class Common { await app2.client.element(RegistrationPage.registrationTabSignIn).click(); await app2.client.element(RegistrationPage.linkDeviceMode).click(); - await Common.setValueWrapper( - app2, - RegistrationPage.textareaLinkDevicePubkey, - app1Pubkey - ); + await Common.setValueWrapper(app2, RegistrationPage.textareaLinkDevicePubkey, app1Pubkey); await app2.client.element(RegistrationPage.linkDeviceTriggerButton).click(); await app1.client.waitForExist(SettingsPage.secretWordsTextInDialog, 7000); const secretWordsapp1 = await app1.client @@ -459,21 +375,14 @@ export class Common { await app1.client.element(ConversationPage.allowPairingButton).click(); await app1.client.element(ConversationPage.okButton).click(); // validate device paired in settings list with correct secrets - await app1.client.waitForExist( - ConversationPage.devicePairedDescription(secretWordsapp1), - 2000 - ); + await app1.client.waitForExist(ConversationPage.devicePairedDescription(secretWordsapp1), 2000); - await app1.client.isExisting(ConversationPage.unpairDeviceButton).should - .eventually.be.true; - await app1.client.isExisting(ConversationPage.linkDeviceButtonDisabled) - .should.eventually.be.true; + await app1.client.isExisting(ConversationPage.unpairDeviceButton).should.eventually.be.true; + await app1.client.isExisting(ConversationPage.linkDeviceButtonDisabled).should.eventually.be + .true; // validate app2 (secondary device) is linked successfully - await app2.client.waitForExist( - RegistrationPage.conversationListContainer, - 4000 - ); + await app2.client.waitForExist(RegistrationPage.conversationListContainer, 4000); // validate primary pubkey of app2 is the same that in app1 await app2.webContents @@ -481,27 +390,21 @@ export class Common { .should.eventually.be.equal(app1Pubkey); } - public static async triggerUnlinkApp2FromApp( - app1: Application, - app2: Application - ) { + public static async triggerUnlinkApp2FromApp(app1: Application, app2: Application) { // check app2 is loggedin - await app2.client.isExisting(RegistrationPage.conversationListContainer) - .should.eventually.be.true; + await app2.client.isExisting(RegistrationPage.conversationListContainer).should.eventually.be + .true; await app1.client.element(SettingsPage.settingsButtonSection).click(); - await app1.client.isExisting(ConversationPage.linkDeviceButtonDisabled) - .should.eventually.be.true; + await app1.client.isExisting(ConversationPage.linkDeviceButtonDisabled).should.eventually.be + .true; // click the unlink button await app1.client.element(ConversationPage.unpairDeviceButton).click(); await app1.client.element(ConversationPage.validateUnpairDevice).click(); - await app1.client.waitForExist( - ConversationPage.noPairedDeviceMessage, - 5000 - ); - await app1.client.element(ConversationPage.linkDeviceButton).isEnabled() - .should.eventually.be.true; + await app1.client.waitForExist(ConversationPage.noPairedDeviceMessage, 5000); + await app1.client.element(ConversationPage.linkDeviceButton).isEnabled().should.eventually.be + .true; // let time to app2 to catch the event and restart dropping its data await Common.timeout(5000); @@ -510,8 +413,8 @@ export class Common { // (did not find a better way than checking the app no longer being accessible) let isApp2Joinable = true; try { - await app2.client.isExisting(RegistrationPage.registrationTabSignIn) - .should.eventually.be.true; + await app2.client.isExisting(RegistrationPage.registrationTabSignIn).should.eventually.be + .true; } catch (err) { // if we get an error here, it means Spectron is lost. // Common is a good thing because it means app2 restarted @@ -525,16 +428,8 @@ export class Common { } } - public static async sendMessage( - app: Application, - messageText: string, - fileLocation?: string - ) { - await Common.setValueWrapper( - app, - ConversationPage.sendMessageTextarea, - messageText - ); + public static async sendMessage(app: Application, messageText: string, fileLocation?: string) { + await Common.setValueWrapper(app, ConversationPage.sendMessageTextarea, messageText); await app.client .element(ConversationPage.sendMessageTextarea) .getValue() @@ -542,11 +437,7 @@ export class Common { // attach a file if (fileLocation) { - await Common.setValueWrapper( - app, - ConversationPage.attachmentInput, - fileLocation - ); + await Common.setValueWrapper(app, ConversationPage.attachmentInput, fileLocation); } // send message @@ -587,12 +478,7 @@ export class Common { if (request.method === 'POST') { if (ENABLE_LOG) { - console.warn( - 'POST', - pubkey.substr(2, 3), - data.substr(4, 10), - timestamp - ); + console.warn('POST', pubkey.substr(2, 3), data.substr(4, 10), timestamp); } let ori = Common.messages[pubkey]; @@ -609,9 +495,7 @@ export class Common { const retrievedMessages = { messages: Common.messages[pubkey] || [] }; if (ENABLE_LOG) { - const messages = retrievedMessages.messages.map((m: any) => - m.data.substr(4, 10) - ); + const messages = retrievedMessages.messages.map((m: any) => m.data.substr(4, 10)); console.warn('GET', pubkey.substr(2, 3), messages); } response.writeHead(200, { 'Content-Type': 'application/json' }); @@ -635,47 +519,27 @@ export class Common { } } - public static async joinOpenGroup( - app: Application, - openGroupUrl: string, - name: string - ) { - await app.client - .element(ConversationPage.conversationButtonSection) - .click(); + public static async joinOpenGroup(app: Application, openGroupUrl: string, name: string) { + await app.client.element(ConversationPage.conversationButtonSection).click(); await app.client.element(ConversationPage.joinOpenGroupButton).click(); - await Common.setValueWrapper( - app, - ConversationPage.openGroupInputUrl, - openGroupUrl - ); + await Common.setValueWrapper(app, ConversationPage.openGroupInputUrl, openGroupUrl); await app.client .element(ConversationPage.openGroupInputUrl) .getValue() .should.eventually.equal(openGroupUrl); await app.client.element(ConversationPage.joinOpenGroupButton).click(); - await app.client.waitForExist( - ConversationPage.sessionToastJoinOpenGroup, - 2 * 1000 - ); + await app.client.waitForExist(ConversationPage.sessionToastJoinOpenGroup, 2 * 1000); // account for slow home internet connection delays... - await app.client.waitForExist( - ConversationPage.sessionToastJoinOpenGroupSuccess, - 20 * 1000 - ); + await app.client.waitForExist(ConversationPage.sessionToastJoinOpenGroupSuccess, 20 * 1000); // validate overlay is closed - await app.client.isExisting(ConversationPage.leftPaneOverlay).should - .eventually.be.false; + await app.client.isExisting(ConversationPage.leftPaneOverlay).should.eventually.be.false; // validate open chat has been added - await app.client.waitForExist( - ConversationPage.rowOpenGroupConversationName(name), - 20 * 1000 - ); + await app.client.waitForExist(ConversationPage.rowOpenGroupConversationName(name), 20 * 1000); } public static async stopStubSnodeServer() { @@ -691,25 +555,15 @@ export class Common { * @param str the string to search (not regex) * Note: getRenderProcessLogs() clears the app logs each calls. */ - public static logsContains( - renderLogs: Array<{ message: string }>, - str: string, - count?: number - ) { + public static logsContains(renderLogs: Array<{ message: string }>, str: string, count?: number) { const foundLines = renderLogs.filter(log => log.message.includes(str)); // tslint:disable-next-line: no-unused-expression - chai.expect( - foundLines.length > 0, - `'${str}' not found in logs but was expected` - ).to.be.true; + chai.expect(foundLines.length > 0, `'${str}' not found in logs but was expected`).to.be.true; if (count) { chai - .expect( - foundLines.length, - `'${str}' found but not the correct number of times` - ) + .expect(foundLines.length, `'${str}' found but not the correct number of times`) .to.be.equal(count); } } diff --git a/ts/test/session/integration/message_functions_itest.ts b/ts/test/session/integration/message_functions_itest.ts index f28d02f3dc547eb48ba36145975ef929a3efb3b5..39aaf05e221f7c112267ab1ffc6e1cc5bf165d4e 100644 --- a/ts/test/session/integration/message_functions_itest.ts +++ b/ts/test/session/integration/message_functions_itest.ts @@ -42,15 +42,9 @@ describe('Message Functions', function() { await Common.sendMessage(app, messageText, fileLocation); // validate attachment sent - await app.client.waitForExist( - ConversationPage.existingSendMessageText(messageText), - 3000 - ); + await app.client.waitForExist(ConversationPage.existingSendMessageText(messageText), 3000); // validate attachment recieved - await app2.client.waitForExist( - ConversationPage.existingReceivedMessageText(messageText), - 5000 - ); + await app2.client.waitForExist(ConversationPage.existingReceivedMessageText(messageText), 5000); }); it('messageFunction: can delete message', async () => { @@ -59,31 +53,19 @@ describe('Message Functions', function() { const messageText = 'delete_me'; await Common.sendMessage(app, messageText); - await app.client.waitForExist( - ConversationPage.existingSendMessageText(messageText), - 6000 - ); - await app2.client.waitForExist( - ConversationPage.existingReceivedMessageText(messageText), - 7000 - ); + await app.client.waitForExist(ConversationPage.existingSendMessageText(messageText), 6000); + await app2.client.waitForExist(ConversationPage.existingReceivedMessageText(messageText), 7000); // delete message in context menu - await app.client - .element(ConversationPage.messageCtxMenu(messageText)) - .click(); + await app.client.element(ConversationPage.messageCtxMenu(messageText)).click(); await app.client.element(ConversationPage.deleteMessageCtxButton).click(); // delete message from modal - await app.client.waitForExist( - ConversationPage.deleteMessageModalButton, - 5000 - ); + await app.client.waitForExist(ConversationPage.deleteMessageModalButton, 5000); await app.client.element(ConversationPage.deleteMessageModalButton).click(); // verify the message is actually deleted - await app.client.isExisting( - ConversationPage.existingSendMessageText(messageText) - ).should.eventually.be.false; + await app.client.isExisting(ConversationPage.existingSendMessageText(messageText)).should + .eventually.be.false; }); }); diff --git a/ts/test/session/integration/open_group_itest.ts b/ts/test/session/integration/open_group_itest.ts index 588bdd1607df647a07f6a440005c4532efdca4cd..5ff87eeba2460c4df192e8a80b8e062d7873f062 100644 --- a/ts/test/session/integration/open_group_itest.ts +++ b/ts/test/session/integration/open_group_itest.ts @@ -29,65 +29,37 @@ describe('Open groups', function() { }); it('openGroup: works with valid open group url', async () => { - await Common.joinOpenGroup( - app, - Common.VALID_GROUP_URL, - Common.VALID_GROUP_NAME - ); + await Common.joinOpenGroup(app, Common.VALID_GROUP_URL, Common.VALID_GROUP_NAME); }); it('openGroup: cannot join two times the same open group', async () => { - await Common.joinOpenGroup( - app, - Common.VALID_GROUP_URL2, - Common.VALID_GROUP_NAME2 - ); + await Common.joinOpenGroup(app, Common.VALID_GROUP_URL2, Common.VALID_GROUP_NAME2); // adding a second time the same open group - await app.client - .element(ConversationPage.conversationButtonSection) - .click(); + await app.client.element(ConversationPage.conversationButtonSection).click(); await app.client.element(ConversationPage.joinOpenGroupButton).click(); - await Common.setValueWrapper( - app, - ConversationPage.openGroupInputUrl, - Common.VALID_GROUP_URL2 - ); + await Common.setValueWrapper(app, ConversationPage.openGroupInputUrl, Common.VALID_GROUP_URL2); await app.client.element(ConversationPage.joinOpenGroupButton).click(); // validate session loader is not shown - await app.client.isExisting(ConversationPage.sessionLoader).should - .eventually.be.false; + await app.client.isExisting(ConversationPage.sessionLoader).should.eventually.be.false; - await app.client.waitForExist( - ConversationPage.sessionToastJoinOpenGroupAlreadyExist, - 1 * 1000 - ); + await app.client.waitForExist(ConversationPage.sessionToastJoinOpenGroupAlreadyExist, 1 * 1000); // validate overlay is still opened as connection failed - await app.client.isExisting(ConversationPage.leftPaneOverlay).should - .eventually.be.true; + await app.client.isExisting(ConversationPage.leftPaneOverlay).should.eventually.be.true; }); it('openGroup: can send message to open group', async () => { // join dev-chat group - await app.client - .element(ConversationPage.conversationButtonSection) - .click(); + await app.client.element(ConversationPage.conversationButtonSection).click(); await app.client.element(ConversationPage.joinOpenGroupButton).click(); - await Common.setValueWrapper( - app, - ConversationPage.openGroupInputUrl, - Common.VALID_GROUP_URL2 - ); + await Common.setValueWrapper(app, ConversationPage.openGroupInputUrl, Common.VALID_GROUP_URL2); await app.client.element(ConversationPage.joinOpenGroupButton).click(); // wait for toast to appear - await app.client.waitForExist( - ConversationPage.sessionToastJoinOpenGroupSuccess, - 30 * 1000 - ); + await app.client.waitForExist(ConversationPage.sessionToastJoinOpenGroupSuccess, 30 * 1000); await Common.timeout(5 * 1000); // wait for toast to clear await app.client.waitForExist( @@ -96,25 +68,17 @@ describe('Open groups', function() { ); // generate a message containing the current timestamp so we can find it in the list of messages const textMessage = Common.generateSendMessageText(); - await app.client - .element(ConversationPage.conversationButtonSection) - .click(); + await app.client.element(ConversationPage.conversationButtonSection).click(); await app.client.isExisting( ConversationPage.rowOpenGroupConversationName(Common.VALID_GROUP_NAME2) ); await app.client - .element( - ConversationPage.rowOpenGroupConversationName(Common.VALID_GROUP_NAME2) - ) + .element(ConversationPage.rowOpenGroupConversationName(Common.VALID_GROUP_NAME2)) .click(); - await Common.setValueWrapper( - app, - ConversationPage.sendMessageTextarea, - textMessage - ); + await Common.setValueWrapper(app, ConversationPage.sendMessageTextarea, textMessage); await app.client .element(ConversationPage.sendMessageTextarea) .getValue() @@ -126,10 +90,7 @@ describe('Open groups', function() { await app.client.keys('Enter'); await Common.timeout(5000); // validate that the message has been added to the message list view - await app.client.waitForExist( - ConversationPage.existingSendMessageText(textMessage), - 3 * 1000 - ); + await app.client.waitForExist(ConversationPage.existingSendMessageText(textMessage), 3 * 1000); // we should validate that the message has been added effectively sent // (checking the check icon on the metadata part of the message?) }); diff --git a/ts/test/session/integration/page-objects/common.page.ts b/ts/test/session/integration/page-objects/common.page.ts index 5295598f73a9bc87a3339469c3d6c3f18598aaad..0a9e56d0495e2c3bed31cb7f2b4db03c3f123548 100644 --- a/ts/test/session/integration/page-objects/common.page.ts +++ b/ts/test/session/integration/page-objects/common.page.ts @@ -14,11 +14,9 @@ export = { inputWithId: (id: string) => `//input[contains(@id, '${id}')]`, textAreaWithPlaceholder: (placeholder: string) => `//textarea[contains(@placeholder, "${placeholder}")]`, - textAreaWithClass: (classname: string) => - `//textarea[contains(@class, "${classname}")]`, + textAreaWithClass: (classname: string) => `//textarea[contains(@class, "${classname}")]`, byId: (id: string) => `//*[@id="${id}"]`, - divWithClass: (classname: string) => - `//div[contains(@class, "${classname}")]`, + divWithClass: (classname: string) => `//div[contains(@class, "${classname}")]`, divWithClassAndText: (classname: string, text: string) => module.exports.objWithClassAndText('div', classname, text), spanWithClassAndText: (classname: string, text: string) => diff --git a/ts/test/session/integration/page-objects/conversation.page.ts b/ts/test/session/integration/page-objects/conversation.page.ts index a15d29d462270869247616288826aa697fc721cc..804120160870538bcf6e6835f18f9d1d4a4ec354 100644 --- a/ts/test/session/integration/page-objects/conversation.page.ts +++ b/ts/test/session/integration/page-objects/conversation.page.ts @@ -5,9 +5,7 @@ export = { sessionLoader: commonPage.divWithClass('session-loader'), leftPaneOverlay: commonPage.divWithClass('module-left-pane-overlay'), sendMessageTextarea: commonPage.textAreaWithClass('send-message'), - sendMessageTextareaAndMessage: commonPage.textAreaWithPlaceholder( - 'Type your message' - ), + sendMessageTextareaAndMessage: commonPage.textAreaWithPlaceholder('Type your message'), existingSendMessageText: (textMessage: string) => `//*[contains(@class, "module-message__text--outgoing") and .//span[contains(@class, "text-selectable")][contains(string(), '${textMessage}')]]`, existingReceivedMessageText: (textMessage: string) => @@ -21,10 +19,7 @@ export = { 'Retry Send' ), headerTitleMembers: (num: number) => - commonPage.spanWithClassAndText( - 'module-conversation-header__title-text', - `${num} members` - ), + commonPage.spanWithClassAndText('module-conversation-header__title-text', `${num} members`), conversationItem: "//*[contains(@class, 'module-conversation-list-item')]", @@ -42,9 +37,7 @@ export = { // channels joinOpenGroupButton: commonPage.divRoleButtonWithText('Join Open Group'), openGroupInputUrl: commonPage.textAreaWithPlaceholder('chat.getsession.org'), - sessionToastJoinOpenGroup: commonPage.toastWithText( - 'Connecting to server...' - ), + sessionToastJoinOpenGroup: commonPage.toastWithText('Connecting to server...'), sessionToastJoinOpenGroupSuccess: commonPage.toastWithText( 'Successfully connected to open group' ), @@ -52,37 +45,19 @@ export = { 'You are already connected to this open group' ), rowOpenGroupConversationName: (groupName: string) => - commonPage.spanWithClassAndText( - 'module-conversation__user__profile-number', - groupName - ), + commonPage.spanWithClassAndText('module-conversation__user__profile-number', groupName), // closed group - createClosedGroupButton: commonPage.divRoleButtonWithText( - 'Create Closed Group' - ), - closedGroupNameTextarea: commonPage.textAreaWithPlaceholder( - 'Enter a group name' - ), + createClosedGroupButton: commonPage.divRoleButtonWithText('Create Closed Group'), + closedGroupNameTextarea: commonPage.textAreaWithPlaceholder('Enter a group name'), createClosedGroupMemberItem: (idx: number) => commonPage.divWithClass(`session-member-item-${idx}`), - createClosedGroupSealedSenderToggle: commonPage.divWithClass( - 'session-toggle' - ), - createClosedGroupMemberItemSelected: commonPage.divWithClass( - 'session-member-item selected' - ), - validateCreationClosedGroupButton: commonPage.divRoleButtonWithText( - 'Create Closed Group' - ), - sessionToastGroupCreatedSuccess: commonPage.toastWithText( - 'Group created successfully' - ), + createClosedGroupSealedSenderToggle: commonPage.divWithClass('session-toggle'), + createClosedGroupMemberItemSelected: commonPage.divWithClass('session-member-item selected'), + validateCreationClosedGroupButton: commonPage.divRoleButtonWithText('Create Closed Group'), + sessionToastGroupCreatedSuccess: commonPage.toastWithText('Group created successfully'), headerTitleGroupName: (groupname: string) => - commonPage.spanWithClassAndText( - 'module-contact-name__profile-name', - groupname - ), + commonPage.spanWithClassAndText('module-contact-name__profile-name', groupname), // contacts contactsButtonSection: @@ -101,17 +76,12 @@ export = { noPairedDeviceMessage: '//*[contains(@class, "session-settings-item__title")][contains(string(), "No linked devices")]', linkDeviceButton: commonPage.divRoleButtonWithText('Link New Device'), - linkDeviceButtonDisabled: commonPage.divRoleButtonWithTextDisabled( - 'Link New Device' - ), + linkDeviceButtonDisabled: commonPage.divRoleButtonWithTextDisabled('Link New Device'), qrImageDiv: commonPage.divWithClass('qr-image'), allowPairingButton: commonPage.divRoleButtonWithText('Allow Linking'), okButton: commonPage.divRoleButtonWithText('OK'), devicePairedDescription: (secretWords: string) => - commonPage.divWithClassAndText( - 'session-settings-item__description', - secretWords - ), + commonPage.divWithClassAndText('session-settings-item__description', secretWords), unpairDeviceButton: commonPage.divRoleButtonDangerWithText('Unlink Device'), deleteAccountButton: commonPage.divRoleButtonDangerWithText('Delete Account'), validateUnpairDevice: commonPage.divRoleButtonDangerWithText('Unlink'), diff --git a/ts/test/session/integration/page-objects/registration.page.ts b/ts/test/session/integration/page-objects/registration.page.ts index 2d7e7ae7ba1383bdff95b0ed69a881af3aeee288..35b9cf7bf5d73b06e95ed2d1867306ae079c951c 100644 --- a/ts/test/session/integration/page-objects/registration.page.ts +++ b/ts/test/session/integration/page-objects/registration.page.ts @@ -7,32 +7,21 @@ export = { // create new account createSessionIDButton: commonPage.divRoleButtonWithText('Create Session ID'), continueButton: commonPage.divRoleButtonWithText('Continue'), - textareaGeneratedPubkey: - '//textarea[contains(@class, "session-id-editable-textarea")]', + textareaGeneratedPubkey: '//textarea[contains(@class, "session-id-editable-textarea")]', getStartedButton: commonPage.divRoleButtonWithText('Get started'), // restore from seed - restoreFromSeedMode: commonPage.divRoleButtonWithText( - 'Restore From Recovery' - ), + restoreFromSeedMode: commonPage.divRoleButtonWithText('Restore From Recovery'), recoveryPhraseInput: commonPage.inputWithPlaceholder('Enter Recovery Phrase'), displayNameInput: commonPage.inputWithPlaceholder('Enter a display name'), passwordInput: commonPage.inputWithPlaceholder('Enter password (optional)'), - continueSessionButton: commonPage.divRoleButtonWithText( - 'Continue Your Session' - ), - conversationListContainer: commonPage.divWithClass( - 'module-conversations-list-content' - ), + continueSessionButton: commonPage.divRoleButtonWithText('Continue Your Session'), + conversationListContainer: commonPage.divWithClass('module-conversations-list-content'), // device linking - linkDeviceMode: commonPage.divRoleButtonWithText( - 'Link Device to Existing Session ID' - ), - textareaLinkDevicePubkey: commonPage.textAreaWithPlaceholder( - 'Enter your Session ID' - ), + linkDeviceMode: commonPage.divRoleButtonWithText('Link Device to Existing Session ID'), + textareaLinkDevicePubkey: commonPage.textAreaWithPlaceholder('Enter your Session ID'), linkDeviceTriggerButton: commonPage.divRoleButtonWithText('Link Device'), toastWrapper: '//*[contains(@class,"session-toast-wrapper")]', secretWordsText: diff --git a/ts/test/session/integration/registration_itest.ts b/ts/test/session/integration/registration_itest.ts index 6f23d2ea091fd91852c86c85e59ca27fa754771a..8e36d2ef7b449e9f504cc3c3ab0ef45b13413d41 100644 --- a/ts/test/session/integration/registration_itest.ts +++ b/ts/test/session/integration/registration_itest.ts @@ -35,9 +35,7 @@ describe('Window Test and Login', function() { it('registration: window title is correct', async () => { app = await Common.startAndAssureCleanedApp(); - app.client - .getTitle() - .should.eventually.be.equal('Session - test-integration-session'); + app.client.getTitle().should.eventually.be.equal('Session - test-integration-session'); }); it('registration: can restore from seed', async () => { @@ -48,9 +46,7 @@ describe('Window Test and Login', function() { await app.client .element(RegistrationPage.recoveryPhraseInput) .setValue(Common.TEST_RECOVERY_PHRASE_1); - await app.client - .element(RegistrationPage.displayNameInput) - .setValue(Common.TEST_DISPLAY_NAME1); + await app.client.element(RegistrationPage.displayNameInput).setValue(Common.TEST_DISPLAY_NAME1); // validate fields are filled await app.client @@ -64,10 +60,7 @@ describe('Window Test and Login', function() { // trigger login await app.client.element(RegistrationPage.continueSessionButton).click(); - await app.client.waitForExist( - RegistrationPage.conversationListContainer, - 4000 - ); + await app.client.waitForExist(RegistrationPage.conversationListContainer, 4000); await Common.timeout(2000); @@ -88,16 +81,10 @@ describe('Window Test and Login', function() { pubkeyGenerated.should.have.lengthOf(66); pubkeyGenerated.substr(0, 2).should.be.equal('05'); await app.client.element(RegistrationPage.continueButton).click(); - await app.client.isExisting(RegistrationPage.displayNameInput).should - .eventually.be.true; - await app.client - .element(RegistrationPage.displayNameInput) - .setValue(Common.TEST_DISPLAY_NAME1); + await app.client.isExisting(RegistrationPage.displayNameInput).should.eventually.be.true; + await app.client.element(RegistrationPage.displayNameInput).setValue(Common.TEST_DISPLAY_NAME1); await app.client.element(RegistrationPage.getStartedButton).click(); - await app.client.waitForExist( - ConversationPage.conversationButtonSection, - 5000 - ); + await app.client.waitForExist(ConversationPage.conversationButtonSection, 5000); await app.webContents .executeJavaScript("window.storage.get('primaryDevicePubKey')") @@ -112,10 +99,7 @@ describe('Window Test and Login', function() { }; app = await Common.startAndStub(login); - await app.client.waitForExist( - RegistrationPage.conversationListContainer, - 4000 - ); + await app.client.waitForExist(RegistrationPage.conversationListContainer, 4000); await app.webContents .executeJavaScript("window.storage.get('primaryDevicePubKey')") @@ -123,8 +107,8 @@ describe('Window Test and Login', function() { // delete account await app.client.element(SettingsPage.settingsButtonSection).click(); await app.client.element(ConversationPage.deleteAccountButton).click(); - await app.client.isExisting(ConversationPage.descriptionDeleteAccount) - .should.eventually.be.true; + await app.client.isExisting(ConversationPage.descriptionDeleteAccount).should.eventually.be + .true; // click on the modal OK button to delete the account await app.client.element(ConversationPage.validateDeleteAccount).click(); // wait for the app restart @@ -142,7 +126,7 @@ describe('Window Test and Login', function() { .executeJavaScript("window.storage.get('primaryDevicePubKey')") .should.eventually.be.equal(null); // and that the conversation list is not shown - await app.client.isExisting(RegistrationPage.conversationListContainer) - .should.eventually.be.false; + await app.client.isExisting(RegistrationPage.conversationListContainer).should.eventually.be + .false; }); }); diff --git a/ts/test/session/integration/sender_keys_itest.ts b/ts/test/session/integration/sender_keys_itest.ts index 3dfbe068bb40b49da2fa3534c9717d5790301746..3fb1f91765221e5ee367411df0d2dc2f0db666a5 100644 --- a/ts/test/session/integration/sender_keys_itest.ts +++ b/ts/test/session/integration/sender_keys_itest.ts @@ -12,9 +12,7 @@ import ConversationPage from './page-objects/conversation.page'; async function generateAndSendMessage(app: Application) { // send a message from app and validate it is received on app2 const textMessage = Common.generateSendMessageText(); - await app.client - .element(ConversationPage.sendMessageTextarea) - .setValue(textMessage); + await app.client.element(ConversationPage.sendMessageTextarea).setValue(textMessage); await app.client .element(ConversationPage.sendMessageTextarea) @@ -24,18 +22,12 @@ async function generateAndSendMessage(app: Application) { await app.client.keys('Enter'); // validate that the message has been added to the message list view - await app.client.waitForExist( - ConversationPage.existingSendMessageText(textMessage), - 2000 - ); + await app.client.waitForExist(ConversationPage.existingSendMessageText(textMessage), 2000); return textMessage; } -async function makeFriendsPlusMessage( - app: Application, - [app2, pubkey]: [Application, string] -) { +async function makeFriendsPlusMessage(app: Application, [app2, pubkey]: [Application, string]) { await Common.makeFriends(app, [app2, pubkey]); // Send something back so that `app` can see our name @@ -43,10 +35,7 @@ async function makeFriendsPlusMessage( await app2.client.element(ConversationPage.conversationItem).click(); const text = await generateAndSendMessage(app2); - await app.client.waitForExist( - ConversationPage.existingReceivedMessageText(text), - 8000 - ); + await app.client.waitForExist(ConversationPage.existingReceivedMessageText(text), 8000); // Click away so we can call this function again await app.client.element(ConversationPage.conversationButtonSection).click(); @@ -61,20 +50,14 @@ async function testTwoMembers() { const text1 = await generateAndSendMessage(app); // validate that the message has been added to the message list view - await app2.client.waitForExist( - ConversationPage.existingReceivedMessageText(text1), - 5000 - ); + await app2.client.waitForExist(ConversationPage.existingReceivedMessageText(text1), 5000); // Send a message back: const text2 = await generateAndSendMessage(app2); // TODO: fix this. We can send messages back manually, not sure // why this test fails - await app.client.waitForExist( - ConversationPage.existingReceivedMessageText(text2), - 10000 - ); + await app.client.waitForExist(ConversationPage.existingReceivedMessageText(text2), 10000); } async function testThreeMembers() { @@ -115,14 +98,8 @@ async function testThreeMembers() { // 4. Test that all members can see the message from app1 const text1 = await generateAndSendMessage(app1); - await app2.client.waitForExist( - ConversationPage.existingReceivedMessageText(text1), - 5000 - ); - await app3.client.waitForExist( - ConversationPage.existingReceivedMessageText(text1), - 5000 - ); + await app2.client.waitForExist(ConversationPage.existingReceivedMessageText(text1), 5000); + await app3.client.waitForExist(ConversationPage.existingReceivedMessageText(text1), 5000); // TODO: test that B and C can send messages to the group // const text2 = await generateAndSendMessage(app3); diff --git a/ts/test/session/integration/settings_itest.ts b/ts/test/session/integration/settings_itest.ts index eabdb6a0b85d8fc9961de41d6d93a633eb3edcce..6dbe58330a2a6ef926a0fa6c708af9fb995d37e8 100644 --- a/ts/test/session/integration/settings_itest.ts +++ b/ts/test/session/integration/settings_itest.ts @@ -44,9 +44,7 @@ describe('Settings', function() { const menuBarVisible = await app.browserWindow.isMenuBarVisible(); await app.client.element(SettingsPage.settingsButtonSection).click(); - await app.client - .element(SettingsPage.settingToggleWithText('Hide Menu Bar')) - .click(); + await app.client.element(SettingsPage.settingToggleWithText('Hide Menu Bar')).click(); // Confirm that toggling works const menuBarToggled = await app.browserWindow.isMenuBarVisible(); @@ -54,19 +52,11 @@ describe('Settings', function() { }); it('settings: can set password', async () => { - await app.client - .element(SettingsPage.settingsRowWithText('Privacy')) - .click(); + await app.client.element(SettingsPage.settingsRowWithText('Privacy')).click(); - await app.client - .element(SettingsPage.settingButtonWithText('Set Password')) - .click(); + await app.client.element(SettingsPage.settingButtonWithText('Set Password')).click(); - await Common.setValueWrapper( - app, - CommonPage.inputWithId(passwordInputID), - password - ); + await Common.setValueWrapper(app, CommonPage.inputWithId(passwordInputID), password); await Common.setValueWrapper( app, CommonPage.inputWithId(`${passwordInputID}-confirm`), @@ -76,46 +66,29 @@ describe('Settings', function() { await app.client.keys('Enter'); // Verify password set - await app.client.waitForExist( - CommonPage.toastWithText('Set Password'), - 2000 - ); + await app.client.waitForExist(CommonPage.toastWithText('Set Password'), 2000); await Common.closeToast(app); }); it('settings: can remove password', async () => { // Enter password to unlock settings - await Common.setValueWrapper( - app, - CommonPage.inputWithId('password-lock-input'), - password - ); + await Common.setValueWrapper(app, CommonPage.inputWithId('password-lock-input'), password); await app.client.keys('Enter'); // Remove password - await app.client - .element(SettingsPage.settingButtonWithText('Remove Password')) - .click(); + await app.client.element(SettingsPage.settingButtonWithText('Remove Password')).click(); - await Common.setValueWrapper( - app, - CommonPage.inputWithId(passwordInputID), - password - ); + await Common.setValueWrapper(app, CommonPage.inputWithId(passwordInputID), password); await app.client.keys('Enter'); // Verify password removed with toast - await app.client.waitForExist( - CommonPage.toastWithText('Removed Password'), - 2000 - ); + await app.client.waitForExist(CommonPage.toastWithText('Removed Password'), 2000); // Verify password actully removed - await app.client.isExisting( - CommonPage.divWithClass('session-settings__password-lock') - ).should.eventually.be.false; + await app.client.isExisting(CommonPage.divWithClass('session-settings__password-lock')).should + .eventually.be.false; }); }); diff --git a/ts/test/session/integration/stubs/stub_app_dot_net_api.ts b/ts/test/session/integration/stubs/stub_app_dot_net_api.ts index 73a2805543b0ffa23963a566f4a26c2d84889cdd..dcc69f813f129d42d2ce63326182bf990fd0526f 100644 --- a/ts/test/session/integration/stubs/stub_app_dot_net_api.ts +++ b/ts/test/session/integration/stubs/stub_app_dot_net_api.ts @@ -34,8 +34,7 @@ const samplesGetMessages = { ], user: { id: 2448, - username: - '050cd79763303bcc251bd489a6f7da823a2b8555402b01a7959ebca550d048600f', + username: '050cd79763303bcc251bd489a6f7da823a2b8555402b01a7959ebca550d048600f', created_at: '2020-03-18T02:42:05.000Z', canonical_url: null, type: null, @@ -68,10 +67,7 @@ const samplesGetMessages = { class StubAppDotNetAPI extends LokiAppDotNetServerAPI { // make a request to the server - public async serverRequest( - endpoint: string, - options: { method?: string } = {} - ) { + public async serverRequest(endpoint: string, options: { method?: string } = {}) { const { method } = options; if (endpoint === 'channels/1/messages') { @@ -92,10 +88,7 @@ class StubAppDotNetAPI extends LokiAppDotNetServerAPI { }; } - if ( - endpoint === 'loki/v1/channel/1/deletes' || - endpoint === 'loki/v1/channel/1/moderators' - ) { + if (endpoint === 'loki/v1/channel/1/deletes' || endpoint === 'loki/v1/channel/1/moderators') { return { statusCode: 200, response: { diff --git a/ts/test/session/integration/stubs/stub_message_api.ts b/ts/test/session/integration/stubs/stub_message_api.ts index 352b9a328907f8facfadbf83b18588e542ea1fc9..9eb430bf14db2738f6bfd46aa32cac24a2f20e48 100644 --- a/ts/test/session/integration/stubs/stub_message_api.ts +++ b/ts/test/session/integration/stubs/stub_message_api.ts @@ -28,9 +28,7 @@ class StubMessageAPI { await insecureNodeFetch( `${ this.baseUrl - }/messages?pubkey=${pubKey}×tamp=${messageTimeStamp}&data=${encodeURIComponent( - data64 - )}`, + }/messages?pubkey=${pubKey}×tamp=${messageTimeStamp}&data=${encodeURIComponent(data64)}`, post ); } diff --git a/ts/test/session/unit/attachments/attachments_test.ts b/ts/test/session/unit/attachments/attachments_test.ts index c3861068c02b72facca4525f910a1cee1d6441e4..deb602f38db76e34946bdba220d441174126befa 100644 --- a/ts/test/session/unit/attachments/attachments_test.ts +++ b/ts/test/session/unit/attachments/attachments_test.ts @@ -5,10 +5,7 @@ import { assert } from 'chai'; import * as Attachments from '../../../../attachments/attachments'; import { stringToArrayBuffer } from '../../../../session/utils/String'; -import { - decryptAttachmentBuffer, - encryptAttachmentBuffer, -} from '../../../../types/Attachment'; +import { decryptAttachmentBuffer, encryptAttachmentBuffer } from '../../../../types/Attachment'; import { TestUtils } from '../../../test-utils'; const PREFIX_LENGTH = 2; @@ -24,8 +21,7 @@ describe('Attachments', () => { tempRootDirectory = tmp.dirSync().name; TestUtils.stubWindow('textsecure', { storage: { - get: () => - '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef', + get: () => '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef', }, }); }); @@ -37,20 +33,13 @@ describe('Attachments', () => { it('should write file to disk and return path', async () => { const input = stringToArrayBuffer('test string'); - const tempDirectory = path.join( - tempRootDirectory, - 'Attachments_createWriterForNew' - ); - const outputPath = await Attachments.createWriterForNew(tempDirectory)( - input - ); + const tempDirectory = path.join(tempRootDirectory, 'Attachments_createWriterForNew'); + const outputPath = await Attachments.createWriterForNew(tempDirectory)(input); const output = await fse.readFile(path.join(tempDirectory, outputPath)); assert.lengthOf(outputPath, PATH_LENGTH); - const outputDecrypted = Buffer.from( - await decryptAttachmentBuffer(output.buffer) - ); + const outputDecrypted = Buffer.from(await decryptAttachmentBuffer(output.buffer)); const inputBuffer = Buffer.from(input); assert.deepEqual(inputBuffer, outputDecrypted); @@ -63,8 +52,7 @@ describe('Attachments', () => { tempRootDirectory = tmp.dirSync().name; TestUtils.stubWindow('textsecure', { storage: { - get: () => - '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef', + get: () => '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef', }, }); }); @@ -76,37 +64,25 @@ describe('Attachments', () => { it('should write file to disk on given path and return path', async () => { const input = stringToArrayBuffer('test string'); - const tempDirectory = path.join( - tempRootDirectory, - 'Attachments_createWriterForExisting' - ); - - const relativePath = Attachments.getRelativePath( - Attachments.createName() - ); + const tempDirectory = path.join(tempRootDirectory, 'Attachments_createWriterForExisting'); + + const relativePath = Attachments.getRelativePath(Attachments.createName()); const attachment = { path: relativePath, data: input, }; - const outputPath = await Attachments.createWriterForExisting( - tempDirectory - )(attachment); + const outputPath = await Attachments.createWriterForExisting(tempDirectory)(attachment); const output = await fse.readFile(path.join(tempDirectory, outputPath)); assert.equal(outputPath, relativePath); - const outputDecrypted = Buffer.from( - await decryptAttachmentBuffer(output.buffer) - ); + const outputDecrypted = Buffer.from(await decryptAttachmentBuffer(output.buffer)); const inputBuffer = Buffer.from(input); assert.deepEqual(inputBuffer, outputDecrypted); }); it('throws if relative path goes higher than root', async () => { const input = stringToArrayBuffer('test string'); - const tempDirectory = path.join( - tempRootDirectory, - 'Attachments_createWriterForExisting' - ); + const tempDirectory = path.join(tempRootDirectory, 'Attachments_createWriterForExisting'); const relativePath = '../../parent'; const attachment = { @@ -130,8 +106,7 @@ describe('Attachments', () => { tempRootDirectory = tmp.dirSync().name; TestUtils.stubWindow('textsecure', { storage: { - get: () => - '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef', + get: () => '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef', }, }); }); @@ -142,14 +117,9 @@ describe('Attachments', () => { }); it('should read file from disk', async () => { - const tempDirectory = path.join( - tempRootDirectory, - 'Attachments_createReader' - ); - - const relativePath = Attachments.getRelativePath( - Attachments.createName() - ); + const tempDirectory = path.join(tempRootDirectory, 'Attachments_createReader'); + + const relativePath = Attachments.getRelativePath(Attachments.createName()); const fullPath = path.join(tempDirectory, relativePath); const input = stringToArrayBuffer('test string'); @@ -158,17 +128,12 @@ describe('Attachments', () => { const inputBuffer = Buffer.from(encryptedInput.encryptedBufferWithHeader); await fse.ensureFile(fullPath); await fse.writeFile(fullPath, inputBuffer); - const outputDecrypted = await Attachments.createReader(tempDirectory)( - relativePath - ); + const outputDecrypted = await Attachments.createReader(tempDirectory)(relativePath); assert.deepEqual(new Uint8Array(input), new Uint8Array(outputDecrypted)); }); it('throws if relative path goes higher than root', async () => { - const tempDirectory = path.join( - tempRootDirectory, - 'Attachments_createReader' - ); + const tempDirectory = path.join(tempRootDirectory, 'Attachments_createReader'); const relativePath = '../../parent'; @@ -194,14 +159,9 @@ describe('Attachments', () => { }); it('should delete file from disk', async () => { - const tempDirectory = path.join( - tempRootDirectory, - 'Attachments_createDeleter' - ); - - const relativePath = Attachments.getRelativePath( - Attachments.createName() - ); + const tempDirectory = path.join(tempRootDirectory, 'Attachments_createDeleter'); + + const relativePath = Attachments.getRelativePath(Attachments.createName()); const fullPath = path.join(tempDirectory, relativePath); const input = stringToArrayBuffer('test string'); @@ -215,10 +175,7 @@ describe('Attachments', () => { }); it('throws if relative path goes higher than root', async () => { - const tempDirectory = path.join( - tempRootDirectory, - 'Attachments_createDeleter' - ); + const tempDirectory = path.join(tempRootDirectory, 'Attachments_createDeleter'); const relativePath = '../../parent'; @@ -241,8 +198,7 @@ describe('Attachments', () => { describe('getRelativePath', () => { it('should return correct path', () => { - const name = - '608ce3bc536edbf7637a6aeb6040bdfec49349140c0dd43e97c7ce263b15ff7e'; + const name = '608ce3bc536edbf7637a6aeb6040bdfec49349140c0dd43e97c7ce263b15ff7e'; assert.lengthOf(Attachments.getRelativePath(name), PATH_LENGTH); }); }); @@ -256,10 +212,7 @@ describe('Attachments', () => { const pathGetter = Attachments.createAbsolutePathGetter(root); const absolutePath = pathGetter(relative); - assert.strictEqual( - absolutePath, - isWindows ? 'C:\\temp\\ab\\abcdef' : '/tmp/ab/abcdef' - ); + assert.strictEqual(absolutePath, isWindows ? 'C:\\temp\\ab\\abcdef' : '/tmp/ab/abcdef'); }); it('throws if relative path goes higher than root', () => { diff --git a/ts/test/session/unit/crypto/MessageEncrypter_test.ts b/ts/test/session/unit/crypto/MessageEncrypter_test.ts index 4e38afef5a713f4731404b9b5a700172eadc5626..b5697e913aef32f13799fa84833cfa7f67e91c9d 100644 --- a/ts/test/session/unit/crypto/MessageEncrypter_test.ts +++ b/ts/test/session/unit/crypto/MessageEncrypter_test.ts @@ -1,11 +1,7 @@ import chai, { expect } from 'chai'; import * as crypto from 'crypto'; import * as sinon from 'sinon'; -import { - concatUInt8Array, - getSodium, - MessageEncrypter, -} from '../../../../session/crypto'; +import { concatUInt8Array, getSodium, MessageEncrypter } from '../../../../session/crypto'; import { EncryptionType } from '../../../../session/types/EncryptionType'; import { Stubs, TestUtils } from '../../../test-utils'; import { SignalService } from '../../../../protobuf'; @@ -118,9 +114,7 @@ describe('MessageEncrypter', () => { }); sandbox.stub(UserUtils, 'getOurPubKeyStrFromCache').returns(ourNumber); - sandbox - .stub(UserUtils, 'getUserED25519KeyPair') - .resolves(ourUserEd25516Keypair); + sandbox.stub(UserUtils, 'getUserED25519KeyPair').resolves(ourUserEd25516Keypair); }); afterEach(() => { @@ -136,9 +130,7 @@ describe('MessageEncrypter', () => { privateHex: '0123456789abcdef', }; - TestUtils.stubData('getLatestClosedGroupEncryptionKeyPair').resolves( - hexKeyPair - ); + TestUtils.stubData('getLatestClosedGroupEncryptionKeyPair').resolves(hexKeyPair); const data = crypto.randomBytes(10); @@ -183,9 +175,7 @@ describe('MessageEncrypter', () => { beforeEach(() => { sandboxSessionProtocol = sinon.createSandbox(); - sandboxSessionProtocol - .stub(UserUtils, 'getIdentityKeyPair') - .resolves(ourIdentityKeypair); + sandboxSessionProtocol.stub(UserUtils, 'getIdentityKeyPair').resolves(ourIdentityKeypair); }); afterEach(() => { @@ -195,11 +185,7 @@ describe('MessageEncrypter', () => { it('should pass the padded message body to encrypt', async () => { const data = crypto.randomBytes(10); const spy = sinon.spy(MessageEncrypter, 'encryptUsingSessionProtocol'); - await MessageEncrypter.encrypt( - TestUtils.generateFakePubKey(), - data, - EncryptionType.Fallback - ); + await MessageEncrypter.encrypt(TestUtils.generateFakePubKey(), data, EncryptionType.Fallback); chai.expect(spy.callCount).to.be.equal(1); const paddedData = MessageEncrypter.padPlainTextBuffer(data); const firstArgument = new Uint8Array(spy.args[0][1]); @@ -211,41 +197,26 @@ describe('MessageEncrypter', () => { const keypair = await UserUtils.getUserED25519KeyPair(); const recipient = TestUtils.generateFakePubKey(); const sodium = await getSodium(); - const cryptoSignDetachedSpy = sandboxSessionProtocol.spy( - sodium, - 'crypto_sign_detached' - ); + const cryptoSignDetachedSpy = sandboxSessionProtocol.spy(sodium, 'crypto_sign_detached'); const plainText = '123456'; - const plainTextBytes = new Uint8Array( - StringUtils.encode(plainText, 'utf8') - ); + const plainTextBytes = new Uint8Array(StringUtils.encode(plainText, 'utf8')); const userED25519PubKeyBytes = new Uint8Array( // tslint:disable: no-non-null-assertion StringUtils.fromHex(keypair!.pubKey) ); - const recipientX25519PublicKeyWithoutPrefix = PubKey.remove05PrefixIfNeeded( - recipient.key - ); + const recipientX25519PublicKeyWithoutPrefix = PubKey.remove05PrefixIfNeeded(recipient.key); const recipientX25519PublicKey = new Uint8Array( StringUtils.fromHex(recipientX25519PublicKeyWithoutPrefix) ); - await MessageEncrypter.encryptUsingSessionProtocol( - recipient, - plainTextBytes - ); - const [ - dataForSign, - userED25519SecretKeyBytes, - ] = cryptoSignDetachedSpy.args[0]; - const userEdPrivkeyBytes = new Uint8Array( - StringUtils.fromHex(keypair!.privKey) - ); + await MessageEncrypter.encryptUsingSessionProtocol(recipient, plainTextBytes); + const [dataForSign, userED25519SecretKeyBytes] = cryptoSignDetachedSpy.args[0]; + const userEdPrivkeyBytes = new Uint8Array(StringUtils.fromHex(keypair!.privKey)); expect(userED25519SecretKeyBytes).to.equalBytes(userEdPrivkeyBytes); // dataForSign must be plaintext | userED25519PubKeyBytes | recipientX25519PublicKey - expect( - (dataForSign as Uint8Array).subarray(0, plainTextBytes.length) - ).to.equalBytes(plainTextBytes); + expect((dataForSign as Uint8Array).subarray(0, plainTextBytes.length)).to.equalBytes( + plainTextBytes + ); expect( (dataForSign as Uint8Array).subarray( plainTextBytes.length, @@ -255,9 +226,7 @@ describe('MessageEncrypter', () => { // the recipient pubkey must have its 05 prefix removed expect( - (dataForSign as Uint8Array).subarray( - plainTextBytes.length + userED25519PubKeyBytes.length - ) + (dataForSign as Uint8Array).subarray(plainTextBytes.length + userED25519PubKeyBytes.length) ).to.equalBytes(recipientX25519PublicKey); }); @@ -266,9 +235,7 @@ describe('MessageEncrypter', () => { const userX25519KeyPair = await UserUtils.getIdentityKeyPair(); const userEd25519KeyPair = await UserUtils.getUserED25519KeyPair(); - const plainTextBytes = new Uint8Array( - StringUtils.encode('123456789', 'utf8') - ); + const plainTextBytes = new Uint8Array(StringUtils.encode('123456789', 'utf8')); const sodium = await getSodium(); @@ -277,9 +244,7 @@ describe('MessageEncrypter', () => { const recipientX25519PublicKeyWithoutPrefix = PubKey.remove05PrefixIfNeeded( recipientX25519PublicKeyHex ); - const recipientX25519PublicKey = new PubKey( - recipientX25519PublicKeyWithoutPrefix - ); + const recipientX25519PublicKey = new PubKey(recipientX25519PublicKeyWithoutPrefix); const ciphertext = await MessageEncrypter.encryptUsingSessionProtocol( recipientX25519PublicKey, plainTextBytes @@ -297,19 +262,13 @@ describe('MessageEncrypter', () => { const ed25519PublicKeySize = sodium.crypto_sign_PUBLICKEYBYTES; const signatureStart = plaintextWithMetadata.byteLength - signatureSize; const signature = plaintextWithMetadata.subarray(signatureStart); - const pubkeyStart = - plaintextWithMetadata.byteLength - - (signatureSize + ed25519PublicKeySize); + const pubkeyStart = plaintextWithMetadata.byteLength - (signatureSize + ed25519PublicKeySize); const pubkeyEnd = plaintextWithMetadata.byteLength - signatureSize; // this should be ours ed25519 pubkey - const senderED25519PublicKey = plaintextWithMetadata.subarray( - pubkeyStart, - pubkeyEnd - ); + const senderED25519PublicKey = plaintextWithMetadata.subarray(pubkeyStart, pubkeyEnd); const plainTextEnd = - plaintextWithMetadata.byteLength - - (signatureSize + ed25519PublicKeySize); + plaintextWithMetadata.byteLength - (signatureSize + ed25519PublicKeySize); const plaintextDecoded = plaintextWithMetadata.subarray(0, plainTextEnd); expect(plaintextDecoded).to.equalBytes(plainTextBytes); diff --git a/ts/test/session/unit/messages/ChatMessage_test.ts b/ts/test/session/unit/messages/ChatMessage_test.ts index ab6f70e8f6e55550a623da06f943011fe2d66c98..8896bb21514d0587596839946ee91287ca2923d7 100644 --- a/ts/test/session/unit/messages/ChatMessage_test.ts +++ b/ts/test/session/unit/messages/ChatMessage_test.ts @@ -79,10 +79,7 @@ describe('VisibleMessage', () => { const decoded = SignalService.Content.decode(plainText); const decodedID = toNumber(decoded.dataMessage?.quote?.id); expect(decodedID).to.be.equal(1234); - expect(decoded.dataMessage?.quote).to.have.deep.property( - 'author', - 'author' - ); + expect(decoded.dataMessage?.quote).to.have.deep.property('author', 'author'); expect(decoded.dataMessage?.quote).to.have.deep.property('text', 'text'); }); @@ -141,9 +138,6 @@ describe('VisibleMessage', () => { timestamp: Date.now(), }); expect(message.identifier).to.not.equal(null, 'identifier cannot be null'); - expect(message.identifier).to.not.equal( - undefined, - 'identifier cannot be undefined' - ); + expect(message.identifier).to.not.equal(undefined, 'identifier cannot be undefined'); }); }); diff --git a/ts/test/session/unit/messages/ClosedGroupChatMessage_test.ts b/ts/test/session/unit/messages/ClosedGroupChatMessage_test.ts index f08c0bb373bcd1b788a9d6141dc2158b9b038de9..c17d76f96ce80c6eded75b7f127d22f03808f10a 100644 --- a/ts/test/session/unit/messages/ClosedGroupChatMessage_test.ts +++ b/ts/test/session/unit/messages/ClosedGroupChatMessage_test.ts @@ -28,12 +28,7 @@ describe('ClosedGroupVisibleMessage', () => { .to.have.property('group') .to.have.deep.property( 'id', - new Uint8Array( - StringUtils.encode( - PubKey.PREFIX_GROUP_TEXTSECURE + groupId.key, - 'utf8' - ) - ) + new Uint8Array(StringUtils.encode(PubKey.PREFIX_GROUP_TEXTSECURE + groupId.key, 'utf8')) ); expect(decoded.dataMessage) .to.have.property('group') @@ -67,10 +62,7 @@ describe('ClosedGroupVisibleMessage', () => { chatMessage, }); expect(message.identifier).to.not.equal(null, 'identifier cannot be null'); - expect(message.identifier).to.not.equal( - undefined, - 'identifier cannot be undefined' - ); + expect(message.identifier).to.not.equal(undefined, 'identifier cannot be undefined'); }); it('should use the identifier passed into it over the one set in chatMessage', () => { diff --git a/ts/test/session/unit/messages/ConfigurationMessage_test.ts b/ts/test/session/unit/messages/ConfigurationMessage_test.ts index 8914ab549dc0f4685dde78c2bffee99136b1cbdc..0fb597084e7bd650782111012e0bd65e2d8e251a 100644 --- a/ts/test/session/unit/messages/ConfigurationMessage_test.ts +++ b/ts/test/session/unit/messages/ConfigurationMessage_test.ts @@ -19,9 +19,7 @@ describe('ConfigurationMessage', () => { displayName: 'displayName', contacts: [], }; - expect(() => new ConfigurationMessage(params)).to.throw( - 'closed group must be set' - ); + expect(() => new ConfigurationMessage(params)).to.throw('closed group must be set'); }); it('throw if open group is not set', () => { @@ -33,9 +31,7 @@ describe('ConfigurationMessage', () => { displayName: 'displayName', contacts: [], }; - expect(() => new ConfigurationMessage(params)).to.throw( - 'open group must be set' - ); + expect(() => new ConfigurationMessage(params)).to.throw('open group must be set'); }); it('throw if display name is not set', () => { @@ -46,9 +42,7 @@ describe('ConfigurationMessage', () => { displayName: undefined as any, contacts: [], }; - expect(() => new ConfigurationMessage(params)).to.throw( - 'displayName must be set' - ); + expect(() => new ConfigurationMessage(params)).to.throw('displayName must be set'); }); it('throw if display name is set but empty', () => { @@ -59,9 +53,7 @@ describe('ConfigurationMessage', () => { displayName: undefined as any, contacts: [], }; - expect(() => new ConfigurationMessage(params)).to.throw( - 'displayName must be set' - ); + expect(() => new ConfigurationMessage(params)).to.throw('displayName must be set'); }); it('ttl is 4 days', () => { @@ -130,9 +122,7 @@ describe('ConfigurationMessage', () => { encryptionKeyPair: TestUtils.generateFakeECKeyPair(), }; - expect(() => new ConfigurationMessageClosedGroup(params)).to.throw( - 'name must be set' - ); + expect(() => new ConfigurationMessageClosedGroup(params)).to.throw('name must be set'); }); it('throw if members is empty', () => { @@ -145,9 +135,7 @@ describe('ConfigurationMessage', () => { encryptionKeyPair: TestUtils.generateFakeECKeyPair(), }; - expect(() => new ConfigurationMessageClosedGroup(params)).to.throw( - 'members must be set' - ); + expect(() => new ConfigurationMessageClosedGroup(params)).to.throw('members must be set'); }); it('throw if admins is empty', () => { @@ -160,9 +148,7 @@ describe('ConfigurationMessage', () => { encryptionKeyPair: TestUtils.generateFakeECKeyPair(), }; - expect(() => new ConfigurationMessageClosedGroup(params)).to.throw( - 'admins must be set' - ); + expect(() => new ConfigurationMessageClosedGroup(params)).to.throw('admins must be set'); }); it('throw if some admins are not members', () => { @@ -191,9 +177,7 @@ describe('ConfigurationMessage', () => { displayName: 'displayName', contacts: undefined as any, }; - expect(() => new ConfigurationMessage(params)).to.throw( - 'contacts must be set' - ); + expect(() => new ConfigurationMessage(params)).to.throw('contacts must be set'); }); it('throw if some admins are not members', () => { const member = TestUtils.generateFakePubKey().key; diff --git a/ts/test/session/unit/messages/GroupInvitationMessage_test.ts b/ts/test/session/unit/messages/GroupInvitationMessage_test.ts index 55d02139ff186496e3258f058c8165f404461f57..6354461952246d002d11ac35ed9068db9882be46 100644 --- a/ts/test/session/unit/messages/GroupInvitationMessage_test.ts +++ b/ts/test/session/unit/messages/GroupInvitationMessage_test.ts @@ -25,18 +25,9 @@ describe('GroupInvitationMessage', () => { const plainText = message.plainTextBuffer(); const decoded = SignalService.Content.decode(plainText); - expect(decoded.dataMessage?.groupInvitation).to.have.property( - 'serverAddress', - serverAddress - ); - expect(decoded.dataMessage?.groupInvitation).to.have.property( - 'channelId', - channelId - ); - expect(decoded.dataMessage?.groupInvitation).to.have.property( - 'serverName', - serverName - ); + expect(decoded.dataMessage?.groupInvitation).to.have.property('serverAddress', serverAddress); + expect(decoded.dataMessage?.groupInvitation).to.have.property('channelId', channelId); + expect(decoded.dataMessage?.groupInvitation).to.have.property('serverName', serverName); }); it('correct ttl', () => { @@ -45,9 +36,6 @@ describe('GroupInvitationMessage', () => { it('has an identifier', () => { expect(message.identifier).to.not.equal(null, 'identifier cannot be null'); - expect(message.identifier).to.not.equal( - undefined, - 'identifier cannot be undefined' - ); + expect(message.identifier).to.not.equal(undefined, 'identifier cannot be undefined'); }); }); diff --git a/ts/test/session/unit/messages/OpenGroupMessage_test.ts b/ts/test/session/unit/messages/OpenGroupMessage_test.ts index 0a834a1d802d67645900e1f78ea5179db2d1ea52..1b5c52b3bed278196721384e2b9567dfba2492b8 100644 --- a/ts/test/session/unit/messages/OpenGroupMessage_test.ts +++ b/ts/test/session/unit/messages/OpenGroupMessage_test.ts @@ -84,9 +84,6 @@ describe('OpenGroupMessage', () => { group, }); expect(message.identifier).to.not.equal(null, 'identifier cannot be null'); - expect(message.identifier).to.not.equal( - undefined, - 'identifier cannot be undefined' - ); + expect(message.identifier).to.not.equal(undefined, 'identifier cannot be undefined'); }); }); diff --git a/ts/test/session/unit/messages/ReceiptMessage_test.ts b/ts/test/session/unit/messages/ReceiptMessage_test.ts index 9d5aa5cfbad4f7b58a98c3ef43195ce52cc518ee..c13509427d79450a9ff99a961ff7fdc6be3ef7b4 100644 --- a/ts/test/session/unit/messages/ReceiptMessage_test.ts +++ b/ts/test/session/unit/messages/ReceiptMessage_test.ts @@ -24,9 +24,7 @@ describe('ReceiptMessage', () => { const decoded = SignalService.Content.decode(plainText); expect(decoded.receiptMessage).to.have.property('type', 1); - const decodedTimestamps = (decoded.receiptMessage?.timestamp ?? []).map( - toNumber - ); + const decodedTimestamps = (decoded.receiptMessage?.timestamp ?? []).map(toNumber); expect(decodedTimestamps).to.deep.equal(timestamps); }); @@ -35,27 +33,17 @@ describe('ReceiptMessage', () => { const decoded = SignalService.Content.decode(plainText); expect(decoded.receiptMessage).to.have.property('type', 0); - const decodedTimestamps = (decoded.receiptMessage?.timestamp ?? []).map( - toNumber - ); + const decodedTimestamps = (decoded.receiptMessage?.timestamp ?? []).map(toNumber); expect(decodedTimestamps).to.deep.equal(timestamps); }); it('correct ttl', () => { expect(readMessage.ttl()).to.equal(Constants.TTL_DEFAULT.REGULAR_MESSAGE); - expect(deliveryMessage.ttl()).to.equal( - Constants.TTL_DEFAULT.REGULAR_MESSAGE - ); + expect(deliveryMessage.ttl()).to.equal(Constants.TTL_DEFAULT.REGULAR_MESSAGE); }); it('has an identifier', () => { - expect(readMessage.identifier).to.not.equal( - null, - 'identifier cannot be null' - ); - expect(readMessage.identifier).to.not.equal( - undefined, - 'identifier cannot be undefined' - ); + expect(readMessage.identifier).to.not.equal(null, 'identifier cannot be null'); + expect(readMessage.identifier).to.not.equal(undefined, 'identifier cannot be undefined'); }); }); diff --git a/ts/test/session/unit/messages/TypingMessage_test.ts b/ts/test/session/unit/messages/TypingMessage_test.ts index 070c1087f514fa39546b7842cc05143bc8c2ab51..09ff2227798da414c70481b49f32fd0eeb0cef2f 100644 --- a/ts/test/session/unit/messages/TypingMessage_test.ts +++ b/ts/test/session/unit/messages/TypingMessage_test.ts @@ -73,9 +73,6 @@ describe('TypingMessage', () => { isTyping: true, }); expect(message.identifier).to.not.equal(null, 'identifier cannot be null'); - expect(message.identifier).to.not.equal( - undefined, - 'identifier cannot be undefined' - ); + expect(message.identifier).to.not.equal(undefined, 'identifier cannot be undefined'); }); }); diff --git a/ts/test/session/unit/receiving/KeyPairRequestManager_test.ts b/ts/test/session/unit/receiving/KeyPairRequestManager_test.ts index 4f5d38bb3ff4bddc69030e6017d911a60b84c9e9..7270cb180ab0525fe6c74a7ac4dd8a88f6b5b028 100644 --- a/ts/test/session/unit/receiving/KeyPairRequestManager_test.ts +++ b/ts/test/session/unit/receiving/KeyPairRequestManager_test.ts @@ -68,8 +68,7 @@ describe('KeyPairRequestManager', () => { it('should return true if there is a timestamp set for this pubkey and it is more than DELAY_BETWEEN_TWO_REQUEST_MS', () => { const groupPubkey = TestUtils.generateFakePubKey(); - const timestamp1 = - Date.now() - KeyPairRequestManager.DELAY_BETWEEN_TWO_REQUEST_MS; + const timestamp1 = Date.now() - KeyPairRequestManager.DELAY_BETWEEN_TWO_REQUEST_MS; inst.markRequestSendFor(groupPubkey, timestamp1); const can = inst.canTriggerRequestWith(groupPubkey); diff --git a/ts/test/session/unit/sending/MessageQueue_test.ts b/ts/test/session/unit/sending/MessageQueue_test.ts index 4c5da075344a26cca3c6884731ed9c48734e3519..49bb2e2c816bbc73e5178d67c2918bb6b279e976 100644 --- a/ts/test/session/unit/sending/MessageQueue_test.ts +++ b/ts/test/session/unit/sending/MessageQueue_test.ts @@ -8,10 +8,7 @@ import { describe } from 'mocha'; import { GroupUtils, PromiseUtils, UserUtils } from '../../../../session/utils'; import { TestUtils } from '../../../../test/test-utils'; import { MessageQueue } from '../../../../session/sending/MessageQueue'; -import { - ContentMessage, - OpenGroupMessage, -} from '../../../../session/messages/outgoing'; +import { ContentMessage, OpenGroupMessage } from '../../../../session/messages/outgoing'; import { PubKey, RawMessage } from '../../../../session/types'; import { MessageSender } from '../../../../session/sending'; import { PendingMessageCacheStub } from '../../../test-utils/stubs'; @@ -39,11 +36,7 @@ describe('MessageQueue', () => { let messageQueueStub: MessageQueue; // Message Sender Stubs - let sendStub: sinon.SinonStub<[ - RawMessage, - (number | undefined)?, - (number | undefined)? - ]>; + let sendStub: sinon.SinonStub<[RawMessage, (number | undefined)?, (number | undefined)?]>; beforeEach(() => { // Utils Stubs @@ -85,11 +78,7 @@ describe('MessageQueue', () => { }); void pendingMessageCache - .add( - device, - TestUtils.generateVisibleMessage(), - waitForMessageSentEvent as any - ) + .add(device, TestUtils.generateVisibleMessage(), waitForMessageSentEvent as any) .then(async () => { return messageQueueStub.processPending(device); }) @@ -108,10 +97,7 @@ describe('MessageQueue', () => { } const device = TestUtils.generateFakePubKey(); - await pendingMessageCache.add( - device, - TestUtils.generateVisibleMessage() - ); + await pendingMessageCache.add(device, TestUtils.generateVisibleMessage()); const initialMessages = await pendingMessageCache.getForDevice(device); expect(initialMessages).to.have.length(1); @@ -134,9 +120,9 @@ describe('MessageQueue', () => { resolve(); try { expect(messageSentHandlerSuccessStub.callCount).to.be.equal(1); - expect( - messageSentHandlerSuccessStub.lastCall.args[0].identifier - ).to.be.equal(message.identifier); + expect(messageSentHandlerSuccessStub.lastCall.args[0].identifier).to.be.equal( + message.identifier + ); done(); } catch (e) { done(e); @@ -162,12 +148,10 @@ describe('MessageQueue', () => { if (messageSentHandlerFailedStub.callCount === 1) { try { expect(messageSentHandlerFailedStub.callCount).to.be.equal(1); - expect( - messageSentHandlerFailedStub.lastCall.args[0].identifier - ).to.be.equal(message.identifier); - expect( - messageSentHandlerFailedStub.lastCall.args[1].message - ).to.equal('failure'); + expect(messageSentHandlerFailedStub.lastCall.args[0].identifier).to.be.equal( + message.identifier + ); + expect(messageSentHandlerFailedStub.lastCall.args[1].message).to.equal('failure'); done(); } catch (e) { done(e); @@ -195,16 +179,14 @@ describe('MessageQueue', () => { describe('sendToGroup', () => { it('should throw an error if invalid non-group message was passed', async () => { const chatMessage = TestUtils.generateVisibleMessage(); - return expect( - messageQueueStub.sendToGroup(chatMessage as any) - ).to.be.rejectedWith('Invalid group message passed in sendToGroup.'); + return expect(messageQueueStub.sendToGroup(chatMessage as any)).to.be.rejectedWith( + 'Invalid group message passed in sendToGroup.' + ); }); describe('closed groups', () => { it('can send to closed group', async () => { - const members = TestUtils.generateFakePubKeys(4).map( - p => new PubKey(p.key) - ); + const members = TestUtils.generateFakePubKeys(4).map(p => new PubKey(p.key)); sandbox.stub(GroupUtils, 'getGroupMembers').resolves(members); const send = sandbox.stub(messageQueueStub, 'sendToPubKey').resolves(); @@ -246,15 +228,13 @@ describe('MessageQueue', () => { const message = TestUtils.generateOpenGroupMessage(); await messageQueueStub.sendToOpenGroup(message); expect(messageSentPublicHandlerSuccessStub.callCount).to.equal(1); - expect( - messageSentPublicHandlerSuccessStub.lastCall.args[0].identifier - ).to.equal(message.identifier); - expect( - messageSentPublicHandlerSuccessStub.lastCall.args[1].serverId - ).to.equal(5125); - expect( - messageSentPublicHandlerSuccessStub.lastCall.args[1].serverTimestamp - ).to.equal(5126); + expect(messageSentPublicHandlerSuccessStub.lastCall.args[0].identifier).to.equal( + message.identifier + ); + expect(messageSentPublicHandlerSuccessStub.lastCall.args[1].serverId).to.equal(5125); + expect(messageSentPublicHandlerSuccessStub.lastCall.args[1].serverTimestamp).to.equal( + 5126 + ); }); it('should emit a fail event if something went wrong', async () => { @@ -263,9 +243,9 @@ describe('MessageQueue', () => { await messageQueueStub.sendToOpenGroup(message); expect(messageSentHandlerFailedStub.callCount).to.equal(1); - expect( - messageSentHandlerFailedStub.lastCall.args[0].identifier - ).to.equal(message.identifier); + expect(messageSentHandlerFailedStub.lastCall.args[0].identifier).to.equal( + message.identifier + ); }); }); }); diff --git a/ts/test/session/unit/sending/MessageSender_test.ts b/ts/test/session/unit/sending/MessageSender_test.ts index 90da9290b9e7a6b0ffc3ebc4e5913af8d82b4fe3..977f80937b72be29145847d0137b6a47b8808e4e 100644 --- a/ts/test/session/unit/sending/MessageSender_test.ts +++ b/ts/test/session/unit/sending/MessageSender_test.ts @@ -28,10 +28,7 @@ describe('MessageSender', () => { 'We cannot send if lokiMessageAPI is not set' ); stub.set(sandbox.createStubInstance(LokiMessageAPI)); - expect(MessageSender.canSendToSnode()).to.equal( - true, - 'We can send if lokiMessageAPI is set' - ); + expect(MessageSender.canSendToSnode()).to.equal(true, 'We can send if lokiMessageAPI is set'); }); }); @@ -46,10 +43,7 @@ describe('MessageSender', () => { beforeEach(() => { // We can do this because LokiMessageAPI has a module export in it - lokiMessageAPISendStub = sandbox.stub< - [string, Uint8Array, number, number], - Promise<void> - >(); + lokiMessageAPISendStub = sandbox.stub<[string, Uint8Array, number, number], Promise<void>>(); TestUtils.stubWindow('lokiMessageAPI', { sendMessage: lokiMessageAPISendStub, }); @@ -103,8 +97,7 @@ describe('MessageSender', () => { }); describe('logic', () => { - let messageEncyrptReturnEnvelopeType = - SignalService.Envelope.Type.UNIDENTIFIED_SENDER; + let messageEncyrptReturnEnvelopeType = SignalService.Envelope.Type.UNIDENTIFIED_SENDER; beforeEach(() => { encryptStub.callsFake(async (_device, plainTextBuffer, _type) => ({ @@ -134,8 +127,7 @@ describe('MessageSender', () => { }); it('should correctly build the envelope', async () => { - messageEncyrptReturnEnvelopeType = - SignalService.Envelope.Type.UNIDENTIFIED_SENDER; + messageEncyrptReturnEnvelopeType = SignalService.Envelope.Type.UNIDENTIFIED_SENDER; // This test assumes the encryption stub returns the plainText passed into it. const device = TestUtils.generateFakePubKey().key; @@ -165,9 +157,7 @@ describe('MessageSender', () => { const envelope = SignalService.Envelope.decode( webSocketMessage.request?.body as Uint8Array ); - expect(envelope.type).to.equal( - SignalService.Envelope.Type.UNIDENTIFIED_SENDER - ); + expect(envelope.type).to.equal(SignalService.Envelope.Type.UNIDENTIFIED_SENDER); expect(envelope.source).to.equal(''); expect(toNumber(envelope.timestamp)).to.equal(timestamp); expect(envelope.content).to.deep.equal(plainTextBuffer); @@ -175,8 +165,7 @@ describe('MessageSender', () => { describe('UNIDENTIFIED_SENDER', () => { it('should set the envelope source to be empty', async () => { - messageEncyrptReturnEnvelopeType = - SignalService.Envelope.Type.UNIDENTIFIED_SENDER; + messageEncyrptReturnEnvelopeType = SignalService.Envelope.Type.UNIDENTIFIED_SENDER; // This test assumes the encryption stub returns the plainText passed into it. const device = TestUtils.generateFakePubKey().key; @@ -206,9 +195,7 @@ describe('MessageSender', () => { const envelope = SignalService.Envelope.decode( webSocketMessage.request?.body as Uint8Array ); - expect(envelope.type).to.equal( - SignalService.Envelope.Type.UNIDENTIFIED_SENDER - ); + expect(envelope.type).to.equal(SignalService.Envelope.Type.UNIDENTIFIED_SENDER); expect(envelope.source).to.equal( '', 'envelope source should be empty in UNIDENTIFIED_SENDER' diff --git a/ts/test/session/unit/sending/PendingMessageCache_test.ts b/ts/test/session/unit/sending/PendingMessageCache_test.ts index a09aece97da5a43d6b6fd5856435a324fcc3c899..28564857d27d2b4954b1ba41e6913973e6343e00 100644 --- a/ts/test/session/unit/sending/PendingMessageCache_test.ts +++ b/ts/test/session/unit/sending/PendingMessageCache_test.ts @@ -74,21 +74,12 @@ describe('PendingMessageCache', () => { it('can add multiple messages belonging to the same user', async () => { const device = TestUtils.generateFakePubKey(); - await pendingMessageCacheStub.add( - device, - TestUtils.generateVisibleMessage() - ); + await pendingMessageCacheStub.add(device, TestUtils.generateVisibleMessage()); // We have to timeout here otherwise it's processed too fast and messages start having the same timestamp await TestUtils.timeout(5); - await pendingMessageCacheStub.add( - device, - TestUtils.generateVisibleMessage() - ); + await pendingMessageCacheStub.add(device, TestUtils.generateVisibleMessage()); await TestUtils.timeout(5); - await pendingMessageCacheStub.add( - device, - TestUtils.generateVisibleMessage() - ); + await pendingMessageCacheStub.add(device, TestUtils.generateVisibleMessage()); // Verify that the message is in the cache const finalCache = await pendingMessageCacheStub.getAllPending(); @@ -126,10 +117,7 @@ describe('PendingMessageCache', () => { device, TestUtils.generateVisibleMessage(message.identifier) ); - const two = await pendingMessageCacheStub.add( - TestUtils.generateFakePubKey(), - message - ); + const two = await pendingMessageCacheStub.add(TestUtils.generateFakePubKey(), message); const initialCache = await pendingMessageCacheStub.getAllPending(); expect(initialCache).to.have.length(3); @@ -197,9 +185,7 @@ describe('PendingMessageCache', () => { // Get pending for each specific device for (const item of cacheItems) { - const pendingForDevice = await pendingMessageCacheStub.getForDevice( - item.device - ); + const pendingForDevice = await pendingMessageCacheStub.getForDevice(item.device); expect(pendingForDevice).to.have.length(1); expect(pendingForDevice[0].device).to.equal(item.device.key); } @@ -293,14 +279,8 @@ describe('PendingMessageCache', () => { // Pull out plainTextBuffer for a separate check const buffersCompare = - Buffer.compare( - message.plainTextBuffer, - addedMessage.plainTextBuffer - ) === 0; - expect(buffersCompare).to.equal( - true, - 'buffers were not loaded properly from database' - ); + Buffer.compare(message.plainTextBuffer, addedMessage.plainTextBuffer) === 0; + expect(buffersCompare).to.equal(true, 'buffers were not loaded properly from database'); // Compare all other valures const trimmedAdded = _.omit(addedMessage, ['plainTextBuffer']); diff --git a/ts/test/session/unit/utils/JobQueue_test.ts b/ts/test/session/unit/utils/JobQueue_test.ts index 4f3c29b8eeb4a81c124d19919479e6bb897d6b93..3b607bbabaa816bec3b0261b0978a7f978e5d495 100644 --- a/ts/test/session/unit/utils/JobQueue_test.ts +++ b/ts/test/session/unit/utils/JobQueue_test.ts @@ -40,17 +40,9 @@ describe('JobQueue', () => { }); const start = Date.now(); - await assert.eventually.deepEqual(Promise.all(input.map(mapper)), [ - 10, - 20, - 30, - ]); + await assert.eventually.deepEqual(Promise.all(input.map(mapper)), [10, 20, 30]); const timeTaken = Date.now() - start; - assert.isAtLeast( - timeTaken, - 20, - 'Queue should take atleast 100ms to run.' - ); + assert.isAtLeast(timeTaken, 20, 'Queue should take atleast 100ms to run.'); }); it('should return the result of the job', async () => { @@ -105,9 +97,7 @@ describe('JobQueue', () => { const queue = new JobQueue(); const id = uuid(); - const successfullJob = queue.addWithId(id, async () => - TestUtils.timeout(10) - ); + const successfullJob = queue.addWithId(id, async () => TestUtils.timeout(10)); assert.isTrue(queue.has(id)); await successfullJob; assert.isFalse(queue.has(id)); diff --git a/ts/test/session/unit/utils/Messages_test.ts b/ts/test/session/unit/utils/Messages_test.ts index 246cd25b78f142fe62b334453503074bd595e880..94a7a2c0f2e1fe987851258ce8ec8fda8d03750c 100644 --- a/ts/test/session/unit/utils/Messages_test.ts +++ b/ts/test/session/unit/utils/Messages_test.ts @@ -9,10 +9,7 @@ import { ClosedGroupVisibleMessage } from '../../../../session/messages/outgoing import { MockConversation } from '../../../test-utils/utils'; import { ConfigurationMessage } from '../../../../session/messages/outgoing/controlMessage/ConfigurationMessage'; -import { - ConversationModel, - ConversationType, -} from '../../../../models/conversation'; +import { ConversationModel, ConversationType } from '../../../../models/conversation'; import chaiAsPromised from 'chai-as-promised'; chai.use(chaiAsPromised as any); @@ -51,9 +48,7 @@ describe('Message Utils', () => { expect(rawMessage.identifier).to.equal(message.identifier); expect(rawMessage.device).to.equal(device.key); - expect(rawMessage.plainTextBuffer).to.deep.equal( - message.plainTextBuffer() - ); + expect(rawMessage.plainTextBuffer).to.deep.equal(message.plainTextBuffer()); expect(rawMessage.timestamp).to.equal(message.timestamp); expect(rawMessage.ttl).to.equal(message.ttl()); }); @@ -252,9 +247,7 @@ describe('Message Utils', () => { beforeEach(() => { convos = []; sandbox.stub(UserUtils, 'getOurPubKeyStrFromCache').resolves(ourNumber); - sandbox - .stub(UserUtils, 'getOurPubKeyFromCache') - .resolves(PubKey.cast(ourNumber)); + sandbox.stub(UserUtils, 'getOurPubKeyFromCache').resolves(PubKey.cast(ourNumber)); }); beforeEach(() => { diff --git a/ts/test/session/unit/utils/Password.ts b/ts/test/session/unit/utils/Password.ts index d27d66891ca439301beebe245394e04d115030e2..a5cca5a397e0e45a8d7e6f99b9225b8dae550665 100644 --- a/ts/test/session/unit/utils/Password.ts +++ b/ts/test/session/unit/utils/Password.ts @@ -50,10 +50,7 @@ describe('Password Util', () => { it('should return an error if password is not a string', () => { const invalid = [0, 123456, [], {}, null, undefined] as any; invalid.forEach((pass: any) => { - assert.strictEqual( - PasswordUtil.validatePassword(pass), - 'Password must be a string' - ); + assert.strictEqual(PasswordUtil.validatePassword(pass), 'Password must be a string'); }); }); diff --git a/ts/test/session/unit/utils/Promise_test.ts b/ts/test/session/unit/utils/Promise_test.ts index 9e54ef6ce9ccd4226913bb9fbb8874486eaa1629..7035d2b0ea2c10f027dda3e7d0db8afae723ab1e 100644 --- a/ts/test/session/unit/utils/Promise_test.ts +++ b/ts/test/session/unit/utils/Promise_test.ts @@ -67,9 +67,7 @@ describe('Promise Utils', () => { expect(pollSpy.callCount).to.equal(1); expect(completionSpy.callCount).to.equal(0); - return promise.should.eventually.be.rejectedWith( - 'Periodic check timeout' - ); + return promise.should.eventually.be.rejectedWith('Periodic check timeout'); }); it('will recur according to interval option', async () => { @@ -140,9 +138,7 @@ describe('Promise Utils', () => { const promise = PromiseUtils.waitUntil(check, 1); expect(waitUntilSpy.callCount).to.equal(1); - return promise.should.eventually.be.rejectedWith( - 'Periodic check timeout' - ); + return promise.should.eventually.be.rejectedWith('Periodic check timeout'); }); }); }); diff --git a/ts/test/session/unit/utils/String_test.ts b/ts/test/session/unit/utils/String_test.ts index 503a9023bd587aaa5f83396baf87d52db39e0275..b814e614fe494388f2b478033d6999b110c5d4b9 100644 --- a/ts/test/session/unit/utils/String_test.ts +++ b/ts/test/session/unit/utils/String_test.ts @@ -68,9 +68,9 @@ describe('String Utils', () => { const testString = ''; expect(testString).to.have.length(0); - const allEncodedings = (['base64', 'hex', 'binary', 'utf8'] as Array< - Encoding - >).map(e => StringUtils.encode(testString, e)); + const allEncodedings = (['base64', 'hex', 'binary', 'utf8'] as Array<Encoding>).map(e => + StringUtils.encode(testString, e) + ); allEncodedings.forEach(encoded => { expect(encoded instanceof ArrayBuffer).to.equal( @@ -87,9 +87,9 @@ describe('String Utils', () => { .fill('0') .join(''); - const allEncodedings = (['base64', 'hex', 'binary', 'utf8'] as Array< - Encoding - >).map(e => StringUtils.encode(testString, e)); + const allEncodedings = (['base64', 'hex', 'binary', 'utf8'] as Array<Encoding>).map(e => + StringUtils.encode(testString, e) + ); allEncodedings.forEach(encoded => { expect(encoded instanceof ArrayBuffer).to.equal( diff --git a/ts/test/test-utils/utils/envelope.ts b/ts/test/test-utils/utils/envelope.ts index 73b59ad4cdf243313ac015b3905cfde0479e07ad..3f21cb9c844d97a951a0c02a29e81b36b42985fa 100644 --- a/ts/test/test-utils/utils/envelope.ts +++ b/ts/test/test-utils/utils/envelope.ts @@ -4,10 +4,7 @@ import { SignalService } from '../../../protobuf'; import uuid from 'uuid'; import { fromHexToArray } from '../../../session/utils/String'; -export function generateEnvelopePlusClosedGroup( - groupId: string, - sender: string -): EnvelopePlus { +export function generateEnvelopePlusClosedGroup(groupId: string, sender: string): EnvelopePlus { const envelope: EnvelopePlus = { senderIdentity: sender, receivedAt: Date.now(), diff --git a/ts/test/test-utils/utils/message.ts b/ts/test/test-utils/utils/message.ts index c7ee4b52ca724f75da11b7ba044e77a520ddf0a2..468e0d2a861b928094a3ac1138b21162f6d15af6 100644 --- a/ts/test/test-utils/utils/message.ts +++ b/ts/test/test-utils/utils/message.ts @@ -1,10 +1,7 @@ import { v4 as uuid } from 'uuid'; import { generateFakePubKey, generateFakePubKeys } from './pubkey'; import { ClosedGroupVisibleMessage } from '../../../session/messages/outgoing/visibleMessage/ClosedGroupVisibleMessage'; -import { - ConversationAttributes, - ConversationType, -} from '../../../models/conversation'; +import { ConversationAttributes, ConversationType } from '../../../models/conversation'; import { OpenGroupMessage } from '../../../session/messages/outgoing'; import { VisibleMessage } from '../../../session/messages/outgoing/visibleMessage/VisibleMessage'; import { OpenGroup } from '../../../opengroup/opengroupV1/OpenGroup'; @@ -39,9 +36,7 @@ export function generateOpenGroupMessage(): OpenGroupMessage { }); } -export function generateClosedGroupMessage( - groupId?: string -): ClosedGroupVisibleMessage { +export function generateClosedGroupMessage(groupId?: string): ClosedGroupVisibleMessage { return new ClosedGroupVisibleMessage({ identifier: uuid(), groupId: groupId ?? generateFakePubKey().key, diff --git a/ts/test/test-utils/utils/stubbing.ts b/ts/test/test-utils/utils/stubbing.ts index 4607006f0498f118210955cae4c453baed1d981f..cd84c22e914b7e2c7a0803452621c36c80c9fcb4 100644 --- a/ts/test/test-utils/utils/stubbing.ts +++ b/ts/test/test-utils/utils/stubbing.ts @@ -29,10 +29,7 @@ type WindowValue<K extends keyof Window> = Partial<Window[K]> | undefined; * Note: This uses a custom sandbox. * Please call `restoreStubs()` or `stub.restore()` to restore original functionality. */ -export function stubWindow<K extends keyof Window>( - fn: K, - value: WindowValue<K> -) { +export function stubWindow<K extends keyof Window>(fn: K, value: WindowValue<K>) { // tslint:disable-next-line: no-typeof-undefined if (typeof globalAny.window === 'undefined') { globalAny.window = {}; @@ -61,17 +58,11 @@ export async function spyMessageQueueSend(app: Application) { } export async function getAllMessagesSent(app: Application) { - const messageQueueSpy = await app.webContents.executeJavaScript( - 'messageQueueSpy.args;' - ); + const messageQueueSpy = await app.webContents.executeJavaScript('messageQueueSpy.args;'); if (!messageQueueSpy) { - throw new Error( - 'Be sure to call spyMessageQueueSend() on the correct app first.' - ); + throw new Error('Be sure to call spyMessageQueueSend() on the correct app first.'); } - const messages = await app.webContents.executeJavaScript( - 'messageQueueSpy.args' - ); + const messages = await app.webContents.executeJavaScript('messageQueueSpy.args'); return messages; } diff --git a/ts/test/util/blockedNumberController_test.ts b/ts/test/util/blockedNumberController_test.ts index f4d3dee3feecb7a3e1dfb1499f382f7be12b79b0..4eb1d2dc4543bad3307f288148dd931ba343fc1e 100644 --- a/ts/test/util/blockedNumberController_test.ts +++ b/ts/test/util/blockedNumberController_test.ts @@ -168,9 +168,7 @@ describe('BlockedNumberController', () => { let ourDevice: PubKey; beforeEach(() => { ourDevice = TestUtils.generateFakePubKey(); - sandbox - .stub(UserUtils, 'getOurPubKeyStrFromCache') - .returns(ourDevice.key); + sandbox.stub(UserUtils, 'getOurPubKeyStrFromCache').returns(ourDevice.key); }); it('should return false for our device', async () => { const isBlocked = await BlockedNumberController.isBlockedAsync(ourDevice); @@ -182,10 +180,7 @@ describe('BlockedNumberController', () => { memoryDB.blocked = [other.key]; const isBlocked = await BlockedNumberController.isBlockedAsync(other); - expect(isBlocked).to.equal( - true, - 'Expected isBlockedAsync to return true.' - ); + expect(isBlocked).to.equal(true, 'Expected isBlockedAsync to return true.'); }); it('should return false if device is not blocked', async () => { @@ -193,10 +188,7 @@ describe('BlockedNumberController', () => { memoryDB.blocked = []; const isBlocked = await BlockedNumberController.isBlockedAsync(other); - expect(isBlocked).to.equal( - false, - 'Expected isBlockedAsync to return false.' - ); + expect(isBlocked).to.equal(false, 'Expected isBlockedAsync to return false.'); }); }); diff --git a/ts/types/Attachment.ts b/ts/types/Attachment.ts index 5f1c11ecf207380225e06b55964aa4bb40310928..d4da15da3d7339d4eeaf662794f26dd05ebb4089 100644 --- a/ts/types/Attachment.ts +++ b/ts/types/Attachment.ts @@ -5,10 +5,7 @@ import { isArrayBuffer, padStart } from 'lodash'; import * as MIME from './MIME'; import { saveURLAsFile } from '../util/saveURLAsFile'; import { SignalService } from '../protobuf'; -import { - isImageTypeSupported, - isVideoTypeSupported, -} from '../util/GoogleChrome'; +import { isImageTypeSupported, isVideoTypeSupported } from '../util/GoogleChrome'; import { LocalizerType } from './Util'; import { fromHexToArray } from '../session/utils/String'; import { getSodium } from '../session/crypto'; @@ -90,14 +87,7 @@ export function canDisplayImage(attachments?: Array<AttachmentType>) { const { height, width } = attachments && attachments[0] ? attachments[0] : { height: 0, width: 0 }; - return ( - height && - height > 0 && - height <= 4096 && - width && - width > 0 && - width <= 4096 - ); + return height && height > 0 && height <= 4096 && width && width > 0 && width <= 4096; } export function getThumbnailUrl(attachment: AttachmentType) { @@ -127,17 +117,11 @@ export function isImage(attachments?: Array<AttachmentType>) { export function isImageAttachment(attachment: AttachmentType): boolean { return Boolean( - attachment && - attachment.contentType && - isImageTypeSupported(attachment.contentType) + attachment && attachment.contentType && isImageTypeSupported(attachment.contentType) ); } export function hasImage(attachments?: Array<AttachmentType>): boolean { - return Boolean( - attachments && - attachments[0] && - (attachments[0].url || attachments[0].pending) - ); + return Boolean(attachments && attachments[0] && (attachments[0].url || attachments[0].pending)); } export function isVideo(attachments?: Array<AttachmentType>): boolean { @@ -146,20 +130,14 @@ export function isVideo(attachments?: Array<AttachmentType>): boolean { export function isVideoAttachment(attachment?: AttachmentType): boolean { return Boolean( - !!attachment && - !!attachment.contentType && - isVideoTypeSupported(attachment.contentType) + !!attachment && !!attachment.contentType && isVideoTypeSupported(attachment.contentType) ); } export function hasVideoScreenshot(attachments?: Array<AttachmentType>) { const firstAttachment = attachments ? attachments[0] : null; - return ( - firstAttachment && - firstAttachment.screenshot && - firstAttachment.screenshot.url - ); + return firstAttachment && firstAttachment.screenshot && firstAttachment.screenshot.url; } type DimensionsType = { @@ -198,9 +176,7 @@ export function getImageDimensions(attachment: AttachmentType): DimensionsType { }; } -export function areAllAttachmentsVisual( - attachments?: Array<AttachmentType> -): boolean { +export function areAllAttachmentsVisual(attachments?: Array<AttachmentType>): boolean { if (!attachments) { return false; } @@ -216,9 +192,7 @@ export function areAllAttachmentsVisual( return true; } -export function getGridDimensions( - attachments?: Array<AttachmentType> -): null | DimensionsType { +export function getGridDimensions(attachments?: Array<AttachmentType>): null | DimensionsType { if (!attachments || !attachments.length) { return null; } @@ -251,13 +225,8 @@ export function getGridDimensions( }; } -export function getAlt( - attachment: AttachmentType, - i18n: LocalizerType -): string { - return isVideoAttachment(attachment) - ? i18n('videoAttachmentAlt') - : i18n('imageAttachmentAlt'); +export function getAlt(attachment: AttachmentType, i18n: LocalizerType): string { + return isVideoAttachment(attachment) ? i18n('videoAttachmentAlt') : i18n('imageAttachmentAlt'); } // Migration-related attachment stuff @@ -366,9 +335,7 @@ export const getSuggestedFilename = ({ index?: number; }): string => { const prefix = 'session-attachment'; - const suffix = timestamp - ? moment(timestamp).format('-YYYY-MM-DD-HHmmss') - : ''; + const suffix = timestamp ? moment(timestamp).format('-YYYY-MM-DD-HHmmss') : ''; const fileType = getFileExtension(attachment); const extension = fileType ? `.${fileType}` : ''; const indexSuffix = index ? `_${padStart(index.toString(), 3, '0')}` : ''; @@ -385,18 +352,14 @@ export const getSuggestedFilenameSending = ({ timestamp?: number | Date; }): string => { const prefix = 'session-attachment'; - const suffix = timestamp - ? moment(timestamp).format('-YYYY-MM-DD-HHmmss') - : ''; + const suffix = timestamp ? moment(timestamp).format('-YYYY-MM-DD-HHmmss') : ''; const fileType = getFileExtension(attachment); const extension = fileType ? `.${fileType}` : ''; return `${prefix}${suffix}${extension}`; }; -export const getFileExtension = ( - attachment: AttachmentType -): string | undefined => { +export const getFileExtension = (attachment: AttachmentType): string | undefined => { // we override textplain to the extension of the file if (!attachment.contentType || attachment.contentType === 'text/plain') { if (attachment.fileName?.length) { @@ -425,15 +388,10 @@ export const encryptAttachmentBuffer = async (bufferIn: ArrayBuffer) => { const uintArrayIn = new Uint8Array(bufferIn); const sodium = await getSodium(); - const encryptingKey = window.textsecure.storage.get( - 'local_attachment_encrypted_key' - ); + const encryptingKey = window.textsecure.storage.get('local_attachment_encrypted_key'); /* Set up a new stream: initialize the state and create the header */ - const { - state, - header, - } = sodium.crypto_secretstream_xchacha20poly1305_init_push( + const { state, header } = sodium.crypto_secretstream_xchacha20poly1305_init_push( fromHexToArray(encryptingKey) ); /* Now, encrypt the buffer. */ @@ -444,25 +402,19 @@ export const encryptAttachmentBuffer = async (bufferIn: ArrayBuffer) => { sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL ); - const encryptedBufferWithHeader = new Uint8Array( - bufferOut.length + header.length - ); + const encryptedBufferWithHeader = new Uint8Array(bufferOut.length + header.length); encryptedBufferWithHeader.set(header); encryptedBufferWithHeader.set(bufferOut, header.length); return { encryptedBufferWithHeader, header }; }; -export const decryptAttachmentBuffer = async ( - bufferIn: ArrayBuffer -): Promise<Uint8Array> => { +export const decryptAttachmentBuffer = async (bufferIn: ArrayBuffer): Promise<Uint8Array> => { if (!isArrayBuffer(bufferIn)) { throw new TypeError("'bufferIn' must be an array buffer"); } const sodium = await getSodium(); - const encryptingKey = window.textsecure.storage.get( - 'local_attachment_encrypted_key' - ); + const encryptingKey = window.textsecure.storage.get('local_attachment_encrypted_key'); const header = new Uint8Array( bufferIn.slice(0, sodium.crypto_secretstream_xchacha20poly1305_HEADERBYTES) @@ -479,15 +431,10 @@ export const decryptAttachmentBuffer = async ( ); // what if ^ this call fail (? try to load as a unencrypted attachment?) - const messageTag = sodium.crypto_secretstream_xchacha20poly1305_pull( - state, - encryptedBuffer - ); + const messageTag = sodium.crypto_secretstream_xchacha20poly1305_pull(state, encryptedBuffer); // we expect the final tag to be there. If not, we might have an issue with this file // maybe not encrypted locally? - if ( - messageTag.tag === sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL - ) { + if (messageTag.tag === sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL) { return messageTag.message; } } catch (e) { diff --git a/ts/types/Contact.tsx b/ts/types/Contact.tsx index 9ba91635993bd4c7de43245b6396c8879de120e5..d16fcc4bddf39dc8a3e1facf8089164d659c6ba3 100644 --- a/ts/types/Contact.tsx +++ b/ts/types/Contact.tsx @@ -50,8 +50,7 @@ export function getName(contact: Contact): string | undefined { const displayName = (name && name.displayName) || undefined; const givenName = (name && name.givenName) || undefined; const familyName = (name && name.familyName) || undefined; - const backupName = - (givenName && familyName && `${givenName} ${familyName}`) || undefined; + const backupName = (givenName && familyName && `${givenName} ${familyName}`) || undefined; return displayName || organization || backupName || givenName || familyName; } diff --git a/ts/types/Conversation.ts b/ts/types/Conversation.ts index e6a073f4aad17e3fd62c3b5cad4d49119143286b..9f3289e3de14ac6792ae6dd6158910318922d84d 100644 --- a/ts/types/Conversation.ts +++ b/ts/types/Conversation.ts @@ -31,9 +31,7 @@ export const createLastMessageUpdate = ({ ); const shouldUpdateTimestamp = Boolean(!isExpireTimerUpdateFromSync); - const newTimestamp = shouldUpdateTimestamp - ? lastMessage.sent_at - : currentTimestamp; + const newTimestamp = shouldUpdateTimestamp ? lastMessage.sent_at : currentTimestamp; return { lastMessage: lastMessageNotificationText || '', diff --git a/ts/types/Settings.ts b/ts/types/Settings.ts index 5231bdf0fa80c0e20ce2ee3db027e81631d2c5a1..8a460796b0bbcc87215f4964dc9ca80dc3af61bb 100644 --- a/ts/types/Settings.ts +++ b/ts/types/Settings.ts @@ -2,8 +2,7 @@ import * as OS from '../OS'; const MIN_WINDOWS_VERSION = '8.0.0'; -export const isAudioNotificationSupported = () => - OS.isWindows(MIN_WINDOWS_VERSION) || OS.isMacOS(); +export const isAudioNotificationSupported = () => OS.isWindows(MIN_WINDOWS_VERSION) || OS.isMacOS(); // Using `Notification::tag` has a bug on Windows 7: // https://github.com/electron/electron/issues/11189 diff --git a/ts/types/message/initializeAttachmentMetadata.ts b/ts/types/message/initializeAttachmentMetadata.ts index f4b191f13254ead80996e1ef29b60f7bb3c14f00..4ca7c9e61200fb773c2a4d16b1c077e951c310c9 100644 --- a/ts/types/message/initializeAttachmentMetadata.ts +++ b/ts/types/message/initializeAttachmentMetadata.ts @@ -2,20 +2,16 @@ import * as Attachment from '../Attachment'; import * as IndexedDB from '../IndexedDB'; import { Message, UserMessage } from '../Message'; -const hasAttachment = ( - predicate: (value: Attachment.Attachment) => boolean -) => (message: UserMessage): IndexedDB.IndexablePresence => +const hasAttachment = (predicate: (value: Attachment.Attachment) => boolean) => ( + message: UserMessage +): IndexedDB.IndexablePresence => IndexedDB.toIndexablePresence(message.attachments.some(predicate)); const hasFileAttachment = hasAttachment(Attachment.isFile); const hasVisualMediaAttachment = hasAttachment(Attachment.isVisualMedia); -export const initializeAttachmentMetadata = async ( - message: Message -): Promise<Message> => { - const hasAttachments = IndexedDB.toIndexableBoolean( - message.attachments.length > 0 - ); +export const initializeAttachmentMetadata = async (message: Message): Promise<Message> => { + const hasAttachments = IndexedDB.toIndexableBoolean(message.attachments.length > 0); const hasFileAttachments = hasFileAttachment(message); const hasVisualMediaAttachments = hasVisualMediaAttachment(message); diff --git a/ts/updater/common.ts b/ts/updater/common.ts index e6bf4df13ebdc5d6306f8dac49ef135d15fe75cb..6aa68f9bbd3b7bd28900ed1ecaed9daa5e10edf6 100644 --- a/ts/updater/common.ts +++ b/ts/updater/common.ts @@ -65,10 +65,7 @@ export async function showUpdateDialog( return ret.response === RESTART_BUTTON; } -export async function showCannotUpdateDialog( - mainWindow: BrowserWindow, - messages: MessagesType -) { +export async function showCannotUpdateDialog(mainWindow: BrowserWindow, messages: MessagesType) { const options = { type: 'error', buttons: [messages.ok.message], diff --git a/ts/updater/curve.ts b/ts/updater/curve.ts index 6af746457cadc57fb7830e231dec0e0580c86574..150954d510a0e65883a04821da032c361d994e17 100644 --- a/ts/updater/curve.ts +++ b/ts/updater/curve.ts @@ -21,18 +21,11 @@ interface CurveType { privKey: BinaryType; }; sign: (privateKey: BinaryType, message: BinaryType) => BinaryType; - verify: ( - publicKey: BinaryType, - message: BinaryType, - signature: BinaryType - ) => boolean; + verify: (publicKey: BinaryType, message: BinaryType, signature: BinaryType) => boolean; } -const { - keyPair: internalKeyPair, - sign: internalSign, - verify: internalVerify, -} = g.Internal.curve25519 as CurveType; +const { keyPair: internalKeyPair, sign: internalSign, verify: internalVerify } = g.Internal + .curve25519 as CurveType; export function keyPair() { const privateKey = randomBytes(32); @@ -48,11 +41,7 @@ export function sign(privateKey: BinaryType, message: BinaryType) { return internalSign(privateKey, message); } -export function verify( - publicKey: BinaryType, - message: BinaryType, - signature: BinaryType -) { +export function verify(publicKey: BinaryType, message: BinaryType, signature: BinaryType) { const failed = internalVerify(publicKey, message, signature); return !failed; diff --git a/ts/updater/index.ts b/ts/updater/index.ts index f081b26be58b5de4913fda4fecd4909d28b83f65..4327b7155756f92172e639c3ac2cb5e4aae40600 100644 --- a/ts/updater/index.ts +++ b/ts/updater/index.ts @@ -34,9 +34,7 @@ export async function start( After that you can change `updatesEnabled` to `true` in the default config. */ - logger.info( - 'updater/start: Updates disabled - not starting new version checks' - ); + logger.info('updater/start: Updates disabled - not starting new version checks'); return; } diff --git a/ts/updater/updater.ts b/ts/updater/updater.ts index cec397221ebaa00d3fa49e004142af9e5d737eb0..aa1918b5147cf989501476db4904ea461a70a891 100644 --- a/ts/updater/updater.ts +++ b/ts/updater/updater.ts @@ -95,10 +95,7 @@ async function checkForUpdates( } logger.info('auto-update: showing download dialog...'); - const shouldDownload = await showDownloadUpdateDialog( - getMainWindow(), - messages - ); + const shouldDownload = await showDownloadUpdateDialog(getMainWindow(), messages); if (!shouldDownload) { downloadIgnored = true; @@ -152,10 +149,7 @@ async function canAutoUpdate(): Promise<boolean> { // Taken from: https://github.com/electron-userland/electron-builder/blob/d4feb6d3c8b008f8b455c761d654c8088f90d8fa/packages/electron-updater/src/ElectronAppAdapter.ts#L25 const updateFile = isPackaged ? 'app-update.yml' : 'dev-app-update.yml'; - const basePath = - isPackaged && process.resourcesPath - ? process.resourcesPath - : app.getAppPath(); + const basePath = isPackaged && process.resourcesPath ? process.resourcesPath : app.getAppPath(); const appUpdateConfigPath = path.join(basePath, updateFile); return new Promise(resolve => { diff --git a/ts/util/accountManager.ts b/ts/util/accountManager.ts index cf7fe27249ced55f625af2f27140721f88d891c2..6d7aaab9987614437debe9d626754ba48bde37d7 100644 --- a/ts/util/accountManager.ts +++ b/ts/util/accountManager.ts @@ -1,11 +1,7 @@ import { ConversationController } from '../session/conversations'; import { getSodium } from '../session/crypto'; import { UserUtils } from '../session/utils'; -import { - fromArrayBufferToBase64, - fromHex, - toHex, -} from '../session/utils/String'; +import { fromArrayBufferToBase64, fromHex, toHex } from '../session/utils/String'; import { getOurPubKeyStrFromCache } from '../session/utils/User'; import { trigger } from '../shims/events'; import { @@ -28,17 +24,13 @@ export async function sessionGenerateKeyPair( ): Promise<{ pubKey: ArrayBufferLike; privKey: ArrayBufferLike }> { const sodium = await getSodium(); const ed25519KeyPair = sodium.crypto_sign_seed_keypair(new Uint8Array(seed)); - const x25519PublicKey = sodium.crypto_sign_ed25519_pk_to_curve25519( - ed25519KeyPair.publicKey - ); + const x25519PublicKey = sodium.crypto_sign_ed25519_pk_to_curve25519(ed25519KeyPair.publicKey); // prepend version byte (coming from `processKeys(raw_keys)`) const origPub = new Uint8Array(x25519PublicKey); const prependedX25519PublicKey = new Uint8Array(33); prependedX25519PublicKey.set(origPub, 1); prependedX25519PublicKey[0] = 5; - const x25519SecretKey = sodium.crypto_sign_ed25519_sk_to_curve25519( - ed25519KeyPair.privateKey - ); + const x25519SecretKey = sodium.crypto_sign_ed25519_sk_to_curve25519(ed25519KeyPair.privateKey); // prepend with 05 the public key const x25519KeyPair = { @@ -81,14 +73,9 @@ export async function signInWithRecovery( * @param mnemonic the mnemonic the user duly saved in a safe place. We will restore his sessionID based on this. * @param mnemonicLanguage 'english' only is supported */ -export async function signInByLinkingDevice( - mnemonic: string, - mnemonicLanguage: string -) { +export async function signInByLinkingDevice(mnemonic: string, mnemonicLanguage: string) { if (!mnemonic) { - throw new Error( - 'Session always needs a mnemonic. Either generated or given by the user' - ); + throw new Error('Session always needs a mnemonic. Either generated or given by the user'); } if (!mnemonicLanguage) { throw new Error('We always needs a mnemonicLanguage'); @@ -116,9 +103,7 @@ export async function registerSingleDevice( profileName: string ) { if (!generatedMnemonic) { - throw new Error( - 'Session always needs a mnemonic. Either generated or given by the user' - ); + throw new Error('Session always needs a mnemonic. Either generated or given by the user'); } if (!profileName) { throw new Error('We always needs a profileName'); @@ -127,10 +112,7 @@ export async function registerSingleDevice( throw new Error('We always needs a mnemonicLanguage'); } - const identityKeyPair = await generateKeypair( - generatedMnemonic, - mnemonicLanguage - ); + const identityKeyPair = await generateKeypair(generatedMnemonic, mnemonicLanguage); await createAccount(identityKeyPair); UserUtils.saveRecoveryPhrase(generatedMnemonic); @@ -165,9 +147,7 @@ export async function clearSessionsAndPreKeys() { export async function deleteAccount(reason?: string) { const deleteEverything = async () => { - window.log.info( - 'configuration message sent successfully. Deleting everything' - ); + window.log.info('configuration message sent successfully. Deleting everything'); await window.Signal.Logs.deleteAll(); await window.Signal.Data.removeAll(); await window.Signal.Data.close(); @@ -223,10 +203,7 @@ async function createAccount(identityKeyPair: any) { await window.textsecure.storage.put('read-receipt-setting', false); // Enable typing indicators by default - await window.textsecure.storage.put( - 'typing-indicators-setting', - Boolean(true) - ); + await window.textsecure.storage.put('typing-indicators-setting', Boolean(true)); await window.textsecure.storage.user.setNumberAndDeviceId(pubKeyString, 1); } diff --git a/ts/util/attachmentsUtil.ts b/ts/util/attachmentsUtil.ts index cb5740654804446c187e27f0546470e2829a1ff0..70be1265893c7f1ad5e2fe3ad6111260e354b9dd 100644 --- a/ts/util/attachmentsUtil.ts +++ b/ts/util/attachmentsUtil.ts @@ -33,21 +33,15 @@ export async function autoScale<T extends { contentType: string; file: any }>( img.onload = () => { URL.revokeObjectURL(url); - if ( - maxMeasurements?.maxSide && - (maxMeasurements?.maxHeight || maxMeasurements?.maxWidth) - ) { + if (maxMeasurements?.maxSide && (maxMeasurements?.maxHeight || maxMeasurements?.maxWidth)) { reject('Cannot have maxSide and another dimension set together'); } const maxSize = - maxMeasurements?.maxSize || - Constants.CONVERSATION.MAX_ATTACHMENT_FILESIZE_BYTES; + maxMeasurements?.maxSize || Constants.CONVERSATION.MAX_ATTACHMENT_FILESIZE_BYTES; const makeSquare = Boolean(maxMeasurements?.maxSide); - const maxHeight = - maxMeasurements?.maxHeight || maxMeasurements?.maxSide || 4096; - const maxWidth = - maxMeasurements?.maxWidth || maxMeasurements?.maxSide || 4096; + const maxHeight = maxMeasurements?.maxHeight || maxMeasurements?.maxSide || 4096; + const maxWidth = maxMeasurements?.maxWidth || maxMeasurements?.maxSide || 4096; if ( img.naturalWidth <= maxWidth && @@ -83,9 +77,7 @@ export async function autoScale<T extends { contentType: string; file: any }>( let blob; do { i -= 1; - blob = window.dataURLToBlobSync( - canvas.toDataURL('image/jpeg', quality) - ); + blob = window.dataURLToBlobSync(canvas.toDataURL('image/jpeg', quality)); quality = (quality * maxSize) / blob.size; if (quality > 1) { @@ -102,10 +94,7 @@ export async function autoScale<T extends { contentType: string; file: any }>( }); } -export async function getFile( - attachment: StagedAttachmentType, - maxMeasurements?: MaxScaleSize -) { +export async function getFile(attachment: StagedAttachmentType, maxMeasurements?: MaxScaleSize) { if (!attachment) { return Promise.resolve(); } diff --git a/ts/util/blockedNumberController.ts b/ts/util/blockedNumberController.ts index 6330fb1f50ce47d4d4fd503c1cd7978ec3b4871c..abdfc4b06d6633ab11c24abb3f9a3c6edd49d7b9 100644 --- a/ts/util/blockedNumberController.ts +++ b/ts/util/blockedNumberController.ts @@ -38,8 +38,7 @@ export class BlockedNumberController { public static isBlocked(device: string | PubKey): boolean { // This function is not `async` because the old `isBlocked` function in js was also not async. // To convert it means we'll have to re-wire all our UI components to work with async. - const stringValue = - device instanceof PubKey ? device.key : device.toLowerCase(); + const stringValue = device instanceof PubKey ? device.key : device.toLowerCase(); return this.blockedNumbers.has(stringValue); } @@ -50,8 +49,7 @@ export class BlockedNumberController { * @param groupId The group id. */ public static isGroupBlocked(groupId: string | PubKey): boolean { - const stringValue = - groupId instanceof PubKey ? groupId.key : groupId.toLowerCase(); + const stringValue = groupId instanceof PubKey ? groupId.key : groupId.toLowerCase(); return this.blockedGroups.has(stringValue); } @@ -89,20 +87,14 @@ export class BlockedNumberController { } } - public static async setBlocked( - user: string | PubKey, - blocked: boolean - ): Promise<void> { + public static async setBlocked(user: string | PubKey, blocked: boolean): Promise<void> { if (blocked) { return BlockedNumberController.block(user); } return BlockedNumberController.unblock(user); } - public static async setGroupBlocked( - groupId: string | PubKey, - blocked: boolean - ): Promise<void> { + public static async setGroupBlocked(groupId: string | PubKey, blocked: boolean): Promise<void> { if (blocked) { return BlockedNumberController.blockGroup(groupId); } @@ -156,10 +148,7 @@ export class BlockedNumberController { return new Set(data.value); } - private static async saveToDB( - id: string, - numbers: Set<string> - ): Promise<void> { + private static async saveToDB(id: string, numbers: Set<string>): Promise<void> { await createOrUpdateItem({ id, value: [...numbers], diff --git a/ts/util/cleanSearchTerm.ts b/ts/util/cleanSearchTerm.ts index 75c8837c1efb14a4e0937a7c2ce9b9a4d25696f0..f78fb5b16febe6e393bcc2b49e114b2b0bba49e1 100644 --- a/ts/util/cleanSearchTerm.ts +++ b/ts/util/cleanSearchTerm.ts @@ -1,9 +1,6 @@ export function cleanSearchTerm(searchTerm: string) { const lowercase = searchTerm.toLowerCase(); - const withoutSpecialCharacters = lowercase.replace( - /([!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~])/g, - ' ' - ); + const withoutSpecialCharacters = lowercase.replace(/([!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~])/g, ' '); const whiteSpaceNormalized = withoutSpecialCharacters.replace(/\s+/g, ' '); const byToken = whiteSpaceNormalized.split(' '); const withoutSpecialTokens = byToken.filter( diff --git a/ts/util/emoji.ts b/ts/util/emoji.ts index 9593aa625731d7c317fa018b341670618a008cc1..687b503f84f50710d0a1277c1bddcd914f923f50 100644 --- a/ts/util/emoji.ts +++ b/ts/util/emoji.ts @@ -4,8 +4,7 @@ import EmojiConvertor from 'emoji-js'; const instance = new EmojiConvertor(); instance.init_unified(); instance.init_colons(); -instance.img_sets.apple.path = - 'node_modules/emoji-datasource-apple/img/apple/64/'; +instance.img_sets.apple.path = 'node_modules/emoji-datasource-apple/img/apple/64/'; instance.include_title = true; instance.replace_mode = 'img'; instance.supports_css = false; // needed to avoid spans with background-image diff --git a/ts/util/findMember.ts b/ts/util/findMember.ts index d95a4db6fe5d33d07807f63e3c164fb66cbdc44b..9e007718797d916fb39eaba20de94e75f459d0bf 100644 --- a/ts/util/findMember.ts +++ b/ts/util/findMember.ts @@ -32,9 +32,7 @@ export class FindMember { const publicMembers = await window.lokiPublicChatAPI.getListOfMembers(); const memberConversations = publicMembers .map(publicMember => - ConversationController.getInstance().get( - publicMember.authorPhoneNumber - ) + ConversationController.getInstance().get(publicMember.authorPhoneNumber) ) .filter((c: any) => !!c); groupMembers = memberConversations; diff --git a/ts/util/linkPreviewFetch.ts b/ts/util/linkPreviewFetch.ts index 2f3900247f633ba7c14b331f48b1059cc3122fdf..e40f42412cb01750c21bbe0103b80a35461e149f 100644 --- a/ts/util/linkPreviewFetch.ts +++ b/ts/util/linkPreviewFetch.ts @@ -1,14 +1,7 @@ import { RequestInit, Response } from 'node-fetch'; import { AbortSignal } from 'abort-controller'; -import { - IMAGE_GIF, - IMAGE_ICO, - IMAGE_JPEG, - IMAGE_PNG, - IMAGE_WEBP, - MIMEType, -} from '../types/MIME'; +import { IMAGE_GIF, IMAGE_ICO, IMAGE_JPEG, IMAGE_PNG, IMAGE_WEBP, MIMEType } from '../types/MIME'; const MAX_REQUEST_COUNT_WITH_REDIRECTS = 20; // tslint:disable: prefer-for-of @@ -62,9 +55,7 @@ export interface LinkPreviewImage { contentType: MIMEType; } -type ParsedContentType = - | { type: null; charset: null } - | { type: MIMEType; charset: null | string }; +type ParsedContentType = { type: null; charset: null } | { type: MIMEType; charset: null | string }; // This throws non-helpful errors because (1) it logs (2) it will be immediately caught. async function fetchWithRedirects( @@ -176,17 +167,13 @@ const parseContentLength = (headerValue: string | null): number => { return Number.isNaN(result) ? Infinity : result; }; -const emptyHtmlDocument = (): HTMLDocument => - new DOMParser().parseFromString('', 'text/html'); +const emptyHtmlDocument = (): HTMLDocument => new DOMParser().parseFromString('', 'text/html'); // The charset behavior here follows the [W3 guidelines][0]. The priority is BOM, HTTP // header, `http-equiv` meta tag, `charset` meta tag, and finally a UTF-8 fallback. // (This fallback could, perhaps, be smarter based on user locale.) // [0]: https://www.w3.org/International/questions/qa-html-encoding-declarations.en -const parseHtmlBytes = ( - bytes: Readonly<Uint8Array>, - httpCharset: string | null -): HTMLDocument => { +const parseHtmlBytes = (bytes: Readonly<Uint8Array>, httpCharset: string | null): HTMLDocument => { const hasBom = bytes[0] === 0xef && bytes[1] === 0xbb && bytes[2] === 0xbf; let isSureOfCharset: boolean; @@ -232,9 +219,7 @@ const parseHtmlBytes = ( } } - const metaCharset = document - .querySelector('meta[charset]') - ?.getAttribute('charset'); + const metaCharset = document.querySelector('meta[charset]')?.getAttribute('charset'); if (metaCharset) { return parseHtmlBytes(bytes, metaCharset); } @@ -265,21 +250,14 @@ const getHtmlDocument = async ( // This check exists to satisfy TypeScript; chunk should always be a Buffer. if (typeof chunk === 'string') { - if ( - httpCharset !== null && - httpCharset !== undefined && - Buffer.isEncoding(httpCharset) - ) { + if (httpCharset !== null && httpCharset !== undefined && Buffer.isEncoding(httpCharset)) { chunk = Buffer.from(chunk, httpCharset); } else { chunk = Buffer.from(chunk, 'utf8'); } } - const truncatedChunk = chunk.slice( - 0, - maxHtmlBytesToLoad - bytesLoadedSoFar - ); + const truncatedChunk = chunk.slice(0, maxHtmlBytesToLoad - bytesLoadedSoFar); buffer.set(truncatedChunk, bytesLoadedSoFar); bytesLoadedSoFar += truncatedChunk.byteLength; @@ -292,9 +270,7 @@ const getHtmlDocument = async ( } /* eslint-enable no-restricted-syntax */ } catch (err) { - window.log.warn( - 'getHtmlDocument: error when reading body; continuing with what we got' - ); + window.log.warn('getHtmlDocument: error when reading body; continuing with what we got'); } return result; @@ -334,16 +310,10 @@ const getLinkHrefAttribute = ( return null; }; -const parseMetadata = ( - document: HTMLDocument, - href: string -): LinkPreviewMetadata | null => { - const title = - getOpenGraphContent(document, ['og:title']) || document.title.trim(); +const parseMetadata = (document: HTMLDocument, href: string): LinkPreviewMetadata | null => { + const title = getOpenGraphContent(document, ['og:title']) || document.title.trim(); if (!title) { - window.log.warn( - "parseMetadata: HTML document doesn't have a title; bailing" - ); + window.log.warn("parseMetadata: HTML document doesn't have a title; bailing"); return null; } @@ -357,11 +327,7 @@ const parseMetadata = ( const rawImageHref = getOpenGraphContent(document, ['og:image', 'og:image:url']) || - getLinkHrefAttribute(document, [ - 'shortcut icon', - 'icon', - 'apple-touch-icon', - ]); + getLinkHrefAttribute(document, ['shortcut icon', 'icon', 'apple-touch-icon']); const imageUrl = rawImageHref ? maybeParseUrl(rawImageHref, href) : null; const imageHref = imageUrl ? imageUrl.href : null; @@ -419,16 +385,12 @@ export async function fetchLinkPreviewMetadata( signal: abortSignal, }); } catch (err) { - window.log.warn( - 'fetchLinkPreviewMetadata: failed to fetch link preview HTML; bailing' - ); + window.log.warn('fetchLinkPreviewMetadata: failed to fetch link preview HTML; bailing'); return null; } if (!response.ok) { - window.log.warn( - `fetchLinkPreviewMetadata: got a ${response.status} status code; bailing` - ); + window.log.warn(`fetchLinkPreviewMetadata: got a ${response.status} status code; bailing`); return null; } @@ -437,12 +399,8 @@ export async function fetchLinkPreviewMetadata( return null; } - if ( - !isInlineContentDisposition(response.headers.get('Content-Disposition')) - ) { - window.log.warn( - 'fetchLinkPreviewMetadata: Content-Disposition header is not inline; bailing' - ); + if (!isInlineContentDisposition(response.headers.get('Content-Disposition'))) { + window.log.warn('fetchLinkPreviewMetadata: Content-Disposition header is not inline; bailing'); return null; } @@ -450,21 +408,15 @@ export async function fetchLinkPreviewMetadata( return null; } - const contentLength = parseContentLength( - response.headers.get('Content-Length') - ); + const contentLength = parseContentLength(response.headers.get('Content-Length')); if (contentLength < MIN_HTML_CONTENT_LENGTH) { - window.log.warn( - 'fetchLinkPreviewMetadata: Content-Length is too short; bailing' - ); + window.log.warn('fetchLinkPreviewMetadata: Content-Length is too short; bailing'); return null; } const contentType = parseContentType(response.headers.get('Content-Type')); if (contentType.type !== 'text/html') { - window.log.warn( - 'fetchLinkPreviewMetadata: Content-Type is not HTML; bailing' - ); + window.log.warn('fetchLinkPreviewMetadata: Content-Type is not HTML; bailing'); return null; } @@ -525,35 +477,23 @@ export async function fetchLinkPreviewImage( } if (!response.ok) { - window.log.warn( - `fetchLinkPreviewImage: got a ${response.status} status code; bailing` - ); + window.log.warn(`fetchLinkPreviewImage: got a ${response.status} status code; bailing`); return null; } - const contentLength = parseContentLength( - response.headers.get('Content-Length') - ); + const contentLength = parseContentLength(response.headers.get('Content-Length')); if (contentLength < MIN_IMAGE_CONTENT_LENGTH) { - window.log.warn( - 'fetchLinkPreviewImage: Content-Length is too short; bailing' - ); + window.log.warn('fetchLinkPreviewImage: Content-Length is too short; bailing'); return null; } if (contentLength > MAX_IMAGE_CONTENT_LENGTH) { - window.log.warn( - 'fetchLinkPreviewImage: Content-Length is too large or is unset; bailing' - ); + window.log.warn('fetchLinkPreviewImage: Content-Length is too large or is unset; bailing'); return null; } - const { type: contentType } = parseContentType( - response.headers.get('Content-Type') - ); + const { type: contentType } = parseContentType(response.headers.get('Content-Type')); if (!contentType || !VALID_IMAGE_MIME_TYPES.has(contentType)) { - window.log.warn( - 'fetchLinkPreviewImage: Content-Type is not an image; bailing' - ); + window.log.warn('fetchLinkPreviewImage: Content-Type is not an image; bailing'); return null; } diff --git a/ts/util/makeLookup.ts b/ts/util/makeLookup.ts index 23cea025f563632c36cab74787a35ba7497018e6..3042c518e788184426d4b805b1f9a3b6c0f9ea2e 100644 --- a/ts/util/makeLookup.ts +++ b/ts/util/makeLookup.ts @@ -1,9 +1,6 @@ import { fromPairs, map } from 'lodash'; -export function makeLookup<T>( - items: Array<T>, - key: string -): { [key: string]: T } { +export function makeLookup<T>(items: Array<T>, key: string): { [key: string]: T } { // Yep, we can't index into item without knowing what it is. True. But we want to. // @ts-ignore const pairs = map(items, item => [item[key], item]); diff --git a/ts/util/missingCaseError.ts b/ts/util/missingCaseError.ts index f5f9ae047672f85a58e06d8cb5773aa023b2c1c4..4673f5c5f969bbb3d1f43a15d71d943a8c241823 100644 --- a/ts/util/missingCaseError.ts +++ b/ts/util/missingCaseError.ts @@ -17,5 +17,4 @@ // above would trigger a compiler error stating that `'links'` has not been // handled by our `switch` / `case` statement which is useful for code // maintenance and system evolution. -export const missingCaseError = (x: never): TypeError => - new TypeError(`Unhandled case: ${x}`); +export const missingCaseError = (x: never): TypeError => new TypeError(`Unhandled case: ${x}`); diff --git a/ts/util/timer.ts b/ts/util/timer.ts index 83e8f700cbf0d16d2f37204d3aea713055b2f799..03db356cbc2a5404b3d4c4a3ac7e1d74ecefacc8 100644 --- a/ts/util/timer.ts +++ b/ts/util/timer.ts @@ -13,10 +13,7 @@ export function getIncrement(length: number): number { return Math.ceil(length / 12); } -export function getTimerBucketIcon( - expiration: number, - length: number -): SessionIconType { +export function getTimerBucketIcon(expiration: number, length: number): SessionIconType { const delta = expiration - Date.now(); if (delta < 0) { return SessionIconType.Timer60; diff --git a/tslint.json b/tslint.json index 9b974cd23896c7b8ffb0744685a4d9b8078e8ffa..6d1a64b5e3eb715f67a5f8d6c858add083ce3436 100644 --- a/tslint.json +++ b/tslint.json @@ -41,13 +41,7 @@ "named-imports-order": "case-insensitive" } ], - "quotemark": [ - true, - "single", - "jsx-double", - "avoid-template", - "avoid-escape" - ], + "quotemark": [true, "single", "jsx-double", "avoid-template", "avoid-escape"], // Preferred by Prettier: "semicolon": [true, "always", "ignore-bound-class-methods"], // Preferred by Prettier: @@ -67,12 +61,7 @@ // Disabling a large set of Microsoft-recommended rules // Modifying: // React components and namespaces are Pascal case - "variable-name": [ - true, - "check-format", - "allow-leading-underscore", - "allow-pascal-case" - ], + "variable-name": [true, "check-format", "allow-leading-underscore", "allow-pascal-case"], "function-name": [ true, {