mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-20 16:49:40 +01:00
Generate request credential presentation before submitting subscription job.
This commit is contained in:
committed by
Greyson Parrelli
parent
a5c2595796
commit
a0d70a955a
@@ -20,7 +20,7 @@ import org.thoughtcrime.securesms.jobmanager.JobManager;
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.subscription.Subscriber;
|
||||
import org.thoughtcrime.securesms.subscription.DonorBadgeNotifications;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.signalservice.api.subscriptions.ActiveSubscription;
|
||||
import org.whispersystems.signalservice.api.subscriptions.SubscriberId;
|
||||
import org.whispersystems.signalservice.internal.ServiceResponse;
|
||||
@@ -45,10 +45,9 @@ public class SubscriptionReceiptRequestResponseJob extends BaseJob {
|
||||
|
||||
public static final Object MUTEX = new Object();
|
||||
|
||||
private ReceiptCredentialRequestContext requestContext;
|
||||
|
||||
private final SubscriberId subscriberId;
|
||||
private final boolean isForKeepAlive;
|
||||
private final ReceiptCredentialRequestContext requestContext;
|
||||
private final SubscriberId subscriberId;
|
||||
private final boolean isForKeepAlive;
|
||||
|
||||
private static SubscriptionReceiptRequestResponseJob createJob(SubscriberId subscriberId, boolean isForKeepAlive) {
|
||||
return new SubscriptionReceiptRequestResponseJob(
|
||||
@@ -60,12 +59,28 @@ public class SubscriptionReceiptRequestResponseJob extends BaseJob {
|
||||
.setLifespan(TimeUnit.DAYS.toMillis(1))
|
||||
.setMaxAttempts(Parameters.UNLIMITED)
|
||||
.build(),
|
||||
null,
|
||||
generateRequestContext(),
|
||||
subscriberId,
|
||||
isForKeepAlive
|
||||
);
|
||||
}
|
||||
|
||||
private static ReceiptCredentialRequestContext generateRequestContext() {
|
||||
Log.d(TAG, "Generating request credentials context for token redemption...", true);
|
||||
SecureRandom secureRandom = new SecureRandom();
|
||||
byte[] randomBytes = Util.getSecretBytes(ReceiptSerial.SIZE);
|
||||
|
||||
try {
|
||||
ReceiptSerial receiptSerial = new ReceiptSerial(randomBytes);
|
||||
ClientZkReceiptOperations operations = ApplicationDependencies.getClientZkReceiptOperations();
|
||||
|
||||
return operations.createReceiptCredentialRequestContext(secureRandom, receiptSerial);
|
||||
} catch (InvalidInputException | VerificationFailedException e) {
|
||||
Log.e(TAG, "Failed to create credential.", e);
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static JobManager.Chain createSubscriptionContinuationJobChain() {
|
||||
return createSubscriptionContinuationJobChain(false);
|
||||
}
|
||||
@@ -83,7 +98,7 @@ public class SubscriptionReceiptRequestResponseJob extends BaseJob {
|
||||
}
|
||||
|
||||
private SubscriptionReceiptRequestResponseJob(@NonNull Parameters parameters,
|
||||
@Nullable ReceiptCredentialRequestContext requestContext,
|
||||
@NonNull ReceiptCredentialRequestContext requestContext,
|
||||
@NonNull SubscriberId subscriberId,
|
||||
boolean isForKeepAlive)
|
||||
{
|
||||
@@ -96,11 +111,8 @@ public class SubscriptionReceiptRequestResponseJob extends BaseJob {
|
||||
@Override
|
||||
public @NonNull Data serialize() {
|
||||
Data.Builder builder = new Data.Builder().putBlobAsString(DATA_SUBSCRIBER_ID, subscriberId.getBytes())
|
||||
.putBoolean(DATA_IS_FOR_KEEP_ALIVE, isForKeepAlive);
|
||||
|
||||
if (requestContext != null) {
|
||||
builder.putBlobAsString(DATA_REQUEST_BYTES, requestContext.serialize());
|
||||
}
|
||||
.putBoolean(DATA_IS_FOR_KEEP_ALIVE, isForKeepAlive)
|
||||
.putBlobAsString(DATA_REQUEST_BYTES, requestContext.serialize());
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
@@ -139,21 +151,6 @@ public class SubscriptionReceiptRequestResponseJob extends BaseJob {
|
||||
MultiDeviceSubscriptionSyncRequestJob.enqueue();
|
||||
}
|
||||
|
||||
if (requestContext == null) {
|
||||
Log.d(TAG, "Generating request credentials context for token redemption...", true);
|
||||
SecureRandom secureRandom = new SecureRandom();
|
||||
byte[] randomBytes = new byte[ReceiptSerial.SIZE];
|
||||
|
||||
secureRandom.nextBytes(randomBytes);
|
||||
|
||||
ReceiptSerial receiptSerial = new ReceiptSerial(randomBytes);
|
||||
ClientZkReceiptOperations operations = ApplicationDependencies.getClientZkReceiptOperations();
|
||||
|
||||
requestContext = operations.createReceiptCredentialRequestContext(secureRandom, receiptSerial);
|
||||
} else {
|
||||
Log.d(TAG, "Already have credentials generated for this request. Retrying web service call...", true);
|
||||
}
|
||||
|
||||
Log.d(TAG, "Submitting receipt credential request.");
|
||||
ServiceResponse<ReceiptCredentialResponse> response = ApplicationDependencies.getDonationsService()
|
||||
.submitReceiptCredentialRequest(subscriberId, requestContext.getRequest())
|
||||
@@ -201,7 +198,6 @@ public class SubscriptionReceiptRequestResponseJob extends BaseJob {
|
||||
return operations.createReceiptCredentialPresentation(receiptCredential);
|
||||
} catch (VerificationFailedException e) {
|
||||
Log.w(TAG, "getReceiptCredentialPresentation: encountered a verification failure in zk", e, true);
|
||||
requestContext = null;
|
||||
throw new RetryableException();
|
||||
}
|
||||
}
|
||||
@@ -213,7 +209,6 @@ public class SubscriptionReceiptRequestResponseJob extends BaseJob {
|
||||
return operations.receiveReceiptCredential(requestContext, response);
|
||||
} catch (VerificationFailedException e) {
|
||||
Log.w(TAG, "getReceiptCredential: encountered a verification failure in zk", e, true);
|
||||
requestContext = null;
|
||||
throw new RetryableException();
|
||||
}
|
||||
}
|
||||
@@ -269,7 +264,7 @@ public class SubscriptionReceiptRequestResponseJob extends BaseJob {
|
||||
* - expiration_time mod 86400 == 0
|
||||
* - expiration_time is between now and 60 days from now
|
||||
*/
|
||||
private boolean isCredentialValid(@NonNull ActiveSubscription.Subscription subscription, @NonNull ReceiptCredential receiptCredential) {
|
||||
private static boolean isCredentialValid(@NonNull ActiveSubscription.Subscription subscription, @NonNull ReceiptCredential receiptCredential) {
|
||||
long now = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis());
|
||||
long maxExpirationTime = now + TimeUnit.DAYS.toSeconds(60);
|
||||
boolean isSameLevel = subscription.getLevel() == receiptCredential.getReceiptLevel();
|
||||
@@ -292,28 +287,30 @@ public class SubscriptionReceiptRequestResponseJob extends BaseJob {
|
||||
return e instanceof RetryableException;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
final static class RetryableException extends Exception {
|
||||
@VisibleForTesting final static class RetryableException extends Exception {
|
||||
}
|
||||
|
||||
public static class Factory implements Job.Factory<SubscriptionReceiptRequestResponseJob> {
|
||||
@Override
|
||||
public @NonNull SubscriptionReceiptRequestResponseJob create(@NonNull Parameters parameters, @NonNull Data data) {
|
||||
SubscriberId subscriberId = SubscriberId.fromBytes(data.getStringAsBlob(DATA_SUBSCRIBER_ID));
|
||||
boolean isForKeepAlive = data.getBooleanOrDefault(DATA_IS_FOR_KEEP_ALIVE, false);
|
||||
SubscriberId subscriberId = SubscriberId.fromBytes(data.getStringAsBlob(DATA_SUBSCRIBER_ID));
|
||||
boolean isForKeepAlive = data.getBooleanOrDefault(DATA_IS_FOR_KEEP_ALIVE, false);
|
||||
byte[] requestContextBytes = data.getStringAsBlob(DATA_REQUEST_BYTES);
|
||||
|
||||
try {
|
||||
if (data.hasString(DATA_REQUEST_BYTES)) {
|
||||
byte[] blob = data.getStringAsBlob(DATA_REQUEST_BYTES);
|
||||
ReceiptCredentialRequestContext requestContext = new ReceiptCredentialRequestContext(blob);
|
||||
|
||||
return new SubscriptionReceiptRequestResponseJob(parameters, requestContext, subscriberId, isForKeepAlive);
|
||||
} else {
|
||||
return new SubscriptionReceiptRequestResponseJob(parameters, null, subscriberId, isForKeepAlive);
|
||||
ReceiptCredentialRequestContext requestContext;
|
||||
if (requestContextBytes == null) {
|
||||
Log.i(TAG, "Generating a request context for a legacy instance of SubscriptionReceiptRequestResponseJob", true);
|
||||
requestContext = generateRequestContext();
|
||||
} else {
|
||||
try {
|
||||
requestContext = new ReceiptCredentialRequestContext(requestContextBytes);
|
||||
} catch (InvalidInputException e) {
|
||||
Log.e(TAG, "Failed to generate request context from bytes", e);
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
} catch (InvalidInputException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
|
||||
return new SubscriptionReceiptRequestResponseJob(parameters, requestContext, subscriberId, isForKeepAlive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user