Add subscriber information to storage service account record.

This commit is contained in:
Alex Hart 2021-10-29 10:33:35 -03:00 committed by Greyson Parrelli
parent 102f9de06f
commit 6673da0b04
6 changed files with 123 additions and 26 deletions

View file

@ -14,6 +14,7 @@ import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.jobs.BoostReceiptRequestResponseJob
import org.thoughtcrime.securesms.jobs.SubscriptionReceiptRequestResponseJob
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.storage.StorageSyncHelper
import org.thoughtcrime.securesms.subscription.LevelUpdateOperation
import org.thoughtcrime.securesms.subscription.Subscriber
import org.thoughtcrime.securesms.util.Environment
@ -99,6 +100,8 @@ class DonationPaymentRepository(activity: Activity) : StripeApi.PaymentIntentFet
SignalStore
.donationsValues()
.setSubscriber(Subscriber(subscriberId, SignalStore.donationsValues().getSubscriptionCurrency().currencyCode))
StorageSyncHelper.scheduleSyncForDataChange()
}
}

View file

@ -7,6 +7,7 @@ import androidx.annotation.Nullable;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.subscription.Subscriber;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.storage.SignalAccountRecord;
import org.whispersystems.signalservice.api.storage.SignalAccountRecord.PinnedConversation;
@ -82,6 +83,14 @@ public class AccountRecordProcessor extends DefaultStorageRecordProcessor<Signal
payments = local.getPayments();
}
SignalAccountRecord.Subscriber subscriber;
if (remote.getSubscriber().getId().isPresent()) {
subscriber = remote.getSubscriber();
} else {
subscriber = local.getSubscriber();
}
byte[] unknownFields = remote.serializeUnknownFields();
String avatarUrlPath = remote.getAvatarUrlPath().or(local.getAvatarUrlPath()).or("");
byte[] profileKey = remote.getProfileKey().or(local.getProfileKey()).orNull();
@ -99,8 +108,8 @@ public class AccountRecordProcessor extends DefaultStorageRecordProcessor<Signal
boolean primarySendsSms = local.isPrimarySendsSms();
String e164 = local.getE164();
List<String> defaultReactions = remote.getDefaultReactions().size() > 0 ? remote.getDefaultReactions() : local.getDefaultReactions();
boolean matchesRemote = doParamsMatch(remote, unknownFields, givenName, familyName, avatarUrlPath, profileKey, noteToSelfArchived, noteToSelfForcedUnread, readReceipts, typingIndicators, sealedSenderIndicators, linkPreviews, phoneNumberSharingMode, unlisted, pinnedConversations, preferContactAvatars, payments, universalExpireTimer, primarySendsSms, e164, defaultReactions);
boolean matchesLocal = doParamsMatch(local, unknownFields, givenName, familyName, avatarUrlPath, profileKey, noteToSelfArchived, noteToSelfForcedUnread, readReceipts, typingIndicators, sealedSenderIndicators, linkPreviews, phoneNumberSharingMode, unlisted, pinnedConversations, preferContactAvatars, payments, universalExpireTimer, primarySendsSms, e164, defaultReactions);
boolean matchesRemote = doParamsMatch(remote, unknownFields, givenName, familyName, avatarUrlPath, profileKey, noteToSelfArchived, noteToSelfForcedUnread, readReceipts, typingIndicators, sealedSenderIndicators, linkPreviews, phoneNumberSharingMode, unlisted, pinnedConversations, preferContactAvatars, payments, universalExpireTimer, primarySendsSms, e164, defaultReactions, subscriber);
boolean matchesLocal = doParamsMatch(local, unknownFields, givenName, familyName, avatarUrlPath, profileKey, noteToSelfArchived, noteToSelfForcedUnread, readReceipts, typingIndicators, sealedSenderIndicators, linkPreviews, phoneNumberSharingMode, unlisted, pinnedConversations, preferContactAvatars, payments, universalExpireTimer, primarySendsSms, e164, defaultReactions, subscriber);
if (matchesRemote) {
return remote;
@ -129,6 +138,7 @@ public class AccountRecordProcessor extends DefaultStorageRecordProcessor<Signal
.setPrimarySendsSms(primarySendsSms)
.setE164(e164)
.setDefaultReactions(defaultReactions)
.setSubscriber(subscriber)
.build();
}
}
@ -168,27 +178,29 @@ public class AccountRecordProcessor extends DefaultStorageRecordProcessor<Signal
int universalExpireTimer,
boolean primarySendsSms,
String e164,
@NonNull List <String> defaultReactions)
@NonNull List <String> defaultReactions,
@NonNull SignalAccountRecord.Subscriber subscriber)
{
return Arrays.equals(contact.serializeUnknownFields(), unknownFields) &&
Objects.equals(contact.getGivenName().or(""), givenName) &&
Objects.equals(contact.getFamilyName().or(""), familyName) &&
Objects.equals(contact.getAvatarUrlPath().or(""), avatarUrlPath) &&
Objects.equals(contact.getPayments(), payments) &&
Objects.equals(contact.getE164(), e164) &&
Objects.equals(contact.getDefaultReactions(), defaultReactions) &&
Arrays.equals(contact.getProfileKey().orNull(), profileKey) &&
contact.isNoteToSelfArchived() == noteToSelfArchived &&
contact.isNoteToSelfForcedUnread() == noteToSelfForcedUnread &&
contact.isReadReceiptsEnabled() == readReceipts &&
contact.isTypingIndicatorsEnabled() == typingIndicators &&
contact.isSealedSenderIndicatorsEnabled() == sealedSenderIndicators &&
contact.isLinkPreviewsEnabled() == linkPreviewsEnabled &&
contact.getPhoneNumberSharingMode() == phoneNumberSharingMode &&
contact.isPhoneNumberUnlisted() == unlistedPhoneNumber &&
contact.isPreferContactAvatars() == preferContactAvatars &&
contact.getUniversalExpireTimer() == universalExpireTimer &&
contact.isPrimarySendsSms() == primarySendsSms &&
Objects.equals(contact.getPinnedConversations(), pinnedConversations);
return Arrays.equals(contact.serializeUnknownFields(), unknownFields) &&
Objects.equals(contact.getGivenName().or(""), givenName) &&
Objects.equals(contact.getFamilyName().or(""), familyName) &&
Objects.equals(contact.getAvatarUrlPath().or(""), avatarUrlPath) &&
Objects.equals(contact.getPayments(), payments) &&
Objects.equals(contact.getE164(), e164) &&
Objects.equals(contact.getDefaultReactions(), defaultReactions) &&
Arrays.equals(contact.getProfileKey().orNull(), profileKey) &&
contact.isNoteToSelfArchived() == noteToSelfArchived &&
contact.isNoteToSelfForcedUnread() == noteToSelfForcedUnread &&
contact.isReadReceiptsEnabled() == readReceipts &&
contact.isTypingIndicatorsEnabled() == typingIndicators &&
contact.isSealedSenderIndicatorsEnabled() == sealedSenderIndicators &&
contact.isLinkPreviewsEnabled() == linkPreviewsEnabled &&
contact.getPhoneNumberSharingMode() == phoneNumberSharingMode &&
contact.isPhoneNumberUnlisted() == unlistedPhoneNumber &&
contact.isPreferContactAvatars() == preferContactAvatars &&
contact.getUniversalExpireTimer() == universalExpireTimer &&
contact.isPrimarySendsSms() == primarySendsSms &&
Objects.equals(contact.getPinnedConversations(), pinnedConversations) &&
Objects.equals(contact.getSubscriber(), subscriber);
}
}

