mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-24 21:15:48 +00:00
Add provisioning support for PNP.
This commit is contained in:
@@ -19,6 +19,7 @@ import org.whispersystems.libsignal.logging.Log;
|
||||
import org.whispersystems.libsignal.state.PreKeyRecord;
|
||||
import org.whispersystems.libsignal.state.SignedPreKeyRecord;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.libsignal.util.guava.Preconditions;
|
||||
import org.whispersystems.signalservice.api.account.AccountAttributes;
|
||||
import org.whispersystems.signalservice.api.crypto.InvalidCiphertextException;
|
||||
import org.whispersystems.signalservice.api.crypto.ProfileCipher;
|
||||
@@ -35,6 +36,7 @@ import org.whispersystems.signalservice.api.profiles.ProfileAndCredential;
|
||||
import org.whispersystems.signalservice.api.profiles.SignalServiceProfileWrite;
|
||||
import org.whispersystems.signalservice.api.push.ACI;
|
||||
import org.whispersystems.signalservice.api.push.AccountIdentifier;
|
||||
import org.whispersystems.signalservice.api.push.PNI;
|
||||
import org.whispersystems.signalservice.api.push.SignedPreKeyEntity;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.NoContentException;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException;
|
||||
@@ -128,14 +130,16 @@ public class SignalServiceAccountManager {
|
||||
|
||||
/**
|
||||
* Construct a SignalServiceAccountManager.
|
||||
* @param configuration The URL for the Signal Service.
|
||||
* @param aci The Signal Service UUID.
|
||||
* @param configuration The URL for the Signal Service.
|
||||
* @param aci The Signal Service ACI.
|
||||
* @param pni The Signal Service PNI.
|
||||
* @param e164 The Signal Service phone number.
|
||||
* @param password A Signal Service password.
|
||||
* @param signalAgent A string which identifies the client software.
|
||||
*/
|
||||
public SignalServiceAccountManager(SignalServiceConfiguration configuration,
|
||||
ACI aci,
|
||||
PNI pni,
|
||||
String e164,
|
||||
int deviceId,
|
||||
String password,
|
||||
@@ -143,7 +147,7 @@ public class SignalServiceAccountManager {
|
||||
boolean automaticNetworkRetry)
|
||||
{
|
||||
this(configuration,
|
||||
new StaticCredentialsProvider(aci, e164, deviceId, password),
|
||||
new StaticCredentialsProvider(aci, pni, e164, deviceId, password),
|
||||
signalAgent,
|
||||
new GroupsV2Operations(ClientZkOperations.create(configuration)),
|
||||
automaticNetworkRetry);
|
||||
@@ -715,36 +719,32 @@ public class SignalServiceAccountManager {
|
||||
|
||||
public void addDevice(String deviceIdentifier,
|
||||
ECPublicKey deviceKey,
|
||||
IdentityKeyPair identityKeyPair,
|
||||
Optional<byte[]> profileKey,
|
||||
IdentityKeyPair aciIdentityKeyPair,
|
||||
IdentityKeyPair pniIdentityKeyPair,
|
||||
ProfileKey profileKey,
|
||||
String code)
|
||||
throws InvalidKeyException, IOException
|
||||
{
|
||||
PrimaryProvisioningCipher cipher = new PrimaryProvisioningCipher(deviceKey);
|
||||
ProvisionMessage.Builder message = ProvisionMessage.newBuilder()
|
||||
.setIdentityKeyPublic(ByteString.copyFrom(identityKeyPair.getPublicKey().serialize()))
|
||||
.setIdentityKeyPrivate(ByteString.copyFrom(identityKeyPair.getPrivateKey().serialize()))
|
||||
.setProvisioningCode(code)
|
||||
.setProvisioningVersion(ProvisioningVersion.CURRENT_VALUE);
|
||||
|
||||
String e164 = credentials.getE164();
|
||||
ACI aci = credentials.getAci();
|
||||
PNI pni = credentials.getPni();
|
||||
|
||||
if (e164 != null) {
|
||||
message.setNumber(e164);
|
||||
} else {
|
||||
throw new AssertionError("Missing phone number!");
|
||||
}
|
||||
Preconditions.checkArgument(e164 != null, "Missing e164!");
|
||||
Preconditions.checkArgument(aci != null, "Missing ACI!");
|
||||
Preconditions.checkArgument(pni != null, "Missing PNI!");
|
||||
|
||||
if (aci != null) {
|
||||
message.setUuid(aci.toString());
|
||||
} else {
|
||||
Log.w(TAG, "[addDevice] Missing UUID.");
|
||||
}
|
||||
|
||||
if (profileKey.isPresent()) {
|
||||
message.setProfileKey(ByteString.copyFrom(profileKey.get()));
|
||||
}
|
||||
PrimaryProvisioningCipher cipher = new PrimaryProvisioningCipher(deviceKey);
|
||||
ProvisionMessage.Builder message = ProvisionMessage.newBuilder()
|
||||
.setAciIdentityKeyPublic(ByteString.copyFrom(aciIdentityKeyPair.getPublicKey().serialize()))
|
||||
.setAciIdentityKeyPrivate(ByteString.copyFrom(aciIdentityKeyPair.getPrivateKey().serialize()))
|
||||
.setPniIdentityKeyPublic(ByteString.copyFrom(pniIdentityKeyPair.getPublicKey().serialize()))
|
||||
.setPniIdentityKeyPrivate(ByteString.copyFrom(pniIdentityKeyPair.getPrivateKey().serialize()))
|
||||
.setAci(aci.toString())
|
||||
.setPni(pni.toString())
|
||||
.setNumber(e164)
|
||||
.setProfileKey(ByteString.copyFrom(profileKey.serialize()))
|
||||
.setProvisioningCode(code)
|
||||
.setProvisioningVersion(ProvisioningVersion.CURRENT_VALUE);
|
||||
|
||||
byte[] ciphertext = cipher.encrypt(message.build());
|
||||
this.pushServiceSocket.sendProvisioningMessage(deviceIdentifier, ciphertext);
|
||||
|
||||
@@ -43,4 +43,8 @@ public class RequestMessage {
|
||||
public boolean isKeysRequest() {
|
||||
return request.getType() == Request.Type.KEYS;
|
||||
}
|
||||
|
||||
public boolean isPniIdentityRequest() {
|
||||
return request.getType() == Request.Type.PNI_IDENTITY;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ package org.whispersystems.signalservice.api.messages.multidevice;
|
||||
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage.PniIdentity;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
@@ -28,6 +29,7 @@ public class SignalServiceSyncMessage {
|
||||
private final Optional<KeysMessage> keys;
|
||||
private final Optional<MessageRequestResponseMessage> messageRequestResponse;
|
||||
private final Optional<OutgoingPaymentMessage> outgoingPaymentMessage;
|
||||
private final Optional<PniIdentity> pniIdentity;
|
||||
private final Optional<List<ViewedMessage>> views;
|
||||
|
||||
private SignalServiceSyncMessage(Optional<SentTranscriptMessage> sent,
|
||||
@@ -44,7 +46,8 @@ public class SignalServiceSyncMessage {
|
||||
Optional<KeysMessage> keys,
|
||||
Optional<MessageRequestResponseMessage> messageRequestResponse,
|
||||
Optional<OutgoingPaymentMessage> outgoingPaymentMessage,
|
||||
Optional<List<ViewedMessage>> views)
|
||||
Optional<List<ViewedMessage>> views,
|
||||
Optional<PniIdentity> pniIdentity)
|
||||
{
|
||||
this.sent = sent;
|
||||
this.contacts = contacts;
|
||||
@@ -61,6 +64,7 @@ public class SignalServiceSyncMessage {
|
||||
this.messageRequestResponse = messageRequestResponse;
|
||||
this.outgoingPaymentMessage = outgoingPaymentMessage;
|
||||
this.views = views;
|
||||
this.pniIdentity = pniIdentity;
|
||||
}
|
||||
|
||||
public static SignalServiceSyncMessage forSentTranscript(SentTranscriptMessage sent) {
|
||||
@@ -78,6 +82,7 @@ public class SignalServiceSyncMessage {
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent());
|
||||
}
|
||||
|
||||
@@ -96,6 +101,7 @@ public class SignalServiceSyncMessage {
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent());
|
||||
}
|
||||
|
||||
@@ -114,6 +120,7 @@ public class SignalServiceSyncMessage {
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent());
|
||||
}
|
||||
|
||||
@@ -132,6 +139,7 @@ public class SignalServiceSyncMessage {
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent());
|
||||
}
|
||||
|
||||
@@ -150,6 +158,7 @@ public class SignalServiceSyncMessage {
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent());
|
||||
}
|
||||
|
||||
@@ -168,7 +177,8 @@ public class SignalServiceSyncMessage {
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.of(views));
|
||||
Optional.of(views),
|
||||
Optional.absent());
|
||||
}
|
||||
|
||||
public static SignalServiceSyncMessage forViewOnceOpen(ViewOnceOpenMessage timerRead) {
|
||||
@@ -186,6 +196,7 @@ public class SignalServiceSyncMessage {
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent());
|
||||
}
|
||||
|
||||
@@ -207,6 +218,7 @@ public class SignalServiceSyncMessage {
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent());
|
||||
}
|
||||
|
||||
@@ -225,6 +237,7 @@ public class SignalServiceSyncMessage {
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent());
|
||||
}
|
||||
|
||||
@@ -243,6 +256,7 @@ public class SignalServiceSyncMessage {
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent());
|
||||
}
|
||||
|
||||
@@ -261,6 +275,7 @@ public class SignalServiceSyncMessage {
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent());
|
||||
}
|
||||
|
||||
@@ -279,6 +294,7 @@ public class SignalServiceSyncMessage {
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent());
|
||||
}
|
||||
|
||||
@@ -297,6 +313,7 @@ public class SignalServiceSyncMessage {
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent());
|
||||
}
|
||||
|
||||
@@ -315,6 +332,7 @@ public class SignalServiceSyncMessage {
|
||||
Optional.of(keys),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent());
|
||||
}
|
||||
|
||||
@@ -333,6 +351,7 @@ public class SignalServiceSyncMessage {
|
||||
Optional.absent(),
|
||||
Optional.of(messageRequestResponse),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent());
|
||||
}
|
||||
|
||||
@@ -351,9 +370,29 @@ public class SignalServiceSyncMessage {
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.of(outgoingPaymentMessage),
|
||||
Optional.absent(),
|
||||
Optional.absent());
|
||||
}
|
||||
|
||||
public static SignalServiceSyncMessage forPniIdentity(PniIdentity pniIdentity) {
|
||||
return new SignalServiceSyncMessage(Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.of(pniIdentity));
|
||||
}
|
||||
|
||||
public static SignalServiceSyncMessage empty() {
|
||||
return new SignalServiceSyncMessage(Optional.absent(),
|
||||
Optional.absent(),
|
||||
@@ -369,6 +408,7 @@ public class SignalServiceSyncMessage {
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent());
|
||||
}
|
||||
|
||||
@@ -432,6 +472,10 @@ public class SignalServiceSyncMessage {
|
||||
return views;
|
||||
}
|
||||
|
||||
public Optional<PniIdentity> getPniIdentity() {
|
||||
return pniIdentity;
|
||||
}
|
||||
|
||||
public enum FetchType {
|
||||
LOCAL_PROFILE,
|
||||
STORAGE_MANIFEST,
|
||||
|
||||
@@ -7,9 +7,11 @@
|
||||
package org.whispersystems.signalservice.api.util;
|
||||
|
||||
import org.whispersystems.signalservice.api.push.ACI;
|
||||
import org.whispersystems.signalservice.api.push.PNI;
|
||||
|
||||
public interface CredentialsProvider {
|
||||
ACI getAci();
|
||||
PNI getPni();
|
||||
String getE164();
|
||||
int getDeviceId();
|
||||
String getPassword();
|
||||
|
||||
@@ -7,17 +7,20 @@
|
||||
package org.whispersystems.signalservice.internal.util;
|
||||
|
||||
import org.whispersystems.signalservice.api.push.ACI;
|
||||
import org.whispersystems.signalservice.api.push.PNI;
|
||||
import org.whispersystems.signalservice.api.util.CredentialsProvider;
|
||||
|
||||
public class StaticCredentialsProvider implements CredentialsProvider {
|
||||
|
||||
private final ACI aci;
|
||||
private final PNI pni;
|
||||
private final String e164;
|
||||
private final int deviceId;
|
||||
private final int deviceId;
|
||||
private final String password;
|
||||
|
||||
public StaticCredentialsProvider(ACI aci, String e164, int deviceId, String password) {
|
||||
public StaticCredentialsProvider(ACI aci, PNI pni, String e164, int deviceId, String password) {
|
||||
this.aci = aci;
|
||||
this.pni = pni;
|
||||
this.e164 = e164;
|
||||
this.deviceId = deviceId;
|
||||
this.password = password;
|
||||
@@ -28,6 +31,11 @@ public class StaticCredentialsProvider implements CredentialsProvider {
|
||||
return aci;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PNI getPni() {
|
||||
return pni;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getE164() {
|
||||
return e164;
|
||||
|
||||
@@ -20,15 +20,19 @@ message ProvisionEnvelope {
|
||||
}
|
||||
|
||||
message ProvisionMessage {
|
||||
optional bytes identityKeyPublic = 1;
|
||||
optional bytes identityKeyPrivate = 2;
|
||||
optional string number = 3;
|
||||
optional string uuid = 8;
|
||||
optional string provisioningCode = 4;
|
||||
optional string userAgent = 5;
|
||||
optional bytes profileKey = 6;
|
||||
optional bool readReceipts = 7;
|
||||
optional uint32 provisioningVersion = 9;
|
||||
optional bytes aciIdentityKeyPublic = 1;
|
||||
optional bytes aciIdentityKeyPrivate = 2;
|
||||
optional bytes pniIdentityKeyPublic = 11;
|
||||
optional bytes pniIdentityKeyPrivate = 12;
|
||||
optional string aci = 8;
|
||||
optional string pni = 10;
|
||||
optional string number = 3;
|
||||
optional string provisioningCode = 4;
|
||||
optional string userAgent = 5;
|
||||
optional bytes profileKey = 6;
|
||||
optional bool readReceipts = 7;
|
||||
optional uint32 provisioningVersion = 9;
|
||||
// NEXT ID: 13
|
||||
}
|
||||
|
||||
enum ProvisioningVersion {
|
||||
|
||||
@@ -26,12 +26,14 @@ message Envelope {
|
||||
optional string sourceE164 = 2;
|
||||
optional string sourceUuid = 11;
|
||||
optional uint32 sourceDevice = 7;
|
||||
optional string destinationUuid = 13;
|
||||
optional string relay = 3;
|
||||
optional uint64 timestamp = 5;
|
||||
optional bytes legacyMessage = 6; // Contains an encrypted DataMessage
|
||||
optional bytes content = 8; // Contains an encrypted Content
|
||||
optional string serverGuid = 9;
|
||||
optional uint64 serverTimestamp = 10;
|
||||
// NEXT ID: 14
|
||||
}
|
||||
|
||||
message Content {
|
||||
@@ -408,6 +410,7 @@ message SyncMessage {
|
||||
BLOCKED = 3;
|
||||
CONFIGURATION = 4;
|
||||
KEYS = 5;
|
||||
PNI_IDENTITY = 6;
|
||||
}
|
||||
|
||||
optional Type type = 1;
|
||||
@@ -466,6 +469,11 @@ message SyncMessage {
|
||||
optional bytes storageService = 1;
|
||||
}
|
||||
|
||||
message PniIdentity {
|
||||
optional bytes publicKey = 1;
|
||||
optional bytes privateKey = 2;
|
||||
}
|
||||
|
||||
message MessageRequestResponse {
|
||||
enum Type {
|
||||
UNKNOWN = 0;
|
||||
|
||||
Reference in New Issue
Block a user