move ConversationController to typescript
This commit is contained in:
parent
1a128ab055
commit
2fe6b11e89
|
@ -148,7 +148,6 @@
|
|||
<script type='text/javascript' src='js/chromium.js'></script>
|
||||
<script type='text/javascript' src='js/registration.js'></script>
|
||||
<script type='text/javascript' src='js/expire.js'></script>
|
||||
<script type='text/javascript' src='js/conversation_controller.js'></script>
|
||||
|
||||
<script type='text/javascript' src='js/views/react_wrapper_view.js'></script>
|
||||
<script type='text/javascript' src='js/views/whisper_view.js'></script>
|
||||
|
|
|
@ -152,7 +152,6 @@
|
|||
<script type='text/javascript' src='js/chromium.js'></script>
|
||||
<script type='text/javascript' src='js/registration.js'></script>
|
||||
<script type='text/javascript' src='js/expire.js'></script>
|
||||
<script type='text/javascript' src='js/conversation_controller.js'></script>
|
||||
|
||||
<script type='text/javascript' src='js/views/react_wrapper_view.js'></script>
|
||||
<script type='text/javascript' src='js/views/whisper_view.js'></script>
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
import { ConversationModel } from './models/conversations';
|
||||
|
||||
export type ConversationControllerType = {
|
||||
reset: () => void;
|
||||
load: () => Promise<void>;
|
||||
get: (id: string) => ConversationModel | undefined;
|
||||
getOrThrow: (id: string) => ConversationModel;
|
||||
getOrCreateAndWait: (id: string, type: string) => Promise<ConversationModel>;
|
||||
getOrCreate: (id: string, type: string) => Promise<ConversationModel>;
|
||||
dangerouslyCreateAndAdd: (any) => any;
|
||||
getContactProfileNameOrShortenedPubKey: (id: string) => string;
|
||||
getContactProfileNameOrFullPubKey: (
|
||||
hexEncodedGroupPublicKey: string
|
||||
) => string;
|
||||
isMediumGroup: (id: string) => boolean;
|
||||
};
|
|
@ -2,7 +2,6 @@
|
|||
$,
|
||||
_,
|
||||
Backbone,
|
||||
ConversationController,
|
||||
getAccountManager,
|
||||
Signal,
|
||||
storage,
|
||||
|
@ -371,7 +370,7 @@
|
|||
|
||||
try {
|
||||
await Promise.all([
|
||||
ConversationController.load(),
|
||||
window.getConversationController().load(),
|
||||
textsecure.storage.protocol.hydrateCaches(),
|
||||
BlockedNumberController.load(),
|
||||
]);
|
||||
|
@ -406,7 +405,9 @@
|
|||
return;
|
||||
}
|
||||
|
||||
const conversation = ConversationController.get(conversationId);
|
||||
const conversation = window
|
||||
.getConversationController()
|
||||
.get(conversationId);
|
||||
messageIds.forEach(id => {
|
||||
if (conversation) {
|
||||
conversation.removeMessage(id);
|
||||
|
@ -561,10 +562,9 @@
|
|||
|
||||
window.showEditProfileDialog = async () => {
|
||||
const ourNumber = window.storage.get('primaryDevicePubKey');
|
||||
const conversation = await ConversationController.getOrCreateAndWait(
|
||||
ourNumber,
|
||||
'private'
|
||||
);
|
||||
const conversation = await window
|
||||
.getConversationController()
|
||||
.getOrCreateAndWait(ourNumber, 'private');
|
||||
|
||||
const readFile = attachment =>
|
||||
new Promise((resolve, reject) => {
|
||||
|
@ -679,6 +679,7 @@
|
|||
|
||||
if (avatar) {
|
||||
window
|
||||
.getConversationController()
|
||||
.getConversations()
|
||||
.filter(convo => convo.isPublic() && !convo.isRss())
|
||||
.forEach(convo =>
|
||||
|
@ -765,9 +766,9 @@
|
|||
const conversationId = `publicChat:${channelId}@${rawServerURL}`;
|
||||
|
||||
// Quickly peak to make sure we don't already have it
|
||||
const conversationExists = window.ConversationController.get(
|
||||
conversationId
|
||||
);
|
||||
const conversationExists = window
|
||||
.getConversationController()
|
||||
.get(conversationId);
|
||||
if (conversationExists) {
|
||||
// We are already a member of this public chat
|
||||
return new Promise((_resolve, reject) => {
|
||||
|
@ -788,10 +789,9 @@
|
|||
}
|
||||
|
||||
// Create conversation
|
||||
const conversation = await window.ConversationController.getOrCreateAndWait(
|
||||
conversationId,
|
||||
'group'
|
||||
);
|
||||
const conversation = await window
|
||||
.getConversationController()
|
||||
.getOrCreateAndWait(conversationId, 'group');
|
||||
|
||||
// Convert conversation to a public one
|
||||
await conversation.setPublicSource(completeServerURL, channelId);
|
||||
|
@ -842,7 +842,9 @@
|
|||
const sslServerUrl = `https://${rawServerUrl}`;
|
||||
const conversationId = `publicChat:${channelId}@${rawServerUrl}`;
|
||||
|
||||
const conversationExists = ConversationController.get(conversationId);
|
||||
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();
|
||||
|
@ -850,10 +852,9 @@
|
|||
return;
|
||||
}
|
||||
|
||||
const conversation = await ConversationController.getOrCreateAndWait(
|
||||
conversationId,
|
||||
'group'
|
||||
);
|
||||
const conversation = await window
|
||||
.getConversationController()
|
||||
.getOrCreateAndWait(conversationId, 'group');
|
||||
await conversation.setPublicSource(sslServerUrl, channelId);
|
||||
|
||||
const channelAPI = await window.lokiPublicChatAPI.findOrCreateChannel(
|
||||
|
@ -897,10 +898,9 @@
|
|||
});
|
||||
|
||||
Whisper.events.on('onShowUserDetails', async ({ userPubKey }) => {
|
||||
const conversation = await ConversationController.getOrCreateAndWait(
|
||||
userPubKey,
|
||||
'private'
|
||||
);
|
||||
const conversation = await window
|
||||
.getConversationController()
|
||||
.getOrCreateAndWait(userPubKey, 'private');
|
||||
|
||||
const avatarPath = conversation.getAvatarPath();
|
||||
const profile = conversation.getLokiProfile();
|
||||
|
@ -953,7 +953,7 @@
|
|||
|
||||
Whisper.events.on('calculatingPoW', ({ pubKey, timestamp }) => {
|
||||
try {
|
||||
const conversation = ConversationController.get(pubKey);
|
||||
const conversation = window.getConversationController().get(pubKey);
|
||||
conversation.onCalculatingPoW(pubKey, timestamp);
|
||||
} catch (e) {
|
||||
window.log.error('Error showing PoW cog');
|
||||
|
@ -964,7 +964,7 @@
|
|||
'publicMessageSent',
|
||||
({ pubKey, timestamp, serverId, serverTimestamp }) => {
|
||||
try {
|
||||
const conversation = ConversationController.get(pubKey);
|
||||
const conversation = window.getConversationController().get(pubKey);
|
||||
conversation.onPublicMessageSent(
|
||||
pubKey,
|
||||
timestamp,
|
||||
|
@ -1031,7 +1031,7 @@
|
|||
await libsession.getMessageQueue().send(device, unlinkMessage);
|
||||
// Remove all traces of the device
|
||||
setTimeout(() => {
|
||||
ConversationController.deleteContact(pubKey);
|
||||
window.getConversationController().deleteContact(pubKey);
|
||||
Whisper.events.trigger('refreshLinkedDeviceList');
|
||||
callback();
|
||||
}, 1000);
|
||||
|
|
|
@ -1,329 +0,0 @@
|
|||
/* global Whisper, textsecure, libsignal, log */
|
||||
|
||||
/* eslint-disable more/no-then */
|
||||
|
||||
// eslint-disable-next-line func-names
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
window.Whisper = window.Whisper || {};
|
||||
|
||||
const conversations = new Whisper.ConversationCollection();
|
||||
|
||||
window.getConversations = () => conversations;
|
||||
|
||||
window.getMessagesByKey = async key => {
|
||||
// loadLive gets messages live, not from the database which can lag behind.
|
||||
|
||||
let messages = [];
|
||||
const messageSet = await window.Signal.Data.getMessagesByConversation(key, {
|
||||
limit: 100,
|
||||
MessageCollection: Whisper.MessageCollection,
|
||||
});
|
||||
|
||||
messages = messageSet.models.map(conv => conv.attributes);
|
||||
return messages;
|
||||
};
|
||||
|
||||
window.ConversationController = {
|
||||
get(id) {
|
||||
if (!this._initialFetchComplete) {
|
||||
throw new Error(
|
||||
'ConversationController.get() needs complete initial fetch'
|
||||
);
|
||||
}
|
||||
|
||||
return conversations.get(id);
|
||||
},
|
||||
getOrThrow(id) {
|
||||
if (!this._initialFetchComplete) {
|
||||
throw new Error(
|
||||
'ConversationController.get() needs complete initial fetch'
|
||||
);
|
||||
}
|
||||
|
||||
const convo = conversations.get(id);
|
||||
|
||||
if (convo) {
|
||||
return convo;
|
||||
}
|
||||
throw new Error(
|
||||
`Conversation ${id} does not exist on ConversationController.get()`
|
||||
);
|
||||
},
|
||||
// Needed for some model setup which happens during the initial fetch() call below
|
||||
getUnsafe(id) {
|
||||
return conversations.get(id);
|
||||
},
|
||||
dangerouslyCreateAndAdd(attributes) {
|
||||
return conversations.add(attributes);
|
||||
},
|
||||
getOrCreate(id, type) {
|
||||
if (typeof id !== 'string') {
|
||||
throw new TypeError("'id' must be a string");
|
||||
}
|
||||
|
||||
if (type !== 'private' && type !== 'group') {
|
||||
throw new TypeError(
|
||||
`'type' must be 'private' or 'group'; got: '${type}'`
|
||||
);
|
||||
}
|
||||
|
||||
if (!this._initialFetchComplete) {
|
||||
throw new Error(
|
||||
'ConversationController.get() needs complete initial fetch'
|
||||
);
|
||||
}
|
||||
|
||||
let conversation = conversations.get(id);
|
||||
if (conversation) {
|
||||
return conversation;
|
||||
}
|
||||
|
||||
conversation = conversations.add({
|
||||
id,
|
||||
type,
|
||||
version: 2,
|
||||
});
|
||||
|
||||
const create = async () => {
|
||||
if (!conversation.isValid()) {
|
||||
const validationError = conversation.validationError || {};
|
||||
window.log.error(
|
||||
'Contact is not valid. Not saving, but adding to collection:',
|
||||
conversation.idForLogging(),
|
||||
validationError.stack
|
||||
);
|
||||
|
||||
return conversation;
|
||||
}
|
||||
|
||||
try {
|
||||
await window.Signal.Data.saveConversation(conversation.attributes, {
|
||||
Conversation: Whisper.Conversation,
|
||||
});
|
||||
} catch (error) {
|
||||
window.log.error(
|
||||
'Conversation save failed! ',
|
||||
id,
|
||||
type,
|
||||
'Error:',
|
||||
error && error.stack ? error.stack : error
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
|
||||
return conversation;
|
||||
};
|
||||
|
||||
conversation.initialPromise = create();
|
||||
conversation.initialPromise.then(() => {
|
||||
if (!conversation.isPublic() && !conversation.isRss()) {
|
||||
Promise.all([
|
||||
conversation.updateProfileAvatar(),
|
||||
// NOTE: we request snodes updating the cache, but ignore the result
|
||||
window.SnodePool.getSnodesFor(id),
|
||||
]);
|
||||
}
|
||||
if (window.inboxStore) {
|
||||
conversation.on('change', this.updateReduxConvoChanged);
|
||||
window.inboxStore.dispatch(
|
||||
window.actionsCreators.conversationAdded(
|
||||
conversation.id,
|
||||
conversation.getProps()
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return conversation;
|
||||
},
|
||||
async deleteContact(id) {
|
||||
if (typeof id !== 'string') {
|
||||
throw new TypeError("'id' must be a string");
|
||||
}
|
||||
|
||||
if (!this._initialFetchComplete) {
|
||||
throw new Error(
|
||||
'ConversationController.get() needs complete initial fetch'
|
||||
);
|
||||
}
|
||||
|
||||
const conversation = conversations.get(id);
|
||||
if (!conversation) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Close group leaving
|
||||
if (conversation.isClosedGroup()) {
|
||||
await conversation.leaveGroup();
|
||||
} else if (conversation.isPublic()) {
|
||||
const channelAPI = await conversation.getPublicSendData();
|
||||
if (channelAPI === null) {
|
||||
log.warn(`Could not get API for public conversation ${id}`);
|
||||
} else {
|
||||
channelAPI.serverAPI.partChannel(channelAPI.channelId);
|
||||
}
|
||||
} else if (conversation.isPrivate()) {
|
||||
const deviceIds = await textsecure.storage.protocol.getDeviceIds(id);
|
||||
await Promise.all(
|
||||
deviceIds.map(deviceId => {
|
||||
const address = new libsignal.SignalProtocolAddress(id, deviceId);
|
||||
const sessionCipher = new libsignal.SessionCipher(
|
||||
textsecure.storage.protocol,
|
||||
address
|
||||
);
|
||||
return sessionCipher.deleteAllSessionsForDevice();
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
await conversation.destroyMessages();
|
||||
|
||||
await window.Signal.Data.removeConversation(id, {
|
||||
Conversation: Whisper.Conversation,
|
||||
});
|
||||
conversation.off('change', this.updateReduxConvoChanged);
|
||||
conversations.remove(conversation);
|
||||
if (window.inboxStore) {
|
||||
window.inboxStore.dispatch(
|
||||
window.actionsCreators.conversationRemoved(conversation.id)
|
||||
);
|
||||
}
|
||||
},
|
||||
getOrCreateAndWait(id, type) {
|
||||
return this._initialPromise.then(() => {
|
||||
if (!id) {
|
||||
return Promise.reject(
|
||||
new Error('getOrCreateAndWait: invalid id passed.')
|
||||
);
|
||||
}
|
||||
const pubkey = id && id.key ? id.key : id;
|
||||
const conversation = this.getOrCreate(pubkey, type);
|
||||
|
||||
if (conversation) {
|
||||
return conversation.initialPromise.then(() => conversation);
|
||||
}
|
||||
|
||||
return Promise.reject(
|
||||
new Error('getOrCreateAndWait: did not get conversation')
|
||||
);
|
||||
});
|
||||
},
|
||||
async getAllGroupsInvolvingId(id) {
|
||||
const groups = await window.Signal.Data.getAllGroupsInvolvingId(id, {
|
||||
ConversationCollection: Whisper.ConversationCollection,
|
||||
});
|
||||
return groups.map(group => conversations.add(group));
|
||||
},
|
||||
loadPromise() {
|
||||
return this._initialPromise;
|
||||
},
|
||||
reset() {
|
||||
this._initialPromise = Promise.resolve();
|
||||
this._initialFetchComplete = false;
|
||||
conversations.reset([]);
|
||||
if (window.inboxStore) {
|
||||
conversations.forEach(convo =>
|
||||
convo.off('change', this.updateReduxConvoChanged)
|
||||
);
|
||||
|
||||
window.inboxStore.dispatch(
|
||||
window.actionsCreators.removeAllConversations()
|
||||
);
|
||||
}
|
||||
},
|
||||
updateReduxConvoChanged(convo) {
|
||||
if (window.inboxStore) {
|
||||
window.inboxStore.dispatch(
|
||||
window.actionsCreators.conversationChanged(convo.id, convo.getProps())
|
||||
);
|
||||
}
|
||||
},
|
||||
async load() {
|
||||
window.log.info('ConversationController: starting initial fetch');
|
||||
|
||||
if (conversations.length) {
|
||||
throw new Error('ConversationController: Already loaded!');
|
||||
}
|
||||
|
||||
const load = async () => {
|
||||
try {
|
||||
const collection = await window.Signal.Data.getAllConversations({
|
||||
ConversationCollection: Whisper.ConversationCollection,
|
||||
});
|
||||
|
||||
conversations.add(collection.models);
|
||||
|
||||
this._initialFetchComplete = true;
|
||||
const promises = [];
|
||||
conversations.forEach(conversation => {
|
||||
if (!conversation.get('lastMessage')) {
|
||||
promises.push(conversation.updateLastMessage());
|
||||
}
|
||||
|
||||
promises.concat([
|
||||
conversation.updateProfileName(),
|
||||
conversation.updateProfileAvatar(),
|
||||
]);
|
||||
});
|
||||
conversations.forEach(conversation => {
|
||||
// register for change event on each conversation, and forward to redux
|
||||
conversation.on('change', this.updateReduxConvoChanged);
|
||||
});
|
||||
await Promise.all(promises);
|
||||
|
||||
// Remove any unused images
|
||||
window.profileImages.removeImagesNotInArray(
|
||||
conversations.map(c => c.id)
|
||||
);
|
||||
|
||||
window.log.info('ConversationController: done with initial fetch');
|
||||
} catch (error) {
|
||||
window.log.error(
|
||||
'ConversationController: initial fetch failed',
|
||||
error && error.stack ? error.stack : error
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
await window.BlockedNumberController.load();
|
||||
|
||||
this._initialPromise = load();
|
||||
|
||||
return this._initialPromise;
|
||||
},
|
||||
getContactProfileNameOrShortenedPubKey: pubKey => {
|
||||
const conversation = window.ConversationController.get(pubKey);
|
||||
if (!conversation) {
|
||||
return pubKey;
|
||||
}
|
||||
return conversation.getContactProfileNameOrShortenedPubKey();
|
||||
},
|
||||
|
||||
getContactProfileNameOrFullPubKey: pubKey => {
|
||||
const conversation = window.ConversationController.get(pubKey);
|
||||
if (!conversation) {
|
||||
return pubKey;
|
||||
}
|
||||
return conversation.getContactProfileNameOrFullPubKey();
|
||||
},
|
||||
|
||||
isMediumGroup: hexEncodedGroupPublicKey =>
|
||||
conversations
|
||||
.filter(c => c.isMediumGroup())
|
||||
.some(c => c.id === hexEncodedGroupPublicKey),
|
||||
_handleOnline: pubKey => {
|
||||
try {
|
||||
const conversation = this.get(pubKey);
|
||||
conversation.set({ isOnline: true });
|
||||
} catch (e) {} // eslint-disable-line
|
||||
},
|
||||
_handleOffline: pubKey => {
|
||||
try {
|
||||
const conversation = this.get(pubKey);
|
||||
conversation.set({ isOnline: false });
|
||||
} catch (e) {} // eslint-disable-line
|
||||
},
|
||||
};
|
||||
})();
|
|
@ -1,7 +1,6 @@
|
|||
/* global
|
||||
Backbone,
|
||||
Whisper,
|
||||
ConversationController,
|
||||
getMessageController,
|
||||
_,
|
||||
*/
|
||||
|
@ -106,9 +105,9 @@
|
|||
}
|
||||
|
||||
// notify frontend listeners
|
||||
const conversation = ConversationController.get(
|
||||
message.get('conversationId')
|
||||
);
|
||||
const conversation = window
|
||||
.getConversationController()
|
||||
.get(message.get('conversationId'));
|
||||
if (conversation) {
|
||||
conversation.trigger('delivered', message);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* global Whisper, SignalProtocolStore, ConversationController, _ */
|
||||
/* global Whisper, SignalProtocolStore, _ */
|
||||
|
||||
/* eslint-disable more/no-then */
|
||||
|
||||
|
@ -15,13 +15,14 @@
|
|||
}
|
||||
|
||||
signalProtocolStore.on('keychange', async id => {
|
||||
const conversation = await ConversationController.getOrCreateAndWait(
|
||||
id,
|
||||
'private'
|
||||
);
|
||||
const conversation = await window
|
||||
.getConversationController()
|
||||
.getOrCreateAndWait(id, 'private');
|
||||
conversation.addKeyChange(id);
|
||||
|
||||
const groups = await ConversationController.getAllGroupsInvolvingId(id);
|
||||
const groups = await window
|
||||
.getConversationController()
|
||||
.getAllGroupsInvolvingId(id);
|
||||
_.forEach(groups, group => {
|
||||
group.addKeyChange(id);
|
||||
});
|
||||
|
|
|
@ -21,10 +21,15 @@ interface ConversationAttributes {
|
|||
subscriberCount?: number;
|
||||
sessionRestoreSeen?: boolean;
|
||||
is_medium_group?: boolean;
|
||||
type: string;
|
||||
lastMessage?: string;
|
||||
}
|
||||
|
||||
export interface ConversationModel
|
||||
extends Backbone.Model<ConversationAttributes> {
|
||||
destroyMessages();
|
||||
getPublicSendData();
|
||||
leaveGroup();
|
||||
idForLogging: () => string;
|
||||
// Save model changes to the database
|
||||
commit: () => Promise<void>;
|
||||
|
@ -64,7 +69,6 @@ export interface ConversationModel
|
|||
isModerator: (id?: string) => boolean;
|
||||
throttledBumpTyping: () => void;
|
||||
|
||||
lastMessage: string;
|
||||
messageCollection: Backbone.Collection<MessageModel>;
|
||||
|
||||
// types to make more specific
|
||||
|
@ -106,4 +110,9 @@ export interface ConversationModel
|
|||
sendGroupInfo: any;
|
||||
onUpdateGroupName: any;
|
||||
getContactProfileNameOrShortenedPubKey: () => string;
|
||||
getContactProfileNameOrFullPubKey: () => string;
|
||||
getProps(): any;
|
||||
updateLastMessage: () => void;
|
||||
updateProfileName: any;
|
||||
updateProfileAvatar: any;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
i18n,
|
||||
Backbone,
|
||||
libsession,
|
||||
ConversationController,
|
||||
getMessageController,
|
||||
storage,
|
||||
textsecure,
|
||||
|
@ -670,10 +669,9 @@
|
|||
device
|
||||
);
|
||||
|
||||
return ConversationController.getOrCreateAndWait(
|
||||
primary.key,
|
||||
'private'
|
||||
);
|
||||
return window
|
||||
.getConversationController()
|
||||
.getOrCreateAndWait(primary.key, 'private');
|
||||
}
|
||||
|
||||
// Something funky has happened
|
||||
|
@ -925,11 +923,14 @@
|
|||
);
|
||||
|
||||
if (this.isPrivate()) {
|
||||
ConversationController.getAllGroupsInvolvingId(this.id).then(groups => {
|
||||
_.forEach(groups, group => {
|
||||
group.addVerifiedChange(this.id, verified, options);
|
||||
window
|
||||
.getConversationController()
|
||||
.getAllGroupsInvolvingId(this.id)
|
||||
.then(groups => {
|
||||
_.forEach(groups, group => {
|
||||
group.addVerifiedChange(this.id, verified, options);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -2026,7 +2027,9 @@
|
|||
// This function is wrongly named by signal
|
||||
// This is basically an `update` function and thus we have overwritten it with such
|
||||
async getProfile(id) {
|
||||
const c = await ConversationController.getOrCreateAndWait(id, 'private');
|
||||
const c = await window
|
||||
.getConversationController()
|
||||
.getOrCreateAndWait(id, 'private');
|
||||
|
||||
// We only need to update the profile as they are all stored inside the conversation
|
||||
await c.updateProfileName();
|
||||
|
@ -2141,7 +2144,7 @@
|
|||
}
|
||||
const members = this.get('members') || [];
|
||||
const promises = members.map(number =>
|
||||
ConversationController.getOrCreateAndWait(number, 'private')
|
||||
window.getConversationController().getOrCreateAndWait(number, 'private')
|
||||
);
|
||||
|
||||
return Promise.all(promises).then(contacts => {
|
||||
|
@ -2188,7 +2191,7 @@
|
|||
title,
|
||||
message,
|
||||
resolve: () => {
|
||||
ConversationController.deleteContact(this.id);
|
||||
window.getConversationController().deleteContact(this.id);
|
||||
},
|
||||
});
|
||||
},
|
||||
|
@ -2364,7 +2367,9 @@
|
|||
// Secondary devices have their profile stored
|
||||
// in their primary device's conversation
|
||||
const ourNumber = window.storage.get('primaryDevicePubKey');
|
||||
const ourConversation = window.ConversationController.get(ourNumber);
|
||||
const ourConversation = window
|
||||
.getConversationController()
|
||||
.get(ourNumber);
|
||||
let profileKey = null;
|
||||
if (this.get('profileSharing')) {
|
||||
profileKey = new Uint8Array(storage.get('profileKey'));
|
||||
|
@ -2424,32 +2429,32 @@
|
|||
}
|
||||
const conversationId = this.id;
|
||||
|
||||
return ConversationController.getOrCreateAndWait(
|
||||
message.get('source'),
|
||||
'private'
|
||||
).then(sender =>
|
||||
sender.getNotificationIcon().then(iconUrl => {
|
||||
const messageJSON = message.toJSON();
|
||||
const messageSentAt = messageJSON.sent_at;
|
||||
const messageId = message.id;
|
||||
const isExpiringMessage = Message.hasExpiration(messageJSON);
|
||||
return window
|
||||
.getConversationController()
|
||||
.getOrCreateAndWait(message.get('source'), 'private')
|
||||
.then(sender =>
|
||||
sender.getNotificationIcon().then(iconUrl => {
|
||||
const messageJSON = message.toJSON();
|
||||
const messageSentAt = messageJSON.sent_at;
|
||||
const messageId = message.id;
|
||||
const isExpiringMessage = Message.hasExpiration(messageJSON);
|
||||
|
||||
// window.log.info('Add notification', {
|
||||
// conversationId: this.idForLogging(),
|
||||
// isExpiringMessage,
|
||||
// messageSentAt,
|
||||
// });
|
||||
Whisper.Notifications.add({
|
||||
conversationId,
|
||||
iconUrl,
|
||||
isExpiringMessage,
|
||||
message: message.getNotificationText(),
|
||||
messageId,
|
||||
messageSentAt,
|
||||
title: sender.getTitle(),
|
||||
});
|
||||
})
|
||||
);
|
||||
// window.log.info('Add notification', {
|
||||
// conversationId: this.idForLogging(),
|
||||
// isExpiringMessage,
|
||||
// messageSentAt,
|
||||
// });
|
||||
Whisper.Notifications.add({
|
||||
conversationId,
|
||||
iconUrl,
|
||||
isExpiringMessage,
|
||||
message: message.getNotificationText(),
|
||||
messageId,
|
||||
messageSentAt,
|
||||
title: sender.getTitle(),
|
||||
});
|
||||
})
|
||||
);
|
||||
},
|
||||
notifyTyping(options = {}) {
|
||||
const { isTyping, sender, senderDevice } = options;
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
Backbone,
|
||||
storage,
|
||||
filesize,
|
||||
ConversationController,
|
||||
getMessageController,
|
||||
i18n,
|
||||
Signal,
|
||||
|
@ -177,9 +176,9 @@
|
|||
} else if (groupUpdate.left) {
|
||||
return i18n(
|
||||
'leftTheGroup',
|
||||
ConversationController.getContactProfileNameOrShortenedPubKey(
|
||||
groupUpdate.left
|
||||
)
|
||||
window
|
||||
.getConversationController()
|
||||
.getContactProfileNameOrShortenedPubKey(groupUpdate.left)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -196,7 +195,9 @@
|
|||
}
|
||||
if (groupUpdate.joined && groupUpdate.joined.length) {
|
||||
const names = groupUpdate.joined.map(pubKey =>
|
||||
ConversationController.getContactProfileNameOrFullPubKey(pubKey)
|
||||
window
|
||||
.getConversationController()
|
||||
.getContactProfileNameOrFullPubKey(pubKey)
|
||||
);
|
||||
|
||||
if (names.length > 1) {
|
||||
|
@ -209,7 +210,8 @@
|
|||
if (groupUpdate.kicked && groupUpdate.kicked.length) {
|
||||
const names = _.map(
|
||||
groupUpdate.kicked,
|
||||
ConversationController.getContactProfileNameOrShortenedPubKey
|
||||
window.getConversationController()
|
||||
.getContactProfileNameOrShortenedPubKey
|
||||
);
|
||||
|
||||
if (names.length > 1) {
|
||||
|
@ -260,9 +262,9 @@
|
|||
);
|
||||
const pubkeysInDesc = description.match(regex);
|
||||
(pubkeysInDesc || []).forEach(pubkey => {
|
||||
const displayName = ConversationController.getContactProfileNameOrShortenedPubKey(
|
||||
pubkey.slice(1)
|
||||
);
|
||||
const displayName = window
|
||||
.getConversationController()
|
||||
.getContactProfileNameOrShortenedPubKey(pubkey.slice(1));
|
||||
if (displayName && displayName.length) {
|
||||
description = description.replace(pubkey, `@${displayName}`);
|
||||
}
|
||||
|
@ -383,7 +385,7 @@
|
|||
};
|
||||
},
|
||||
findContact(phoneNumber) {
|
||||
return ConversationController.get(phoneNumber);
|
||||
return window.getConversationController().get(phoneNumber);
|
||||
},
|
||||
findAndFormatContact(phoneNumber) {
|
||||
const { format } = PhoneNumber;
|
||||
|
@ -726,7 +728,7 @@
|
|||
const regionCode = storage.get('regionCode');
|
||||
|
||||
const { author, id, referencedMessageNotFound } = quote;
|
||||
const contact = author && ConversationController.get(author);
|
||||
const contact = author && window.getConversationController().get(author);
|
||||
|
||||
const authorPhoneNumber = format(author, {
|
||||
ourRegionCode: regionCode,
|
||||
|
@ -1029,7 +1031,9 @@
|
|||
|
||||
const { body, attachments, preview, quote } = await this.uploadData();
|
||||
const ourNumber = window.storage.get('primaryDevicePubKey');
|
||||
const ourConversation = window.ConversationController.get(ourNumber);
|
||||
const ourConversation = window
|
||||
.getConversationController()
|
||||
.get(ourNumber);
|
||||
|
||||
const chatParams = {
|
||||
identifier: this.id,
|
||||
|
@ -1304,7 +1308,7 @@
|
|||
if (error.name === 'SignedPreKeyRotationError') {
|
||||
await window.getAccountManager().rotateSignedPreKey();
|
||||
} else if (error.name === 'OutgoingIdentityKeyError') {
|
||||
const c = ConversationController.get(sentMessage.device);
|
||||
const c = window.getConversationController().get(sentMessage.device);
|
||||
await c.getProfiles();
|
||||
}
|
||||
}
|
||||
|
@ -1330,15 +1334,16 @@
|
|||
// 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.getUnsafe(this.get('conversationId'));
|
||||
return window
|
||||
.getConversationController()
|
||||
.getUnsafe(this.get('conversationId'));
|
||||
},
|
||||
getSourceDeviceConversation() {
|
||||
// This gets the conversation of the device that sent this message
|
||||
// while getConversation will return the primary device conversation
|
||||
return ConversationController.getOrCreateAndWait(
|
||||
this.get('source'),
|
||||
'private'
|
||||
);
|
||||
return window
|
||||
.getConversationController()
|
||||
.getOrCreateAndWait(this.get('source'), 'private');
|
||||
},
|
||||
getIncomingContact() {
|
||||
if (!this.isIncoming()) {
|
||||
|
@ -1351,7 +1356,7 @@
|
|||
|
||||
const key = source.key ? source.key : source;
|
||||
|
||||
return ConversationController.getOrCreate(key, 'private');
|
||||
return window.getConversationController().getOrCreate(key, 'private');
|
||||
},
|
||||
getQuoteContact() {
|
||||
const quote = this.get('quote');
|
||||
|
@ -1363,7 +1368,7 @@
|
|||
return null;
|
||||
}
|
||||
|
||||
return ConversationController.get(author);
|
||||
return window.getConversationController().get(author);
|
||||
},
|
||||
|
||||
getSource() {
|
||||
|
@ -1384,7 +1389,9 @@
|
|||
// is PubKey ano not a string
|
||||
const sourceStr = source.key ? source.key : source;
|
||||
|
||||
return ConversationController.getOrCreate(sourceStr, 'private');
|
||||
return window
|
||||
.getConversationController()
|
||||
.getOrCreate(sourceStr, 'private');
|
||||
},
|
||||
isOutgoing() {
|
||||
return this.get('type') === 'outgoing';
|
||||
|
|
|
@ -1,169 +0,0 @@
|
|||
/* eslint-env node */
|
||||
/* global log */
|
||||
|
||||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
|
||||
const {
|
||||
isFunction,
|
||||
isNumber,
|
||||
isObject,
|
||||
isString,
|
||||
random,
|
||||
range,
|
||||
sample,
|
||||
} = require('lodash');
|
||||
|
||||
const Attachments = require('../../app/attachments');
|
||||
const Message = require('./types/message');
|
||||
const { sleep } = require('./sleep');
|
||||
|
||||
// See: https://en.wikipedia.org/wiki/Fictitious_telephone_number#North_American_Numbering_Plan
|
||||
const SENDER_ID = '+12126647665';
|
||||
|
||||
exports.createConversation = async ({
|
||||
ConversationController,
|
||||
numMessages,
|
||||
WhisperMessage,
|
||||
} = {}) => {
|
||||
if (
|
||||
!isObject(ConversationController) ||
|
||||
!isFunction(ConversationController.getOrCreateAndWait)
|
||||
) {
|
||||
throw new TypeError("'ConversationController' is required");
|
||||
}
|
||||
|
||||
if (!isNumber(numMessages) || numMessages <= 0) {
|
||||
throw new TypeError("'numMessages' must be a positive number");
|
||||
}
|
||||
|
||||
if (!isFunction(WhisperMessage)) {
|
||||
throw new TypeError("'WhisperMessage' is required");
|
||||
}
|
||||
|
||||
const conversation = await ConversationController.getOrCreateAndWait(
|
||||
SENDER_ID,
|
||||
'private'
|
||||
);
|
||||
conversation.set({
|
||||
active_at: Date.now(),
|
||||
unread: numMessages,
|
||||
});
|
||||
const conversationId = conversation.get('id');
|
||||
await conversation.commit();
|
||||
|
||||
await Promise.all(
|
||||
range(0, numMessages).map(async index => {
|
||||
await sleep(index * 100);
|
||||
log.info(`Create message ${index + 1}`);
|
||||
const message = await createRandomMessage({ conversationId });
|
||||
return message.commit();
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const SAMPLE_MESSAGES = [
|
||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
|
||||
'Integer et rutrum leo, eu ultrices ligula.',
|
||||
'Nam vel aliquam quam.',
|
||||
'Suspendisse posuere nunc vitae pulvinar lobortis.',
|
||||
'Nunc et sapien ex.',
|
||||
'Duis nec neque eu arcu ultrices ullamcorper in et mauris.',
|
||||
'Praesent mi felis, hendrerit a nulla id, mattis consectetur est.',
|
||||
'Duis venenatis posuere est sit amet congue.',
|
||||
'Vestibulum vitae sapien ultricies, auctor purus vitae, laoreet lacus.',
|
||||
'Fusce laoreet nisi dui, a bibendum metus consequat in.',
|
||||
'Nulla sed iaculis odio, sed lobortis lacus.',
|
||||
'Etiam massa felis, gravida at nibh viverra, tincidunt convallis justo.',
|
||||
'Maecenas ut egestas urna.',
|
||||
'Pellentesque consectetur mattis imperdiet.',
|
||||
'Maecenas pulvinar efficitur justo a cursus.',
|
||||
];
|
||||
|
||||
const ATTACHMENT_SAMPLE_RATE = 0.33;
|
||||
const createRandomMessage = async ({ conversationId } = {}) => {
|
||||
if (!isString(conversationId)) {
|
||||
throw new TypeError("'conversationId' must be a string");
|
||||
}
|
||||
|
||||
const sentAt = Date.now() - random(100 * 24 * 60 * 60 * 1000);
|
||||
const receivedAt = sentAt + random(30 * 1000);
|
||||
|
||||
const hasAttachment = Math.random() <= ATTACHMENT_SAMPLE_RATE;
|
||||
const attachments = hasAttachment
|
||||
? [await createRandomInMemoryAttachment()]
|
||||
: [];
|
||||
const type = sample(['incoming', 'outgoing']);
|
||||
const commonProperties = {
|
||||
attachments,
|
||||
body: sample(SAMPLE_MESSAGES),
|
||||
conversationId,
|
||||
received_at: receivedAt,
|
||||
sent_at: sentAt,
|
||||
timestamp: receivedAt,
|
||||
type,
|
||||
};
|
||||
|
||||
const message = _createMessage({ commonProperties, conversationId, type });
|
||||
return Message.initializeSchemaVersion({ message, logger: log });
|
||||
};
|
||||
|
||||
const _createMessage = ({ commonProperties, conversationId, type } = {}) => {
|
||||
switch (type) {
|
||||
case 'incoming':
|
||||
return Object.assign({}, commonProperties, {
|
||||
flags: 0,
|
||||
source: conversationId,
|
||||
sourceDevice: 1,
|
||||
});
|
||||
case 'outgoing':
|
||||
return Object.assign({}, commonProperties, {
|
||||
delivered: 1,
|
||||
delivered_to: [conversationId],
|
||||
expireTimer: 0,
|
||||
recipients: [conversationId],
|
||||
sent_to: [conversationId],
|
||||
synced: true,
|
||||
});
|
||||
default:
|
||||
throw new TypeError(`Unknown message type: '${type}'`);
|
||||
}
|
||||
};
|
||||
|
||||
const FIXTURES_PATH = path.join(__dirname, '..', '..', 'fixtures');
|
||||
const readData = Attachments.createReader(FIXTURES_PATH);
|
||||
const createRandomInMemoryAttachment = async () => {
|
||||
const files = (await fs.readdir(FIXTURES_PATH)).map(createFileEntry);
|
||||
const { contentType, fileName } = sample(files);
|
||||
const data = await readData(fileName);
|
||||
|
||||
return {
|
||||
contentType,
|
||||
data,
|
||||
fileName,
|
||||
size: data.byteLength,
|
||||
};
|
||||
};
|
||||
|
||||
const createFileEntry = fileName => ({
|
||||
fileName,
|
||||
contentType: fileNameToContentType(fileName),
|
||||
});
|
||||
const fileNameToContentType = fileName => {
|
||||
const fileExtension = path.extname(fileName).toLowerCase();
|
||||
switch (fileExtension) {
|
||||
case '.gif':
|
||||
return 'image/gif';
|
||||
case '.png':
|
||||
return 'image/png';
|
||||
case '.jpg':
|
||||
case '.jpeg':
|
||||
return 'image/jpeg';
|
||||
case '.mp4':
|
||||
return 'video/mp4';
|
||||
case '.txt':
|
||||
return 'text/plain';
|
||||
default:
|
||||
return 'application/octet-stream';
|
||||
}
|
||||
};
|
|
@ -1,4 +1,4 @@
|
|||
/* global log, textsecure, libloki, Signal, Whisper, ConversationController,
|
||||
/* global log, textsecure, libloki, Signal, Whisper,
|
||||
clearTimeout, getMessageController, libsignal, StringView, window, _,
|
||||
dcodeIO, Buffer, process */
|
||||
const nodeFetch = require('node-fetch');
|
||||
|
@ -599,7 +599,7 @@ class LokiAppDotNetServerAPI {
|
|||
const ourNumber =
|
||||
window.storage.get('primaryDevicePubKey') ||
|
||||
textsecure.storage.user.getNumber();
|
||||
const profileConvo = ConversationController.get(ourNumber);
|
||||
const profileConvo = window.getConversationController().get(ourNumber);
|
||||
const profile = profileConvo && profileConvo.getLokiProfile();
|
||||
const profileName = profile && profile.displayName;
|
||||
// if doesn't match, write it to the network
|
||||
|
@ -1050,7 +1050,9 @@ class LokiPublicChannelAPI {
|
|||
this.channelId = channelId;
|
||||
this.baseChannelUrl = `channels/${this.channelId}`;
|
||||
this.conversationId = conversationId;
|
||||
this.conversation = ConversationController.getOrThrow(conversationId);
|
||||
this.conversation = window
|
||||
.getConversationController()
|
||||
.getOrThrow(conversationId);
|
||||
this.lastMessageServerID = null;
|
||||
this.modStatus = false;
|
||||
this.deleteLastId = 1;
|
||||
|
@ -2012,7 +2014,9 @@ class LokiPublicChannelAPI {
|
|||
// if we received one of our own messages
|
||||
if (lastProfileName !== false) {
|
||||
// get current profileName
|
||||
const profileConvo = ConversationController.get(ourNumberProfile);
|
||||
const profileConvo = window
|
||||
.getConversationController()
|
||||
.get(ourNumberProfile);
|
||||
const profileName = profileConvo.getProfileName();
|
||||
// check to see if it out of sync
|
||||
if (profileName !== lastProfileName) {
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
Whisper,
|
||||
Backbone,
|
||||
_,
|
||||
ConversationController,
|
||||
getMessageController,
|
||||
window
|
||||
*/
|
||||
|
@ -105,9 +104,9 @@
|
|||
}
|
||||
|
||||
// notify frontend listeners
|
||||
const conversation = ConversationController.get(
|
||||
message.get('conversationId')
|
||||
);
|
||||
const conversation = window
|
||||
.getConversationController()
|
||||
.get(message.get('conversationId'));
|
||||
if (conversation) {
|
||||
conversation.trigger('read', message);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
_,
|
||||
libsignal,
|
||||
textsecure,
|
||||
ConversationController,
|
||||
stringObject,
|
||||
BlockedNumberController
|
||||
*/
|
||||
|
@ -890,9 +889,9 @@
|
|||
window.storage.reset();
|
||||
await window.storage.fetch();
|
||||
|
||||
ConversationController.reset();
|
||||
window.getConversationController().reset();
|
||||
BlockedNumberController.reset();
|
||||
await ConversationController.load();
|
||||
await window.getConversationController().load();
|
||||
await BlockedNumberController.load();
|
||||
},
|
||||
async removeAllConfiguration() {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* global Backbone, i18n, Whisper, storage, _, ConversationController, $ */
|
||||
/* global Backbone, i18n, Whisper, storage, _, $ */
|
||||
|
||||
/* eslint-disable more/no-then */
|
||||
|
||||
|
@ -112,9 +112,12 @@
|
|||
window,
|
||||
initialLoadComplete: options.initialLoadComplete,
|
||||
});
|
||||
return ConversationController.loadPromise().then(() => {
|
||||
this.openView(this.inboxView);
|
||||
});
|
||||
return window
|
||||
.getConversationController()
|
||||
.loadPromise()
|
||||
.then(() => {
|
||||
this.openView(this.inboxView);
|
||||
});
|
||||
}
|
||||
if (!$.contains(this.el, this.inboxView.el)) {
|
||||
this.openView(this.inboxView);
|
||||
|
@ -212,7 +215,8 @@
|
|||
window.confirmationDialog({
|
||||
title,
|
||||
message,
|
||||
resolve: () => ConversationController.deleteContact(groupConvo.id),
|
||||
resolve: () =>
|
||||
window.getConversationController().deleteContact(groupConvo.id),
|
||||
theme: this.getThemeObject(),
|
||||
});
|
||||
},
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
Signal,
|
||||
storage,
|
||||
Whisper,
|
||||
ConversationController,
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line func-names
|
||||
|
@ -138,7 +137,7 @@
|
|||
);
|
||||
|
||||
const allMembers = allPubKeys.map(pubKey => {
|
||||
const conv = ConversationController.get(pubKey);
|
||||
const conv = window.getConversationController().get(pubKey);
|
||||
let profileName = 'Anonymous';
|
||||
if (conv) {
|
||||
profileName = conv.getProfileName();
|
||||
|
@ -1149,8 +1148,9 @@
|
|||
}
|
||||
|
||||
const privateConvos = window
|
||||
.getConversationController()
|
||||
.getConversations()
|
||||
.models.filter(d => d.isPrivate());
|
||||
.filter(d => d.isPrivate());
|
||||
const memberConvos = members
|
||||
.map(m => privateConvos.find(c => c.id === m))
|
||||
.filter(c => !!c && c.getLokiProfile());
|
||||
|
|
|
@ -105,7 +105,10 @@
|
|||
this.isAdmin = groupConvo.isMediumGroup()
|
||||
? true
|
||||
: groupConvo.get('groupAdmins').includes(ourPK);
|
||||
const convos = window.getConversations().models.filter(d => !!d);
|
||||
const convos = window
|
||||
.getConversationController()
|
||||
.getConversations()
|
||||
.filter(d => !!d);
|
||||
|
||||
this.existingMembers = groupConvo.get('members') || [];
|
||||
// Show a contact if they are our friend or if they are a member
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* global Whisper, storage, i18n, ConversationController */
|
||||
/* global Whisper, storage, i18n */
|
||||
|
||||
/* eslint-disable more/no-then */
|
||||
|
||||
|
@ -171,9 +171,11 @@
|
|||
});
|
||||
},
|
||||
finishLightImport(directory) {
|
||||
ConversationController.reset();
|
||||
window.getConversationController().reset();
|
||||
|
||||
return ConversationController.load()
|
||||
return window
|
||||
.getConversationController()
|
||||
.load()
|
||||
.then(() =>
|
||||
Promise.all([
|
||||
Whisper.Import.saveLocation(directory),
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
this.close = this.close.bind(this);
|
||||
this.submit = this.submit.bind(this);
|
||||
this.theme = convo.theme;
|
||||
const convos = window.getConversations().models;
|
||||
const convos = window.getConversationController().getConversations();
|
||||
|
||||
this.contacts = convos.filter(
|
||||
d =>
|
||||
|
@ -64,10 +64,9 @@
|
|||
channelId: this.channelId,
|
||||
};
|
||||
pubkeys.forEach(async pubkeyStr => {
|
||||
const convo = await window.ConversationController.getOrCreateAndWait(
|
||||
pubkeyStr,
|
||||
'private'
|
||||
);
|
||||
const convo = await window
|
||||
.getConversationController()
|
||||
.getOrCreateAndWait(pubkeyStr, 'private');
|
||||
|
||||
if (convo) {
|
||||
convo.sendMessage('', null, null, null, serverInfos);
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
// get current list of moderators
|
||||
this.channelAPI = await convo.getPublicSendData();
|
||||
const modPubKeys = await this.channelAPI.getModerators();
|
||||
const convos = window.getConversations().models;
|
||||
const convos = window.getConversationController().getConversations();
|
||||
const moderators = modPubKeys
|
||||
.map(
|
||||
pubKey =>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* global window, textsecure, libsession, ConversationController */
|
||||
/* global window, textsecure, libsession */
|
||||
/* eslint-disable no-bitwise */
|
||||
|
||||
// eslint-disable-next-line func-names
|
||||
|
@ -101,7 +101,9 @@
|
|||
const ourPubKey = textsecure.storage.user.getNumber();
|
||||
if (memberStr !== ourPubKey) {
|
||||
const memberPubkey = new libsession.Types.PubKey(memberStr);
|
||||
await ConversationController.getOrCreateAndWait(memberStr, 'private');
|
||||
await window
|
||||
.getConversationController()
|
||||
.getOrCreateAndWait(memberStr, 'private');
|
||||
await libsession.Protocols.SessionProtocol.sendSessionRequestIfNeeded(
|
||||
memberPubkey
|
||||
);
|
||||
|
|
|
@ -417,10 +417,9 @@
|
|||
|
||||
let conversation;
|
||||
try {
|
||||
conversation = await window.ConversationController.getOrCreateAndWait(
|
||||
this.protocolAddress.getName(),
|
||||
'private'
|
||||
);
|
||||
conversation = await window
|
||||
.getConversationController()
|
||||
.getOrCreateAndWait(this.protocolAddress.getName(), 'private');
|
||||
} catch (e) {
|
||||
window.log.info(
|
||||
'Error getting conversation: ',
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
StringView,
|
||||
log,
|
||||
Event,
|
||||
ConversationController,
|
||||
Whisper
|
||||
*/
|
||||
|
||||
|
@ -407,10 +406,9 @@
|
|||
textsecure.storage.put('primaryDevicePubKey', number);
|
||||
}
|
||||
// Ensure that we always have a conversation for ourself
|
||||
const conversation = await ConversationController.getOrCreateAndWait(
|
||||
number,
|
||||
'private'
|
||||
);
|
||||
const conversation = await window
|
||||
.getConversationController()
|
||||
.getOrCreateAndWait(number, 'private');
|
||||
await conversation.setLokiProfile({ displayName });
|
||||
|
||||
this.dispatchEvent(new Event('registration'));
|
||||
|
@ -419,10 +417,9 @@
|
|||
// throws if invalid
|
||||
this.validatePubKeyHex(primaryDevicePubKey);
|
||||
// we need a conversation for sending a message
|
||||
await ConversationController.getOrCreateAndWait(
|
||||
primaryDevicePubKey,
|
||||
'private'
|
||||
);
|
||||
await window
|
||||
.getConversationController()
|
||||
.getOrCreateAndWait(primaryDevicePubKey, 'private');
|
||||
const ourPubKey = textsecure.storage.user.getNumber();
|
||||
if (primaryDevicePubKey === ourPubKey) {
|
||||
throw new Error('Cannot request to pair with ourselves');
|
||||
|
@ -491,10 +488,9 @@
|
|||
await libsession.Protocols.MultiDeviceProtocol.savePairingAuthorisation(
|
||||
authorisation
|
||||
);
|
||||
const ourConversation = await ConversationController.getOrCreateAndWait(
|
||||
ourPubKey,
|
||||
'private'
|
||||
);
|
||||
const ourConversation = await window
|
||||
.getConversationController()
|
||||
.getOrCreateAndWait(ourPubKey, 'private');
|
||||
|
||||
// We need to send the our profile to the secondary device
|
||||
const lokiProfile = ourConversation.getOurProfile();
|
||||
|
@ -531,7 +527,9 @@
|
|||
// Send sync messages
|
||||
// bad hack to send sync messages when secondary device is ready to process them
|
||||
setTimeout(async () => {
|
||||
const conversations = window.getConversations().models;
|
||||
const conversations = window
|
||||
.getConversationController()
|
||||
.getConversations();
|
||||
await textsecure.messaging.sendGroupSyncMessage(conversations);
|
||||
await textsecure.messaging.sendOpenGroupsSyncMessage(conversations);
|
||||
await textsecure.messaging.sendContactSyncMessage();
|
||||
|
|
|
@ -152,9 +152,9 @@ Message.prototype = {
|
|||
profile.displayName = this.profile.displayName;
|
||||
}
|
||||
|
||||
const conversation = window.ConversationController.get(
|
||||
textsecure.storage.user.getNumber()
|
||||
);
|
||||
const conversation = window
|
||||
.getConversationController()
|
||||
.get(textsecure.storage.user.getNumber());
|
||||
const avatarPointer = conversation.get('avatarPointer');
|
||||
if (avatarPointer) {
|
||||
profile.avatar = avatarPointer;
|
||||
|
|
|
@ -180,6 +180,9 @@ window.libsession = require('./ts/session');
|
|||
window.getMessageController =
|
||||
window.libsession.Messages.MessageController.getInstance;
|
||||
|
||||
window.getConversationController =
|
||||
window.libsession.Conversations.ConversationController.getInstance;
|
||||
|
||||
// We never do these in our code, so we'll prevent it everywhere
|
||||
window.open = () => null;
|
||||
// eslint-disable-next-line no-eval, no-multi-assign
|
||||
|
@ -217,9 +220,9 @@ window.onUnblockNumber = async number => {
|
|||
}
|
||||
|
||||
// Update the conversation
|
||||
if (window.ConversationController) {
|
||||
if (window.getConversationController()) {
|
||||
try {
|
||||
const conversation = window.ConversationController.get(number);
|
||||
const conversation = window.getConversationController().get(number);
|
||||
await conversation.unblock();
|
||||
} catch (e) {
|
||||
window.log.info(
|
||||
|
@ -415,7 +418,6 @@ window.Signal = Signal.setup({
|
|||
|
||||
// Pulling these in separately since they access filesystem, electron
|
||||
window.Signal.Backup = require('./js/modules/backup');
|
||||
window.Signal.Debug = require('./js/modules/debug');
|
||||
window.Signal.Logs = require('./js/modules/logs');
|
||||
|
||||
window.addEventListener('contextmenu', e => {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* global $, ConversationController, textsecure, Whisper */
|
||||
/* global $, textsecure, Whisper */
|
||||
|
||||
'use strict';
|
||||
|
||||
|
@ -14,17 +14,16 @@ describe('Fixtures', () => {
|
|||
'testDevice'
|
||||
);
|
||||
|
||||
await ConversationController.getOrCreateAndWait(
|
||||
textsecure.storage.user.getNumber(),
|
||||
'private'
|
||||
);
|
||||
await window
|
||||
.getConversationController()
|
||||
.getOrCreateAndWait(textsecure.storage.user.getNumber(), 'private');
|
||||
});
|
||||
|
||||
it('renders', async () => {
|
||||
await Whisper.Fixtures().saveAll();
|
||||
|
||||
ConversationController.reset();
|
||||
await ConversationController.load();
|
||||
window.getConversationController().reset();
|
||||
await window.getConversationController().load();
|
||||
|
||||
let view = new Whisper.InboxView({ window });
|
||||
view.$el.prependTo($('#render-light-theme'));
|
||||
|
|
|
@ -184,7 +184,6 @@
|
|||
|
||||
<script type="text/javascript" src="../js/models/messages.js" data-cover></script>
|
||||
<script type="text/javascript" src="../js/models/conversations.js" data-cover></script>
|
||||
<script type="text/javascript" src="../js/conversation_controller.js" data-cover></script>
|
||||
<script type="text/javascript" src="../js/keychange_listener.js" data-cover></script>
|
||||
<script type="text/javascript" src="../js/expiring_messages.js" data-cover></script>
|
||||
<script type="text/javascript" src="../js/notifications.js" data-cover></script>
|
||||
|
@ -225,7 +224,6 @@
|
|||
<script type="text/javascript" src="models/conversations_test.js"></script>
|
||||
<script type="text/javascript" src="models/messages_test.js"></script>
|
||||
|
||||
<script type="text/javascript" src="conversation_controller_test.js"></script>
|
||||
<script type="text/javascript" src="storage_test.js"></script>
|
||||
<script type="text/javascript" src="keychange_listener_test.js"></script>
|
||||
<script type="text/javascript" src="reliable_trigger_test.js"></script>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* global ConversationController, i18n, Whisper */
|
||||
/* global i18n, Whisper */
|
||||
|
||||
'use strict';
|
||||
|
||||
|
@ -15,8 +15,8 @@ const source = '+14155555555';
|
|||
describe('MessageCollection', () => {
|
||||
before(async () => {
|
||||
await clearDatabase();
|
||||
ConversationController.reset();
|
||||
await ConversationController.load();
|
||||
window.getConversationController().reset();
|
||||
await window.getConversationController().load();
|
||||
});
|
||||
after(() => {
|
||||
return clearDatabase();
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
// tslint:disable-next-line: no-implicit-dependencies
|
||||
import { assert } from 'chai';
|
||||
import { ConversationController } from '../../ts/session/conversations';
|
||||
|
||||
const { libsignal, Whisper, ConversationController } = window;
|
||||
const { libsignal, Whisper } = window;
|
||||
|
||||
describe('KeyChangeListener', () => {
|
||||
const phoneNumberWithKeyChange = '+13016886524'; // nsa
|
||||
|
@ -29,10 +30,10 @@ describe('KeyChangeListener', () => {
|
|||
|
||||
let convo: any;
|
||||
before(async () => {
|
||||
convo = ConversationController.dangerouslyCreateAndAdd({
|
||||
convo = ConversationController.getInstance().dangerouslyCreateAndAdd({
|
||||
id: phoneNumberWithKeyChange,
|
||||
type: 'private',
|
||||
});
|
||||
} as any);
|
||||
await window.Signal.Data.saveConversation(convo.attributes, {
|
||||
Conversation: Whisper.Conversation,
|
||||
});
|
||||
|
@ -58,11 +59,11 @@ describe('KeyChangeListener', () => {
|
|||
let convo: any;
|
||||
|
||||
before(async () => {
|
||||
convo = ConversationController.dangerouslyCreateAndAdd({
|
||||
convo = ConversationController.getInstance().dangerouslyCreateAndAdd({
|
||||
id: 'groupId',
|
||||
type: 'group',
|
||||
members: [phoneNumberWithKeyChange],
|
||||
});
|
||||
} as any);
|
||||
await window.Signal.Data.saveConversation(convo.attributes, {
|
||||
Conversation: Whisper.Conversation,
|
||||
});
|
||||
|
|
|
@ -8,6 +8,7 @@ import { toast } from 'react-toastify';
|
|||
import { SessionToast, SessionToastType } from './session/SessionToast';
|
||||
import { ToastUtils } from '../session/utils';
|
||||
import { DefaultTheme } from 'styled-components';
|
||||
import { ConversationController } from '../session/conversations';
|
||||
|
||||
interface Props {
|
||||
onClose: any;
|
||||
|
@ -191,7 +192,7 @@ export class DevicePairingDialog extends React.Component<Props, State> {
|
|||
throw new Error('pubKeyToUnpair must be set in renderUnpairDeviceView()');
|
||||
}
|
||||
const secretWords = window.mnemonic.pubkey_to_secret_words(pubKeyToUnpair);
|
||||
const conv = window.ConversationController.get(pubKeyToUnpair);
|
||||
const conv = ConversationController.getInstance().get(pubKeyToUnpair);
|
||||
let description;
|
||||
|
||||
if (conv && conv.getNickname()) {
|
||||
|
@ -302,7 +303,7 @@ export class DevicePairingDialog extends React.Component<Props, State> {
|
|||
);
|
||||
const { currentPubKey } = this.state;
|
||||
if (currentPubKey) {
|
||||
const conv = window.ConversationController.get(currentPubKey);
|
||||
const conv = ConversationController.getInstance().get(currentPubKey);
|
||||
if (conv) {
|
||||
void conv.setNickname(this.state.deviceAlias);
|
||||
}
|
||||
|
|
|
@ -284,6 +284,7 @@ class MessageInner extends React.PureComponent<Props, State> {
|
|||
showSkipControls={false}
|
||||
showJumpControls={false}
|
||||
showDownloadProgress={false}
|
||||
listenInterval={100}
|
||||
customIcons={{
|
||||
play: (
|
||||
<SessionIcon
|
||||
|
|
|
@ -13,6 +13,7 @@ import { StateType } from '../../state/reducer';
|
|||
import { MessageEncrypter } from '../../session/crypto';
|
||||
import { PubKey } from '../../session/types';
|
||||
import { UserUtil } from '../../util';
|
||||
import { ConversationController } from '../../session/conversations';
|
||||
// tslint:disable-next-line: no-import-side-effect no-submodule-imports
|
||||
|
||||
export enum SectionType {
|
||||
|
@ -89,7 +90,7 @@ class ActionsPanelPrivate extends React.Component<Props> {
|
|||
|
||||
if (type === SectionType.Profile) {
|
||||
const ourPrimary = window.storage.get('primaryDevicePubKey');
|
||||
const conversation = window.ConversationController.get(ourPrimary);
|
||||
const conversation = ConversationController.getInstance().get(ourPrimary);
|
||||
|
||||
const profile = conversation?.getLokiProfile();
|
||||
const userName = (profile && profile.displayName) || ourPrimary;
|
||||
|
|
|
@ -17,6 +17,7 @@ import {
|
|||
import { ToastUtils } from '../../session/utils';
|
||||
import { DefaultTheme } from 'styled-components';
|
||||
import { LeftPaneSectionHeader } from './LeftPaneSectionHeader';
|
||||
import { ConversationController } from '../../session/conversations';
|
||||
|
||||
export interface Props {
|
||||
directContacts: Array<ConversationType>;
|
||||
|
@ -127,12 +128,11 @@ export class LeftPaneContactSection extends React.Component<Props, State> {
|
|||
ToastUtils.pushToastError('addContact', error);
|
||||
} else {
|
||||
// tslint:disable-next-line: no-floating-promises
|
||||
window.ConversationController.getOrCreateAndWait(
|
||||
sessionID,
|
||||
'private'
|
||||
).then(() => {
|
||||
this.props.openConversationExternal(sessionID);
|
||||
});
|
||||
ConversationController.getInstance()
|
||||
.getOrCreateAndWait(sessionID, 'private')
|
||||
.then(() => {
|
||||
this.props.openConversationExternal(sessionID);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ import { OpenGroup } from '../../session/types';
|
|||
import { ToastUtils } from '../../session/utils';
|
||||
import { DefaultTheme } from 'styled-components';
|
||||
import { LeftPaneSectionHeader } from './LeftPaneSectionHeader';
|
||||
import { ConversationController } from '../../session/conversations';
|
||||
|
||||
export interface Props {
|
||||
searchTerm: string;
|
||||
|
@ -395,7 +396,10 @@ export class LeftPaneMessageSection extends React.Component<Props, State> {
|
|||
|
||||
const error = validateNumber(pubkey);
|
||||
if (!error) {
|
||||
await window.ConversationController.getOrCreateAndWait(pubkey, 'private');
|
||||
await ConversationController.getInstance().getOrCreateAndWait(
|
||||
pubkey,
|
||||
'private'
|
||||
);
|
||||
openConversationExternal(pubkey);
|
||||
} else {
|
||||
ToastUtils.pushToastError('invalidPubKey', error);
|
||||
|
|
|
@ -13,6 +13,7 @@ import { SessionIdEditable } from './SessionIdEditable';
|
|||
import { SessionSpinner } from './SessionSpinner';
|
||||
import { StringUtils, ToastUtils } from '../../session/utils';
|
||||
import { lightTheme } from '../../state/ducks/SessionTheme';
|
||||
import { ConversationController } from '../../session/conversations';
|
||||
|
||||
enum SignInMode {
|
||||
Default,
|
||||
|
@ -788,8 +789,8 @@ export class RegistrationTabs extends React.Component<any, State> {
|
|||
private async resetRegistration() {
|
||||
await window.Signal.Data.removeAll();
|
||||
await window.storage.fetch();
|
||||
window.ConversationController.reset();
|
||||
await window.ConversationController.load();
|
||||
ConversationController.getInstance().reset();
|
||||
await ConversationController.getInstance().load();
|
||||
window.Whisper.RotateSignedPreKeyListener.stop(window.Whisper.events);
|
||||
|
||||
this.setState({
|
||||
|
|
|
@ -2,6 +2,8 @@ import React from 'react';
|
|||
import { Provider } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { getMessageQueue } from '../../session';
|
||||
import { ConversationController } from '../../session/conversations/ConversationController';
|
||||
import { MessageController } from '../../session/messages';
|
||||
import { OpenGroupMessage } from '../../session/messages/outgoing';
|
||||
import { RawMessage } from '../../session/types';
|
||||
import { createStore } from '../../state/createStore';
|
||||
|
@ -130,7 +132,7 @@ export class SessionInboxView extends React.Component<Props, State> {
|
|||
}
|
||||
|
||||
// find the corresponding conversation of this message
|
||||
const conv = window.ConversationController.get(
|
||||
const conv = ConversationController.getInstance().get(
|
||||
tmpMsg.get('conversationId')
|
||||
);
|
||||
|
||||
|
@ -175,13 +177,15 @@ export class SessionInboxView extends React.Component<Props, State> {
|
|||
|
||||
private async setupLeftPane() {
|
||||
// Here we set up a full redux store with initial state for our LeftPane Root
|
||||
const convoCollection = window.getConversations();
|
||||
const convoCollection = ConversationController.getInstance().getConversations();
|
||||
const conversations = convoCollection.map(
|
||||
(conversation: any) => conversation.cachedProps
|
||||
);
|
||||
|
||||
const filledConversations = conversations.map(async (conv: any) => {
|
||||
const messages = await window.getMessagesByKey(conv.id);
|
||||
const messages = await MessageController.getInstance().getMessagesByKeyFromDb(
|
||||
conv.id
|
||||
);
|
||||
return { ...conv, messages };
|
||||
});
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ import { Mention, MentionsInput } from 'react-mentions';
|
|||
import { MemberItem } from '../../conversation/MemberList';
|
||||
import { CaptionEditor } from '../../CaptionEditor';
|
||||
import { DefaultTheme } from 'styled-components';
|
||||
import { ConversationController } from '../../../session/conversations/ConversationController';
|
||||
|
||||
export interface ReplyingToMessageProps {
|
||||
convoId: string;
|
||||
|
@ -451,7 +452,7 @@ export class SessionCompositionBox extends React.Component<Props, State> {
|
|||
}
|
||||
|
||||
private fetchUsersForClosedGroup(query: any, callback: any) {
|
||||
const conversationModel = window.ConversationController.get(
|
||||
const conversationModel = ConversationController.getInstance().get(
|
||||
this.props.conversationKey
|
||||
);
|
||||
if (!conversationModel) {
|
||||
|
@ -460,7 +461,7 @@ export class SessionCompositionBox extends React.Component<Props, State> {
|
|||
const allPubKeys = conversationModel.get('members');
|
||||
|
||||
const allMembers = allPubKeys.map(pubKey => {
|
||||
const conv = window.ConversationController.get(pubKey);
|
||||
const conv = ConversationController.getInstance().get(pubKey);
|
||||
let profileName = 'Anonymous';
|
||||
if (conv) {
|
||||
profileName = conv.getProfileName();
|
||||
|
@ -722,7 +723,7 @@ export class SessionCompositionBox extends React.Component<Props, State> {
|
|||
// Also, check for a message length change before firing it up, to avoid
|
||||
// catching ESC, tab, or whatever which is not typing
|
||||
if (message.length && message.length !== this.lastBumpTypingMessageLength) {
|
||||
const conversationModel = window.ConversationController.get(
|
||||
const conversationModel = ConversationController.getInstance().get(
|
||||
this.props.conversationKey
|
||||
);
|
||||
if (!conversationModel) {
|
||||
|
|
|
@ -31,6 +31,7 @@ import { MessageView } from '../../MainViewController';
|
|||
import { getMessageById } from '../../../../js/modules/data';
|
||||
import { pushUnblockToSend } from '../../../session/utils/Toast';
|
||||
import { MessageDetail } from '../../conversation/MessageDetail';
|
||||
import { ConversationController } from '../../../session/conversations';
|
||||
|
||||
interface State {
|
||||
// Message sending progress
|
||||
|
@ -87,7 +88,7 @@ export class SessionConversation extends React.Component<Props, State> {
|
|||
|
||||
const { conversationKey } = this.props;
|
||||
|
||||
const conversationModel = window.ConversationController.get(
|
||||
const conversationModel = ConversationController.getInstance().get(
|
||||
conversationKey
|
||||
);
|
||||
|
||||
|
@ -253,7 +254,7 @@ export class SessionConversation extends React.Component<Props, State> {
|
|||
const selectionMode = !!selectedMessages.length;
|
||||
|
||||
const { conversation, conversationKey, messages } = this.props;
|
||||
const conversationModel = window.ConversationController.get(
|
||||
const conversationModel = ConversationController.getInstance().get(
|
||||
conversationKey
|
||||
);
|
||||
|
||||
|
@ -395,7 +396,7 @@ export class SessionConversation extends React.Component<Props, State> {
|
|||
|
||||
public async loadInitialMessages() {
|
||||
const { conversationKey } = this.props;
|
||||
const conversationModel = window.ConversationController.get(
|
||||
const conversationModel = ConversationController.getInstance().get(
|
||||
conversationKey
|
||||
);
|
||||
if (!conversationModel) {
|
||||
|
@ -419,7 +420,7 @@ export class SessionConversation extends React.Component<Props, State> {
|
|||
infoViewState,
|
||||
messageDetailShowProps,
|
||||
} = this.state;
|
||||
const conversation = window.ConversationController.getOrThrow(
|
||||
const conversation = ConversationController.getInstance().getOrThrow(
|
||||
conversationKey
|
||||
);
|
||||
const expireTimer = conversation.get('expireTimer');
|
||||
|
@ -545,7 +546,7 @@ export class SessionConversation extends React.Component<Props, State> {
|
|||
|
||||
public getRightPanelProps() {
|
||||
const { conversationKey } = this.props;
|
||||
const conversation = window.ConversationController.getOrThrow(
|
||||
const conversation = ConversationController.getInstance().getOrThrow(
|
||||
conversationKey
|
||||
);
|
||||
|
||||
|
@ -661,7 +662,7 @@ export class SessionConversation extends React.Component<Props, State> {
|
|||
// Get message objects
|
||||
const { conversationKey, messages } = this.props;
|
||||
|
||||
const conversationModel = window.ConversationController.getOrThrow(
|
||||
const conversationModel = ConversationController.getInstance().getOrThrow(
|
||||
conversationKey
|
||||
);
|
||||
const selectedMessages = messages.filter(message =>
|
||||
|
@ -815,7 +816,7 @@ export class SessionConversation extends React.Component<Props, State> {
|
|||
}
|
||||
if (!_.isEqual(this.state.quotedMessageTimestamp, quotedMessageTimestamp)) {
|
||||
const { messages, conversationKey } = this.props;
|
||||
const conversationModel = window.ConversationController.getOrThrow(
|
||||
const conversationModel = ConversationController.getInstance().getOrThrow(
|
||||
conversationKey
|
||||
);
|
||||
|
||||
|
@ -1222,7 +1223,7 @@ export class SessionConversation extends React.Component<Props, State> {
|
|||
);
|
||||
|
||||
const allMembers = allPubKeys.map((pubKey: string) => {
|
||||
const conv = window.ConversationController.get(pubKey);
|
||||
const conv = ConversationController.getInstance().get(pubKey);
|
||||
let profileName = 'Anonymous';
|
||||
if (conv) {
|
||||
profileName = conv.getProfileName();
|
||||
|
|
|
@ -17,6 +17,7 @@ import { SessionLastSeenIndicator } from './SessionLastSeedIndicator';
|
|||
import { VerificationNotification } from '../../conversation/VerificationNotification';
|
||||
import { ToastUtils } from '../../../session/utils';
|
||||
import { TypingBubble } from '../../conversation/TypingBubble';
|
||||
import { ConversationController } from '../../../session/conversations';
|
||||
|
||||
interface State {
|
||||
showScrollButton: boolean;
|
||||
|
@ -134,7 +135,7 @@ export class SessionMessagesList extends React.Component<Props, State> {
|
|||
|
||||
let displayedName = null;
|
||||
if (conversation.type === 'direct') {
|
||||
displayedName = window.ConversationController.getContactProfileNameOrShortenedPubKey(
|
||||
displayedName = ConversationController.getInstance().getContactProfileNameOrShortenedPubKey(
|
||||
conversationKey
|
||||
);
|
||||
}
|
||||
|
@ -366,7 +367,7 @@ export class SessionMessagesList extends React.Component<Props, State> {
|
|||
return;
|
||||
}
|
||||
|
||||
const conversation = window.ConversationController.getOrThrow(
|
||||
const conversation = ConversationController.getInstance().getOrThrow(
|
||||
conversationKey
|
||||
);
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ import {
|
|||
import { mapDispatchToProps } from '../../../state/actions';
|
||||
import { connect } from 'react-redux';
|
||||
import { StateType } from '../../../state/reducer';
|
||||
import { ConversationController } from '../../../session/conversations';
|
||||
|
||||
export enum SessionSettingCategory {
|
||||
Appearance = 'appearance',
|
||||
|
@ -341,7 +342,7 @@ class SettingsViewInner extends React.Component<SettingsViewProps, State> {
|
|||
}
|
||||
|
||||
const secretWords = window.mnemonic.pubkey_to_secret_words(pubKey);
|
||||
const conv = window.ConversationController.get(pubKey);
|
||||
const conv = ConversationController.getInstance().get(pubKey);
|
||||
const deviceAlias = conv ? conv.getNickname() : 'Unnamed Device';
|
||||
|
||||
return { deviceAlias, secretWords };
|
||||
|
@ -594,7 +595,9 @@ class SettingsViewInner extends React.Component<SettingsViewProps, State> {
|
|||
for (const blockedNumber of blockedNumbers) {
|
||||
let title: string;
|
||||
|
||||
const currentModel = window.ConversationController.get(blockedNumber);
|
||||
const currentModel = ConversationController.getInstance().get(
|
||||
blockedNumber
|
||||
);
|
||||
if (currentModel) {
|
||||
title =
|
||||
currentModel.getProfileName() ||
|
||||
|
|
|
@ -3,6 +3,7 @@ import { UserUtil } from '../../util';
|
|||
import { PubKey } from '../../session/types';
|
||||
import React from 'react';
|
||||
import * as _ from 'lodash';
|
||||
import { ConversationController } from '../../session/conversations';
|
||||
|
||||
export type ConversationAvatar = {
|
||||
avatarPath?: string;
|
||||
|
@ -69,7 +70,10 @@ export function usingClosedConversationDetails(WrappedComponent: any) {
|
|||
members = members.slice(0, 2);
|
||||
const memberConvos = await Promise.all(
|
||||
members.map(async m =>
|
||||
window.ConversationController.getOrCreateAndWait(m.key, 'private')
|
||||
ConversationController.getInstance().getOrCreateAndWait(
|
||||
m.key,
|
||||
'private'
|
||||
)
|
||||
)
|
||||
);
|
||||
const memberAvatars = memberConvos.map(m => {
|
||||
|
|
|
@ -20,6 +20,7 @@ import { StringUtils } from '../session/utils';
|
|||
import { UserUtil } from '../util';
|
||||
import { fromHex, toHex } from '../session/utils/String';
|
||||
import { concatUInt8Array, getSodium } from '../session/crypto';
|
||||
import { ConversationController } from '../session/conversations';
|
||||
|
||||
export async function handleContentMessage(envelope: EnvelopePlus) {
|
||||
try {
|
||||
|
@ -147,7 +148,7 @@ async function decryptWithSessionProtocol(
|
|||
case SignalService.Envelope.Type.MEDIUM_GROUP_CIPHERTEXT: {
|
||||
const hexEncodedGroupPublicKey = envelope.source;
|
||||
|
||||
isMediumGroup = window.ConversationController.isMediumGroup(
|
||||
isMediumGroup = ConversationController.getInstance().isMediumGroup(
|
||||
hexEncodedGroupPublicKey
|
||||
);
|
||||
|
||||
|
@ -490,7 +491,7 @@ async function decrypt(
|
|||
// include the prekeyId in that new message.
|
||||
// We won't find this preKeyId as we already burnt it when the sender established the session.
|
||||
|
||||
const convo = window.ConversationController.get(envelope.source);
|
||||
const convo = ConversationController.getInstance().get(envelope.source);
|
||||
if (!convo) {
|
||||
window.log.warn('PreKeyMissing but convo is missing too. Dropping...');
|
||||
return;
|
||||
|
@ -543,7 +544,7 @@ function shouldDropBlockedUserMessage(content: SignalService.Content): boolean {
|
|||
}
|
||||
const groupId = StringUtils.decode(content.dataMessage.group.id, 'utf8');
|
||||
|
||||
const groupConvo = window.ConversationController.get(groupId);
|
||||
const groupConvo = ConversationController.getInstance().get(groupId);
|
||||
if (!groupConvo) {
|
||||
return true;
|
||||
}
|
||||
|
@ -579,7 +580,6 @@ export async function innerHandleContentMessage(
|
|||
envelope: EnvelopePlus,
|
||||
plaintext: ArrayBuffer
|
||||
): Promise<void> {
|
||||
const { ConversationController } = window;
|
||||
try {
|
||||
const content = SignalService.Content.decode(new Uint8Array(plaintext));
|
||||
|
||||
|
@ -597,7 +597,10 @@ export async function innerHandleContentMessage(
|
|||
}
|
||||
const { FALLBACK_MESSAGE } = SignalService.Envelope.Type;
|
||||
|
||||
await ConversationController.getOrCreateAndWait(envelope.source, 'private');
|
||||
await ConversationController.getInstance().getOrCreateAndWait(
|
||||
envelope.source,
|
||||
'private'
|
||||
);
|
||||
|
||||
if (envelope.type !== FALLBACK_MESSAGE) {
|
||||
const device = new PubKey(envelope.source);
|
||||
|
@ -737,7 +740,6 @@ async function handleTypingMessage(
|
|||
|
||||
const typingMessage = iTypingMessage as SignalService.TypingMessage;
|
||||
|
||||
const { ConversationController } = window;
|
||||
const { timestamp, groupId, action } = typingMessage;
|
||||
const { source } = envelope;
|
||||
|
||||
|
@ -770,7 +772,7 @@ async function handleTypingMessage(
|
|||
|
||||
const convoId = (primaryDevice && primaryDevice.key) || source;
|
||||
|
||||
const conversation = ConversationController.get(convoId);
|
||||
const conversation = ConversationController.getInstance().get(convoId);
|
||||
|
||||
const started = action === SignalService.TypingMessage.Action.STARTED;
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ import _ from 'lodash';
|
|||
import { StringUtils } from '../session/utils';
|
||||
import { DeliveryReceiptMessage } from '../session/messages/outgoing';
|
||||
import { getMessageQueue } from '../session';
|
||||
import { ConversationController } from '../session/conversations';
|
||||
|
||||
export async function updateProfile(
|
||||
conversation: any,
|
||||
|
@ -75,11 +76,10 @@ export async function updateProfile(
|
|||
const allUserDevices = await MultiDeviceProtocol.getAllDevices(
|
||||
conversation.id
|
||||
);
|
||||
const { ConversationController } = window;
|
||||
|
||||
await Promise.all(
|
||||
allUserDevices.map(async device => {
|
||||
const conv = await ConversationController.getOrCreateAndWait(
|
||||
const conv = await ConversationController.getInstance().getOrCreateAndWait(
|
||||
device.key,
|
||||
'private'
|
||||
);
|
||||
|
@ -300,7 +300,7 @@ export async function handleDataMessage(
|
|||
const ourPubKey = window.textsecure.storage.user.getNumber();
|
||||
const senderPubKey = envelope.senderIdentity || envelope.source;
|
||||
const isMe = senderPubKey === ourPubKey;
|
||||
const conversation = window.ConversationController.get(senderPubKey);
|
||||
const conversation = ConversationController.getInstance().get(senderPubKey);
|
||||
|
||||
const { UNPAIRING_REQUEST } = SignalService.DataMessage.Flags;
|
||||
|
||||
|
@ -417,7 +417,7 @@ async function handleProfileUpdate(
|
|||
const profileKey = StringUtils.decode(profileKeyBuffer, 'base64');
|
||||
|
||||
if (!isIncoming) {
|
||||
const receiver = await window.ConversationController.getOrCreateAndWait(
|
||||
const receiver = await ConversationController.getInstance().getOrCreateAndWait(
|
||||
convoId,
|
||||
convoType
|
||||
);
|
||||
|
@ -427,7 +427,7 @@ async function handleProfileUpdate(
|
|||
|
||||
// Then we update our own profileKey if it's different from what we have
|
||||
const ourNumber = window.textsecure.storage.user.getNumber();
|
||||
const me = await window.ConversationController.getOrCreate(
|
||||
const me = await ConversationController.getInstance().getOrCreate(
|
||||
ourNumber,
|
||||
'private'
|
||||
);
|
||||
|
@ -435,7 +435,7 @@ async function handleProfileUpdate(
|
|||
// Will do the save for us if needed
|
||||
await me.setProfileKey(profileKey);
|
||||
} else {
|
||||
const sender = await window.ConversationController.getOrCreateAndWait(
|
||||
const sender = await ConversationController.getInstance().getOrCreateAndWait(
|
||||
convoId,
|
||||
'private'
|
||||
);
|
||||
|
@ -669,7 +669,7 @@ export async function handleMessageEvent(event: MessageEvent): Promise<void> {
|
|||
);
|
||||
}
|
||||
|
||||
const conv = await window.ConversationController.getOrCreateAndWait(
|
||||
const conv = await ConversationController.getInstance().getOrCreateAndWait(
|
||||
conversationId,
|
||||
type
|
||||
);
|
||||
|
@ -720,7 +720,9 @@ export async function handleMessageEvent(event: MessageEvent): Promise<void> {
|
|||
}
|
||||
|
||||
// the conversation with the primary device of that source (can be the same as conversationOrigin)
|
||||
const conversation = window.ConversationController.getOrThrow(conversationId);
|
||||
const conversation = ConversationController.getInstance().getOrThrow(
|
||||
conversationId
|
||||
);
|
||||
|
||||
conversation.queueJob(() => {
|
||||
handleMessageJob(
|
||||
|
|
|
@ -2,13 +2,12 @@ import { initIncomingMessage } from './dataMessage';
|
|||
import { toNumber } from 'lodash';
|
||||
import { SessionProtocol } from '../session/protocols';
|
||||
import { PubKey } from '../session/types';
|
||||
import { ConversationController } from '../session/conversations';
|
||||
|
||||
async function onNoSession(ev: any) {
|
||||
const { ConversationController, Whisper } = window;
|
||||
|
||||
const pubkey = ev.proto.source;
|
||||
|
||||
const convo = await ConversationController.getOrCreateAndWait(
|
||||
const convo = await ConversationController.getInstance().getOrCreateAndWait(
|
||||
pubkey,
|
||||
'private'
|
||||
);
|
||||
|
@ -40,7 +39,6 @@ export async function onError(ev: any) {
|
|||
return;
|
||||
}
|
||||
|
||||
const { ConversationController, Whisper } = window;
|
||||
const { error } = ev;
|
||||
window.log.error(
|
||||
'background onError:',
|
||||
|
@ -62,7 +60,7 @@ export async function onError(ev: any) {
|
|||
|
||||
message.saveErrors(error || new Error('Error was null'));
|
||||
const id = message.get('conversationId');
|
||||
const conversation = await ConversationController.getOrCreateAndWait(
|
||||
const conversation = await ConversationController.getInstance().getOrCreateAndWait(
|
||||
id,
|
||||
'private'
|
||||
);
|
||||
|
|
|
@ -4,6 +4,7 @@ import { getMessageQueue } from '../session';
|
|||
import { PubKey } from '../session/types';
|
||||
import _ from 'lodash';
|
||||
import { BlockedNumberController } from '../util/blockedNumberController';
|
||||
import { ConversationController } from '../session/conversations';
|
||||
|
||||
function isGroupBlocked(groupId: string) {
|
||||
return BlockedNumberController.isGroupBlocked(groupId);
|
||||
|
@ -34,7 +35,7 @@ export async function preprocessGroupMessage(
|
|||
primarySource: string
|
||||
) {
|
||||
const conversationId = group.id;
|
||||
const conversation = await window.ConversationController.getOrCreateAndWait(
|
||||
const conversation = await ConversationController.getInstance().getOrCreateAndWait(
|
||||
conversationId,
|
||||
'group'
|
||||
);
|
||||
|
|
|
@ -14,6 +14,7 @@ import {
|
|||
createSenderKeyForGroup,
|
||||
shareSenderKeys,
|
||||
} from '../session/medium_group/senderKeys';
|
||||
import { ConversationController } from '../session/conversations';
|
||||
|
||||
async function handleSenderKeyRequest(
|
||||
envelope: EnvelopePlus,
|
||||
|
@ -161,7 +162,7 @@ async function handleNewGroup(
|
|||
const members = membersBinary.map(toHex);
|
||||
const admins = adminsBinary.map(toHex);
|
||||
|
||||
const maybeConvo = window.ConversationController.get(groupId);
|
||||
const maybeConvo = ConversationController.getInstance().get(groupId);
|
||||
|
||||
const groupExists = !!maybeConvo;
|
||||
|
||||
|
@ -185,7 +186,10 @@ async function handleNewGroup(
|
|||
|
||||
const convo =
|
||||
maybeConvo ||
|
||||
(await window.ConversationController.getOrCreateAndWait(groupId, 'group'));
|
||||
(await ConversationController.getInstance().getOrCreateAndWait(
|
||||
groupId,
|
||||
'group'
|
||||
));
|
||||
|
||||
await SenderKeyAPI.addUpdateMessage(convo, { newName: name }, 'incoming');
|
||||
|
||||
|
@ -265,7 +269,7 @@ async function handleMediumGroupChange(
|
|||
|
||||
const groupId = toHex(groupPublicKey);
|
||||
|
||||
const convo = window.ConversationController.get(groupId);
|
||||
const convo = ConversationController.getInstance().get(groupId);
|
||||
|
||||
if (!convo) {
|
||||
log.warn(
|
||||
|
|
|
@ -13,6 +13,7 @@ import { PubKey } from '../session/types';
|
|||
|
||||
import ByteBuffer from 'bytebuffer';
|
||||
import { BlockedNumberController } from '../util';
|
||||
import { ConversationController } from '../session/conversations';
|
||||
|
||||
async function unpairingRequestIsLegit(source: string, ourPubKey: string) {
|
||||
const { textsecure, storage, lokiFileServerAPI } = window;
|
||||
|
@ -144,7 +145,7 @@ async function handleAuthorisationForSelf(
|
|||
pairingAuthorisation: SignalService.IPairingAuthorisationMessage,
|
||||
dataMessage: SignalService.IDataMessage | undefined | null
|
||||
) {
|
||||
const { ConversationController, libloki, Whisper } = window;
|
||||
const { libloki, Whisper } = window;
|
||||
|
||||
const valid = await libloki.crypto.validateAuthorisation(
|
||||
pairingAuthorisation
|
||||
|
@ -174,7 +175,7 @@ async function handleAuthorisationForSelf(
|
|||
await MultiDeviceProtocol.savePairingAuthorisation(
|
||||
pairingAuthorisation as Data.PairingAuthorisation
|
||||
);
|
||||
const primaryConversation = await ConversationController.getOrCreateAndWait(
|
||||
const primaryConversation = await ConversationController.getInstance().getOrCreateAndWait(
|
||||
primaryDevicePubKey,
|
||||
'private'
|
||||
);
|
||||
|
@ -186,7 +187,7 @@ async function handleAuthorisationForSelf(
|
|||
|
||||
if (profile && profileKey) {
|
||||
const ourNumber = window.storage.get('primaryDevicePubKey');
|
||||
const me = window.ConversationController.get(ourNumber);
|
||||
const me = ConversationController.getInstance().get(ourNumber);
|
||||
if (me) {
|
||||
await updateProfile(me, profile, profileKey);
|
||||
}
|
||||
|
@ -298,13 +299,7 @@ export async function handleContacts(
|
|||
|
||||
// tslint:disable-next-line: max-func-body-length
|
||||
async function onContactReceived(details: any) {
|
||||
const {
|
||||
ConversationController,
|
||||
storage,
|
||||
textsecure,
|
||||
libloki,
|
||||
Whisper,
|
||||
} = window;
|
||||
const { storage, textsecure, libloki, Whisper } = window;
|
||||
const { Errors } = window.Signal.Types;
|
||||
|
||||
const id = details.number;
|
||||
|
@ -334,7 +329,7 @@ async function onContactReceived(details: any) {
|
|||
}
|
||||
|
||||
try {
|
||||
const conversation = await ConversationController.getOrCreateAndWait(
|
||||
const conversation = await ConversationController.getInstance().getOrCreateAndWait(
|
||||
id,
|
||||
'private'
|
||||
);
|
||||
|
@ -349,13 +344,13 @@ async function onContactReceived(details: any) {
|
|||
|
||||
const primaryDevice = await MultiDeviceProtocol.getPrimaryDevice(id);
|
||||
const secondaryDevices = await MultiDeviceProtocol.getSecondaryDevices(id);
|
||||
const primaryConversation = await ConversationController.getOrCreateAndWait(
|
||||
const primaryConversation = await ConversationController.getInstance().getOrCreateAndWait(
|
||||
primaryDevice.key,
|
||||
'private'
|
||||
);
|
||||
const secondaryConversations = await Promise.all(
|
||||
secondaryDevices.map(async d => {
|
||||
const secondaryConv = await ConversationController.getOrCreateAndWait(
|
||||
const secondaryConv = await ConversationController.getInstance().getOrCreateAndWait(
|
||||
d.key,
|
||||
'private'
|
||||
);
|
||||
|
|
|
@ -8,6 +8,7 @@ import _ from 'lodash';
|
|||
import { MultiDeviceProtocol } from '../session/protocols';
|
||||
import { SignalService } from '../protobuf';
|
||||
import { StringUtils } from '../session/utils';
|
||||
import { ConversationController } from '../session/conversations';
|
||||
|
||||
async function handleGroups(
|
||||
conversation: ConversationModel,
|
||||
|
@ -372,7 +373,6 @@ async function handleRegularMessage(
|
|||
ourNumber: any,
|
||||
primarySource: PubKey
|
||||
) {
|
||||
const { ConversationController } = window;
|
||||
const { upgradeMessageSchema } = window.Signal.Migrations;
|
||||
|
||||
const type = message.get('type');
|
||||
|
@ -448,13 +448,13 @@ async function handleRegularMessage(
|
|||
!conversationTimestamp ||
|
||||
message.get('sent_at') > conversationTimestamp
|
||||
) {
|
||||
conversation.lastMessage = message.getNotificationText();
|
||||
conversation.set({
|
||||
timestamp: message.get('sent_at'),
|
||||
lastMessage: message.getNotificationText(),
|
||||
});
|
||||
}
|
||||
|
||||
const sendingDeviceConversation = await ConversationController.getOrCreateAndWait(
|
||||
const sendingDeviceConversation = await ConversationController.getInstance().getOrCreateAndWait(
|
||||
source,
|
||||
'private'
|
||||
);
|
||||
|
|
|
@ -23,6 +23,7 @@ import { getEnvelopeId } from './common';
|
|||
import { StringUtils } from '../session/utils';
|
||||
import { SignalService } from '../protobuf';
|
||||
import { MultiDeviceProtocol } from '../session/protocols';
|
||||
import { ConversationController } from '../session/conversations';
|
||||
|
||||
// TODO: check if some of these exports no longer needed
|
||||
|
||||
|
@ -285,7 +286,7 @@ export async function handleUnencryptedMessage({ message: outerMessage }: any) {
|
|||
const isMe = source === ourNumber;
|
||||
|
||||
if (!isMe && profile) {
|
||||
const conversation = await window.ConversationController.getOrCreateAndWait(
|
||||
const conversation = await ConversationController.getInstance().getOrCreateAndWait(
|
||||
source,
|
||||
'private'
|
||||
);
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { ConversationController } from '../session/conversations';
|
||||
|
||||
export async function handleEndSession(number: string): Promise<void> {
|
||||
window.log.info('got end session');
|
||||
|
||||
const { ConversationController } = window;
|
||||
|
||||
try {
|
||||
const conversation = ConversationController.get(number);
|
||||
const conversation = ConversationController.getInstance().get(number);
|
||||
if (conversation) {
|
||||
// this just marks the conversation as being waiting for a new session
|
||||
// it does trigger a message to be sent. (the message is sent from handleSessionRequestMessage())
|
||||
|
|
|
@ -17,6 +17,7 @@ import { handleContacts } from './multidevice';
|
|||
import { updateOrCreateGroupFromSync } from '../session/medium_group';
|
||||
import { MultiDeviceProtocol } from '../session/protocols';
|
||||
import { BlockedNumberController } from '../util';
|
||||
import { ConversationController } from '../session/conversations';
|
||||
|
||||
export async function handleSyncMessage(
|
||||
envelope: EnvelopePlus,
|
||||
|
@ -107,8 +108,6 @@ async function handleSentMessage(
|
|||
return;
|
||||
}
|
||||
|
||||
const { ConversationController } = window;
|
||||
|
||||
// tslint:disable-next-line no-bitwise
|
||||
if (msg.flags && msg.flags & SignalService.DataMessage.Flags.END_SESSION) {
|
||||
await handleEndSession(destination as string);
|
||||
|
@ -125,7 +124,9 @@ async function handleSentMessage(
|
|||
// handle profileKey and avatar updates
|
||||
if (envelope.source === primaryDevicePubKey) {
|
||||
const { profileKey, profile } = message;
|
||||
const primaryConversation = ConversationController.get(primaryDevicePubKey);
|
||||
const primaryConversation = ConversationController.getInstance().get(
|
||||
primaryDevicePubKey
|
||||
);
|
||||
if (profile) {
|
||||
await updateProfile(primaryConversation, profile, profileKey);
|
||||
}
|
||||
|
@ -188,7 +189,7 @@ async function handleBlocked(
|
|||
);
|
||||
|
||||
async function markConvoBlocked(block: boolean, n: string) {
|
||||
const conv = window.ConversationController.get(n);
|
||||
const conv = ConversationController.getInstance().get(n);
|
||||
if (conv) {
|
||||
if (conv.isPrivate()) {
|
||||
await BlockedNumberController.setBlocked(n, block);
|
||||
|
@ -260,7 +261,7 @@ async function handleVerified(
|
|||
}
|
||||
|
||||
export async function onVerified(ev: any) {
|
||||
const { ConversationController, textsecure, Whisper } = window;
|
||||
const { Whisper } = window;
|
||||
const { Errors } = window.Signal.Types;
|
||||
|
||||
const number = ev.verified.destination;
|
||||
|
@ -300,7 +301,7 @@ export async function onVerified(ev: any) {
|
|||
ev.viaContactSync ? 'via contact sync' : ''
|
||||
);
|
||||
|
||||
const contact = await ConversationController.getOrCreateAndWait(
|
||||
const contact = await ConversationController.getInstance().getOrCreateAndWait(
|
||||
number,
|
||||
'private'
|
||||
);
|
||||
|
|
|
@ -0,0 +1,336 @@
|
|||
import {
|
||||
ConversationAttributes,
|
||||
ConversationModel,
|
||||
} from '../../../js/models/conversations';
|
||||
import { BlockedNumberController } from '../../util';
|
||||
|
||||
// It's not only data from the db which is stored on the MessageController entries, we could fetch this again. What we cannot fetch from the db and which is stored here is all listeners a particular messages is linked to for instance. We will be able to get rid of this once we don't use backbone models at all
|
||||
export class ConversationController {
|
||||
private static instance: ConversationController | null;
|
||||
private readonly conversations: any;
|
||||
private _initialFetchComplete: boolean = false;
|
||||
private _initialPromise?: Promise<any>;
|
||||
|
||||
private constructor() {
|
||||
this.conversations = new window.Whisper.ConversationCollection();
|
||||
}
|
||||
|
||||
public static getInstance() {
|
||||
if (ConversationController.instance) {
|
||||
return ConversationController.instance;
|
||||
}
|
||||
ConversationController.instance = new ConversationController();
|
||||
return ConversationController.instance;
|
||||
}
|
||||
|
||||
public get(id: string): ConversationModel {
|
||||
if (!this._initialFetchComplete) {
|
||||
throw new Error(
|
||||
'ConversationController.get() needs complete initial fetch'
|
||||
);
|
||||
}
|
||||
|
||||
return this.conversations.get(id);
|
||||
}
|
||||
|
||||
public getOrThrow(id: string) {
|
||||
if (!this._initialFetchComplete) {
|
||||
throw new Error(
|
||||
'ConversationController.get() needs complete initial fetch'
|
||||
);
|
||||
}
|
||||
|
||||
const convo = this.conversations.get(id);
|
||||
|
||||
if (convo) {
|
||||
return convo;
|
||||
}
|
||||
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) {
|
||||
return this.conversations.get(id);
|
||||
}
|
||||
|
||||
public dangerouslyCreateAndAdd(attributes: ConversationAttributes) {
|
||||
return this.conversations.add(attributes);
|
||||
}
|
||||
|
||||
public getOrCreate(id: string, type: string) {
|
||||
if (typeof id !== 'string') {
|
||||
throw new TypeError("'id' must be a string");
|
||||
}
|
||||
|
||||
if (type !== 'private' && type !== 'group') {
|
||||
throw new TypeError(
|
||||
`'type' must be 'private' or 'group'; got: '${type}'`
|
||||
);
|
||||
}
|
||||
|
||||
if (!this._initialFetchComplete) {
|
||||
throw new Error(
|
||||
'ConversationController.get() needs complete initial fetch'
|
||||
);
|
||||
}
|
||||
|
||||
let conversation = this.conversations.get(id);
|
||||
if (conversation) {
|
||||
return conversation;
|
||||
}
|
||||
|
||||
conversation = this.conversations.add({
|
||||
id,
|
||||
type,
|
||||
version: 2,
|
||||
} as any);
|
||||
|
||||
const create = async () => {
|
||||
if (!conversation.isValid()) {
|
||||
const validationError = conversation.validationError || {};
|
||||
window.log.error(
|
||||
'Contact is not valid. Not saving, but adding to collection:',
|
||||
conversation.idForLogging(),
|
||||
validationError.stack
|
||||
);
|
||||
|
||||
return conversation;
|
||||
}
|
||||
|
||||
try {
|
||||
await window.Signal.Data.saveConversation(conversation.attributes, {
|
||||
Conversation: window.Whisper.Conversation,
|
||||
});
|
||||
} catch (error) {
|
||||
window.log.error(
|
||||
'Conversation save failed! ',
|
||||
id,
|
||||
type,
|
||||
'Error:',
|
||||
error && error.stack ? error.stack : error
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
|
||||
return conversation;
|
||||
};
|
||||
|
||||
conversation.initialPromise = create();
|
||||
conversation.initialPromise.then(async () => {
|
||||
if (!conversation.isPublic() && !conversation.isRss()) {
|
||||
await Promise.all([
|
||||
conversation.updateProfileAvatar(),
|
||||
// NOTE: we request snodes updating the cache, but ignore the result
|
||||
window.SnodePool.getSnodesFor(id),
|
||||
]);
|
||||
}
|
||||
if (window.inboxStore) {
|
||||
conversation.on('change', this.updateReduxConvoChanged);
|
||||
window.inboxStore.dispatch(
|
||||
window.actionsCreators.conversationAdded(
|
||||
conversation.id,
|
||||
conversation.getProps()
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return conversation;
|
||||
}
|
||||
|
||||
public getContactProfileNameOrShortenedPubKey(pubKey: string): string {
|
||||
const conversation = ConversationController.getInstance().get(pubKey);
|
||||
if (!conversation) {
|
||||
return pubKey;
|
||||
}
|
||||
return conversation.getContactProfileNameOrShortenedPubKey();
|
||||
}
|
||||
|
||||
public getContactProfileNameOrFullPubKey(pubKey: string): string {
|
||||
const conversation = this.conversations.get(pubKey);
|
||||
if (!conversation) {
|
||||
return pubKey;
|
||||
}
|
||||
return conversation.getContactProfileNameOrFullPubKey();
|
||||
}
|
||||
|
||||
public isMediumGroup(hexEncodedGroupPublicKey: string): boolean {
|
||||
const convo = this.conversations.get(hexEncodedGroupPublicKey);
|
||||
if (convo) {
|
||||
return convo.isMediumGroup();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public async getOrCreateAndWait(id: any, type: string) {
|
||||
const initialPromise = this._initialPromise !== undefined ? this._initialPromise : Promise.resolve();
|
||||
return initialPromise.then(() => {
|
||||
if (!id) {
|
||||
return Promise.reject(
|
||||
new Error('getOrCreateAndWait: invalid id passed.')
|
||||
);
|
||||
}
|
||||
const pubkey = id && id.key ? id.key : id;
|
||||
const conversation = this.getOrCreate(pubkey, type);
|
||||
|
||||
if (conversation) {
|
||||
return conversation.initialPromise.then(() => conversation);
|
||||
}
|
||||
|
||||
return Promise.reject(
|
||||
new Error('getOrCreateAndWait: did not get conversation')
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
public async getAllGroupsInvolvingId(id: String) {
|
||||
const groups = await window.Signal.Data.getAllGroupsInvolvingId(id, {
|
||||
ConversationCollection: window.Whisper.ConversationCollection,
|
||||
});
|
||||
return groups.map((group: any) => this.conversations.add(group));
|
||||
}
|
||||
|
||||
public async deleteContact(id: string) {
|
||||
if (typeof id !== 'string') {
|
||||
throw new TypeError("'id' must be a string");
|
||||
}
|
||||
|
||||
if (!this._initialFetchComplete) {
|
||||
throw new Error(
|
||||
'ConversationController.get() needs complete initial fetch'
|
||||
);
|
||||
}
|
||||
|
||||
const conversation = this.conversations.get(id);
|
||||
if (!conversation) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Close group leaving
|
||||
if (conversation.isClosedGroup()) {
|
||||
await conversation.leaveGroup();
|
||||
} else if (conversation.isPublic()) {
|
||||
const channelAPI = await conversation.getPublicSendData();
|
||||
if (channelAPI === null) {
|
||||
window.log.warn(`Could not get API for public conversation ${id}`);
|
||||
} else {
|
||||
channelAPI.serverAPI.partChannel(channelAPI.channelId);
|
||||
}
|
||||
} else if (conversation.isPrivate()) {
|
||||
const deviceIds = await window.textsecure.storage.protocol.getDeviceIds(
|
||||
id
|
||||
);
|
||||
await Promise.all(
|
||||
deviceIds.map((deviceId: string) => {
|
||||
const address = new window.libsignal.SignalProtocolAddress(
|
||||
id,
|
||||
deviceId
|
||||
);
|
||||
const sessionCipher = new window.libsignal.SessionCipher(
|
||||
window.textsecure.storage.protocol,
|
||||
address
|
||||
);
|
||||
return sessionCipher.deleteAllSessionsForDevice();
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
await conversation.destroyMessages();
|
||||
|
||||
await window.Signal.Data.removeConversation(id, {
|
||||
Conversation: window.Whisper.Conversation,
|
||||
});
|
||||
conversation.off('change', this.updateReduxConvoChanged);
|
||||
this.conversations.remove(conversation);
|
||||
if (window.inboxStore) {
|
||||
window.inboxStore.dispatch(
|
||||
window.actionsCreators.conversationRemoved(conversation.id)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public getConversations(): Array<ConversationModel> {
|
||||
return Array.from(this.conversations.models.values());
|
||||
}
|
||||
|
||||
public async load() {
|
||||
window.log.info('ConversationController: starting initial fetch');
|
||||
|
||||
if (this.conversations.length) {
|
||||
throw new Error('ConversationController: Already loaded!');
|
||||
}
|
||||
|
||||
const load = async () => {
|
||||
try {
|
||||
const collection = await window.Signal.Data.getAllConversations({
|
||||
ConversationCollection: window.Whisper.ConversationCollection,
|
||||
});
|
||||
|
||||
this.conversations.add(collection.models);
|
||||
|
||||
this._initialFetchComplete = true;
|
||||
const promises: any = [];
|
||||
this.conversations.forEach((conversation: ConversationModel) => {
|
||||
if (!conversation.get('lastMessage')) {
|
||||
// tslint:disable-next-line: no-void-expression
|
||||
promises.push(conversation.updateLastMessage());
|
||||
}
|
||||
|
||||
promises.concat([
|
||||
conversation.updateProfileName(),
|
||||
conversation.updateProfileAvatar(),
|
||||
]);
|
||||
});
|
||||
this.conversations.forEach((conversation: ConversationModel) => {
|
||||
// register for change event on each conversation, and forward to redux
|
||||
conversation.on('change', this.updateReduxConvoChanged);
|
||||
});
|
||||
await Promise.all(promises);
|
||||
|
||||
// Remove any unused images
|
||||
window.profileImages.removeImagesNotInArray(
|
||||
this.conversations.map((c: any) => c.id)
|
||||
);
|
||||
window.log.info('ConversationController: done with initial fetch');
|
||||
} catch (error) {
|
||||
window.log.error(
|
||||
'ConversationController: initial fetch failed',
|
||||
error && error.stack ? error.stack : error
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
await BlockedNumberController.load();
|
||||
|
||||
this._initialPromise = load();
|
||||
|
||||
return this._initialPromise;
|
||||
}
|
||||
|
||||
public loadPromise() {
|
||||
return this._initialPromise;
|
||||
}
|
||||
public reset() {
|
||||
this._initialPromise = Promise.resolve();
|
||||
this._initialFetchComplete = false;
|
||||
if (window.inboxStore) {
|
||||
this.conversations.forEach((convo: ConversationModel) =>
|
||||
convo.off('change', this.updateReduxConvoChanged)
|
||||
);
|
||||
|
||||
window.inboxStore.dispatch(
|
||||
window.actionsCreators.removeAllConversations()
|
||||
);
|
||||
}
|
||||
this.conversations.reset([]);
|
||||
}
|
||||
|
||||
private updateReduxConvoChanged(convo: ConversationModel) {
|
||||
if (window.inboxStore) {
|
||||
window.inboxStore.dispatch(
|
||||
window.actionsCreators.conversationChanged(convo.id, convo.getProps())
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
import { ConversationController } from './ConversationController';
|
||||
|
||||
export { ConversationController };
|
|
@ -1,4 +1,5 @@
|
|||
import * as Messages from './messages';
|
||||
import * as Conversations from './conversations';
|
||||
import * as Protocols from './protocols';
|
||||
import * as Types from './types';
|
||||
import * as Utils from './utils';
|
||||
|
@ -8,4 +9,13 @@ import * as MediumGroup from './medium_group';
|
|||
|
||||
export * from './instance';
|
||||
|
||||
export { Messages, Utils, Protocols, Types, Sending, Constants, MediumGroup };
|
||||
export {
|
||||
Conversations,
|
||||
Messages,
|
||||
Utils,
|
||||
Protocols,
|
||||
Types,
|
||||
Sending,
|
||||
Constants,
|
||||
MediumGroup,
|
||||
};
|
||||
|
|
|
@ -28,6 +28,7 @@ import { ConversationModel } from '../../../js/models/conversations';
|
|||
import { MediumGroupUpdateMessage } from '../messages/outgoing/content/data/mediumgroup/MediumGroupUpdateMessage';
|
||||
import uuid from 'uuid';
|
||||
import { BlockedNumberController } from '../../util/blockedNumberController';
|
||||
import { ConversationController } from '../conversations';
|
||||
|
||||
export {
|
||||
createSenderKeyForGroup,
|
||||
|
@ -63,7 +64,7 @@ export async function createMediumGroup(
|
|||
groupName: string,
|
||||
members: Array<string>
|
||||
) {
|
||||
const { ConversationController, libsignal } = window;
|
||||
const { libsignal } = window;
|
||||
|
||||
// ***** 1. Create group parameters *****
|
||||
|
||||
|
@ -92,7 +93,7 @@ export async function createMediumGroup(
|
|||
|
||||
// ***** 2. Send group update message *****
|
||||
|
||||
const convo = await ConversationController.getOrCreateAndWait(
|
||||
const convo = await ConversationController.getInstance().getOrCreateAndWait(
|
||||
groupId,
|
||||
'group'
|
||||
);
|
||||
|
@ -142,7 +143,7 @@ export async function createLegacyGroup(
|
|||
groupName: string,
|
||||
members: Array<string>
|
||||
) {
|
||||
const { ConversationController, libsignal } = window;
|
||||
const { libsignal } = window;
|
||||
|
||||
const keypair = await libsignal.KeyHelper.generateIdentityKeyPair();
|
||||
const groupId = toHex(keypair.pubKey);
|
||||
|
@ -163,7 +164,7 @@ export async function createLegacyGroup(
|
|||
|
||||
await updateOrCreateGroup(groupDetails);
|
||||
|
||||
const convo = await ConversationController.getOrCreateAndWait(
|
||||
const convo = await ConversationController.getInstance().getOrCreateAndWait(
|
||||
groupId,
|
||||
'group'
|
||||
);
|
||||
|
@ -187,7 +188,6 @@ export async function createLegacyGroup(
|
|||
}
|
||||
|
||||
export async function leaveMediumGroup(groupId: string) {
|
||||
const { ConversationController } = window;
|
||||
// NOTE: we should probably remove sender keys for groupId,
|
||||
// and its secret key, but it is low priority
|
||||
|
||||
|
@ -195,7 +195,7 @@ export async function leaveMediumGroup(groupId: string) {
|
|||
window.SwarmPolling.removePubkey(groupId);
|
||||
// TODO audric: we just left a group, we have to regenerate our senderkey
|
||||
|
||||
const maybeConvo = ConversationController.get(groupId);
|
||||
const maybeConvo = ConversationController.getInstance().get(groupId);
|
||||
|
||||
if (!maybeConvo) {
|
||||
window.log.error('Cannot leave non-existing group');
|
||||
|
@ -360,9 +360,7 @@ export async function initiateGroupUpdate(
|
|||
members: Array<string>,
|
||||
avatar: any
|
||||
) {
|
||||
const { ConversationController } = window;
|
||||
|
||||
const convo = await ConversationController.getOrCreateAndWait(
|
||||
const convo = await ConversationController.getInstance().getOrCreateAndWait(
|
||||
groupId,
|
||||
'group'
|
||||
);
|
||||
|
@ -470,8 +468,7 @@ async function sendToMembers(
|
|||
message: MediumGroupMessage,
|
||||
dbMessage: MessageModel
|
||||
) {
|
||||
const { ConversationController } = window;
|
||||
const convo = await ConversationController.getOrCreateAndWait(
|
||||
const convo = await ConversationController.getInstance().getOrCreateAndWait(
|
||||
groupId,
|
||||
'group'
|
||||
);
|
||||
|
@ -801,7 +798,7 @@ export async function updateOrCreateGroupFromSync(details: GroupInfo) {
|
|||
|
||||
// update conversation model
|
||||
async function updateOrCreateGroup(details: GroupInfo) {
|
||||
const { ConversationController, libloki, storage, textsecure } = window;
|
||||
const { libloki, textsecure } = window;
|
||||
|
||||
const { id } = details;
|
||||
|
||||
|
@ -812,7 +809,7 @@ async function updateOrCreateGroup(details: GroupInfo) {
|
|||
details
|
||||
);
|
||||
|
||||
const conversation = await ConversationController.getOrCreateAndWait(
|
||||
const conversation = await ConversationController.getInstance().getOrCreateAndWait(
|
||||
id,
|
||||
'group'
|
||||
);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// You can see MessageController for in memory registered messages.
|
||||
// Ee register messages to it everytime we send one, so that when an event happens we can find which message it was based on this id.
|
||||
|
||||
import { ConversationModel } from '../../../js/models/conversations';
|
||||
import { MessageModel } from '../../../js/models/messages';
|
||||
|
||||
type MessageControllerEntry = {
|
||||
|
@ -70,4 +71,19 @@ export class MessageController {
|
|||
public get(identifier: string) {
|
||||
return this.messageLookup.get(identifier);
|
||||
}
|
||||
|
||||
public async getMessagesByKeyFromDb(key: string) {
|
||||
// loadLive gets messages live, not from the database which can lag behind.
|
||||
|
||||
let messages = [];
|
||||
const messageSet = await window.Signal.Data.getMessagesByConversation(key, {
|
||||
limit: 100,
|
||||
MessageCollection: window.Whisper.MessageCollection,
|
||||
});
|
||||
|
||||
messages = messageSet.models.map(
|
||||
(conv: ConversationModel) => conv.attributes
|
||||
);
|
||||
return messages;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import _ from 'lodash';
|
|||
import * as Data from '../../../js/modules/data';
|
||||
|
||||
import { StringUtils } from '../../session/utils';
|
||||
import { ConversationController } from '../conversations/ConversationController';
|
||||
|
||||
type PubkeyToHash = { [key: string]: string };
|
||||
|
||||
|
@ -147,7 +148,7 @@ export class SwarmPolling {
|
|||
|
||||
private loadGroupIds() {
|
||||
// Start polling for medium size groups as well (they might be in different swarms)
|
||||
const convos = window
|
||||
const convos = ConversationController.getInstance()
|
||||
.getConversations()
|
||||
.filter((c: any) => c.isMediumGroup());
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { ConversationModel } from '../../../js/models/conversations';
|
||||
import { ConversationController } from '../conversations';
|
||||
import { PromiseUtils } from '../utils';
|
||||
|
||||
interface OpenGroupParams {
|
||||
|
@ -160,7 +161,7 @@ export class OpenGroup {
|
|||
const conversationId = `publicChat:${channelId}@${rawServerURL}`;
|
||||
|
||||
// Quickly peak to make sure we don't already have it
|
||||
return window.ConversationController.get(conversationId);
|
||||
return ConversationController.getInstance().get(conversationId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
import _ from 'lodash';
|
||||
import { PrimaryPubKey, PubKey } from '../types';
|
||||
import { MultiDeviceProtocol } from '../protocols';
|
||||
import { ConversationController } from '../conversations';
|
||||
|
||||
export async function getGroupMembers(
|
||||
groupId: PubKey
|
||||
): Promise<Array<PrimaryPubKey>> {
|
||||
const groupConversation = window.ConversationController.get(groupId.key);
|
||||
const groupConversation = ConversationController.getInstance().get(
|
||||
groupId.key
|
||||
);
|
||||
const groupMembers = groupConversation
|
||||
? groupConversation.attributes.members
|
||||
: undefined;
|
||||
|
@ -23,7 +26,7 @@ export async function getGroupMembers(
|
|||
}
|
||||
|
||||
export function isMediumGroup(groupId: PubKey): boolean {
|
||||
const conversation = window.ConversationController.get(groupId.key);
|
||||
const conversation = ConversationController.getInstance().get(groupId.key);
|
||||
|
||||
if (!conversation) {
|
||||
return false;
|
||||
|
|
|
@ -9,6 +9,7 @@ import {
|
|||
SentSyncMessage,
|
||||
} from '../messages/outgoing';
|
||||
import { PubKey } from '../types';
|
||||
import { ConversationController } from '../conversations';
|
||||
|
||||
export function getSentSyncMessage(params: {
|
||||
message: ContentMessage;
|
||||
|
@ -64,7 +65,7 @@ export async function getSyncContacts(): Promise<Array<any> | undefined> {
|
|||
);
|
||||
|
||||
const secondaryContactsPromise = secondaryContactsPartial.map(async c =>
|
||||
window.ConversationController.getOrCreateAndWait(
|
||||
ConversationController.getInstance().getOrCreateAndWait(
|
||||
c.getPrimaryDevicePubKey(),
|
||||
'private'
|
||||
)
|
||||
|
|
|
@ -3,6 +3,7 @@ import _, { omit } from 'lodash';
|
|||
import { Constants } from '../../session';
|
||||
import { createAsyncThunk } from '@reduxjs/toolkit';
|
||||
import { MessageModel } from '../../../js/models/messages';
|
||||
import { ConversationController } from '../../session/conversations';
|
||||
|
||||
// State
|
||||
|
||||
|
@ -92,7 +93,9 @@ async function getMessages(
|
|||
conversationKey: string,
|
||||
numMessages: number
|
||||
): Promise<Array<MessageTypeInConvo>> {
|
||||
const conversation = window.ConversationController.get(conversationKey);
|
||||
const conversation = ConversationController.getInstance().get(
|
||||
conversationKey
|
||||
);
|
||||
if (!conversation) {
|
||||
// no valid conversation, early return
|
||||
window.log.error('Failed to get convo on reducer.');
|
||||
|
|
|
@ -6,6 +6,7 @@ import { TestUtils } from '../../../test-utils';
|
|||
import { UserUtil } from '../../../../util';
|
||||
import { MultiDeviceProtocol } from '../../../../session/protocols';
|
||||
import { SyncMessage } from '../../../../session/messages/outgoing';
|
||||
import { ConversationController } from '../../../../session/conversations';
|
||||
|
||||
// tslint:disable-next-line: no-require-imports no-var-requires
|
||||
const chaiAsPromised = require('chai-as-promised');
|
||||
|
@ -17,7 +18,7 @@ describe('Sync Message Utils', () => {
|
|||
describe('getSyncContacts', () => {
|
||||
let getAllConversationsStub: sinon.SinonStub;
|
||||
let getOrCreateAndWaitStub: sinon.SinonStub;
|
||||
let getOrCreatAndWaitItem: any;
|
||||
let getOrCreateAndWaitItem: any;
|
||||
|
||||
// Fill half with secondaries, half with primaries
|
||||
const numConversations = 20;
|
||||
|
@ -57,7 +58,7 @@ describe('Sync Message Utils', () => {
|
|||
secondaryConversations[getOrCreateAndWaitStub.callCount - 1];
|
||||
|
||||
// Make the item a primary device to match the call in SyncMessage under secondaryContactsPromise
|
||||
getOrCreatAndWaitItem = {
|
||||
getOrCreateAndWaitItem = {
|
||||
...item,
|
||||
getPrimaryDevicePubKey: () => item.id,
|
||||
attributes: {
|
||||
|
@ -65,12 +66,12 @@ describe('Sync Message Utils', () => {
|
|||
},
|
||||
};
|
||||
|
||||
return getOrCreatAndWaitItem;
|
||||
return getOrCreateAndWaitItem;
|
||||
});
|
||||
|
||||
TestUtils.stubWindow('ConversationController', {
|
||||
getOrCreateAndWait: getOrCreateAndWaitStub,
|
||||
});
|
||||
sandbox
|
||||
.stub(ConversationController.getInstance(), 'getOrCreateAndWait')
|
||||
.resolves(getOrCreateAndWaitStub);
|
||||
|
||||
// Stubs
|
||||
sandbox.stub(UserUtil, 'getCurrentDevicePubKey').resolves(ourNumber);
|
||||
|
@ -94,20 +95,5 @@ describe('Sync Message Utils', () => {
|
|||
expect(contacts).to.have.length(numConversations / 2);
|
||||
expect(contacts?.find(c => c.attributes.secondaryStatus)).to.not.exist;
|
||||
});
|
||||
|
||||
it('can get sync contacts of assorted primaries and secondaries', async () => {
|
||||
// Map secondary contacts to stub resolution
|
||||
const contacts = await SyncMessageUtils.getSyncContacts();
|
||||
expect(getAllConversationsStub.callCount).to.equal(1);
|
||||
|
||||
// We should have numConversations unique contacts
|
||||
expect(contacts).to.have.length(numConversations);
|
||||
|
||||
// All contacts should be primary; half of which some from secondaries in secondaryContactsPromise
|
||||
expect(contacts?.find(c => c.attributes.secondaryStatus)).to.not.exist;
|
||||
expect(contacts?.filter(c => c.isPrimary)).to.have.length(
|
||||
numConversations / 2
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -81,6 +81,7 @@ export class MockConversation {
|
|||
this.attributes = {
|
||||
id: this.id,
|
||||
name: '',
|
||||
type: '',
|
||||
members,
|
||||
left: false,
|
||||
expireTimer: dayInSeconds,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { ConversationModel } from '../../js/models/conversations';
|
||||
import { ConversationController } from '../session/conversations/ConversationController';
|
||||
|
||||
// tslint:disable: no-unnecessary-class
|
||||
export class FindMember {
|
||||
|
@ -9,9 +10,11 @@ export class FindMember {
|
|||
): Promise<ConversationModel | null> {
|
||||
let groupMembers;
|
||||
|
||||
const groupConvos = window.getConversations().models.filter((d: any) => {
|
||||
return !d.isPrivate();
|
||||
});
|
||||
const groupConvos = ConversationController.getInstance()
|
||||
.getConversations()
|
||||
.filter((d: any) => {
|
||||
return !d.isPrivate();
|
||||
});
|
||||
const thisConvo = groupConvos.find((d: any) => {
|
||||
return d.id === convoId;
|
||||
});
|
||||
|
@ -29,14 +32,16 @@ export class FindMember {
|
|||
const publicMembers = await window.lokiPublicChatAPI.getListOfMembers();
|
||||
const memberConversations = publicMembers
|
||||
.map(publicMember =>
|
||||
window.ConversationController.get(publicMember.authorPhoneNumber)
|
||||
ConversationController.getInstance().get(
|
||||
publicMember.authorPhoneNumber
|
||||
)
|
||||
)
|
||||
.filter((c: any) => !!c);
|
||||
groupMembers = memberConversations;
|
||||
} else {
|
||||
const privateConvos = window
|
||||
const privateConvos = ConversationController.getInstance()
|
||||
.getConversations()
|
||||
.models.filter((d: any) => d.isPrivate());
|
||||
.filter((d: any) => d.isPrivate());
|
||||
const members = thisConvo.attributes.members;
|
||||
if (!members) {
|
||||
return null;
|
||||
|
|
|
@ -75,22 +75,6 @@
|
|||
"updated": "2018-09-19T21:59:32.770Z",
|
||||
"reasonDetail": "Protected from arbitrary input"
|
||||
},
|
||||
{
|
||||
"rule": "jQuery-load(",
|
||||
"path": "js/conversation_controller.js",
|
||||
"line": " async load() {",
|
||||
"lineNumber": 178,
|
||||
"reasonCategory": "falseMatch",
|
||||
"updated": "2018-10-02T21:00:44.007Z"
|
||||
},
|
||||
{
|
||||
"rule": "jQuery-load(",
|
||||
"path": "js/conversation_controller.js",
|
||||
"line": " this._initialPromise = load();",
|
||||
"lineNumber": 213,
|
||||
"reasonCategory": "falseMatch",
|
||||
"updated": "2018-10-02T21:00:44.007Z"
|
||||
},
|
||||
{
|
||||
"rule": "jQuery-$(",
|
||||
"path": "js/debug_log_start.js",
|
||||
|
@ -209,14 +193,6 @@
|
|||
"updated": "2018-09-19T18:13:29.628Z",
|
||||
"reasonDetail": "Interacting with already-existing DOM nodes"
|
||||
},
|
||||
{
|
||||
"rule": "jQuery-load(",
|
||||
"path": "js/signal_protocol_store.js",
|
||||
"line": " await ConversationController.load();",
|
||||
"lineNumber": 868,
|
||||
"reasonCategory": "falseMatch",
|
||||
"updated": "2018-09-15T00:38:04.183Z"
|
||||
},
|
||||
{
|
||||
"rule": "jQuery-wrap(",
|
||||
"path": "js/util_worker_tasks.js",
|
||||
|
@ -341,14 +317,6 @@
|
|||
"updated": "2018-09-15T00:38:04.183Z",
|
||||
"reasonDetail": "Getting the value, not setting it"
|
||||
},
|
||||
{
|
||||
"rule": "jQuery-load(",
|
||||
"path": "js/views/import_view.js",
|
||||
"line": " return ConversationController.load()",
|
||||
"lineNumber": 176,
|
||||
"reasonCategory": "falseMatch",
|
||||
"updated": "2018-09-15T00:38:04.183Z"
|
||||
},
|
||||
{
|
||||
"rule": "jQuery-$(",
|
||||
"path": "js/views/inbox_view.js",
|
||||
|
|
|
@ -28,7 +28,6 @@ If you import anything in global.d.ts, the type system won't work correctly.
|
|||
declare global {
|
||||
interface Window {
|
||||
CONSTANTS: any;
|
||||
ConversationController: ConversationControllerType;
|
||||
SignalProtocolStore: any;
|
||||
Events: any;
|
||||
Lodash: any;
|
||||
|
@ -104,6 +103,10 @@ declare global {
|
|||
ContactBuffer: any;
|
||||
GroupBuffer: any;
|
||||
SwarmPolling: SwarmPolling;
|
||||
SnodePool: {
|
||||
getSnodesFor: (string) => any;
|
||||
};
|
||||
profileImages: any;
|
||||
MediaRecorder: any;
|
||||
dataURLToBlobSync: any;
|
||||
autoOrientImage: any;
|
||||
|
@ -113,7 +116,6 @@ declare global {
|
|||
) => Promise<{ pubKey: ArrayBufferLike; privKey: ArrayBufferLike }>;
|
||||
setClockParams: any;
|
||||
clientClockSynced: number | undefined;
|
||||
getMessagesByKey: any;
|
||||
inboxStore: Store;
|
||||
getSocketStatus: any;
|
||||
actionsCreators: any;
|
||||
|
|
Loading…
Reference in New Issue