Big refactor, prekeybundle moved back to a content message

pull/62/head
Beaudan 6 years ago
parent 7c92eeac30
commit 35c89ea4d9

@ -1,5 +1,6 @@
/* global _: false */ /* global _: false */
/* global Backbone: false */ /* global Backbone: false */
/* global BlockedNumberController: false */
/* global ConversationController: false */ /* global ConversationController: false */
/* global i18n: false */ /* global i18n: false */
/* global libsignal: false */ /* global libsignal: false */
@ -42,14 +43,10 @@
const FriendStatusEnum = Object.freeze({ const FriendStatusEnum = Object.freeze({
// New conversation, no messages sent or received // New conversation, no messages sent or received
none: 0, none: 0,
// Have received a friend request, waiting to accept/decline // Friend request not complete yet, input blocked
pendingAction: 1, pending: 1,
// Have sent a friend request, waiting for response
pendingResponse: 2,
// Have sent and received prekeybundle, waiting for ciphertext confirming key exchange
pendingCipher: 3,
// We did it! // We did it!
friends: 4, friends: 2,
}); });
const COLORS = [ const COLORS = [
@ -66,26 +63,6 @@
'blue_grey', 'blue_grey',
]; ];
/**
* A few key things that need to be known in this is the difference
* between isFriend() and isKeyExchangeCompleted().
*
* `isFriend` returns whether we have accepted the other user as a friend.
* - This is explicilty stored as a state in the conversation
*
* `isKeyExchangeCompleted` return whether we know for certain
* that both of our preKeyBundles have been exchanged.
* - This will be set when we receive a valid CIPHER or
* PREKEY_BUNDLE message from the other user.
* * Valid meaning we can decypher the message using the preKeys provided
* or the keys we have stored.
*
* `isFriend` will determine whether we should send a FRIEND_REQUEST message.
*
* `isKeyExchangeCompleted` will determine whether we keep
* sending preKeyBundle to the other user.
*/
Whisper.Conversation = Backbone.Model.extend({ Whisper.Conversation = Backbone.Model.extend({
storeName: 'conversations', storeName: 'conversations',
defaults() { defaults() {
@ -93,7 +70,6 @@
unreadCount: 0, unreadCount: 0,
verified: textsecure.storage.protocol.VerifiedStatus.DEFAULT, verified: textsecure.storage.protocol.VerifiedStatus.DEFAULT,
friendStatus: FriendStatusEnum.none, friendStatus: FriendStatusEnum.none,
keyExchangeCompleted: false,
unlockTimestamp: null, // Timestamp used for expiring friend requests. unlockTimestamp: null, // Timestamp used for expiring friend requests.
}; };
}, },
@ -477,50 +453,17 @@
return contact.isVerified(); return contact.isVerified();
}); });
}, },
isKeyExchangeCompleted() {
if (!this.isPrivate()) {
return false;
// throw new Error('isKeyExchangeCompleted not implemented for groups');
}
if (this.isMe()) {
return true;
}
return this.get('friendStatus') === FriendStatusEnum.friends;
},
async setKeyExchangeCompleted() {
if (this.get('friendStatus') !== FriendStatusEnum.pendingCipher) return;
this.set({ friendStatus: FriendStatusEnum.friends });
await window.Signal.Data.updateConversation(this.id, this.attributes, {
Conversation: Whisper.Conversation,
});
},
async waitingForFriendRequestApproval() { async waitingForFriendRequestApproval() {
// Check if we have an incoming friend request // Check if we have an incoming friend request
// Or any successful outgoing ones // Or any successful outgoing ones
const incoming = await this.getPendingFriendRequests('incoming'); const incoming = await this.getPendingFriendRequests('incoming');
const outgoing = await this.getPendingFriendRequests('outgoing'); const outgoing = await this.getPendingFriendRequests('outgoing');
const successfulOutgoing = outgoing.filter(o => !o.hasErrors()); const successfulOutgoing = outgoing.filter(o => !o.hasErrors());
return (incoming.length > 0 || successfulOutgoing.length > 0); return (incoming.length > 0 || successfulOutgoing.length > 0);
},
getPreKeyBundleType() {
switch (this.get('friendStatus')) {
case FriendStatusEnum.none:
case FriendStatusEnum.pendingResponse:
return textsecure.protobuf.PreKeyBundleMessage.Type.FRIEND_REQUEST;
case FriendStatusEnum.pendingAction:
case FriendStatusEnum.pendingCipher:
return textsecure.protobuf.PreKeyBundleMessage.Type.FRIEND_REQUEST_ACCEPT;
default:
return textsecure.protobuf.PreKeyBundleMessage.Type.UNKNOWN;
}
}, },
isFriend() { isFriend() {
return this.get('friendStatus') === FriendStatusEnum.pendingCipher || return this.get('friendStatus') === FriendStatusEnum.friends;
this.get('friendStatus') === FriendStatusEnum.friends;
}, },
// Update any pending friend requests for the current user // Update any pending friend requests for the current user
async updateFriendRequestUI() { async updateFriendRequestUI() {
@ -554,7 +497,7 @@
// We have declined an incoming friend request // We have declined an incoming friend request
async onDeclineFriendRequest() { async onDeclineFriendRequest() {
// Should we change states for other states? (They should never happen) // Should we change states for other states? (They should never happen)
if (this.get('friendStatus') === FriendStatusEnum.pendingAction) { if (this.get('friendStatus') === FriendStatusEnum.pending) {
this.set({ friendStatus: FriendStatusEnum.none }); this.set({ friendStatus: FriendStatusEnum.none });
await window.Signal.Data.updateConversation(this.id, this.attributes, { await window.Signal.Data.updateConversation(this.id, this.attributes, {
Conversation: Whisper.Conversation, Conversation: Whisper.Conversation,
@ -567,8 +510,8 @@
// We have accepted an incoming friend request // We have accepted an incoming friend request
async onAcceptFriendRequest() { async onAcceptFriendRequest() {
// Should we change states for other states? (They should never happen) // Should we change states for other states? (They should never happen)
if (this.get('friendStatus') === FriendStatusEnum.pendingAction) { if (this.get('friendStatus') === FriendStatusEnum.pending) {
this.set({ friendStatus: FriendStatusEnum.pendingCipher }); this.set({ friendStatus: FriendStatusEnum.friends });
await window.Signal.Data.updateConversation(this.id, this.attributes, { await window.Signal.Data.updateConversation(this.id, this.attributes, {
Conversation: Whisper.Conversation, Conversation: Whisper.Conversation,
}); });
@ -579,9 +522,8 @@
}, },
// Our outgoing friend request has been accepted // Our outgoing friend request has been accepted
async onFriendRequestAccepted() { async onFriendRequestAccepted() {
// TODO: Think about how we want to handle other states if (this.get('friendStatus') === FriendStatusEnum.pending) {
if (this.get('friendStatus') === FriendStatusEnum.pendingResponse) { this.set({ friendStatus: FriendStatusEnum.friends });
this.set({ friendStatus: FriendStatusEnum.pendingCipher });
await window.Signal.Data.updateConversation(this.id, this.attributes, { await window.Signal.Data.updateConversation(this.id, this.attributes, {
Conversation: Whisper.Conversation, Conversation: Whisper.Conversation,
}); });
@ -622,30 +564,12 @@
await this.updateFriendRequestUI(); await this.updateFriendRequestUI();
}, },
async onFriendRequestReceived() { async onFriendRequestReceived() {
switch (this.get('friendStatus')) { if (this.get('friendStatus') === FriendStatusEnum.none) {
case FriendStatusEnum.none: this.set({ friendStatus: FriendStatusEnum.pending });
this.set({ friendStatus: FriendStatusEnum.pendingAction }); await window.Signal.Data.updateConversation(this.id, this.attributes, {
await window.Signal.Data.updateConversation(this.id, this.attributes, { Conversation: Whisper.Conversation,
Conversation: Whisper.Conversation, });
}); await this.updateFriendRequestUI();
await this.updateFriendRequestUI();
return;
case FriendStatusEnum.pendingResponse:
this.set({ friendStatus: FriendStatusEnum.pendingCipher });
await window.Signal.Data.updateConversation(this.id, this.attributes, {
Conversation: Whisper.Conversation,
});
await this.updateFriendRequestUI();
return;
case FriendStatusEnum.pendingAction:
case FriendStatusEnum.pendingCipher:
// No need to change state
return;
case FriendStatusEnum.friends:
// TODO: Handle this case (discuss with squad)
return;
default:
throw new TypeError(`Invalid friendStatus type: '${this.friendStatus}'`);
} }
}, },
async onFriendRequestSent() { async onFriendRequestSent() {
@ -665,7 +589,7 @@
} }
if (this.get('friendStatus') === FriendStatusEnum.none) { if (this.get('friendStatus') === FriendStatusEnum.none) {
this.set({ friendStatus: FriendStatusEnum.pendingResponse }); this.set({ friendStatus: FriendStatusEnum.pending });
await window.Signal.Data.updateConversation(this.id, this.attributes, { await window.Signal.Data.updateConversation(this.id, this.attributes, {
Conversation: Whisper.Conversation, Conversation: Whisper.Conversation,
}); });
@ -1170,6 +1094,7 @@
); );
const options = this.getSendOptions(); const options = this.getSendOptions();
options.messageType = message.attributes.type;
// Add the message sending on another queue so that our UI doesn't get blocked // Add the message sending on another queue so that our UI doesn't get blocked
this.queueMessageSend(async () => this.queueMessageSend(async () =>
@ -1295,12 +1220,10 @@
getSendOptions(options = {}) { getSendOptions(options = {}) {
const senderCertificate = storage.get('senderCertificate'); const senderCertificate = storage.get('senderCertificate');
const numberInfo = this.getNumberInfo(options); const numberInfo = this.getNumberInfo(options);
const preKeyBundleType = this.getPreKeyBundleType();
return { return {
senderCertificate, senderCertificate,
numberInfo, numberInfo,
preKeyBundleType,
}; };
}, },
@ -1371,8 +1294,8 @@
// Delete the old messages if it's pending // Delete the old messages if it's pending
await Promise.all( await Promise.all(
incoming incoming
.filter(i => i.id !== message.id) .filter(i => i.id !== message.id)
.map(request => this._removeMessage(request.id)) .map(request => this._removeMessage(request.id))
); );
// If we have an outgoing friend request then // If we have an outgoing friend request then

@ -164,7 +164,7 @@
color: this.model.getColor(), color: this.model.getColor(),
avatarPath: this.model.getAvatarPath(), avatarPath: this.model.getAvatarPath(),
isVerified: this.model.isVerified(), isVerified: this.model.isVerified(),
isKeysPending: this.model.isKeyExchangeCompleted() === false, isKeysPending: this.model.isFriend() === false,
isMe: this.model.isMe(), isMe: this.model.isMe(),
isBlocked: this.model.isBlocked(), isBlocked: this.model.isBlocked(),
isGroup: !this.model.isPrivate(), isGroup: !this.model.isPrivate(),

@ -25,7 +25,7 @@
ivAndCiphertext.set(new Uint8Array(iv)); ivAndCiphertext.set(new Uint8Array(iv));
ivAndCiphertext.set(new Uint8Array(ciphertext), iv.byteLength); ivAndCiphertext.set(new Uint8Array(ciphertext), iv.byteLength);
return { return {
type: textsecure.protobuf.Envelope.Type.FALLBACK_CIPHERTEXT, type: textsecure.protobuf.Envelope.Type.FRIEND_REQUEST,
body: ivAndCiphertext, body: ivAndCiphertext,
registrationId: null, registrationId: null,
}; };
@ -141,9 +141,7 @@
log.info('empty message sent successfully'); log.info('empty message sent successfully');
} }
}; };
const options = { const options = {};
preKeyBundleType: textsecure.protobuf.PreKeyBundleMessage.Type.FRIEND_REQUEST_ACCEPT,
};
// send an empty message. The logic in ougoing_message will attach the prekeys. // send an empty message. The logic in ougoing_message will attach the prekeys.
const outgoingMessage = new textsecure.OutgoingMessage( const outgoingMessage = new textsecure.OutgoingMessage(
null, // server null, // server

@ -631,9 +631,6 @@ MessageReceiver.prototype.extend({
return this.onDeliveryReceipt(envelope); return this.onDeliveryReceipt(envelope);
} }
if (envelope.preKeyBundleMessage) {
return this.handlePreKeyBundleMessage(envelope);
}
if (envelope.content) { if (envelope.content) {
return this.handleContentMessage(envelope); return this.handleContentMessage(envelope);
} }
@ -725,7 +722,7 @@ MessageReceiver.prototype.extend({
promise = sessionCipher.decryptWhisperMessage(ciphertext) promise = sessionCipher.decryptWhisperMessage(ciphertext)
.then(this.unpad); .then(this.unpad);
break; break;
case textsecure.protobuf.Envelope.Type.FALLBACK_CIPHERTEXT: { case textsecure.protobuf.Envelope.Type.FRIEND_REQUEST: {
window.log.info('friend-request message from ', envelope.source); window.log.info('friend-request message from ', envelope.source);
promise = fallBackSessionCipher.decrypt(ciphertext.toArrayBuffer()) promise = fallBackSessionCipher.decrypt(ciphertext.toArrayBuffer())
.then(this.unpad); .then(this.unpad);
@ -984,45 +981,39 @@ MessageReceiver.prototype.extend({
let conversation; let conversation;
try { try {
conversation = window.ConversationController.get(envelope.source); conversation = await window.ConversationController.getOrCreateAndWait(envelope.source, 'private');
} catch (e) { } catch (e) {
window.log.info('Error getting conversation: ', envelope.source); window.log.info('Error getting conversation: ', envelope.source);
} }
if (envelope.type === textsecure.protobuf.Envelope.Type.FRIEND_REQUEST) {
if ( conversation.onFriendRequestReceived();
envelope.preKeyBundleMessage &&
envelope.preKeyBundleMessage.type ===
textsecure.protobuf.PreKeyBundleMessage.Type.FRIEND_REQUEST
) {
return this.handleFriendRequestMessage(envelope, content.dataMessage);
} else if (
envelope.type === textsecure.protobuf.Envelope.Type.CIPHERTEXT ||
// We also need to check for PREKEY_BUNDLE aswell if the session hasn't started.
// ref: libsignal-protocol.js:36120
envelope.type === textsecure.protobuf.Envelope.Type.PREKEY_BUNDLE
) {
// If we get a cipher and we're already friends
// then we set our key exchange to complete
if (conversation && conversation.isFriend()) {
await conversation.setKeyExchangeCompleted();
}
} }
if (content.syncMessage) { if (content.preKeyBundleMessage) {
const preKeyBundleMessage =
this.decodePreKeyBundleMessage(content.preKeyBundleMessage);
await this.savePreKeyBundleMessage(
envelope.source,
preKeyBundleMessage
);
return this.handleDataMessage(envelope, content.dataMessage, 'friend-request');
}
if (content.syncMessage)
return this.handleSyncMessage(envelope, content.syncMessage); return this.handleSyncMessage(envelope, content.syncMessage);
} else if (content.dataMessage) { if (content.dataMessage)
return this.handleDataMessage(envelope, content.dataMessage); return this.handleDataMessage(envelope, content.dataMessage);
} else if (content.nullMessage) { if (content.nullMessage)
return this.handleNullMessage(envelope, content.nullMessage); return this.handleNullMessage(envelope, content.nullMessage);
} else if (content.callMessage) { if (content.callMessage)
return this.handleCallMessage(envelope, content.callMessage); return this.handleCallMessage(envelope, content.callMessage);
} else if (content.receiptMessage) { if (content.receiptMessage)
return this.handleReceiptMessage(envelope, content.receiptMessage); return this.handleReceiptMessage(envelope, content.receiptMessage);
}
this.removeFromCache(envelope);
if (envelope.preKeyBundleMessage) return null;
throw new Error('Unsupported content message'); this.removeFromCache(envelope);
// TODO: The empty friend request response could get lost
// Need to trigger this event whenever a message is received in the pending state
conversation.onFriendRequestAccepted();
return null;
}, },
handleCallMessage(envelope) { handleCallMessage(envelope) {
window.log.info('call message from', this.getEnvelopeId(envelope)); window.log.info('call message from', this.getEnvelopeId(envelope));
@ -1240,43 +1231,6 @@ MessageReceiver.prototype.extend({
signature, signature,
}; };
}, },
async handlePreKeyBundleMessage(envelope) {
const preKeyBundleMessage = await this.decryptPreKeyBundleMessage(envelope);
// eslint-disable-next-line no-param-reassign
envelope.preKeyBundleMessage = preKeyBundleMessage;
await this.savePreKeyBundleMessage(
envelope.source,
preKeyBundleMessage
);
const conversation = await window.ConversationController.getOrCreateAndWait(
envelope.source,
'private'
);
if (preKeyBundleMessage.type === textsecure.protobuf.PreKeyBundleMessage.Type.FRIEND_REQUEST) {
conversation.onFriendRequestReceived();
} else if (preKeyBundleMessage.type === textsecure.protobuf.PreKeyBundleMessage.Type.FRIEND_REQUEST_ACCEPT) {
conversation.onFriendRequestAccepted();
} else {
window.log.warn('Unknown PreKeyBundleMessage Type')
}
if (envelope.content)
return this.handleContentMessage(envelope);
return null;
},
async decryptPreKeyBundleMessage(envelope) {
if (!envelope.preKeyBundleMessage) return null;
const address = new libsignal.SignalProtocolAddress(envelope.source, envelope.sourceDevice);
const fallBackSessionCipher = new libloki.FallBackSessionCipher(
address
);
const decryptedText =
await fallBackSessionCipher.decrypt(envelope.preKeyBundleMessage.toArrayBuffer());
const unpadded = await this.unpad(decryptedText);
const decodedProto = textsecure.protobuf.PreKeyBundleMessage.decode(unpadded);
const decodedBundle = this.decodePreKeyBundleMessage(decodedProto);
return decodedBundle;
},
async savePreKeyBundleMessage(pubKey, preKeyBundleMessage) { async savePreKeyBundleMessage(pubKey, preKeyBundleMessage) {
if (!preKeyBundleMessage) return null; if (!preKeyBundleMessage) return null;

@ -43,11 +43,11 @@ function OutgoingMessage(
this.failoverNumbers = []; this.failoverNumbers = [];
this.unidentifiedDeliveries = []; this.unidentifiedDeliveries = [];
const { numberInfo, senderCertificate, preKeyBundleType } = options; const { numberInfo, senderCertificate, messageType } = options;
this.numberInfo = numberInfo; this.numberInfo = numberInfo;
this.senderCertificate = senderCertificate; this.senderCertificate = senderCertificate;
this.preKeyBundleType = this.messageType =
preKeyBundleType || textsecure.protobuf.PreKeyBundleMessage.Type.UNKNOWN; messageType || 'outgoing';
} }
OutgoingMessage.prototype = { OutgoingMessage.prototype = {
@ -221,16 +221,12 @@ OutgoingMessage.prototype = {
return this.plaintext; return this.plaintext;
}, },
async wrapInWebsocketMessage(outgoingObject) { async wrapInWebsocketMessage(outgoingObject) {
const preKeyEnvelope = outgoingObject.preKeyBundleMessage ? {
preKeyBundleMessage: outgoingObject.preKeyBundleMessage,
} : {};
const messageEnvelope = new textsecure.protobuf.Envelope({ const messageEnvelope = new textsecure.protobuf.Envelope({
type: outgoingObject.type, type: outgoingObject.type,
source: outgoingObject.ourKey, source: outgoingObject.ourKey,
sourceDevice: outgoingObject.sourceDevice, sourceDevice: outgoingObject.sourceDevice,
timestamp: this.timestamp, timestamp: this.timestamp,
content: outgoingObject.content, content: outgoingObject.content,
...preKeyEnvelope,
}); });
const requestMessage = new textsecure.protobuf.WebSocketRequestMessage({ const requestMessage = new textsecure.protobuf.WebSocketRequestMessage({
id: new Uint8Array(libsignal.crypto.getRandomBytes(1))[0], // random ID for now id: new Uint8Array(libsignal.crypto.getRandomBytes(1))[0], // random ID for now
@ -248,7 +244,6 @@ OutgoingMessage.prototype = {
}, },
doSendMessage(number, deviceIds, recurse) { doSendMessage(number, deviceIds, recurse) {
const ciphers = {}; const ciphers = {};
const plaintext = this.getPlaintext();
/* Disabled because i'm not sure how senderCertificate works :thinking: /* Disabled because i'm not sure how senderCertificate works :thinking:
const { numberInfo, senderCertificate } = this; const { numberInfo, senderCertificate } = this;
@ -288,25 +283,11 @@ OutgoingMessage.prototype = {
const fallBackEncryption = new libloki.FallBackSessionCipher(address); const fallBackEncryption = new libloki.FallBackSessionCipher(address);
// Check if we need to attach the preKeys // Check if we need to attach the preKeys
let preKeys = {}; let sessionCipher;
if (this.attachPrekeys) { if (this.messageType === 'friend-request') {
// Encrypt them with the fallback // Encrypt them with the fallback
const preKeyBundleMessage = await libloki.getPreKeyBundleForNumber(number); this.message.preKeyBundleMessage = await libloki.getPreKeyBundleForNumber(number);
preKeyBundleMessage.type = this.preKeyBundleType;
const textBundle = this.convertMessageToText(preKeyBundleMessage);
const encryptedBundle = await fallBackEncryption.encrypt(textBundle);
preKeys = { preKeyBundleMessage: encryptedBundle.body };
window.log.info('attaching prekeys to outgoing message'); window.log.info('attaching prekeys to outgoing message');
}
// No limit on message keys if we're communicating with our other devices
if (ourKey === number) {
options.messageKeysLimit = false;
}
let sessionCipher;
if (this.fallBackEncryption) {
sessionCipher = fallBackEncryption; sessionCipher = fallBackEncryption;
} else { } else {
sessionCipher = new libsignal.SessionCipher( sessionCipher = new libsignal.SessionCipher(
@ -315,6 +296,13 @@ OutgoingMessage.prototype = {
options options
); );
} }
const plaintext = this.getPlaintext();
// No limit on message keys if we're communicating with our other devices
if (ourKey === number) {
options.messageKeysLimit = false;
}
ciphers[address.getDeviceId()] = sessionCipher; ciphers[address.getDeviceId()] = sessionCipher;
// Encrypt our plain text // Encrypt our plain text
@ -334,7 +322,6 @@ OutgoingMessage.prototype = {
sourceDevice: 1, sourceDevice: 1,
destinationRegistrationId: ciphertext.registrationId, destinationRegistrationId: ciphertext.registrationId,
content: ciphertext.body, content: ciphertext.body,
...preKeys,
}; };
}) })
) )
@ -344,10 +331,7 @@ OutgoingMessage.prototype = {
const socketMessage = await this.wrapInWebsocketMessage(outgoingObject); const socketMessage = await this.wrapInWebsocketMessage(outgoingObject);
let ttl; let ttl;
// TODO: Allow user to set ttl manually // TODO: Allow user to set ttl manually
if ( if (outgoingObject.type === textsecure.protobuf.Envelope.Type.FRIEND_REQUEST) {
outgoingObject.type ===
textsecure.protobuf.Envelope.Type.FALLBACK_CIPHERTEXT
) {
ttl = 4 * 24 * 60 * 60; // 4 days for friend request message ttl = 4 * 24 * 60 * 60; // 4 days for friend request message
} else { } else {
ttl = 24 * 60 * 60; // 1 day default for any other message ttl = 24 * 60 * 60; // 1 day default for any other message
@ -465,17 +449,9 @@ OutgoingMessage.prototype = {
return this.getStaleDeviceIdsForNumber(number).then(updateDevices => return this.getStaleDeviceIdsForNumber(number).then(updateDevices =>
this.getKeysForNumber(number, updateDevices) this.getKeysForNumber(number, updateDevices)
.then(async keysFound => { .then(async keysFound => {
this.attachPrekeys = false;
if (!keysFound) { if (!keysFound) {
log.info('Fallback encryption enabled'); log.info('Fallback encryption enabled');
this.fallBackEncryption = true; this.fallBackEncryption = true;
this.attachPrekeys = true;
} else if (conversation) {
try {
this.attachPrekeys = !conversation.isKeyExchangeCompleted();
} catch (e) {
// do nothing
}
} }
if (this.fallBackEncryption && conversation) { if (this.fallBackEncryption && conversation) {

@ -12,7 +12,7 @@ message Envelope {
PREKEY_BUNDLE = 3; //Used By Signal. DO NOT TOUCH! we don't use this at all. PREKEY_BUNDLE = 3; //Used By Signal. DO NOT TOUCH! we don't use this at all.
RECEIPT = 5; RECEIPT = 5;
UNIDENTIFIED_SENDER = 6; UNIDENTIFIED_SENDER = 6;
FALLBACK_CIPHERTEXT = 101; // contains prekeys + message and is using simple encryption FRIEND_REQUEST = 101; // contains prekeys + message and is using simple encryption
} }
optional Type type = 1; optional Type type = 1;
@ -24,7 +24,6 @@ message Envelope {
optional bytes content = 8; // Contains an encrypted Content optional bytes content = 8; // Contains an encrypted Content
optional string serverGuid = 9; optional string serverGuid = 9;
optional uint64 serverTimestamp = 10; optional uint64 serverTimestamp = 10;
optional bytes preKeyBundleMessage = 101;
} }
@ -34,16 +33,10 @@ message Content {
optional CallMessage callMessage = 3; optional CallMessage callMessage = 3;
optional NullMessage nullMessage = 4; optional NullMessage nullMessage = 4;
optional ReceiptMessage receiptMessage = 5; optional ReceiptMessage receiptMessage = 5;
optional PreKeyBundleMessage preKeyBundleMessage = 101;
} }
message PreKeyBundleMessage { message PreKeyBundleMessage {
enum Type {
UNKNOWN = 0;
FRIEND_REQUEST = 1;
FRIEND_REQUEST_ACCEPT = 2;
RESET_SESSION = 3;
RESET_SESSION_ACK = 4;
}
optional bytes identityKey = 1; optional bytes identityKey = 1;
optional uint32 deviceId = 2; optional uint32 deviceId = 2;
optional uint32 preKeyId = 3; optional uint32 preKeyId = 3;
@ -51,7 +44,6 @@ message PreKeyBundleMessage {
optional bytes preKey = 5; optional bytes preKey = 5;
optional bytes signedKey = 6; optional bytes signedKey = 6;
optional bytes signature = 7; optional bytes signature = 7;
optional Type type = 8;
} }
message CallMessage { message CallMessage {

Loading…
Cancel
Save