Support for Contact Discovery Service

This commit is contained in:
Ken Powers 2020-09-03 21:25:19 -04:00 committed by Scott Nonnenberg
parent f6dcf91dbf
commit 8290881bd8
21 changed files with 961 additions and 79 deletions

View file

@ -230,10 +230,14 @@
});
let messageReceiver;
let preMessageReceiverStatus;
window.getSocketStatus = () => {
if (messageReceiver) {
return messageReceiver.getStatus();
}
if (_.isNumber(preMessageReceiverStatus)) {
return preMessageReceiverStatus;
}
return -1;
};
Whisper.events = _.clone(Backbone.Events);
@ -1633,6 +1637,8 @@
return;
}
preMessageReceiverStatus = WebSocket.CONNECTING;
if (messageReceiver) {
await messageReceiver.stopProcessing();
@ -1647,6 +1653,52 @@
const PASSWORD = storage.get('password');
const mySignalingKey = storage.get('signaling_key');
window.textsecure.messaging = new textsecure.MessageSender(
USERNAME || OLD_USERNAME,
PASSWORD
);
try {
if (connectCount === 0) {
const lonelyE164s = window
.getConversations()
.filter(
c =>
c.isPrivate() &&
c.get('e164') &&
!c.get('uuid') &&
!c.isEverUnregistered()
)
.map(c => c.get('e164'));
if (lonelyE164s.length > 0) {
const lookup = await textsecure.messaging.getUuidsForE164s(
lonelyE164s
);
const e164s = Object.keys(lookup);
e164s.forEach(e164 => {
const uuid = lookup[e164];
if (!uuid) {
const byE164 = window.ConversationController.get(e164);
if (byE164) {
byE164.setUnregistered();
}
}
window.ConversationController.ensureContactIds({
e164,
uuid,
highTrust: true,
});
});
}
}
} catch (error) {
window.log.error(
'Error fetching UUIDs for lonely e164s:',
error && error.stack ? error.stack : error
);
}
connectCount += 1;
const options = {
retryCached: connectCount === 1,
@ -1667,6 +1719,8 @@
);
window.textsecure.messageReceiver = messageReceiver;
preMessageReceiverStatus = null;
function addQueuedEventListener(name, handler) {
messageReceiver.addEventListener(name, (...args) =>
eventHandlerQueue.add(async () => {
@ -1709,11 +1763,6 @@
logger: window.log,
});
window.textsecure.messaging = new textsecure.MessageSender(
USERNAME || OLD_USERNAME,
PASSWORD
);
if (connectCount === 1) {
window.Signal.Stickers.downloadQueuedPacks();
await window.textsecure.messaging.sendRequestKeySyncMessage();

View file

@ -184,6 +184,39 @@
);
},
isEverUnregistered() {
return Boolean(this.get('discoveredUnregisteredAt'));
},
isUnregistered() {
const now = Date.now();
const sixHoursAgo = now - 1000 * 60 * 60 * 6;
const discoveredUnregisteredAt = this.get('discoveredUnregisteredAt');
if (discoveredUnregisteredAt && discoveredUnregisteredAt > sixHoursAgo) {
return true;
}
return false;
},
setUnregistered() {
window.log.info(
`Conversation ${this.idForLogging()} is now unregistered`
);
this.set({
discoveredUnregisteredAt: Date.now(),
});
window.Signal.Data.updateConversation(this.attributes);
},
setRegistered() {
window.log.info(
`Conversation ${this.idForLogging()} is registered once again`
);
this.set({
discoveredUnregisteredAt: undefined,
});
window.Signal.Data.updateConversation(this.attributes);
},
isBlocked() {
const uuid = this.get('uuid');
if (uuid) {
@ -1258,6 +1291,11 @@
if (c.id === me) {
return null;
}
// We don't want to even attempt a send if we have recently discovered that they
// are unregistered.
if (c.isUnregistered()) {
return null;
}
return c.getSendTarget();
})
);
@ -1422,7 +1460,7 @@
});
Whisper.Reactions.onReaction(reactionModel);
const destination = this.get('e164');
const destination = this.getSendTarget();
const recipients = this.getRecipients();
let profileKey;
@ -1717,7 +1755,8 @@
if (result) {
await this.handleMessageSendResult(
result.failoverIdentifiers,
result.unidentifiedDeliveries
result.unidentifiedDeliveries,
result.discoveredIdentifierPairs
);
}
return result;
@ -1727,7 +1766,8 @@
if (result) {
await this.handleMessageSendResult(
result.failoverIdentifiers,
result.unidentifiedDeliveries
result.unidentifiedDeliveries,
result.discoveredIdentifierPairs
);
}
throw result;
@ -1735,7 +1775,20 @@
);
},
async handleMessageSendResult(failoverIdentifiers, unidentifiedDeliveries) {
async handleMessageSendResult(
failoverIdentifiers,
unidentifiedDeliveries,
discoveredIdentifierPairs
) {
discoveredIdentifierPairs.forEach(item => {
const { uuid, e164 } = item;
window.ConversationController.ensureContactIds({
uuid,
e164,
highTrust: true,
});
});
await Promise.all(
(failoverIdentifiers || []).map(async identifier => {
const conversation = ConversationController.get(identifier);

View file

@ -1716,6 +1716,14 @@
let promises = [];
// If we successfully sent to a user, we can remove our unregistered flag.
result.successfulIdentifiers.forEach(identifier => {
const c = ConversationController.get(identifier);
if (c && c.isEverUnregistered()) {
c.setRegistered();
}
});
if (result instanceof Error) {
this.saveErrors(result);
if (result.name === 'SignedPreKeyRotationError') {
@ -1728,6 +1736,24 @@
if (result.successfulIdentifiers.length > 0) {
const sentTo = this.get('sent_to') || [];
// If we just found out that we couldn't send to a user because they are no
// longer registered, we will update our unregistered flag. In groups we
// will not event try to send to them for 6 hours. And we will never try
// to fetch them on startup again.
// The way to discover registration once more is:
// 1) any attempt to send to them in 1:1 conversation
// 2) the six-hour time period has passed and we send in a group again
const unregisteredUserErrors = _.filter(
result.errors,
error => error.name === 'UnregisteredUserError'
);
unregisteredUserErrors.forEach(error => {
const c = ConversationController.get(error.identifier);
if (c) {
c.setUnregistered();
}
});
// In groups, we don't treat unregistered users as a user-visible
// error. The message will look successful, but the details
// screen will show that we didn't send to these unregistered users.

View file

@ -157,7 +157,9 @@
this.onEmpty();
break;
default:
// We also replicate empty here
window.log.warn(
'startConnectionListener: Found unexpected socket status; calling onEmpty() manually.'
);
this.onEmpty();
break;
}