Combine username confirmation and link creation into a single operation.
This commit is contained in:
parent
459c5c0a55
commit
54012cb33a
5 changed files with 45 additions and 39 deletions
|
@ -131,12 +131,7 @@ object UsernameRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates or rotates the username link for the local user. If successful, the [UsernameLinkComponents] will be returned.
|
* Creates or rotates the username link for the local user.
|
||||||
* If it fails for any reason, the optional will be empty.
|
|
||||||
*
|
|
||||||
* The assumption here is that when the user clicks this button, they will either have a new link, or no link at all.
|
|
||||||
* This is to prevent indeterminate states where the network call fails but may have actually succeeded, that kind of thing.
|
|
||||||
* As such, it's recommended to block calling this method on a network check.
|
|
||||||
*/
|
*/
|
||||||
fun createOrResetUsernameLink(): Single<UsernameLinkResetResult> {
|
fun createOrResetUsernameLink(): Single<UsernameLinkResetResult> {
|
||||||
if (!NetworkUtil.isConnected(ApplicationDependencies.getApplication())) {
|
if (!NetworkUtil.isConnected(ApplicationDependencies.getApplication())) {
|
||||||
|
@ -376,9 +371,10 @@ object UsernameRepository {
|
||||||
Log.i(TAG, "[confirmUsernameAndCreateNewLink] Beginning username confirmation...")
|
Log.i(TAG, "[confirmUsernameAndCreateNewLink] Beginning username confirmation...")
|
||||||
|
|
||||||
return try {
|
return try {
|
||||||
accountManager.confirmUsername(username)
|
val linkComponents: UsernameLinkComponents = accountManager.confirmUsernameAndCreateNewLink(username)
|
||||||
|
|
||||||
SignalStore.account().username = username.username
|
SignalStore.account().username = username.username
|
||||||
SignalStore.account().usernameLink = null
|
SignalStore.account().usernameLink = linkComponents
|
||||||
SignalDatabase.recipients.setUsername(Recipient.self().id, username.username)
|
SignalDatabase.recipients.setUsername(Recipient.self().id, username.username)
|
||||||
SignalStore.account().usernameSyncState = AccountValues.UsernameSyncState.IN_SYNC
|
SignalStore.account().usernameSyncState = AccountValues.UsernameSyncState.IN_SYNC
|
||||||
SignalStore.account().usernameSyncErrorCount = 0
|
SignalStore.account().usernameSyncErrorCount = 0
|
||||||
|
@ -387,12 +383,6 @@ object UsernameRepository {
|
||||||
StorageSyncHelper.scheduleSyncForDataChange()
|
StorageSyncHelper.scheduleSyncForDataChange()
|
||||||
Log.i(TAG, "[confirmUsernameAndCreateNewLink] Successfully confirmed username.")
|
Log.i(TAG, "[confirmUsernameAndCreateNewLink] Successfully confirmed username.")
|
||||||
|
|
||||||
if (tryToSetUsernameLink(username)) {
|
|
||||||
Log.i(TAG, "[confirmUsernameAndCreateNewLink] Successfully confirmed username link.")
|
|
||||||
} else {
|
|
||||||
Log.w(TAG, "[confirmUsernameAndCreateNewLink] Failed to confirm a username link. We'll try again when the user goes to view their link.")
|
|
||||||
}
|
|
||||||
|
|
||||||
UsernameSetResult.SUCCESS
|
UsernameSetResult.SUCCESS
|
||||||
} catch (e: UsernameTakenException) {
|
} catch (e: UsernameTakenException) {
|
||||||
Log.w(TAG, "[confirmUsernameAndCreateNewLink] Username gone.")
|
Log.w(TAG, "[confirmUsernameAndCreateNewLink] Username gone.")
|
||||||
|
@ -409,23 +399,6 @@ object UsernameRepository {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun tryToSetUsernameLink(username: Username): Boolean {
|
|
||||||
for (i in 0..2) {
|
|
||||||
try {
|
|
||||||
val linkComponents = accountManager.createUsernameLink(username)
|
|
||||||
SignalStore.account().usernameLink = linkComponents
|
|
||||||
|
|
||||||
SignalDatabase.recipients.markNeedsSync(Recipient.self().id)
|
|
||||||
StorageSyncHelper.scheduleSyncForDataChange()
|
|
||||||
return true
|
|
||||||
} catch (e: IOException) {
|
|
||||||
Log.w(TAG, "[tryToSetUsernameLink] Failed with IOException on attempt " + (i + 1) + "/3", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
private fun deleteUsernameInternal(): UsernameDeleteResult {
|
private fun deleteUsernameInternal(): UsernameDeleteResult {
|
||||||
return try {
|
return try {
|
||||||
|
|
|
@ -783,8 +783,15 @@ public class SignalServiceAccountManager {
|
||||||
return this.pushServiceSocket.reserveUsername(usernameHashes);
|
return this.pushServiceSocket.reserveUsername(usernameHashes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void confirmUsername(Username username) throws IOException {
|
public UsernameLinkComponents confirmUsernameAndCreateNewLink(Username username) throws IOException {
|
||||||
this.pushServiceSocket.confirmUsername(username);
|
try {
|
||||||
|
UsernameLink link = link = username.generateLink();
|
||||||
|
UUID serverId = this.pushServiceSocket.confirmUsernameAndCreateNewLink(username, link);
|
||||||
|
|
||||||
|
return new UsernameLinkComponents(link.getEntropy(), serverId);
|
||||||
|
} catch (BaseUsernameException e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public UsernameLinkComponents updateUsernameLink(UsernameLink newUsernameLink) throws IOException {
|
public UsernameLinkComponents updateUsernameLink(UsernameLink newUsernameLink) throws IOException {
|
||||||
|
|
|
@ -9,8 +9,12 @@ class ConfirmUsernameRequest {
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private String zkProof;
|
private String zkProof;
|
||||||
|
|
||||||
ConfirmUsernameRequest(String usernameHash, String zkProof) {
|
@JsonProperty
|
||||||
|
private String encryptedUsername;
|
||||||
|
|
||||||
|
ConfirmUsernameRequest(String usernameHash, String zkProof, String encryptedUsername) {
|
||||||
this.usernameHash = usernameHash;
|
this.usernameHash = usernameHash;
|
||||||
this.zkProof = zkProof;
|
this.zkProof = zkProof;
|
||||||
|
this.encryptedUsername = encryptedUsername;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
package org.whispersystems.signalservice.internal.push
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
|
||||||
|
import org.whispersystems.signalservice.internal.util.JsonUtil
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
/** Response body for confirming a username reservation. */
|
||||||
|
class ConfirmUsernameResponse(
|
||||||
|
@JsonProperty
|
||||||
|
val usernameHash: String,
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
@JsonDeserialize(using = JsonUtil.UuidDeserializer::class)
|
||||||
|
val usernameLinkHandle: UUID
|
||||||
|
)
|
|
@ -1112,15 +1112,19 @@ public class PushServiceSocket {
|
||||||
* @param username The username the user wishes to confirm.
|
* @param username The username the user wishes to confirm.
|
||||||
* @throws IOException Thrown when the username is invalid or taken, or when another network error occurs.
|
* @throws IOException Thrown when the username is invalid or taken, or when another network error occurs.
|
||||||
*/
|
*/
|
||||||
public void confirmUsername(Username username) throws IOException {
|
public UUID confirmUsernameAndCreateNewLink(Username username, Username.UsernameLink link) throws IOException {
|
||||||
try {
|
try {
|
||||||
byte[] randomness = new byte[32];
|
byte[] randomness = new byte[32];
|
||||||
random.nextBytes(randomness);
|
random.nextBytes(randomness);
|
||||||
|
|
||||||
byte[] proof = username.generateProofWithRandomness(randomness);
|
byte[] proof = username.generateProofWithRandomness(randomness);
|
||||||
ConfirmUsernameRequest confirmUsernameRequest = new ConfirmUsernameRequest(Base64.encodeUrlSafeWithoutPadding(username.getHash()), Base64.encodeUrlSafeWithoutPadding(proof));
|
ConfirmUsernameRequest confirmUsernameRequest = new ConfirmUsernameRequest(
|
||||||
|
Base64.encodeUrlSafeWithoutPadding(username.getHash()),
|
||||||
|
Base64.encodeUrlSafeWithoutPadding(proof),
|
||||||
|
Base64.encodeUrlSafeWithoutPadding(link.getEncryptedUsername())
|
||||||
|
);
|
||||||
|
|
||||||
makeServiceRequest(CONFIRM_USERNAME_PATH, "PUT", JsonUtil.toJson(confirmUsernameRequest), NO_HEADERS, (responseCode, body) -> {
|
String response = makeServiceRequest(CONFIRM_USERNAME_PATH, "PUT", JsonUtil.toJson(confirmUsernameRequest), NO_HEADERS, (responseCode, body) -> {
|
||||||
switch (responseCode) {
|
switch (responseCode) {
|
||||||
case 409:
|
case 409:
|
||||||
throw new UsernameIsNotReservedException();
|
throw new UsernameIsNotReservedException();
|
||||||
|
@ -1128,6 +1132,8 @@ public class PushServiceSocket {
|
||||||
throw new UsernameTakenException();
|
throw new UsernameTakenException();
|
||||||
}
|
}
|
||||||
}, Optional.empty());
|
}, Optional.empty());
|
||||||
|
|
||||||
|
return JsonUtil.fromJson(response, ConfirmUsernameResponse.class).getUsernameLinkHandle();
|
||||||
} catch (BaseUsernameException e) {
|
} catch (BaseUsernameException e) {
|
||||||
throw new IOException(e);
|
throw new IOException(e);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue