remove stuff related to web api

pull/1434/head
Audric Ackermann 4 years ago
parent 6abda94e62
commit 75b7788fa9
No known key found for this signature in database
GPG Key ID: 999F434D76324AD4

@ -90,8 +90,6 @@ module.exports = grunt => {
'libtextsecure/websocket-resources.js',
'libtextsecure/http-resources.js',
'libtextsecure/message_receiver.js',
'libtextsecure/sendmessage.js',
'libtextsecure/sync_request.js',
'libtextsecure/contacts_parser.js',
'libtextsecure/ProvisioningCipher.js',
'libtextsecure/task_with_timeout.js',
@ -100,7 +98,6 @@ module.exports = grunt => {
},
libloki: {
src: [
'libloki/api.js',
'libloki/crypto.js',
'libloki/service_nodes.js',
'libloki/storage.js',

@ -113,12 +113,6 @@
textsecure.startWorker('js/libsignal-protocol-worker.js');
Whisper.KeyChangeListener.init(textsecure.storage.protocol);
let messageReceiver;
window.getSocketStatus = () => {
if (messageReceiver) {
return messageReceiver.getStatus();
}
return -1;
};
Whisper.events = _.clone(Backbone.Events);
Whisper.events.isListenedTo = eventName =>
Whisper.events._events ? !!Whisper.events._events[eventName] : false;
@ -1038,9 +1032,6 @@
});
}
window.getSyncRequest = () =>
new textsecure.SyncRequest(textsecure.messaging, messageReceiver);
let disconnectTimer = null;
function onOffline() {
window.log.info('offline');
@ -1060,7 +1051,7 @@
window.removeEventListener('online', onOnline);
window.addEventListener('offline', onOffline);
if (disconnectTimer && isSocketOnline()) {
if (disconnectTimer) {
window.log.warn('Already online. Had a blip in online/offline status.');
clearTimeout(disconnectTimer);
disconnectTimer = null;
@ -1074,13 +1065,6 @@
connect();
}
function isSocketOnline() {
const socketStatus = window.getSocketStatus();
return (
socketStatus === WebSocket.CONNECTING || socketStatus === WebSocket.OPEN
);
}
async function disconnect() {
window.log.info('disconnect');
@ -1124,14 +1108,8 @@
if (messageReceiver) {
await messageReceiver.close();
}
const mySignalingKey = storage.get('signaling_key');
connectCount += 1;
const options = {
retryCached: connectCount === 1,
serverTrustRoot: window.getServerTrustRoot(),
};
Whisper.Notifications.disable(); // avoid notification flood until empty
setTimeout(() => {
Whisper.Notifications.enable();
@ -1152,18 +1130,18 @@
);
window.lokiPublicChatAPI = null;
window.feeds = [];
messageReceiver = new textsecure.MessageReceiver(mySignalingKey, options);
messageReceiver = new textsecure.MessageReceiver();
messageReceiver.addEventListener(
'message',
window.DataMessageReceiver.handleMessageEvent
);
window.textsecure.messaging = new textsecure.MessageSender();
window.textsecure.messaging = true;
return;
}
initAPIs();
await initSpecialConversations();
messageReceiver = new textsecure.MessageReceiver(mySignalingKey, options);
messageReceiver = new textsecure.MessageReceiver();
messageReceiver.addEventListener(
'message',
window.DataMessageReceiver.handleMessageEvent
@ -1180,55 +1158,7 @@
logger: window.log,
});
window.textsecure.messaging = new textsecure.MessageSender();
// On startup after upgrading to a new version, request a contact sync
// (but only if we're not the primary device)
if (
!firstRun &&
connectCount === 1 &&
newVersion &&
// eslint-disable-next-line eqeqeq
textsecure.storage.user.getDeviceId() != '1'
) {
window.getSyncRequest();
}
const deviceId = textsecure.storage.user.getDeviceId();
if (firstRun === true && deviceId !== '1') {
const hasThemeSetting = Boolean(storage.get('theme-setting'));
if (!hasThemeSetting && textsecure.storage.get('userAgent') === 'OWI') {
storage.put('theme-setting', 'ios');
}
const syncRequest = new textsecure.SyncRequest(
textsecure.messaging,
messageReceiver
);
Whisper.events.trigger('contactsync:begin');
syncRequest.addEventListener('success', () => {
window.log.info('sync successful');
storage.put('synced_at', Date.now());
Whisper.events.trigger('contactsync');
});
syncRequest.addEventListener('timeout', () => {
window.log.error('sync timed out');
Whisper.events.trigger('contactsync');
});
if (Whisper.Import.isComplete()) {
const { CONFIGURATION } = textsecure.protobuf.SyncMessage.Request.Type;
const { RequestSyncMessage } = window.libsession.Messages.Outgoing;
const requestConfigurationSyncMessage = new RequestSyncMessage({
timestamp: Date.now(),
reqestType: CONFIGURATION,
});
await libsession
.getMessageQueue()
.sendSyncMessage(requestConfigurationSyncMessage);
// sending of the message is handled in the 'private' case below
}
}
window.textsecure.messaging = true;
libsession.Protocols.SessionProtocol.checkSessionRequestExpiry().catch(
e => {

@ -217,7 +217,7 @@
: BlockedNumberController.blockGroup(this.id);
await promise;
this.commit();
await textsecure.messaging.sendBlockedListSyncMessage();
await libsession.Utils.SyncMessageUtils.sendBlockedListSyncMessage();
},
async unblock() {
if (!this.id || this.isPublic() || this.isRss()) {
@ -228,7 +228,7 @@
: BlockedNumberController.unblockGroup(this.id);
await promise;
this.commit();
await textsecure.messaging.sendBlockedListSyncMessage();
await libsession.Utils.SyncMessageUtils.sendBlockedListSyncMessage();
},
async bumpTyping() {
if (this.isPublic() || this.isMediumGroup()) {
@ -612,13 +612,6 @@
local: !options.viaSyncMessage,
});
}
if (!options.viaSyncMessage) {
await this.sendVerifySyncMessage(this.id, verified);
}
},
async sendVerifySyncMessage(number, state) {
const key = await textsecure.storage.protocol.loadIdentityKey(number);
return textsecure.messaging.syncVerification(number, state, key);
},
isVerified() {
if (this.isPrivate()) {
@ -1690,7 +1683,7 @@
window.log.info(`Sending ${read.length} read receipts`);
// Because syncReadMessages sends to our other devices, and sendReadReceipts goes
// to a contact, we need accessKeys for both.
await textsecure.messaging.syncReadMessages(read);
await libsession.Utils.SyncMessageUtils.syncReadMessages(read);
if (storage.get('read-receipt-setting')) {
await Promise.all(

@ -1,356 +0,0 @@
const fetch = require('node-fetch');
const { Agent } = require('https');
/* global Buffer, setTimeout, log, _ */
/* eslint-disable more/no-then, no-bitwise, no-nested-ternary */
function _btoa(str) {
let buffer;
if (str instanceof Buffer) {
buffer = str;
} else {
buffer = Buffer.from(str.toString(), 'binary');
}
return buffer.toString('base64');
}
const _call = object => Object.prototype.toString.call(object);
const ArrayBufferToString = _call(new ArrayBuffer());
const Uint8ArrayToString = _call(new Uint8Array());
function _getString(thing) {
if (typeof thing !== 'string') {
if (_call(thing) === Uint8ArrayToString) {
return String.fromCharCode.apply(null, thing);
}
if (_call(thing) === ArrayBufferToString) {
return _getString(new Uint8Array(thing));
}
}
return thing;
}
function _validateResponse(response, schema) {
try {
// eslint-disable-next-line guard-for-in, no-restricted-syntax
for (const i in schema) {
switch (schema[i]) {
case 'object':
case 'string':
case 'number':
// eslint-disable-next-line valid-typeof
if (typeof response[i] !== schema[i]) {
return false;
}
break;
default:
}
}
} catch (ex) {
return false;
}
return true;
}
const FIVE_MINUTES = 1000 * 60 * 5;
const agents = {
unauth: null,
auth: null,
};
function getContentType(response) {
if (response.headers && response.headers.get) {
return response.headers.get('content-type');
}
return null;
}
function _promiseAjax(providedUrl, options) {
return new Promise((resolve, reject) => {
const url = providedUrl || `${options.host}/${options.path}`;
if (options.disableLogs) {
log.info(
`${options.type} [REDACTED_URL]${
options.unauthenticated ? ' (unauth)' : ''
}`
);
} else {
log.info(
`${options.type} ${url}${options.unauthenticated ? ' (unauth)' : ''}`
);
}
const timeout =
typeof options.timeout !== 'undefined' ? options.timeout : 10000;
const { proxyUrl } = options;
const agentType = options.unauthenticated ? 'unauth' : 'auth';
const cacheKey = `${proxyUrl}-${agentType}`;
const { timestamp } = agents[cacheKey] || {};
if (!timestamp || timestamp + FIVE_MINUTES < Date.now()) {
if (timestamp) {
log.info(`Cycling agent for type ${cacheKey}`);
}
agents[cacheKey] = {
agent: new Agent({ keepAlive: true }),
timestamp: Date.now(),
};
}
const { agent } = agents[cacheKey];
const fetchOptions = {
method: options.type,
body: options.data || null,
headers: {
'User-Agent': 'Session',
'X-Loki-Messenger-Agent': 'OWD',
...options.headers,
},
redirect: options.redirect,
agent,
ca: options.certificateAuthority,
timeout,
};
if (fetchOptions.body instanceof ArrayBuffer) {
// node-fetch doesn't support ArrayBuffer, only node Buffer
const contentLength = fetchOptions.body.byteLength;
fetchOptions.body = Buffer.from(fetchOptions.body);
// node-fetch doesn't set content-length like S3 requires
fetchOptions.headers['Content-Length'] = contentLength;
}
const { accessKey, unauthenticated } = options;
if (unauthenticated) {
if (!accessKey) {
throw new Error(
'_promiseAjax: mode is aunathenticated, but accessKey was not provided'
);
}
// Access key is already a Base64 string
fetchOptions.headers['Unidentified-Access-Key'] = accessKey;
} else if (options.user && options.password) {
const user = _getString(options.user);
const password = _getString(options.password);
const auth = _btoa(`${user}:${password}`);
fetchOptions.headers.Authorization = `Basic ${auth}`;
}
if (options.contentType) {
fetchOptions.headers['Content-Type'] = options.contentType;
}
fetch(url, fetchOptions)
.then(response => {
let resultPromise;
if (
options.responseType === 'json' &&
response.headers.get('Content-Type') === 'application/json'
) {
resultPromise = response.json();
} else if (
options.responseType === 'arraybuffer' ||
options.responseType === 'arraybufferwithdetails'
) {
resultPromise = response.buffer();
} else {
resultPromise = response.text();
}
return resultPromise.then(result => {
if (
options.responseType === 'arraybuffer' ||
options.responseType === 'arraybufferwithdetails'
) {
// eslint-disable-next-line no-param-reassign
result = result.buffer.slice(
result.byteOffset,
result.byteOffset + result.byteLength
);
}
if (options.responseType === 'json') {
if (options.validateResponse) {
if (!_validateResponse(result, options.validateResponse)) {
if (options.disableLogs) {
log.info(
options.type,
'[REDACTED_URL]',
response.status,
'Error'
);
} else {
log.error(options.type, url, response.status, 'Error');
}
return reject(
HTTPError(
'promiseAjax: invalid response',
response.status,
result,
options.stack
)
);
}
}
}
if (response.status >= 0 && response.status < 400) {
if (options.disableLogs) {
log.info(
options.type,
'[REDACTED_URL]',
response.status,
'Success'
);
} else {
log.info(options.type, url, response.status, 'Success');
}
if (options.responseType === 'arraybufferwithdetails') {
return resolve({
data: result,
contentType: getContentType(response),
response,
});
}
return resolve(result, response.status);
}
if (options.disableLogs) {
log.info(options.type, '[REDACTED_URL]', response.status, 'Error');
} else {
log.error(options.type, url, response.status, 'Error');
}
return reject(
HTTPError(
'promiseAjax: error response',
response.status,
result,
options.stack
)
);
});
})
.catch(e => {
if (options.disableLogs) {
log.error(options.type, '[REDACTED_URL]', 0, 'Error');
} else {
log.error(options.type, url, 0, 'Error');
}
const stack = `${e.stack}\nInitial stack:\n${options.stack}`;
reject(HTTPError('promiseAjax catch', 0, e.toString(), stack));
});
});
}
function _retryAjax(url, options, providedLimit, providedCount) {
const count = (providedCount || 0) + 1;
const limit = providedLimit || 3;
return _promiseAjax(url, options).catch(e => {
if (e.name === 'HTTPError' && e.code === -1 && count < limit) {
return new Promise(resolve => {
setTimeout(() => {
resolve(_retryAjax(url, options, limit, count));
}, 1000);
});
}
throw e;
});
}
function _outerAjax(url, options) {
// eslint-disable-next-line no-param-reassign
options.stack = new Error().stack; // just in case, save stack here.
return _retryAjax(url, options);
}
function HTTPError(message, providedCode, response, stack) {
const code = providedCode > 999 || providedCode < 100 ? -1 : providedCode;
const e = new Error(`${message}; code: ${code}`);
e.name = 'HTTPError';
e.code = code;
e.stack += `\nOriginal stack:\n${stack}`;
if (response) {
e.response = response;
}
return e;
}
module.exports = {
initialize,
};
// We first set up the data that won't change during this session of the app
function initialize() {
// Thanks to function-hoisting, we can put this return statement before all of the
// below function definitions.
return {
connect,
};
// Then we connect to the server with user-specific information. This is the only API
// exposed to the browser context, ensuring that it can't connect to arbitrary
// locations.
function connect() {
// Thanks, function hoisting!
return {
getAttachment,
getProxiedSize,
makeProxiedRequest,
};
function getAttachment(fileUrl) {
return _outerAjax(fileUrl, {
contentType: 'application/octet-stream',
responseType: 'arraybuffer',
timeout: 0,
type: 'GET',
});
}
// eslint-disable-next-line no-shadow
async function getProxiedSize(url) {
const result = await _outerAjax(url, {
processData: false,
responseType: 'arraybufferwithdetails',
proxyUrl: '',
type: 'HEAD',
disableLogs: true,
});
const { response } = result;
if (!response.headers || !response.headers.get) {
throw new Error('getProxiedSize: Problem retrieving header value');
}
const size = response.headers.get('content-length');
return parseInt(size, 10);
}
// eslint-disable-next-line no-shadow
function makeProxiedRequest(url, options = {}) {
const { returnArrayBuffer, start, end } = options;
let headers;
if (_.isNumber(start) && _.isNumber(end)) {
headers = {
Range: `bytes=${start}-${end}`,
};
}
return _outerAjax(url, {
processData: false,
responseType: returnArrayBuffer ? 'arraybufferwithdetails' : null,
proxyUrl: '',
type: 'GET',
redirect: 'follow',
disableLogs: true,
headers,
});
}
}
}

@ -1,127 +0,0 @@
/* global window, textsecure, libsession */
/* eslint-disable no-bitwise */
// eslint-disable-next-line func-names
(function() {
window.libloki = window.libloki || {};
const DebugFlagsEnum = {
GROUP_SYNC_MESSAGES: 1,
CONTACT_SYNC_MESSAGES: 2,
FALLBACK_MESSAGES: 8,
SESSION_BACKGROUND_MESSAGE: 32,
GROUP_REQUEST_INFO: 64,
// If you add any new flag, be sure it is bitwise safe! (unique and 2 multiples)
ALL: 65535,
};
const debugFlags = DebugFlagsEnum.ALL;
const debugLogFn = (...args) => {
if (window.lokiFeatureFlags.debugMessageLogs) {
window.log.warn(...args);
}
};
function logGroupSync(...args) {
if (debugFlags & DebugFlagsEnum.GROUP_SYNC_MESSAGES) {
debugLogFn(...args);
}
}
function logGroupRequestInfo(...args) {
if (debugFlags & DebugFlagsEnum.GROUP_REQUEST_INFO) {
debugLogFn(...args);
}
}
function logContactSync(...args) {
if (debugFlags & DebugFlagsEnum.CONTACT_SYNC_MESSAGES) {
debugLogFn(...args);
}
}
function logBackgroundMessage(...args) {
if (debugFlags & DebugFlagsEnum.SESSION_BACKGROUND_MESSAGE) {
debugLogFn(...args);
}
}
async function createContactSyncMessage(sessionContacts) {
if (sessionContacts.length === 0) {
return null;
}
const rawContacts = await Promise.all(
sessionContacts.map(async conversation => {
const profile = conversation.getLokiProfile();
const name = profile
? profile.displayName
: conversation.getProfileName();
const status = await conversation.safeGetVerified();
return {
name,
number: conversation.getNumber(),
nickname: conversation.getNickname(),
blocked: conversation.isBlocked(),
expireTimer: conversation.get('expireTimer'),
verifiedStatus: status,
};
})
);
return new libsession.Messages.Outgoing.ContactSyncMessage({
timestamp: Date.now(),
rawContacts,
});
}
function createGroupSyncMessage(sessionGroup) {
// We are getting a single open group here
const rawGroup = {
id: sessionGroup.id,
name: sessionGroup.get('name'),
members: sessionGroup.get('members') || [],
blocked: sessionGroup.isBlocked(),
expireTimer: sessionGroup.get('expireTimer'),
admins: sessionGroup.get('groupAdmins') || [],
};
return new libsession.Messages.Outgoing.ClosedGroupSyncMessage({
timestamp: Date.now(),
rawGroup,
});
}
async function sendSessionRequestsToMembers(members = []) {
// For every member, trigger a session request if needed
members.forEach(async memberStr => {
const ourPubKey = textsecure.storage.user.getNumber();
if (memberStr !== ourPubKey) {
const memberPubkey = new libsession.Types.PubKey(memberStr);
await window
.getConversationController()
.getOrCreateAndWait(memberStr, 'private');
await libsession.Protocols.SessionProtocol.sendSessionRequestIfNeeded(
memberPubkey
);
}
});
}
const debug = {
logContactSync,
logGroupSync,
logBackgroundMessage,
logGroupRequestInfo,
};
window.libloki.api = {
sendSessionRequestsToMembers,
createContactSyncMessage,
createGroupSyncMessage,
debug,
};
})();

@ -24,7 +24,6 @@
<script type="text/javascript" src="../../libtextsecure/protobufs.js" data-cover></script>
<script type="text/javascript" src="../../libtextsecure/stringview.js" data-cover></script>
<script type="text/javascript" src="../api.js" data-cover></script>
<script type="text/javascript" src="../crypto.js" data-cover></script>
<script type="text/javascript" src="../service_nodes.js" data-cover></script>
<script type="text/javascript" src="../storage.js" data-cover></script>

@ -530,9 +530,13 @@
const conversations = window
.getConversationController()
.getConversations();
await textsecure.messaging.sendGroupSyncMessage(conversations);
await textsecure.messaging.sendOpenGroupsSyncMessage(conversations);
await textsecure.messaging.sendContactSyncMessage();
await libsession.Utils.SyncMessageUtils.sendGroupSyncMessage(
conversations
);
await libsession.Utils.SyncMessageUtils.sendOpenGroupsSyncMessage(
conversations
);
await libsession.Utils.SyncMessageUtils.sendContactSyncMessage();
}, 5000);
},
validatePubKeyHex(pubKey) {

@ -1,7 +1,7 @@
import { LibTextsecureCryptoInterface } from './crypto';
export interface LibTextsecure {
messaging: any;
messaging: boolean;
crypto: LibTextsecureCryptoInterface;
storage: any;
SendMessageNetworkError: any;

@ -1,24 +1,17 @@
/* global window: false */
/* global callWorker: false */
/* global textsecure: false */
/* global WebSocket: false */
/* global Event: false */
/* global dcodeIO: false */
/* global lokiPublicChatAPI: false */
/* global feeds: false */
/* global WebAPI: false */
/* eslint-disable more/no-then */
/* eslint-disable no-unreachable */
let openGroupBound = false;
function MessageReceiver(username, password, signalingKey) {
this.count = 0;
this.signalingKey = signalingKey;
this.server = WebAPI.connect();
function MessageReceiver() {
this.pending = Promise.resolve();
// only do this once to prevent duplicates
@ -58,7 +51,6 @@ MessageReceiver.prototype.extend({
return;
}
this.count = 0;
if (this.hasConnected) {
const ev = new Event('reconnect');
this.dispatchEvent(ev);
@ -94,8 +86,6 @@ MessageReceiver.prototype.extend({
if (lokiPublicChatAPI) {
await lokiPublicChatAPI.close();
}
return this.drain();
},
onopen() {
window.log.info('websocket open');
@ -112,42 +102,18 @@ MessageReceiver.prototype.extend({
this.calledClose
);
},
drain() {
const { incoming } = this;
this.incoming = [];
// This promise will resolve when there are no more messages to be processed.
return Promise.all(incoming);
},
getStatus() {
if (this.hasConnected) {
return WebSocket.CLOSED;
}
return -1;
},
});
window.textsecure = window.textsecure || {};
textsecure.MessageReceiver = function MessageReceiverWrapper(
username,
password,
signalingKey,
options
) {
const messageReceiver = new MessageReceiver(
username,
password,
signalingKey,
options
);
textsecure.MessageReceiver = function MessageReceiverWrapper() {
const messageReceiver = new MessageReceiver();
this.addEventListener = messageReceiver.addEventListener.bind(
messageReceiver
);
this.removeEventListener = messageReceiver.removeEventListener.bind(
messageReceiver
);
this.getStatus = messageReceiver.getStatus.bind(messageReceiver);
this.close = messageReceiver.close.bind(messageReceiver);
this.stopProcessing = messageReceiver.stopProcessing.bind(messageReceiver);

@ -1,388 +0,0 @@
/* global textsecure, WebAPI, window, libloki, _, libsession */
/* eslint-disable more/no-then, no-bitwise */
function stringToArrayBuffer(str) {
if (typeof str !== 'string') {
throw new Error('Passed non-string to stringToArrayBuffer');
}
const res = new ArrayBuffer(str.length);
const uint = new Uint8Array(res);
for (let i = 0; i < str.length; i += 1) {
uint[i] = str.charCodeAt(i);
}
return res;
}
function Message(options) {
this.body = options.body;
this.attachments = options.attachments || [];
this.quote = options.quote;
this.preview = options.preview;
this.group = options.group;
this.flags = options.flags;
this.recipients = options.recipients;
this.timestamp = options.timestamp;
this.needsSync = options.needsSync;
this.expireTimer = options.expireTimer;
this.profileKey = options.profileKey;
this.profile = options.profile;
this.groupInvitation = options.groupInvitation;
this.sessionRestoration = options.sessionRestoration || false;
if (!(this.recipients instanceof Array)) {
throw new Error('Invalid recipient list');
}
if (!this.group && this.recipients.length !== 1) {
throw new Error('Invalid recipient list for non-group');
}
if (typeof this.timestamp !== 'number') {
throw new Error('Invalid timestamp');
}
if (this.expireTimer !== undefined && this.expireTimer !== null) {
if (typeof this.expireTimer !== 'number' || !(this.expireTimer >= 0)) {
throw new Error('Invalid expireTimer');
}
}
if (this.attachments) {
if (!(this.attachments instanceof Array)) {
throw new Error('Invalid message attachments');
}
}
if (this.flags !== undefined) {
if (typeof this.flags !== 'number') {
throw new Error('Invalid message flags');
}
}
if (this.isEndSession()) {
if (
this.body !== null ||
this.group !== null ||
this.attachments.length !== 0
) {
throw new Error('Invalid end session message');
}
} else {
if (
typeof this.timestamp !== 'number' ||
(this.body && typeof this.body !== 'string')
) {
throw new Error('Invalid message body');
}
if (this.group) {
if (
typeof this.group.id !== 'string' ||
typeof this.group.type !== 'number'
) {
throw new Error('Invalid group context');
}
}
}
}
Message.prototype = {
constructor: Message,
isEndSession() {
return this.flags & textsecure.protobuf.DataMessage.Flags.END_SESSION;
},
toProto() {
if (this.dataMessage instanceof textsecure.protobuf.DataMessage) {
return this.dataMessage;
}
const proto = new textsecure.protobuf.DataMessage();
if (this.body) {
proto.body = this.body;
}
proto.attachments = this.attachmentPointers;
if (this.flags) {
proto.flags = this.flags;
}
if (this.group) {
proto.group = new textsecure.protobuf.GroupContext();
proto.group.id = stringToArrayBuffer(this.group.id);
proto.group.type = this.group.type;
}
if (Array.isArray(this.preview)) {
proto.preview = this.preview.map(preview => {
const item = new textsecure.protobuf.DataMessage.Preview();
item.title = preview.title;
item.url = preview.url;
item.image = preview.image || null;
return item;
});
}
if (this.quote) {
const { QuotedAttachment } = textsecure.protobuf.DataMessage.Quote;
const { Quote } = textsecure.protobuf.DataMessage;
proto.quote = new Quote();
const { quote } = proto;
quote.id = this.quote.id;
quote.author = this.quote.author;
quote.text = this.quote.text;
quote.attachments = (this.quote.attachments || []).map(attachment => {
const quotedAttachment = new QuotedAttachment();
quotedAttachment.contentType = attachment.contentType;
quotedAttachment.fileName = attachment.fileName;
if (attachment.attachmentPointer) {
quotedAttachment.thumbnail = attachment.attachmentPointer;
}
return quotedAttachment;
});
}
if (this.expireTimer) {
proto.expireTimer = this.expireTimer;
}
if (this.profileKey) {
proto.profileKey = this.profileKey;
}
// Set the loki profile
if (this.profile) {
const profile = new textsecure.protobuf.DataMessage.LokiProfile();
if (this.profile.displayName) {
profile.displayName = this.profile.displayName;
}
const conversation = window
.getConversationController()
.get(textsecure.storage.user.getNumber());
const avatarPointer = conversation.get('avatarPointer');
if (avatarPointer) {
profile.avatar = avatarPointer;
}
proto.profile = profile;
}
if (this.groupInvitation) {
proto.groupInvitation = new textsecure.protobuf.DataMessage.GroupInvitation(
{
serverAddress: this.groupInvitation.serverAddress,
channelId: this.groupInvitation.channelId,
serverName: this.groupInvitation.serverName,
}
);
}
if (this.sessionRestoration) {
proto.flags = textsecure.protobuf.DataMessage.Flags.SESSION_RESTORE;
}
this.dataMessage = proto;
return proto;
},
toArrayBuffer() {
return this.toProto().toArrayBuffer();
},
};
function MessageSender() {
// Currently only used for getProxiedSize() and makeProxiedRequest(), which are only used for fetching previews
this.server = WebAPI.connect();
}
MessageSender.prototype = {
constructor: MessageSender,
async sendContactSyncMessage(convos) {
let convosToSync;
if (!convos) {
convosToSync = await libsession.Utils.SyncMessageUtils.getSyncContacts();
} else {
convosToSync = convos;
}
if (convosToSync.size === 0) {
window.log.info('No contacts to sync.');
return Promise.resolve();
}
libloki.api.debug.logContactSync(
'Triggering contact sync message with:',
convosToSync
);
// We need to sync across 3 contacts at a time
// This is to avoid hitting storage server limit
const chunked = _.chunk(convosToSync, 3);
const syncMessages = await Promise.all(
chunked.map(c => libloki.api.createContactSyncMessage(c))
);
const syncPromises = syncMessages.map(syncMessage =>
libsession.getMessageQueue().sendSyncMessage(syncMessage)
);
return Promise.all(syncPromises);
},
sendGroupSyncMessage(conversations) {
// If we havn't got a primaryDeviceKey then we are in the middle of pairing
// primaryDevicePubKey is set to our own number if we are the master device
const primaryDeviceKey = window.storage.get('primaryDevicePubKey');
if (!primaryDeviceKey) {
window.log.debug('sendGroupSyncMessage: no primary device pubkey');
return Promise.resolve();
}
// We only want to sync across closed groups that we haven't left
const activeGroups = conversations.filter(
c => c.isClosedGroup() && !c.get('left') && !c.get('isKickedFromGroup')
);
if (activeGroups.length === 0) {
window.log.info('No closed group to sync.');
return Promise.resolve();
}
const mediumGroups = activeGroups.filter(c => c.isMediumGroup());
window.libsession.ClosedGroupV2.syncMediumGroups(mediumGroups);
const legacyGroups = activeGroups.filter(c => !c.isMediumGroup());
// We need to sync across 1 group at a time
// This is because we could hit the storage server limit with one group
const syncPromises = legacyGroups
.map(c => libloki.api.createGroupSyncMessage(c))
.map(syncMessage =>
libsession.getMessageQueue().sendSyncMessage(syncMessage)
);
return Promise.all(syncPromises);
},
async sendOpenGroupsSyncMessage(convos) {
// If we havn't got a primaryDeviceKey then we are in the middle of pairing
// primaryDevicePubKey is set to our own number if we are the master device
const primaryDeviceKey = window.storage.get('primaryDevicePubKey');
if (!primaryDeviceKey) {
return Promise.resolve();
}
const conversations = Array.isArray(convos) ? convos : [convos];
const openGroupsConvos = await libsession.Utils.SyncMessageUtils.filterOpenGroupsConvos(
conversations
);
if (!openGroupsConvos.length) {
window.log.info('No open groups to sync');
return Promise.resolve();
}
// Send the whole list of open groups in a single message
const openGroupsDetails = openGroupsConvos.map(conversation => ({
url: conversation.id,
channelId: conversation.get('channelId'),
}));
const openGroupsSyncParams = {
timestamp: Date.now(),
openGroupsDetails,
};
const openGroupsSyncMessage = new libsession.Messages.Outgoing.OpenGroupSyncMessage(
openGroupsSyncParams
);
return libsession.getMessageQueue().sendSyncMessage(openGroupsSyncMessage);
},
async sendBlockedListSyncMessage() {
// If we havn't got a primaryDeviceKey then we are in the middle of pairing
// primaryDevicePubKey is set to our own number if we are the master device
const primaryDeviceKey = window.storage.get('primaryDevicePubKey');
if (!primaryDeviceKey) {
return Promise.resolve();
}
const currentlyBlockedNumbers = window.BlockedNumberController.getBlockedNumbers();
// currently we only sync user blocked, not groups
const blockedSyncMessage = new libsession.Messages.Outgoing.BlockedListSyncMessage(
{
timestamp: Date.now(),
numbers: currentlyBlockedNumbers,
groups: [],
}
);
return libsession.getMessageQueue().sendSyncMessage(blockedSyncMessage);
},
syncReadMessages(reads) {
const myDevice = textsecure.storage.user.getDeviceId();
// FIXME currently not in used
if (myDevice !== 1 && myDevice !== '1') {
const syncReadMessages = new libsession.Messages.Outgoing.SyncReadMessage(
{
timestamp: Date.now(),
readMessages: reads,
}
);
return libsession.getMessageQueue().sendSyncMessage(syncReadMessages);
}
return Promise.resolve();
},
async syncVerification(destination, state, identityKey) {
const myDevice = textsecure.storage.user.getDeviceId();
// FIXME currently not in used
if (myDevice === 1 || myDevice === '1') {
return Promise.resolve();
}
// send a session established message (used as a nullMessage)
const destinationPubKey = new libsession.Types.PubKey(destination);
const sessionEstablished = new window.libsession.Messages.Outgoing.SessionEstablishedMessage(
{ timestamp: Date.now() }
);
const { padding } = sessionEstablished;
await libsession
.getMessageQueue()
.send(destinationPubKey, sessionEstablished);
const verifiedSyncParams = {
state,
destination: destinationPubKey,
identityKey,
padding,
timestamp: Date.now(),
};
const verifiedSyncMessage = new window.libsession.Messages.Outgoing.VerifiedSyncMessage(
verifiedSyncParams
);
return libsession.getMessageQueue().sendSyncMessage(verifiedSyncMessage);
},
makeProxiedRequest(url, options) {
return this.server.makeProxiedRequest(url, options);
},
getProxiedSize(url) {
return this.server.getProxiedSize(url);
},
};
window.textsecure = window.textsecure || {};
textsecure.MessageSender = function MessageSenderWrapper() {
const sender = new MessageSender();
this.sendContactSyncMessage = sender.sendContactSyncMessage.bind(sender);
this.sendGroupSyncMessage = sender.sendGroupSyncMessage.bind(sender);
this.sendOpenGroupsSyncMessage = sender.sendOpenGroupsSyncMessage.bind(
sender
);
this.syncReadMessages = sender.syncReadMessages.bind(sender);
this.syncVerification = sender.syncVerification.bind(sender);
this.makeProxiedRequest = sender.makeProxiedRequest.bind(sender);
this.getProxiedSize = sender.getProxiedSize.bind(sender);
this.sendBlockedListSyncMessage = sender.sendBlockedListSyncMessage.bind(
sender
);
};
textsecure.MessageSender.prototype = {
constructor: textsecure.MessageSender,
};

@ -35,17 +35,5 @@
getDeviceName() {
return textsecure.storage.get('device_name');
},
setDeviceNameEncrypted() {
return textsecure.storage.put('deviceNameEncrypted', true);
},
getDeviceNameEncrypted() {
return textsecure.storage.get('deviceNameEncrypted');
},
getSignalingKey() {
return textsecure.storage.get('signaling_key');
},
};
})();

@ -1,88 +0,0 @@
/* global Event, textsecure, window, libsession */
/* eslint-disable more/no-then */
// eslint-disable-next-line func-names
(function() {
window.textsecure = window.textsecure || {};
async function SyncRequest() {
// this.receiver = receiver;
window.log.info('SyncRequest created. Sending config sync request...');
const { CONFIGURATION } = textsecure.protobuf.SyncMessage.Request.Type;
const { RequestSyncMessage } = window.libsession.Messages.Outgoing;
const requestConfigurationSyncMessage = new RequestSyncMessage({
timestamp: Date.now(),
reqestType: CONFIGURATION,
});
await libsession
.getMessageQueue()
.sendSyncMessage(requestConfigurationSyncMessage);
window.log.info('SyncRequest now sending contact sync message...');
const { CONTACTS } = textsecure.protobuf.SyncMessage.Request.Type;
const requestContactSyncMessage = new RequestSyncMessage({
timestamp: Date.now(),
reqestType: CONTACTS,
});
await libsession
.getMessageQueue()
.sendSyncMessage(requestContactSyncMessage);
window.log.info('SyncRequest now sending group sync messsage...');
const { GROUPS } = textsecure.protobuf.SyncMessage.Request.Type;
const requestGroupSyncMessage = new RequestSyncMessage({
timestamp: Date.now(),
reqestType: GROUPS,
});
await libsession.getMessageQueue().sendSyncMessage(requestGroupSyncMessage);
this.timeout = setTimeout(this.onTimeout.bind(this), 60000);
}
SyncRequest.prototype = new textsecure.EventTarget();
SyncRequest.prototype.extend({
constructor: SyncRequest,
onContactSyncComplete() {
this.contactSync = true;
this.update();
},
onGroupSyncComplete() {
this.groupSync = true;
this.update();
},
update() {
if (this.contactSync && this.groupSync) {
this.dispatchEvent(new Event('success'));
this.cleanup();
}
},
onTimeout() {
if (this.contactSync || this.groupSync) {
this.dispatchEvent(new Event('success'));
} else {
this.dispatchEvent(new Event('timeout'));
}
this.cleanup();
},
cleanup() {
clearTimeout(this.timeout);
delete this.listeners;
},
});
textsecure.SyncRequest = function SyncRequestWrapper() {
const syncRequest = new SyncRequest();
this.addEventListener = syncRequest.addEventListener.bind(syncRequest);
this.removeEventListener = syncRequest.removeEventListener.bind(
syncRequest
);
};
textsecure.SyncRequest.prototype = {
constructor: textsecure.SyncRequest,
};
})();

@ -1,13 +0,0 @@
window.setImmediate = window.nodeSetImmediate;
const fakeCall = () => Promise.resolve();
const fakeAPI = {
getAttachment: fakeCall,
putAttachment: fakeCall,
putAvatar: fakeCall,
};
window.WebAPI = {
connect: () => fakeAPI,
};

@ -1,29 +0,0 @@
describe('Helpers', () => {
describe('ArrayBuffer->String conversion', () => {
it('works', () => {
const b = new ArrayBuffer(3);
const a = new Uint8Array(b);
a[0] = 0;
a[1] = 255;
a[2] = 128;
assert.equal(getString(b), '\x00\xff\x80');
});
});
describe('stringToArrayBuffer', () => {
it('returns ArrayBuffer when passed string', () => {
const anArrayBuffer = new ArrayBuffer(1);
const typedArray = new Uint8Array(anArrayBuffer);
typedArray[0] = 'a'.charCodeAt(0);
assertEqualArrayBuffers(stringToArrayBuffer('a'), anArrayBuffer);
});
it('throws an error when passed a non string', () => {
const notStringable = [{}, undefined, null, new ArrayBuffer()];
notStringable.forEach(notString => {
assert.throw(() => {
stringToArrayBuffer(notString);
}, Error);
});
});
});
});

@ -12,7 +12,6 @@
<div id="tests">
</div>
<script type="text/javascript" src="fake_web_api.js"></script>
<script type="text/javascript" src="test.js"></script>
<script type="text/javascript" src="in_memory_signal_protocol_store.js"></script>
@ -29,8 +28,6 @@
<script type="text/javascript" src="../websocket-resources.js" data-cover></script>
<script type="text/javascript" src="../helpers.js" data-cover></script>
<script type="text/javascript" src="../stringview.js" data-cover></script>
<script type="text/javascript" src="../api.js"></script>
<script type="text/javascript" src="../sendmessage.js" data-cover></script>
<script type="text/javascript" src="../account_manager.js" data-cover></script>
<script type="text/javascript" src="../contacts_parser.js" data-cover></script>
<script type="text/javascript" src="../task_with_timeout.js" data-cover></script>

@ -1,104 +0,0 @@
/* global libsignal, textsecure, SignalProtocolStore */
describe('MessageReceiver', () => {
textsecure.storage.impl = new SignalProtocolStore();
const { WebSocket } = window;
const number = '+19999999999';
const deviceId = 1;
const signalingKey = libsignal.crypto.getRandomBytes(32 + 20);
before(() => {
window.WebSocket = MockSocket;
textsecure.storage.user.setNumberAndDeviceId(number, deviceId, 'name');
textsecure.storage.put('password', 'password');
textsecure.storage.put('signaling_key', signalingKey);
});
after(() => {
window.WebSocket = WebSocket;
});
describe('connecting', () => {
const attrs = {
type: textsecure.protobuf.Envelope.Type.CIPHERTEXT,
source: number,
sourceDevice: deviceId,
timestamp: Date.now(),
};
const websocketmessage = new textsecure.protobuf.WebSocketMessage({
type: textsecure.protobuf.WebSocketMessage.Type.REQUEST,
request: { verb: 'PUT', path: '/messages' },
});
before(done => {
const signal = new textsecure.protobuf.Envelope(attrs).toArrayBuffer();
const aesKey = signalingKey.slice(0, 32);
const macKey = signalingKey.slice(32, 32 + 20);
window.crypto.subtle
.importKey('raw', aesKey, { name: 'AES-CBC' }, false, ['encrypt'])
.then(key => {
const iv = libsignal.crypto.getRandomBytes(16);
window.crypto.subtle
.encrypt({ name: 'AES-CBC', iv: new Uint8Array(iv) }, key, signal)
.then(ciphertext => {
window.crypto.subtle
.importKey(
'raw',
macKey,
{ name: 'HMAC', hash: { name: 'SHA-256' } },
false,
['sign']
)
.then(innerKey => {
window.crypto.subtle
.sign({ name: 'HMAC', hash: 'SHA-256' }, innerKey, signal)
.then(mac => {
const version = new Uint8Array([1]);
const message = dcodeIO.ByteBuffer.concat([
version,
iv,
ciphertext,
mac,
]);
websocketmessage.request.body = message.toArrayBuffer();
done();
});
});
});
});
});
it('connects', done => {
const mockServer = new MockServer(
`ws://localhost:8080/v1/websocket/?login=${encodeURIComponent(
number
)}.1&password=password`
);
mockServer.on('connection', server => {
server.send(new Blob([websocketmessage.toArrayBuffer()]));
});
window.addEventListener('textsecure:message', ev => {
const signal = ev.proto;
const keys = Object.keys(attrs);
for (let i = 0, max = keys.length; i < max; i += 1) {
const key = keys[i];
assert.strictEqual(attrs[key], signal[key]);
}
assert.strictEqual(signal.message.body, 'hello');
mockServer.close();
done();
});
window.messageReceiver = new textsecure.MessageReceiver(
'signalingKey'
// 'ws://localhost:8080',
// window,
);
});
});
});

@ -1,66 +0,0 @@
/* global TextSecureWebSocket */
describe('TextSecureWebSocket', () => {
const RealWebSocket = window.WebSocket;
before(() => {
window.WebSocket = MockSocket;
});
after(() => {
window.WebSocket = RealWebSocket;
});
it('connects and disconnects', done => {
const mockServer = new MockServer('ws://localhost:8080');
mockServer.on('connection', server => {
socket.close();
server.close();
done();
});
const socket = new TextSecureWebSocket('ws://localhost:8080');
});
it('sends and receives', done => {
const mockServer = new MockServer('ws://localhost:8080');
mockServer.on('connection', server => {
server.on('message', () => {
server.send('ack');
server.close();
});
});
const socket = new TextSecureWebSocket('ws://localhost:8080');
socket.onmessage = response => {
assert.strictEqual(response.data, 'ack');
socket.close();
done();
};
socket.send('syn');
});
it('exposes the socket status', done => {
const mockServer = new MockServer('ws://localhost:8082');
mockServer.on('connection', server => {
assert.strictEqual(socket.getStatus(), WebSocket.OPEN);
server.close();
socket.close();
});
const socket = new TextSecureWebSocket('ws://localhost:8082');
socket.onclose = () => {
assert.strictEqual(socket.getStatus(), WebSocket.CLOSING);
done();
};
});
it('reconnects', function thisNeeded(done) {
this.timeout(60000);
const mockServer = new MockServer('ws://localhost:8082');
const socket = new TextSecureWebSocket('ws://localhost:8082');
socket.onclose = () => {
const secondServer = new MockServer('ws://localhost:8082');
secondServer.on('connection', server => {
socket.close();
server.close();
done();
});
};
mockServer.close();
});
});

@ -340,10 +340,6 @@ if (config.proxyUrl) {
window.nodeSetImmediate = setImmediate;
const { initialize: initializeWebAPI } = require('./js/modules/web_api');
window.WebAPI = initializeWebAPI();
window.seedNodeList = JSON.parse(config.seedNodeList);
const { OnionAPI } = require('./ts/session/onions');
@ -461,7 +457,6 @@ window.lokiFeatureFlags = {
useFileOnionRequests: true,
useFileOnionRequestsV2: true, // more compact encoding of files in response
onionRequestHops: 3,
debugMessageLogs: process.env.ENABLE_MESSAGE_LOGS,
useMultiDevice: false,
};
@ -497,7 +492,6 @@ if (config.environment.includes('test-integration')) {
useOnionRequests: false,
useFileOnionRequests: false,
useOnionRequestsV2: false,
debugMessageLogs: true,
useMultiDevice: false,
};
/* eslint-disable global-require, import/no-extraneous-dependencies */

@ -5,7 +5,6 @@
describe('Fixtures', () => {
before(async () => {
// NetworkStatusView checks this method every five seconds while showing
window.getSocketStatus = () => WebSocket.OPEN;
await clearDatabase();
await textsecure.storage.user.setNumberAndDeviceId(

@ -166,7 +166,6 @@
{{/isError}}
</script>
<script type="text/javascript" src="../libtextsecure/test/fake_web_api.js"></script>
<script type="text/javascript" src="../js/components.js"></script>
<script type="text/javascript" src="../js/reliable_trigger.js" data-cover></script>

@ -3,7 +3,7 @@
// 'use strict';
// FIXME audric enable back those test
describe('ConversationCollection', () => {
// textsecure.messaging = new textsecure.MessageSender();
// textsecure.messaging = true;
// before(clearDatabase);
// after(clearDatabase);
// it('should be ordered newest to oldest', () => {

@ -31,6 +31,7 @@ import { ToastUtils } from '../../session/utils';
import { DefaultTheme } from 'styled-components';
import { LeftPaneSectionHeader } from './LeftPaneSectionHeader';
import { ConversationController } from '../../session/conversations';
import { sendOpenGroupsSyncMessage } from '../../session/utils/SyncMessage';
export interface Props {
searchTerm: string;
@ -456,9 +457,7 @@ export class LeftPaneMessageSection extends React.Component<Props, State> {
if (openGroupConversation) {
// if no errors happened, trigger a sync with just this open group
// so our other devices joins it
await window.textsecure.messaging.sendOpenGroupsSyncMessage(
openGroupConversation
);
await sendOpenGroupsSyncMessage([openGroupConversation]);
} else {
window.log.error(
'Joined an opengroup but did not find ther corresponding conversation'

@ -366,10 +366,6 @@ async function handleUpdateClosedGroupV2(
diff.newName
) {
await ClosedGroupV2.addUpdateMessage(convo, diff, 'incoming');
if (diff.joiningMembers?.length) {
// send a session request for all the members we do not have a session with
await window.libloki.api.sendSessionRequestsToMembers(members);
}
}
convo.set('name', name);

@ -303,12 +303,6 @@ async function onContactReceived(details: any) {
const { Errors } = window.Signal.Types;
const id = details.number;
libloki.api.debug.logContactSync(
'Got sync contact message with',
id,
' details:',
details
);
if (id === textsecure.storage.user.getNumber()) {
// special case for syncing details about ourselves

@ -159,9 +159,6 @@ async function handleOpenGroups(
openGroups: Array<SignalService.SyncMessage.IOpenGroupDetails>
) {
const groupsArray = openGroups.map(openGroup => openGroup.url);
window.libloki.api.debug.logGroupSync(
`Received GROUP_SYNC with open groups: [${groupsArray}]`
);
openGroups.forEach(({ url, channelId }) => {
window.attemptConnection(url, channelId);
});

@ -199,17 +199,8 @@ export function buildGroupDiff(
}
export async function updateOrCreateClosedGroupV2(details: GroupInfo) {
const { libloki } = window;
const { id } = details;
libloki.api.debug.logGroupSync(
'Got sync group message v2with group id',
id,
' details:',
details
);
const conversation = await ConversationController.getInstance().getOrCreateAndWait(
id,
'group'

@ -1,36 +0,0 @@
import { SyncMessage } from './SyncMessage';
import { SignalService } from '../../../../../protobuf';
import { MessageParams } from '../../Message';
import { Constants } from '../../../..';
interface RequestSyncMessageParams extends MessageParams {
requestType: SignalService.SyncMessage.Request.Type;
}
export abstract class RequestSyncMessage extends SyncMessage {
private readonly requestType: SignalService.SyncMessage.Request.Type;
constructor(params: RequestSyncMessageParams) {
super({ timestamp: params.timestamp, identifier: params.identifier });
this.requestType = params.requestType;
}
public ttl(): number {
return Constants.TTL_DEFAULT.REGULAR_MESSAGE;
}
public contentProto(): SignalService.Content {
return new SignalService.Content({
syncMessage: this.syncProto(),
});
}
protected syncProto(): SignalService.SyncMessage {
const syncMessage = super.syncProto();
syncMessage.request = new SignalService.SyncMessage.Request({
type: this.requestType,
});
return syncMessage;
}
}

@ -1,37 +0,0 @@
import { SyncMessage } from './SyncMessage';
import { SignalService } from '../../../../../protobuf';
import { MessageParams } from '../../Message';
import { PubKey } from '../../../../types';
interface VerifiedSyncMessageParams extends MessageParams {
padding: Buffer;
identityKey: Uint8Array;
destination: PubKey;
state: SignalService.Verified.State;
}
export abstract class VerifiedSyncMessage extends SyncMessage {
public readonly state: SignalService.Verified.State;
public readonly destination: PubKey;
public readonly identityKey: Uint8Array;
public readonly padding: Buffer;
constructor(params: VerifiedSyncMessageParams) {
super({ timestamp: params.timestamp, identifier: params.identifier });
this.state = params.state;
this.destination = params.destination;
this.identityKey = params.identityKey;
this.padding = params.padding;
}
protected syncProto(): SignalService.SyncMessage {
const syncMessage = super.syncProto();
syncMessage.verified = new SignalService.Verified();
syncMessage.verified.state = this.state;
syncMessage.verified.destination = this.destination.key;
syncMessage.verified.identityKey = this.identityKey;
syncMessage.verified.nullMessage = this.padding;
return syncMessage;
}
}

@ -1,9 +1,7 @@
export * from './RequestSyncMessage';
export * from './ContactSyncMessage';
export * from './ClosedGroupSyncMessage';
export * from './OpenGroupSyncMessage';
export * from './SyncMessage';
export * from './SentSyncMessage';
export * from './SyncReadMessage';
export * from './VerifiedSyncMessage';
export * from './BlockedListSyncMessage';

@ -1,15 +1,22 @@
import * as _ from 'lodash';
import { UserUtil } from '../../util';
import { BlockedNumberController, UserUtil } from '../../util';
import { getAllConversations } from '../../../js/modules/data';
import { MultiDeviceProtocol } from '../protocols';
import ByteBuffer from 'bytebuffer';
import {
BlockedListSyncMessage,
ClosedGroupSyncMessage,
ContentMessage,
DataMessage,
OpenGroupSyncMessage,
SentSyncMessage,
SyncReadMessage,
} from '../messages/outgoing';
import { PubKey } from '../types';
import { ConversationController } from '../conversations';
import { ConversationModel } from '../../../js/models/conversations';
import { getMessageQueue } from '../instance';
import { syncMediumGroups } from '../groupv2';
export function getSentSyncMessage(params: {
message: ContentMessage;
@ -32,14 +39,13 @@ export function getSentSyncMessage(params: {
});
}
export async function getSyncContacts(): Promise<Array<any> | undefined> {
export async function getSyncContacts(): Promise<Array<ConversationModel>> {
const thisDevice = await UserUtil.getCurrentDevicePubKey();
if (!thisDevice) {
return [];
}
const primaryDevice = await MultiDeviceProtocol.getPrimaryDevice(thisDevice);
const conversations = await getAllConversations({
ConversationCollection: window.Whisper.ConversationCollection,
});
@ -55,28 +61,8 @@ export async function getSyncContacts(): Promise<Array<any> | undefined> {
!!c.get('active_at')
) || [];
const secondaryContactsPartial = conversations.filter(
c =>
c.isPrivate() &&
!c.isOurLocalDevice() &&
!c.isBlocked() &&
c.attributes.secondaryStatus &&
!!c.get('active_at')
);
const secondaryContactsPromise = secondaryContactsPartial.map(async c =>
ConversationController.getInstance().getOrCreateAndWait(
c.getPrimaryDevicePubKey(),
'private'
)
);
const secondaryContacts = (await Promise.all(secondaryContactsPromise))
// Filter out our primary key if it was added here
.filter(c => c.id !== primaryDevice.key);
// Return unique contacts
return _.uniqBy([...primaryContacts, ...secondaryContacts], 'id');
return primaryContacts;
}
export async function filterOpenGroupsConvos(
@ -110,3 +96,188 @@ export function serialiseByteBuffers(buffers: Array<Uint8Array>): ByteBuffer {
result.reset();
return result;
}
export async function sendContactSyncMessage(convos: Array<ConversationModel>) {
throw new Error('Still in use?');
// let convosToSync: Array<ConversationModel>;
// if (!convos?.length) {
// convosToSync = await getSyncContacts();
// } else {
// convosToSync = convos;
// }
// if (convosToSync?.length === 0) {
// window.log.info('No contacts to sync.');
// return Promise.resolve();
// }
// // We need to sync across 3 contacts at a time
// // This is to avoid hitting storage server limit
// const chunked = _.chunk(convosToSync, 3);
// const syncMessages = await Promise.all(
// chunked.map(c => createContactSyncMessage(c))
// );
// const syncPromises = syncMessages.map(syncMessage =>
// getMessageQueue().sendSyncMessage(syncMessage)
// );
// return Promise.all(syncPromises);
}
function createGroupSyncMessage(sessionGroup: any) {
// We are getting a single open group here
// const rawGroup = {
// id: sessionGroup.id,
// name: sessionGroup.get('name'),
// members: sessionGroup.get('members') || [],
// blocked: sessionGroup.isBlocked(),
// expireTimer: sessionGroup.get('expireTimer'),
// admins: sessionGroup.get('groupAdmins') || [],
// };
throw new Error('Still in use?');
// return new ClosedGroupSyncMessage({
// timestamp: Date.now(),
// rawGroup,
// });
}
async function createContactSyncMessage(sessionContacts: Array<any>) {
if (sessionContacts.length === 0) {
return null;
}
const rawContacts = await Promise.all(
sessionContacts.map(async conversation => {
const profile = conversation.getLokiProfile();
const name = profile
? profile.displayName
: conversation.getProfileName();
const status = await conversation.safeGetVerified();
return {
name,
number: conversation.getNumber(),
nickname: conversation.getNickname(),
blocked: conversation.isBlocked(),
expireTimer: conversation.get('expireTimer'),
verifiedStatus: status,
};
})
);
throw new Error('Still in use?');
// return new ContactSyncMessage({
// timestamp: Date.now(),
// rawContacts,
// });
}
export async function sendGroupSyncMessage(
conversations: Array<ConversationModel>
) {
throw new Error('Still in use?');
// If we havn't got a primaryDeviceKey then we are in the middle of pairing
// primaryDevicePubKey is set to our own number if we are the master device
// const primaryDeviceKey = window.storage.get('primaryDevicePubKey');
// if (!primaryDeviceKey) {
// window.log.debug('sendGroupSyncMessage: no primary device pubkey');
// return Promise.resolve();
// }
// // We only want to sync across closed groups that we haven't left
// const activeGroups = conversations.filter(
// c => c.isClosedGroup() && !c.get('left') && !c.get('isKickedFromGroup')
// );
// if (activeGroups.length === 0) {
// window.log.info('No closed group to sync.');
// return Promise.resolve();
// }
// const mediumGroups = activeGroups.filter(c => c.isMediumGroup());
// syncMediumGroups(mediumGroups);
// const legacyGroups = activeGroups.filter(c => !c.isMediumGroup());
// // We need to sync across 1 group at a time
// // This is because we could hit the storage server limit with one group
// const syncPromises = legacyGroups
// .map(c => createGroupSyncMessage(c))
// .map(syncMessage => getMessageQueue().sendSyncMessage(syncMessage));
// return Promise.all(syncPromises);
}
export async function sendOpenGroupsSyncMessage(
convos: Array<ConversationModel>
) {
throw new Error('Still in use?');
// If we havn't got a primaryDeviceKey then we are in the middle of pairing
// primaryDevicePubKey is set to our own number if we are the master device
// const primaryDeviceKey = (await UserUtil.getPrimary()).key;
// if (!primaryDeviceKey) {
// return Promise.resolve();
// }
// const conversations = Array.isArray(convos) ? convos : [convos];
// const openGroupsConvos = await filterOpenGroupsConvos(conversations);
// if (!openGroupsConvos?.length) {
// window.log.info('No open groups to sync');
// return Promise.resolve();
// }
// // Send the whole list of open groups in a single message
// const openGroupsDetails = openGroupsConvos.map(conversation => ({
// url: conversation.id,
// channelId: conversation.get('channelId'),
// }));
// const openGroupsSyncParams = {
// timestamp: Date.now(),
// openGroupsDetails,
// };
// const openGroupsSyncMessage = new OpenGroupSyncMessage(openGroupsSyncParams);
// return getMessageQueue().sendSyncMessage(openGroupsSyncMessage);
}
export async function sendBlockedListSyncMessage() {
throw new Error('Still in use?');
// If we havn't got a primaryDeviceKey then we are in the middle of pairing
// primaryDevicePubKey is set to our own number if we are the master device
// const primaryDeviceKey = window.storage.get('primaryDevicePubKey');
// if (!primaryDeviceKey) {
// return Promise.resolve();
// }
// const currentlyBlockedNumbers = BlockedNumberController.getBlockedNumbers();
// // currently we only sync user blocked, not groups
// const blockedSyncMessage = new BlockedListSyncMessage({
// timestamp: Date.now(),
// numbers: currentlyBlockedNumbers,
// groups: [],
// });
// return getMessageQueue().sendSyncMessage(blockedSyncMessage);
}
export async function syncReadMessages() {
return;
// FIXME currently not in used
// const syncReadMessages = new SyncReadMessage(
// {
// timestamp: Date.now(),
// readMessages: reads,
// }
// );
// return libsession.getMessageQueue().sendSyncMessage(syncReadMessages);
}

@ -965,30 +965,6 @@
"reasonCategory": "falseMatch",
"updated": "2018-09-19T18:13:29.628Z"
},
{
"rule": "jQuery-wrap(",
"path": "libtextsecure/sync_request.js",
"line": " wrap(sender.sendRequestConfigurationSyncMessage(sendOptions));",
"lineNumber": 33,
"reasonCategory": "falseMatch",
"updated": "2018-11-28T19:48:16.607Z"
},
{
"rule": "jQuery-wrap(",
"path": "libtextsecure/sync_request.js",
"line": " wrap(sender.sendRequestContactSyncMessage(sendOptions))",
"lineNumber": 36,
"reasonCategory": "falseMatch",
"updated": "2018-10-05T23:12:28.961Z"
},
{
"rule": "jQuery-wrap(",
"path": "libtextsecure/sync_request.js",
"line": " return wrap(sender.sendRequestGroupSyncMessage(sendOptions));",
"lineNumber": 39,
"reasonCategory": "falseMatch",
"updated": "2018-10-05T23:12:28.961Z"
},
{
"rule": "jQuery-wrap(",
"path": "node_modules/@babel/runtime/node_modules/regenerator-runtime/runtime.js",

3
ts/window.d.ts vendored

@ -41,7 +41,6 @@ declare global {
StringView: any;
StubAppDotNetApi: any;
StubMessageAPI: any;
WebAPI: any;
Whisper: any;
attemptConnection: ConversationType;
clearLocalData: any;
@ -67,7 +66,6 @@ declare global {
useFileOnionRequests: boolean;
useFileOnionRequestsV2: boolean;
onionRequestHops: number;
debugMessageLogs: boolean;
useMultiDevice: boolean;
};
lokiFileServerAPI: LokiFileServerInstance;
@ -116,7 +114,6 @@ declare global {
setClockParams: any;
clientClockSynced: number | undefined;
inboxStore: Store;
getSocketStatus: any;
actionsCreators: any;
extension: {
expired: (boolean) => void;

Loading…
Cancel
Save