That fuck shit the fascists are using
at master 301 lines 14 kB view raw
1package org.tm.archive.util; 2 3import android.content.Context; 4 5import androidx.annotation.NonNull; 6import androidx.annotation.Nullable; 7import androidx.annotation.StringRes; 8 9import org.signal.core.util.concurrent.ListenableFuture; 10import org.signal.core.util.concurrent.SettableFuture; 11import org.signal.core.util.concurrent.SignalExecutors; 12import org.signal.core.util.concurrent.SimpleTask; 13import org.signal.core.util.logging.Log; 14import org.signal.libsignal.protocol.IdentityKey; 15import org.signal.libsignal.protocol.InvalidKeyException; 16import org.signal.libsignal.protocol.SignalProtocolAddress; 17import org.signal.libsignal.protocol.state.SessionRecord; 18import org.signal.libsignal.protocol.state.SessionStore; 19import org.tm.archive.R; 20import org.tm.archive.crypto.ReentrantSessionLock; 21import org.tm.archive.crypto.storage.SignalIdentityKeyStore; 22import org.tm.archive.database.GroupTable; 23import org.tm.archive.database.IdentityTable; 24import org.tm.archive.database.MessageTable; 25import org.tm.archive.database.MessageTable.InsertResult; 26import org.tm.archive.database.SignalDatabase; 27import org.tm.archive.database.model.GroupRecord; 28import org.tm.archive.database.model.IdentityRecord; 29import org.tm.archive.dependencies.ApplicationDependencies; 30import org.tm.archive.mms.IncomingMessage; 31import org.tm.archive.mms.MmsException; 32import org.tm.archive.mms.OutgoingMessage; 33import org.tm.archive.notifications.v2.ConversationId; 34import org.tm.archive.recipients.Recipient; 35import org.tm.archive.recipients.RecipientId; 36import org.whispersystems.signalservice.api.SignalSessionLock; 37import org.whispersystems.signalservice.api.messages.multidevice.VerifiedMessage; 38import org.whispersystems.signalservice.api.push.ServiceId; 39import org.whispersystems.signalservice.api.push.SignalServiceAddress; 40import org.whispersystems.signalservice.internal.push.Verified; 41 42import java.util.List; 43import java.util.Optional; 44 45public final class IdentityUtil { 46 47 private IdentityUtil() {} 48 49 private static final String TAG = Log.tag(IdentityUtil.class); 50 51 public static ListenableFuture<Optional<IdentityRecord>> getRemoteIdentityKey(final Context context, final Recipient recipient) { 52 final SettableFuture<Optional<IdentityRecord>> future = new SettableFuture<>(); 53 final RecipientId recipientId = recipient.getId(); 54 55 SimpleTask.run(SignalExecutors.BOUNDED, 56 () -> ApplicationDependencies.getProtocolStore().aci().identities().getIdentityRecord(recipientId), 57 future::set); 58 59 return future; 60 } 61 62 public static void markIdentityVerified(Context context, Recipient recipient, boolean verified, boolean remote) 63 { 64 long time = System.currentTimeMillis(); 65 MessageTable smsDatabase = SignalDatabase.messages(); 66 GroupTable groupDatabase = SignalDatabase.groups(); 67 68 try (GroupTable.Reader reader = groupDatabase.getGroups()) { 69 70 GroupRecord groupRecord; 71 72 while ((groupRecord = reader.getNext()) != null) { 73 if (groupRecord.getMembers().contains(recipient.getId()) && groupRecord.isActive() && !groupRecord.isMms()) { 74 75 if (remote) { 76 IncomingMessage incoming = verified ? IncomingMessage.identityVerified(recipient.getId(), time, groupRecord.getId()) 77 : IncomingMessage.identityDefault(recipient.getId(), time, groupRecord.getId()); 78 79 try { 80 smsDatabase.insertMessageInbox(incoming); 81 } catch (MmsException e) { 82 throw new AssertionError(e); 83 } 84 } else { 85 RecipientId recipientId = SignalDatabase.recipients().getOrInsertFromGroupId(groupRecord.getId()); 86 Recipient groupRecipient = Recipient.resolved(recipientId); 87 long threadId = SignalDatabase.threads().getOrCreateThreadIdFor(groupRecipient); 88 89 OutgoingMessage outgoing; 90 if (verified) { 91 outgoing = OutgoingMessage.identityVerifiedMessage(recipient, time); 92 } else { 93 outgoing = OutgoingMessage.identityDefaultMessage(recipient, time); 94 } 95 96 try { 97 SignalDatabase.messages().insertMessageOutbox(outgoing, threadId, false, null); 98 } catch (MmsException e) { 99 throw new AssertionError(e); 100 } 101 SignalDatabase.threads().update(threadId, true); 102 } 103 } 104 } 105 } 106 107 if (remote) { 108 IncomingMessage incoming = verified ? IncomingMessage.identityVerified(recipient.getId(), time, null) 109 : IncomingMessage.identityDefault(recipient.getId(), time, null); 110 111 try { 112 smsDatabase.insertMessageInbox(incoming); 113 } catch (MmsException e) { 114 throw new AssertionError(e); 115 } 116 } else { 117 OutgoingMessage outgoing; 118 if (verified) { 119 outgoing = OutgoingMessage.identityVerifiedMessage(recipient, time); 120 } else { 121 outgoing = OutgoingMessage.identityDefaultMessage(recipient, time); 122 } 123 124 long threadId = SignalDatabase.threads().getOrCreateThreadIdFor(recipient); 125 126 Log.i(TAG, "Inserting verified outbox..."); 127 try { 128 SignalDatabase.messages().insertMessageOutbox(outgoing, threadId, false, null); 129 } catch (MmsException e) { 130 throw new AssertionError(); 131 } 132 SignalDatabase.threads().update(threadId, true); 133 } 134 } 135 136 public static void markIdentityUpdate(@NonNull Context context, @NonNull RecipientId recipientId) { 137 Log.w(TAG, "Inserting safety number change event(s) for " + recipientId, new Throwable()); 138 139 long time = System.currentTimeMillis(); 140 MessageTable smsDatabase = SignalDatabase.messages(); 141 GroupTable groupDatabase = SignalDatabase.groups(); 142 143 try (GroupTable.Reader reader = groupDatabase.getGroups()) { 144 GroupRecord groupRecord; 145 146 while ((groupRecord = reader.getNext()) != null) { 147 if (groupRecord.getMembers().contains(recipientId) && groupRecord.isActive()) { 148 IncomingMessage groupUpdate = IncomingMessage.identityUpdate(recipientId, time, groupRecord.getId()); 149 smsDatabase.insertMessageInbox(groupUpdate); 150 } 151 } 152 } catch (MmsException e) { 153 throw new AssertionError(e); 154 } 155 156 try { 157 IncomingMessage individualUpdate = IncomingMessage.identityUpdate(recipientId, time, null); 158 Optional<InsertResult> insertResult = smsDatabase.insertMessageInbox(individualUpdate); 159 160 if (insertResult.isPresent()) { 161 ApplicationDependencies.getMessageNotifier().updateNotification(context, ConversationId.forConversation(insertResult.get().getThreadId())); 162 } 163 } catch (MmsException e) { 164 throw new AssertionError(e); 165 } 166 167 SignalDatabase.messageLog().deleteAllForRecipient(recipientId); 168 } 169 170 public static void saveIdentity(String user, IdentityKey identityKey) { 171 try(SignalSessionLock.Lock unused = ReentrantSessionLock.INSTANCE.acquire()) { 172 SessionStore sessionStore = ApplicationDependencies.getProtocolStore().aci(); 173 SignalProtocolAddress address = new SignalProtocolAddress(user, SignalServiceAddress.DEFAULT_DEVICE_ID); 174 175 if (ApplicationDependencies.getProtocolStore().aci().identities().saveIdentity(address, identityKey)) { 176 if (sessionStore.containsSession(address)) { 177 SessionRecord sessionRecord = sessionStore.loadSession(address); 178 sessionRecord.archiveCurrentState(); 179 180 sessionStore.storeSession(address, sessionRecord); 181 } 182 } 183 } 184 } 185 186 public static void processVerifiedMessage(Context context, Verified verified) throws InvalidKeyException { 187 SignalServiceAddress destination = new SignalServiceAddress(ServiceId.parseOrThrow(verified.destinationAci)); 188 IdentityKey identityKey = new IdentityKey(verified.identityKey.toByteArray(), 0); 189 VerifiedMessage.VerifiedState state; 190 191 switch (verified.state) { 192 case DEFAULT: 193 state = VerifiedMessage.VerifiedState.DEFAULT; 194 break; 195 case VERIFIED: 196 state = VerifiedMessage.VerifiedState.VERIFIED; 197 break; 198 case UNVERIFIED: 199 state = VerifiedMessage.VerifiedState.UNVERIFIED; 200 break; 201 default: 202 throw new IllegalArgumentException(); 203 } 204 205 processVerifiedMessage(context, new VerifiedMessage(destination, identityKey, state, System.currentTimeMillis())); 206 } 207 208 public static void processVerifiedMessage(Context context, VerifiedMessage verifiedMessage) { 209 try(SignalSessionLock.Lock unused = ReentrantSessionLock.INSTANCE.acquire()) { 210 SignalIdentityKeyStore identityStore = ApplicationDependencies.getProtocolStore().aci().identities(); 211 Recipient recipient = Recipient.externalPush(verifiedMessage.getDestination()); 212 213 if (recipient.isSelf()) { 214 Log.w(TAG, "Attempting to change verified status of self to " + verifiedMessage.getVerified() + ", skipping."); 215 return; 216 } 217 218 Optional<IdentityRecord> identityRecord = identityStore.getIdentityRecord(recipient.getId()); 219 220 if (!identityRecord.isPresent() && verifiedMessage.getVerified() == VerifiedMessage.VerifiedState.DEFAULT) { 221 Log.w(TAG, "No existing record for default status"); 222 return; 223 } 224 225 if (verifiedMessage.getVerified() == VerifiedMessage.VerifiedState.DEFAULT && 226 identityRecord.isPresent() && 227 identityRecord.get().getIdentityKey().equals(verifiedMessage.getIdentityKey()) && 228 identityRecord.get().getVerifiedStatus() != IdentityTable.VerifiedStatus.DEFAULT) 229 { 230 Log.i(TAG, "Setting " + recipient.getId() + " verified status to " + IdentityTable.VerifiedStatus.DEFAULT); 231 identityStore.setVerified(recipient.getId(), identityRecord.get().getIdentityKey(), IdentityTable.VerifiedStatus.DEFAULT); 232 markIdentityVerified(context, recipient, false, true); 233 } 234 235 if (verifiedMessage.getVerified() == VerifiedMessage.VerifiedState.VERIFIED && 236 (!identityRecord.isPresent() || 237 (identityRecord.isPresent() && !identityRecord.get().getIdentityKey().equals(verifiedMessage.getIdentityKey())) || 238 (identityRecord.isPresent() && identityRecord.get().getVerifiedStatus() != IdentityTable.VerifiedStatus.VERIFIED))) 239 { 240 Log.i(TAG, "Setting " + recipient.getId() + " verified status to " + IdentityTable.VerifiedStatus.VERIFIED); 241 saveIdentity(verifiedMessage.getDestination().getIdentifier(), verifiedMessage.getIdentityKey()); 242 identityStore.setVerified(recipient.getId(), verifiedMessage.getIdentityKey(), IdentityTable.VerifiedStatus.VERIFIED); 243 markIdentityVerified(context, recipient, true, true); 244 } 245 } 246 } 247 248 249 public static @Nullable String getUnverifiedBannerDescription(@NonNull Context context, 250 @NonNull List<Recipient> unverified) 251 { 252 return getPluralizedIdentityDescription(context, unverified, 253 R.string.IdentityUtil_unverified_banner_one, 254 R.string.IdentityUtil_unverified_banner_two, 255 R.string.IdentityUtil_unverified_banner_many); 256 } 257 258 public static @Nullable String getUnverifiedSendDialogDescription(@NonNull Context context, 259 @NonNull List<Recipient> unverified) 260 { 261 return getPluralizedIdentityDescription(context, unverified, 262 R.string.IdentityUtil_unverified_dialog_one, 263 R.string.IdentityUtil_unverified_dialog_two, 264 R.string.IdentityUtil_unverified_dialog_many); 265 } 266 267 public static @Nullable String getUntrustedSendDialogDescription(@NonNull Context context, 268 @NonNull List<Recipient> untrusted) 269 { 270 return getPluralizedIdentityDescription(context, untrusted, 271 R.string.IdentityUtil_untrusted_dialog_one, 272 R.string.IdentityUtil_untrusted_dialog_two, 273 R.string.IdentityUtil_untrusted_dialog_many); 274 } 275 276 private static @Nullable String getPluralizedIdentityDescription(@NonNull Context context, 277 @NonNull List<Recipient> recipients, 278 @StringRes int resourceOne, 279 @StringRes int resourceTwo, 280 @StringRes int resourceMany) 281 { 282 if (recipients.isEmpty()) return null; 283 284 if (recipients.size() == 1) { 285 String name = recipients.get(0).getDisplayName(context); 286 return context.getString(resourceOne, name); 287 } else { 288 String firstName = recipients.get(0).getDisplayName(context); 289 String secondName = recipients.get(1).getDisplayName(context); 290 291 if (recipients.size() == 2) { 292 return context.getString(resourceTwo, firstName, secondName); 293 } else { 294 int othersCount = recipients.size() - 2; 295 String nMore = context.getResources().getQuantityString(R.plurals.identity_others, othersCount, othersCount); 296 297 return context.getString(resourceMany, firstName, secondName, nMore); 298 } 299 } 300 } 301}