Merge clearnet

pull/1495/head
Audric Ackermann 4 years ago
parent ebf9714e49
commit 7b81c4213a
No known key found for this signature in database
GPG Key ID: 999F434D76324AD4

Binary file not shown.

After

Width:  |  Height:  |  Size: 555 B

@ -287,7 +287,7 @@ const serverRequest = async (endpoint, options = {}) => {
txtResponse = await result.text();
// cloudflare timeouts (504s) will be html...
response = options.textResponse ? txtResponse : JSON.parse(txtResponse);
response = options.noJson ? txtResponse : JSON.parse(txtResponse);
// result.status will always be 200
// emulate the correct http code if available
@ -303,7 +303,7 @@ const serverRequest = async (endpoint, options = {}) => {
e.message,
`json: ${txtResponse}`,
'attempting connection to',
url
url.toString()
);
} else {
log.error(
@ -311,7 +311,7 @@ const serverRequest = async (endpoint, options = {}) => {
e.code,
e.message,
'attempting connection to',
url
url.toString()
);
}

@ -61,6 +61,7 @@ window.lokiFeatureFlags = {
useFileOnionRequests: true,
useFileOnionRequestsV2: true, // more compact encoding of files in response
onionRequestHops: 3,
useRequestEncryptionKeyPair: false,
};
if (
@ -85,7 +86,7 @@ window.isBeforeVersion = (toCheck, baseVersion) => {
};
// eslint-disable-next-line func-names
window.CONSTANTS = new (function() {
window.CONSTANTS = new (function () {
this.MAX_GROUP_NAME_LENGTH = 64;
this.DEFAULT_PUBLIC_CHAT_URL = appConfig.get('defaultPublicChatServer');
this.MAX_LINKED_DEVICES = 1;
@ -376,7 +377,7 @@ window.callWorker = (fnName, ...args) => utilWorker.callWorker(fnName, ...args);
// Linux seems to periodically let the event loop stop, so this is a global workaround
setInterval(() => {
window.nodeSetImmediate(() => {});
window.nodeSetImmediate(() => { });
}, 1000);
const { autoOrientImage } = require('./js/modules/auto_orient_image');
@ -455,9 +456,9 @@ if (process.env.USE_STUBBED_NETWORK) {
}
// eslint-disable-next-line no-extend-native,func-names
Promise.prototype.ignore = function() {
Promise.prototype.ignore = function () {
// eslint-disable-next-line more/no-then
this.then(() => {});
this.then(() => { });
};
if (
@ -484,6 +485,7 @@ if (config.environment.includes('test-integration')) {
useOnionRequests: false,
useFileOnionRequests: false,
useOnionRequestsV2: false,
useRequestEncryptionKeyPair: false,
};
/* eslint-disable global-require, import/no-extraneous-dependencies */
window.sinon = require('sinon');

@ -33,6 +33,11 @@ import { MessageController } from '../session/messages';
import { ClosedGroupEncryptionPairReplyMessage } from '../session/messages/outgoing/content/data/group';
import { queueAllCachedFromSource } from './receiver';
export const distributingClosedGroupEncryptionKeyPairs = new Map<
string,
ECKeyPair
>();
export async function handleClosedGroupControlMessage(
envelope: EnvelopePlus,
groupUpdate: SignalService.DataMessage.ClosedGroupControlMessage
@ -456,6 +461,9 @@ async function handleClosedGroupEncryptionKeyPair(
);
if (isKeyPairAlreadyHere) {
const existingKeyPairs = await getAllEncryptionKeyPairsForGroup(
groupPublicKey
);
window.log.info('Dropping already saved keypair for group', groupPublicKey);
await removeFromCache(envelope);
return;
@ -532,11 +540,18 @@ async function performIfValid(
} else if (groupUpdate.type === Type.MEMBER_LEFT) {
await handleClosedGroupMemberLeft(envelope, groupUpdate, convo);
} else if (groupUpdate.type === Type.ENCRYPTION_KEY_PAIR_REQUEST) {
await handleClosedGroupEncryptionKeyPairRequest(
envelope,
groupUpdate,
convo
);
if (window.lokiFeatureFlags.useRequestEncryptionKeyPair) {
await handleClosedGroupEncryptionKeyPairRequest(
envelope,
groupUpdate,
convo
);
} else {
window.log.warn(
'Received ENCRYPTION_KEY_PAIR_REQUEST message but it is not enabled for now.'
);
await removeFromCache(envelope);
}
// if you add a case here, remember to add it where performIfValid is called too.
}
@ -590,6 +605,15 @@ async function handleClosedGroupMembersAdded(
return;
}
if (await areWeAdmin(convo)) {
await sendLatestKeyPairToUsers(
envelope,
convo,
convo.id,
membersNotAlreadyPresent
);
}
const members = [...oldMembers, ...membersNotAlreadyPresent];
// Only add update message if we have something to show
@ -604,6 +628,16 @@ async function handleClosedGroupMembersAdded(
await removeFromCache(envelope);
}
async function areWeAdmin(groupConvo: ConversationModel) {
if (!groupConvo) {
throw new Error('areWeAdmin needs a convo');
}
const groupAdmins = groupConvo.get('groupAdmins');
const ourNumber = UserUtils.getOurPubKeyStrFromCache();
return groupAdmins?.includes(ourNumber) || false;
}
async function handleClosedGroupMembersRemoved(
envelope: EnvelopePlus,
groupUpdate: SignalService.DataMessage.ClosedGroupControlMessage,
@ -650,8 +684,7 @@ async function handleClosedGroupMembersRemoved(
window.SwarmPolling.removePubkey(groupPubKey);
}
// Generate and distribute a new encryption key pair if needed
const isCurrentUserAdmin = firstAdmin === ourPubKey.key;
if (isCurrentUserAdmin) {
if (await areWeAdmin(convo)) {
try {
await ClosedGroup.generateAndSendNewEncryptionKeyPair(
groupPubKey,
@ -731,58 +764,83 @@ async function handleClosedGroupMemberLeft(
await removeFromCache(envelope);
}
async function handleClosedGroupEncryptionKeyPairRequest(
async function sendLatestKeyPairToUsers(
envelope: EnvelopePlus,
groupUpdate: SignalService.DataMessage.ClosedGroupControlMessage,
convo: ConversationModel
groupConvo: ConversationModel,
groupPubKey: string,
targetUsers: Array<string>
) {
const sender = envelope.senderIdentity;
const groupPublicKey = envelope.source;
// Guard against self-sends
if (UserUtils.isUsFromCache(sender)) {
window.log.info(
'Dropping self send message of type ENCRYPTION_KEYPAIR_REQUEST'
);
await removeFromCache(envelope);
return;
}
// use the inMemory keypair if found
const inMemoryKeyPair = distributingClosedGroupEncryptionKeyPairs.get(
groupPubKey
);
// Get the latest encryption key pair
const latestKeyPair = await getLatestClosedGroupEncryptionKeyPair(
groupPublicKey
groupPubKey
);
if (!latestKeyPair) {
if (!inMemoryKeyPair && !latestKeyPair) {
window.log.info(
'We do not have the keypair ourself, so dropping this message.'
);
await removeFromCache(envelope);
return;
}
window.log.info(
`Responding to closed group encryption key pair request from: ${sender}`
);
await ConversationController.getInstance().getOrCreateAndWait(
sender,
'private'
);
const expireTimer = groupConvo.get('expireTimer') || 0;
const wrappers = await ClosedGroup.buildEncryptionKeyPairWrappers(
[sender],
ECKeyPair.fromHexKeyPair(latestKeyPair)
);
const expireTimer = convo.get('expireTimer') || 0;
await Promise.all(
targetUsers.map(async member => {
window.log.info(
`Sending latest closed group encryption key pair to: ${member}`
);
await ConversationController.getInstance().getOrCreateAndWait(
member,
'private'
);
const keypairsMessage = new ClosedGroupEncryptionPairReplyMessage({
groupId: groupPublicKey,
timestamp: Date.now(),
encryptedKeyPairs: wrappers,
expireTimer,
});
const wrappers = await ClosedGroup.buildEncryptionKeyPairWrappers(
[member],
inMemoryKeyPair || ECKeyPair.fromHexKeyPair(latestKeyPair)
);
// the encryption keypair is sent using established channels
await getMessageQueue().sendToPubKey(PubKey.cast(sender), keypairsMessage);
const keypairsMessage = new ClosedGroupEncryptionPairReplyMessage({
groupId: groupPubKey,
timestamp: Date.now(),
encryptedKeyPairs: wrappers,
expireTimer,
});
// the encryption keypair is sent using established channels
await getMessageQueue().sendToPubKey(
PubKey.cast(member),
keypairsMessage
);
})
);
}
await removeFromCache(envelope);
async function handleClosedGroupEncryptionKeyPairRequest(
envelope: EnvelopePlus,
groupUpdate: SignalService.DataMessage.ClosedGroupControlMessage,
groupConvo: ConversationModel
) {
if (!window.lokiFeatureFlags.useRequestEncryptionKeyPair) {
throw new Error('useRequestEncryptionKeyPair is disabled');
}
const sender = envelope.senderIdentity;
const groupPublicKey = envelope.source;
// Guard against self-sends
if (UserUtils.isUsFromCache(sender)) {
window.log.info(
'Dropping self send message of type ENCRYPTION_KEYPAIR_REQUEST'
);
await removeFromCache(envelope);
return;
}
await sendLatestKeyPairToUsers(envelope, groupConvo, groupPublicKey, [
sender,
]);
return removeFromCache(envelope);
}
export async function createClosedGroup(

@ -124,18 +124,23 @@ async function decryptForClosedGroup(
'decryptWithSessionProtocol for medium group message throw:',
e
);
const keypairRequestManager = KeyPairRequestManager.getInstance();
const groupPubKey = PubKey.cast(envelope.source);
if (keypairRequestManager.canTriggerRequestWith(groupPubKey)) {
keypairRequestManager.markRequestSendFor(groupPubKey, Date.now());
await requestEncryptionKeyPair(groupPubKey);
// To enable back if we decide to enable encryption key pair request work again
if (window.lokiFeatureFlags.useRequestEncryptionKeyPair) {
const keypairRequestManager = KeyPairRequestManager.getInstance();
if (keypairRequestManager.canTriggerRequestWith(groupPubKey)) {
keypairRequestManager.markRequestSendFor(groupPubKey, Date.now());
await requestEncryptionKeyPair(groupPubKey);
}
}
// IMPORTANT do not remove the message from the cache just yet.
// We will try to decrypt it once we get the encryption keypair.
// for that to work, we need to throw an error just like here.
throw new Error(
`Waiting for an encryption keypair to be received for group ${groupPubKey.key}`
);
// do not remove it from the cache yet. We will try to decrypt it once we get the encryption keypair
// TODO drop it if after some time we still don't get to decrypt it
// await removeFromCache(envelope);
return null;
}
}

@ -32,6 +32,7 @@ import { ConversationModel } from '../../models/conversation';
import { MessageModel } from '../../models/message';
import { MessageModelType } from '../../models/messageType';
import { MessageController } from '../messages';
import { distributingClosedGroupEncryptionKeyPairs } from '../../receiver/closedGroups';
export interface GroupInfo {
id: string;
@ -557,11 +558,15 @@ export async function generateAndSendNewEncryptionKeyPair(
expireTimer,
});
distributingClosedGroupEncryptionKeyPairs.set(toHex(groupId), newKeyPair);
const messageSentCallback = async () => {
window.log.info(
`KeyPairMessage for ClosedGroup ${groupPublicKey} is sent. Saving the new encryptionKeyPair.`
);
distributingClosedGroupEncryptionKeyPairs.delete(toHex(groupId));
await addClosedGroupEncryptionKeyPair(
toHex(groupId),
newKeyPair.toHexKeyPair()
@ -611,6 +616,10 @@ export async function buildEncryptionKeyPairWrappers(
export async function requestEncryptionKeyPair(
groupPublicKey: string | PubKey
) {
if (!window.lokiFeatureFlags.useRequestEncryptionKeyPair) {
throw new Error('useRequestEncryptionKeyPair is disabled');
}
const groupConvo = ConversationController.getInstance().get(
PubKey.cast(groupPublicKey).key
);

1
ts/window.d.ts vendored

@ -64,6 +64,7 @@ declare global {
useFileOnionRequests: boolean;
useFileOnionRequestsV2: boolean;
onionRequestHops: number;
useRequestEncryptionKeyPair: boolean;
};
lokiFileServerAPI: LokiFileServerInstance;
lokiMessageAPI: LokiMessageInterface;

Loading…
Cancel
Save