mirror of
https://github.com/signalapp/Signal-Server
synced 2026-04-21 11:38:07 +01:00
Represent identity keys as byte arrays
This commit is contained in:
committed by
Jon Chambers
parent
796863341d
commit
d832eaa759
@@ -8,7 +8,6 @@ package org.whispersystems.textsecuregcm.auth;
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.util.Base64;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.signal.libsignal.protocol.ecc.Curve;
|
||||
import org.signal.libsignal.protocol.ecc.ECPrivateKey;
|
||||
@@ -35,7 +34,7 @@ public class CertificateGenerator {
|
||||
SenderCertificate.Certificate.Builder builder = SenderCertificate.Certificate.newBuilder()
|
||||
.setSenderDevice(Math.toIntExact(device.getId()))
|
||||
.setExpires(System.currentTimeMillis() + TimeUnit.DAYS.toMillis(expiresDays))
|
||||
.setIdentityKey(ByteString.copyFrom(Base64.getDecoder().decode(account.getIdentityKey())))
|
||||
.setIdentityKey(ByteString.copyFrom(account.getIdentityKey()))
|
||||
.setSigner(serverCertificate)
|
||||
.setSenderUuid(account.getUuid().toString());
|
||||
|
||||
|
||||
@@ -31,6 +31,8 @@ import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.signal.libsignal.zkgroup.auth.ServerZkAuthOperations;
|
||||
import org.signal.libsignal.zkgroup.calllinks.CallLinkAuthCredentialResponse;
|
||||
import org.signal.libsignal.zkgroup.GenericServerSecretParams;
|
||||
@@ -38,7 +40,6 @@ import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
||||
import org.whispersystems.textsecuregcm.auth.CertificateGenerator;
|
||||
import org.whispersystems.textsecuregcm.entities.DeliveryCertificate;
|
||||
import org.whispersystems.textsecuregcm.entities.GroupCredentials;
|
||||
import org.whispersystems.textsecuregcm.util.Util;
|
||||
|
||||
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
||||
@Path("/v1/certificate")
|
||||
@@ -74,7 +75,7 @@ public class CertificateController {
|
||||
@QueryParam("includeE164") @DefaultValue("true") boolean includeE164)
|
||||
throws InvalidKeyException {
|
||||
|
||||
if (Util.isEmpty(auth.getAccount().getIdentityKey())) {
|
||||
if (ArrayUtils.isEmpty(auth.getAccount().getIdentityKey())) {
|
||||
throw new WebApplicationException(Response.Status.BAD_REQUEST);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,19 +13,14 @@ import io.micrometer.core.instrument.Metrics;
|
||||
import io.micrometer.core.instrument.Tags;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.enums.ParameterIn;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.ws.rs.Consumes;
|
||||
@@ -40,7 +35,8 @@ import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.whispersystems.textsecuregcm.auth.Anonymous;
|
||||
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
||||
import org.whispersystems.textsecuregcm.auth.ChangesDeviceEnabledState;
|
||||
@@ -120,11 +116,11 @@ public class KeysController {
|
||||
updateAccount = true;
|
||||
}
|
||||
|
||||
final String oldIdentityKey = usePhoneNumberIdentity ? account.getPhoneNumberIdentityKey() : account.getIdentityKey();
|
||||
if (!preKeys.getIdentityKey().equals(oldIdentityKey)) {
|
||||
final byte[] oldIdentityKey = usePhoneNumberIdentity ? account.getPhoneNumberIdentityKey() : account.getIdentityKey();
|
||||
if (!Arrays.equals(preKeys.getIdentityKey(), oldIdentityKey)) {
|
||||
updateAccount = true;
|
||||
|
||||
final boolean hasIdentityKey = StringUtils.isNotBlank(oldIdentityKey);
|
||||
final boolean hasIdentityKey = ArrayUtils.isNotEmpty(oldIdentityKey);
|
||||
final Tags tags = Tags.of(UserAgentTagUtil.getPlatformTag(userAgent))
|
||||
.and(HAS_IDENTITY_KEY_TAG_NAME, String.valueOf(hasIdentityKey))
|
||||
.and(IDENTITY_TYPE_TAG_NAME, usePhoneNumberIdentity ? "pni" : "aci");
|
||||
@@ -183,7 +179,7 @@ public class KeysController {
|
||||
@HeaderParam(HttpHeaders.USER_AGENT) String userAgent)
|
||||
throws RateLimitExceededException {
|
||||
|
||||
if (!auth.isPresent() && !accessKey.isPresent()) {
|
||||
if (auth.isEmpty() && accessKey.isEmpty()) {
|
||||
throw new WebApplicationException(Response.Status.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@@ -225,7 +221,7 @@ public class KeysController {
|
||||
}
|
||||
}
|
||||
|
||||
final String identityKey = usePhoneNumberIdentity ? target.getPhoneNumberIdentityKey() : target.getIdentityKey();
|
||||
final byte[] identityKey = usePhoneNumberIdentity ? target.getPhoneNumberIdentityKey() : target.getIdentityKey();
|
||||
|
||||
if (responseItems.isEmpty()) {
|
||||
return Response.status(404).build();
|
||||
|
||||
@@ -383,13 +383,8 @@ public class ProfileController {
|
||||
if (account.getIdentityKey() == null || account.getPhoneNumberIdentityKey() == null) {
|
||||
return;
|
||||
}
|
||||
byte[] identityKeyBytes;
|
||||
try {
|
||||
identityKeyBytes = Base64.getDecoder().decode(usePhoneNumberIdentity ? account.getPhoneNumberIdentityKey()
|
||||
: account.getIdentityKey());
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
return;
|
||||
}
|
||||
final byte[] identityKeyBytes =
|
||||
usePhoneNumberIdentity ? account.getPhoneNumberIdentityKey() : account.getIdentityKey();
|
||||
md.reset();
|
||||
byte[] digest = md.digest(identityKeyBytes);
|
||||
byte[] fingerprint = Util.truncate(digest, 4);
|
||||
|
||||
@@ -6,13 +6,19 @@
|
||||
package org.whispersystems.textsecuregcm.entities;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import org.whispersystems.textsecuregcm.util.ByteArrayAdapter;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class BaseProfileResponse {
|
||||
|
||||
@JsonProperty
|
||||
private String identityKey;
|
||||
@JsonSerialize(using = ByteArrayAdapter.Serializing.class)
|
||||
@JsonDeserialize(using = ByteArrayAdapter.Deserializing.class)
|
||||
private byte[] identityKey;
|
||||
|
||||
@JsonProperty
|
||||
private String unidentifiedAccess;
|
||||
@@ -32,7 +38,7 @@ public class BaseProfileResponse {
|
||||
public BaseProfileResponse() {
|
||||
}
|
||||
|
||||
public BaseProfileResponse(final String identityKey,
|
||||
public BaseProfileResponse(final byte[] identityKey,
|
||||
final String unidentifiedAccess,
|
||||
final boolean unrestrictedUnidentifiedAccess,
|
||||
final UserCapabilities capabilities,
|
||||
@@ -47,7 +53,7 @@ public class BaseProfileResponse {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
public String getIdentityKey() {
|
||||
public byte[] getIdentityKey() {
|
||||
return identityKey;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import javax.annotation.Nullable;
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.AssertTrue;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import org.whispersystems.textsecuregcm.util.ByteArrayAdapter;
|
||||
|
||||
@@ -36,7 +37,8 @@ public record ChangeNumberRequest(
|
||||
@JsonProperty("reglock") @Nullable String registrationLock,
|
||||
|
||||
@Schema(description="the new public identity key to use for the phone-number identity associated with the new phone number")
|
||||
@NotBlank String pniIdentityKey,
|
||||
@JsonDeserialize(using = ByteArrayAdapter.Deserializing.class)
|
||||
@NotEmpty byte[] pniIdentityKey,
|
||||
|
||||
@Schema(description="""
|
||||
A list of synchronization messages to send to companion devices to supply the private keys
|
||||
|
||||
@@ -6,7 +6,10 @@
|
||||
package org.whispersystems.textsecuregcm.entities;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import org.whispersystems.textsecuregcm.util.ByteArrayAdapter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -27,7 +30,8 @@ public record ChangePhoneNumberRequest(
|
||||
@JsonProperty("reglock") @Nullable String registrationLock,
|
||||
|
||||
@Schema(description="the new public identity key to use for the phone-number identity associated with the new phone number")
|
||||
@Nullable String pniIdentityKey,
|
||||
@JsonDeserialize(using = ByteArrayAdapter.Deserializing.class)
|
||||
@Nullable byte[] pniIdentityKey,
|
||||
|
||||
@Schema(description="""
|
||||
A list of synchronization messages to send to companion devices to supply the private keys
|
||||
|
||||
@@ -10,17 +10,18 @@ import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.AssertTrue;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import org.whispersystems.textsecuregcm.util.ByteArrayAdapter;
|
||||
|
||||
public record PhoneNumberIdentityKeyDistributionRequest(
|
||||
@NotBlank
|
||||
@NotEmpty
|
||||
@JsonDeserialize(using = ByteArrayAdapter.Deserializing.class)
|
||||
@Schema(description="the new identity key for this account's phone-number identity")
|
||||
String pniIdentityKey,
|
||||
byte[] pniIdentityKey,
|
||||
|
||||
@NotNull
|
||||
@Valid
|
||||
|
||||
@@ -6,16 +6,19 @@ package org.whispersystems.textsecuregcm.entities;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import org.whispersystems.textsecuregcm.util.ByteArrayAdapter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PreKeyResponse {
|
||||
|
||||
@JsonProperty
|
||||
@JsonSerialize(using = ByteArrayAdapter.Serializing.class)
|
||||
@Schema(description="the public identity key for the requested identity")
|
||||
private String identityKey;
|
||||
private byte[] identityKey;
|
||||
|
||||
@JsonProperty
|
||||
@Schema(description="information about each requested device")
|
||||
@@ -23,13 +26,13 @@ public class PreKeyResponse {
|
||||
|
||||
public PreKeyResponse() {}
|
||||
|
||||
public PreKeyResponse(String identityKey, List<PreKeyResponseItem> devices) {
|
||||
public PreKeyResponse(byte[] identityKey, List<PreKeyResponseItem> devices) {
|
||||
this.identityKey = identityKey;
|
||||
this.devices = devices;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public String getIdentityKey() {
|
||||
public byte[] getIdentityKey() {
|
||||
return identityKey;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ import static com.codahale.metrics.MetricRegistry.name;
|
||||
|
||||
import io.micrometer.core.instrument.Counter;
|
||||
import io.micrometer.core.instrument.Metrics;
|
||||
import java.util.Base64;
|
||||
import java.util.Collection;
|
||||
import org.signal.libsignal.protocol.InvalidKeyException;
|
||||
import org.signal.libsignal.protocol.ecc.Curve;
|
||||
@@ -18,9 +17,8 @@ public abstract class PreKeySignatureValidator {
|
||||
public static final Counter INVALID_SIGNATURE_COUNTER =
|
||||
Metrics.counter(name(PreKeySignatureValidator.class, "invalidPreKeySignature"));
|
||||
|
||||
public static boolean validatePreKeySignatures(final String identityKeyB64, final Collection<SignedPreKey> spks) {
|
||||
public static boolean validatePreKeySignatures(final byte[] identityKeyBytes, final Collection<SignedPreKey> spks) {
|
||||
try {
|
||||
final byte[] identityKeyBytes = Base64.getDecoder().decode(identityKeyB64);
|
||||
final ECPublicKey identityKey = Curve.decodePoint(identityKeyBytes, 0);
|
||||
|
||||
final boolean success = spks.stream()
|
||||
|
||||
@@ -5,8 +5,11 @@
|
||||
package org.whispersystems.textsecuregcm.entities;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import org.whispersystems.textsecuregcm.util.ByteArrayAdapter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.validation.Valid;
|
||||
@@ -48,23 +51,24 @@ public class PreKeyState {
|
||||
private SignedPreKey pqLastResortPreKey;
|
||||
|
||||
@JsonProperty
|
||||
@JsonDeserialize(using = ByteArrayAdapter.Deserializing.class)
|
||||
@NotEmpty
|
||||
@NotNull
|
||||
@Schema(description="Required. " +
|
||||
"The public identity key for this identity (account or phone-number identity). " +
|
||||
"If this device is not the primary device for the account, " +
|
||||
"must match the existing stored identity key for this identity.")
|
||||
private String identityKey;
|
||||
private byte[] identityKey;
|
||||
|
||||
public PreKeyState() {}
|
||||
|
||||
@VisibleForTesting
|
||||
public PreKeyState(String identityKey, SignedPreKey signedPreKey, List<PreKey> keys) {
|
||||
public PreKeyState(byte[] identityKey, SignedPreKey signedPreKey, List<PreKey> keys) {
|
||||
this(identityKey, signedPreKey, keys, null, null);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public PreKeyState(String identityKey, SignedPreKey signedPreKey, List<PreKey> keys, List<SignedPreKey> pqKeys, SignedPreKey pqLastResortKey) {
|
||||
public PreKeyState(byte[] identityKey, SignedPreKey signedPreKey, List<PreKey> keys, List<SignedPreKey> pqKeys, SignedPreKey pqLastResortKey) {
|
||||
this.identityKey = identityKey;
|
||||
this.signedPreKey = signedPreKey;
|
||||
this.preKeys = keys;
|
||||
@@ -88,7 +92,7 @@ public class PreKeyState {
|
||||
return pqLastResortPreKey;
|
||||
}
|
||||
|
||||
public String getIdentityKey() {
|
||||
public byte[] getIdentityKey() {
|
||||
return identityKey;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,9 +9,11 @@ import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonUnwrapped;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import org.whispersystems.textsecuregcm.util.ByteArrayAdapter;
|
||||
import org.whispersystems.textsecuregcm.util.OptionalBase64ByteArrayDeserializer;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.AssertTrue;
|
||||
@@ -53,14 +55,16 @@ public record RegistrationRequest(@Schema(requiredMode = Schema.RequiredMode.NOT
|
||||
provided, an account will be created "atomically," and all other properties needed for
|
||||
atomic account creation must also be present.
|
||||
""")
|
||||
Optional<String> aciIdentityKey,
|
||||
@JsonDeserialize(using = OptionalBase64ByteArrayDeserializer.class)
|
||||
Optional<byte[]> aciIdentityKey,
|
||||
|
||||
@Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED, description = """
|
||||
The PNI-associated identity key for the account, encoded as a base64 string. If
|
||||
provided, an account will be created "atomically," and all other properties needed for
|
||||
atomic account creation must also be present.
|
||||
""")
|
||||
Optional<String> pniIdentityKey,
|
||||
@JsonDeserialize(using = OptionalBase64ByteArrayDeserializer.class)
|
||||
Optional<byte[]> pniIdentityKey,
|
||||
|
||||
@JsonUnwrapped
|
||||
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
|
||||
@@ -72,8 +76,8 @@ public record RegistrationRequest(@Schema(requiredMode = Schema.RequiredMode.NOT
|
||||
@JsonProperty("recoveryPassword") byte[] recoveryPassword,
|
||||
@JsonProperty("accountAttributes") AccountAttributes accountAttributes,
|
||||
@JsonProperty("skipDeviceTransfer") boolean skipDeviceTransfer,
|
||||
@JsonProperty("aciIdentityKey") Optional<String> aciIdentityKey,
|
||||
@JsonProperty("pniIdentityKey") Optional<String> pniIdentityKey,
|
||||
@JsonProperty("aciIdentityKey") Optional<byte[]> aciIdentityKey,
|
||||
@JsonProperty("pniIdentityKey") Optional<byte[]> pniIdentityKey,
|
||||
@JsonProperty("aciSignedPreKey") Optional<@Valid SignedPreKey> aciSignedPreKey,
|
||||
@JsonProperty("pniSignedPreKey") Optional<@Valid SignedPreKey> pniSignedPreKey,
|
||||
@JsonProperty("aciPqLastResortPreKey") Optional<@Valid SignedPreKey> aciPqLastResortPreKey,
|
||||
@@ -97,7 +101,7 @@ public record RegistrationRequest(@Schema(requiredMode = Schema.RequiredMode.NOT
|
||||
}
|
||||
|
||||
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
||||
private static boolean validatePreKeySignature(final Optional<String> maybeIdentityKey,
|
||||
private static boolean validatePreKeySignature(final Optional<byte[]> maybeIdentityKey,
|
||||
final Optional<SignedPreKey> maybeSignedPreKey) {
|
||||
|
||||
return maybeSignedPreKey.map(signedPreKey -> maybeIdentityKey
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.whispersystems.textsecuregcm.auth.SaltedTokenHash;
|
||||
import org.whispersystems.textsecuregcm.auth.StoredRegistrationLock;
|
||||
import org.whispersystems.textsecuregcm.entities.AccountAttributes;
|
||||
import org.whispersystems.textsecuregcm.storage.Device.DeviceCapabilities;
|
||||
import org.whispersystems.textsecuregcm.util.ByteArrayAdapter;
|
||||
import org.whispersystems.textsecuregcm.util.ByteArrayBase64UrlAdapter;
|
||||
import org.whispersystems.textsecuregcm.util.Util;
|
||||
|
||||
@@ -57,10 +58,14 @@ public class Account {
|
||||
private List<Device> devices = new ArrayList<>();
|
||||
|
||||
@JsonProperty
|
||||
private String identityKey;
|
||||
@JsonSerialize(using = ByteArrayAdapter.Serializing.class)
|
||||
@JsonDeserialize(using = ByteArrayAdapter.Deserializing.class)
|
||||
private byte[] identityKey;
|
||||
|
||||
@JsonProperty("pniIdentityKey")
|
||||
private String phoneNumberIdentityKey;
|
||||
@JsonSerialize(using = ByteArrayAdapter.Serializing.class)
|
||||
@JsonDeserialize(using = ByteArrayAdapter.Deserializing.class)
|
||||
private byte[] phoneNumberIdentityKey;
|
||||
|
||||
@JsonProperty("cpv")
|
||||
private String currentProfileVersion;
|
||||
@@ -282,23 +287,23 @@ public class Account {
|
||||
this.canonicallyDiscoverable = canonicallyDiscoverable;
|
||||
}
|
||||
|
||||
public void setIdentityKey(String identityKey) {
|
||||
public void setIdentityKey(byte[] identityKey) {
|
||||
requireNotStale();
|
||||
|
||||
this.identityKey = identityKey;
|
||||
}
|
||||
|
||||
public String getIdentityKey() {
|
||||
public byte[] getIdentityKey() {
|
||||
requireNotStale();
|
||||
|
||||
return identityKey;
|
||||
}
|
||||
|
||||
public String getPhoneNumberIdentityKey() {
|
||||
public byte[] getPhoneNumberIdentityKey() {
|
||||
return phoneNumberIdentityKey;
|
||||
}
|
||||
|
||||
public void setPhoneNumberIdentityKey(final String phoneNumberIdentityKey) {
|
||||
public void setPhoneNumberIdentityKey(final byte[] phoneNumberIdentityKey) {
|
||||
this.phoneNumberIdentityKey = phoneNumberIdentityKey;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
@@ -242,11 +241,12 @@ public class AccountsManager {
|
||||
}
|
||||
}
|
||||
|
||||
public Account changeNumber(final Account account, final String number,
|
||||
@Nullable final String pniIdentityKey,
|
||||
@Nullable final Map<Long, SignedPreKey> pniSignedPreKeys,
|
||||
@Nullable final Map<Long, SignedPreKey> pniPqLastResortPreKeys,
|
||||
@Nullable final Map<Long, Integer> pniRegistrationIds) throws InterruptedException, MismatchedDevicesException {
|
||||
public Account changeNumber(final Account account,
|
||||
final String number,
|
||||
@Nullable final byte[] pniIdentityKey,
|
||||
@Nullable final Map<Long, SignedPreKey> pniSignedPreKeys,
|
||||
@Nullable final Map<Long, SignedPreKey> pniPqLastResortPreKeys,
|
||||
@Nullable final Map<Long, Integer> pniRegistrationIds) throws InterruptedException, MismatchedDevicesException {
|
||||
|
||||
final String originalNumber = account.getNumber();
|
||||
final UUID originalPhoneNumberIdentifier = account.getPhoneNumberIdentifier();
|
||||
@@ -308,7 +308,7 @@ public class AccountsManager {
|
||||
}
|
||||
|
||||
public Account updatePniKeys(final Account account,
|
||||
final String pniIdentityKey,
|
||||
final byte[] pniIdentityKey,
|
||||
final Map<Long, SignedPreKey> pniSignedPreKeys,
|
||||
@Nullable final Map<Long, SignedPreKey> pniPqLastResortPreKeys,
|
||||
final Map<Long, Integer> pniRegistrationIds) throws MismatchedDevicesException {
|
||||
@@ -327,7 +327,7 @@ public class AccountsManager {
|
||||
}
|
||||
|
||||
private boolean setPniKeys(final Account account,
|
||||
@Nullable final String pniIdentityKey,
|
||||
@Nullable final byte[] pniIdentityKey,
|
||||
@Nullable final Map<Long, SignedPreKey> pniSignedPreKeys,
|
||||
@Nullable final Map<Long, Integer> pniRegistrationIds) {
|
||||
if (ObjectUtils.allNull(pniIdentityKey, pniSignedPreKeys, pniRegistrationIds)) {
|
||||
@@ -336,7 +336,7 @@ public class AccountsManager {
|
||||
throw new IllegalArgumentException("PNI identity key, signed pre-keys, and registration IDs must be all null or all non-null");
|
||||
}
|
||||
|
||||
boolean changed = !pniIdentityKey.equals(account.getPhoneNumberIdentityKey());
|
||||
boolean changed = !Arrays.equals(pniIdentityKey, account.getPhoneNumberIdentityKey());
|
||||
|
||||
for (Device device : account.getDevices()) {
|
||||
if (!device.isEnabled()) {
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
package org.whispersystems.textsecuregcm.storage;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.protobuf.ByteString;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.slf4j.Logger;
|
||||
@@ -40,7 +39,7 @@ public class ChangeNumberManager {
|
||||
}
|
||||
|
||||
public Account changeNumber(final Account account, final String number,
|
||||
@Nullable final String pniIdentityKey,
|
||||
@Nullable final byte[] pniIdentityKey,
|
||||
@Nullable final Map<Long, SignedPreKey> deviceSignedPreKeys,
|
||||
@Nullable final Map<Long, SignedPreKey> devicePqLastResortPreKeys,
|
||||
@Nullable final List<IncomingMessage> deviceMessages,
|
||||
@@ -80,7 +79,7 @@ public class ChangeNumberManager {
|
||||
}
|
||||
|
||||
public Account updatePniKeys(final Account account,
|
||||
final String pniIdentityKey,
|
||||
final byte[] pniIdentityKey,
|
||||
final Map<Long, SignedPreKey> deviceSignedPreKeys,
|
||||
@Nullable final Map<Long, SignedPreKey> devicePqLastResortPreKeys,
|
||||
final List<IncomingMessage> deviceMessages,
|
||||
|
||||
@@ -31,4 +31,3 @@ public class ByteArrayAdapter {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.whispersystems.textsecuregcm.util;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Base64;
|
||||
import java.util.Optional;
|
||||
|
||||
public class OptionalBase64ByteArrayDeserializer extends JsonDeserializer<Optional<byte[]>> {
|
||||
|
||||
@Override
|
||||
public Optional<byte[]> deserialize(final JsonParser jsonParser, final DeserializationContext deserializationContext) throws IOException {
|
||||
return Optional.of(Base64.getDecoder().decode(jsonParser.getValueAsString()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<byte[]> getNullValue(DeserializationContext ctxt) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user