View file

@ -20,6 +20,7 @@ import org.thoughtcrime.securesms.keyvalue.PhoneNumberPrivacyValues;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.payments.Entropy;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.subscription.Subscriber;
import org.thoughtcrime.securesms.util.Base64;
import org.thoughtcrime.securesms.util.SetUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
@ -131,6 +132,7 @@ public final class StorageSyncHelper {
.setUniversalExpireTimer(SignalStore.settings().getUniversalExpireTimer())
.setE164(TextSecurePreferences.getLocalNumber(context))
.setDefaultReactions(SignalStore.emojiValues().getReactions())
.setSubscriber(StorageSyncModels.localToRemoteSubscriber(SignalStore.donationsValues().getSubscriber()))
.build();
return SignalStorageRecord.forAccount(account);
@ -155,6 +157,11 @@ public final class StorageSyncHelper {
SignalStore.settings().setUniversalExpireTimer(update.getNew().getUniversalExpireTimer());
SignalStore.emojiValues().setReactions(update.getNew().getDefaultReactions());
Subscriber subscriber = StorageSyncModels.remoteToLocalSubscriber(update.getNew().getSubscriber());
if (subscriber != null) {
SignalStore.donationsValues().setSubscriber(subscriber);
}
if (fetchProfile && update.getNew().getAvatarUrlPath().isPresent()) {
ApplicationDependencies.getJobManager().add(new RetrieveProfileAvatarJob(self, update.getNew().getAvatarUrlPath().get()));
}

View file

@ -1,6 +1,7 @@
package org.thoughtcrime.securesms.storage;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.annimon.stream.Stream;
@ -10,6 +11,7 @@ import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.database.RecipientDatabase.RecipientSettings;
import org.thoughtcrime.securesms.groups.GroupId;
import org.thoughtcrime.securesms.keyvalue.PhoneNumberPrivacyValues;
import org.thoughtcrime.securesms.subscription.Subscriber;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.storage.SignalAccountRecord;
@ -17,12 +19,11 @@ import org.whispersystems.signalservice.api.storage.SignalContactRecord;
import org.whispersystems.signalservice.api.storage.SignalGroupV1Record;
import org.whispersystems.signalservice.api.storage.SignalGroupV2Record;
import org.whispersystems.signalservice.api.storage.SignalStorageRecord;
import org.whispersystems.signalservice.api.util.UuidUtil;
import org.whispersystems.signalservice.api.subscriptions.SubscriberId;
import org.whispersystems.signalservice.internal.storage.protos.AccountRecord;
import org.whispersystems.signalservice.internal.storage.protos.ContactRecord.IdentityState;
import java.util.List;
import java.util.UUID;
public final class StorageSyncModels {
@ -173,4 +174,19 @@ public final class StorageSyncModels {
}
}
public static @NonNull SignalAccountRecord.Subscriber localToRemoteSubscriber(@Nullable Subscriber subscriber) {
if (subscriber == null) {
return new SignalAccountRecord.Subscriber(null, null);
} else {
return new SignalAccountRecord.Subscriber(subscriber.getCurrencyCode(), subscriber.getSubscriberId().getBytes());
}
}
public static @Nullable Subscriber remoteToLocalSubscriber(@NonNull SignalAccountRecord.Subscriber subscriber) {
if (subscriber.getId().isPresent()) {
return new Subscriber(SubscriberId.fromBytes(subscriber.getId().get()), subscriber.getCurrencyCode().get());
} else {
return null;
}
}
}

View file

@ -10,7 +10,6 @@ import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.util.OptionalUtil;
import org.whispersystems.signalservice.api.util.ProtoUtil;
import org.whispersystems.signalservice.api.util.UuidUtil;
import org.whispersystems.signalservice.internal.storage.protos.AccountRecord;
import java.util.ArrayList;
@ -34,6 +33,7 @@ public final class SignalAccountRecord implements SignalRecord {
private final List<PinnedConversation> pinnedConversations;
private final Payments payments;
private final List<String> defaultReactions;
private final Subscriber subscriber;
public SignalAccountRecord(StorageId id, AccountRecord proto) {
this.id = id;
@ -47,6 +47,7 @@ public final class SignalAccountRecord implements SignalRecord {
this.pinnedConversations = new ArrayList<>(proto.getPinnedConversationsCount());
this.payments = new Payments(proto.getPayments().getEnabled(), OptionalUtil.absentIfEmpty(proto.getPayments().getEntropy()));
this.defaultReactions = new ArrayList<>(proto.getPreferredReactionEmojiList());
this.subscriber = new Subscriber(proto.getSubscriberCurrencyCode(), proto.getSubscriberId().toByteArray());
for (AccountRecord.PinnedConversation conversation : proto.getPinnedConversationsList()) {
pinnedConversations.add(PinnedConversation.fromRemote(conversation));
@ -153,6 +154,10 @@ public final class SignalAccountRecord implements SignalRecord {
diff.add("UnknownFields");
}
if (!Objects.equals(this.getSubscriber(), that.getSubscriber())) {
diff.add("Subscriber");
}
return diff.toString();
} else {
return "Different class. " + getClass().getSimpleName() + " | " + other.getClass().getSimpleName();
@ -243,6 +248,10 @@ public final class SignalAccountRecord implements SignalRecord {
return defaultReactions;
}
public Subscriber getSubscriber() {
return subscriber;
}
AccountRecord toProto() {
return proto;
}
@ -351,6 +360,42 @@ public final class SignalAccountRecord implements SignalRecord {
}
}
public static class Subscriber {
private final Optional<String> currencyCode;
private final Optional<byte[]> id;
public Subscriber(String currencyCode, byte[] id) {
if (currencyCode != null && id != null && id.length == 32) {
this.currencyCode = Optional.of(currencyCode);
this.id = Optional.of(id);
} else {
this.currencyCode = Optional.absent();
this.id = Optional.absent();
}
}
public Optional<String> getCurrencyCode() {
return currencyCode;
}
public Optional<byte[]> getId() {
return id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final Subscriber that = (Subscriber) o;
return Objects.equals(currencyCode, that.currencyCode) && OptionalUtil.byteArrayEquals(id, that.id);
}
@Override
public int hashCode() {
return Objects.hash(currencyCode, id);
}
}
public static class Payments {
private static final String TAG = Payments.class.getSimpleName();
@ -518,6 +563,18 @@ public final class SignalAccountRecord implements SignalRecord {
return this;
}
public Builder setSubscriber(Subscriber subscriber) {
if (subscriber.id.isPresent() && subscriber.currencyCode.isPresent()) {
builder.setSubscriberId(ByteString.copyFrom(subscriber.id.get()));
builder.setSubscriberCurrencyCode(subscriber.currencyCode.get());
} else {
builder.clearSubscriberId();
builder.clearSubscriberCurrencyCode();
}
return this;
}
public SignalAccountRecord build() {
AccountRecord proto = builder.build();

View file

@ -148,4 +148,6 @@ message AccountRecord {
bool primarySendsSms = 18;
string e164 = 19;
repeated string preferredReactionEmoji = 20;
bytes subscriberId = 21;
string subscriberCurrencyCode = 22;
}