import org.signal.libsignal.metadata.ProtocolNoSessionException;
import org.signal.libsignal.metadata.ProtocolUntrustedIdentityException;
import org.signal.libsignal.metadata.SelfSendException;
+import org.signal.zkgroup.InvalidInputException;
+import org.signal.zkgroup.profiles.ProfileKey;
import org.whispersystems.libsignal.IdentityKey;
import org.whispersystems.libsignal.IdentityKeyPair;
import org.whispersystems.libsignal.InvalidKeyException;
import org.whispersystems.signalservice.api.messages.multidevice.SentTranscriptMessage;
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
import org.whispersystems.signalservice.api.messages.multidevice.VerifiedMessage;
+import org.whispersystems.signalservice.api.profiles.SignalServiceProfile;
import org.whispersystems.signalservice.api.push.ContactTokenDetails;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedException;
public class Manager implements Signal {
+ private static final SignalServiceProfile.Capabilities capabilities = new SignalServiceProfile.Capabilities(false, false);
+
private final String settingsPath;
private final String dataPath;
private final String attachmentsPath;
if (username == null) {
account = SignalAccount.createTemporaryAccount(identityKey, registrationId);
} else {
- byte[] profileKey = KeyUtils.createProfileKey();
+ ProfileKey profileKey = KeyUtils.createProfileKey();
account = SignalAccount.create(dataPath, username, identityKey, registrationId, profileKey);
account.save();
}
}
public void updateAccountAttributes() throws IOException {
- accountManager.setAccountAttributes(account.getSignalingKey(), account.getSignalProtocolStore().getLocalRegistrationId(), true, account.getRegistrationLockPin(), account.getRegistrationLock(), getSelfUnidentifiedAccessKey(), false);
+ accountManager.setAccountAttributes(account.getSignalingKey(), account.getSignalProtocolStore().getLocalRegistrationId(), true, account.getRegistrationLockPin(), account.getRegistrationLock(), getSelfUnidentifiedAccessKey(), false, capabilities);
}
public void setProfileName(String name) throws IOException {
}
// Create new account with the synced identity
- byte[] profileKey = ret.getProfileKey();
- if (profileKey == null) {
+ byte[] profileKeyBytes = ret.getProfileKey();
+ ProfileKey profileKey;
+ if (profileKeyBytes == null) {
profileKey = KeyUtils.createProfileKey();
+ } else {
+ try {
+ profileKey = new ProfileKey(profileKeyBytes);
+ } catch (InvalidInputException e) {
+ throw new IOException("Received invalid profileKey", e);
+ }
}
account = SignalAccount.createLinkedAccount(dataPath, username, account.getPassword(), ret.getDeviceId(), ret.getIdentity(), account.getSignalProtocolStore().getLocalRegistrationId(), account.getSignalingKey(), profileKey);
IdentityKeyPair identityKeyPair = account.getSignalProtocolStore().getIdentityKeyPair();
String verificationCode = accountManager.getNewDeviceVerificationCode();
- accountManager.addDevice(deviceIdentifier, deviceKey, identityKeyPair, Optional.of(account.getProfileKey()), verificationCode);
+ accountManager.addDevice(deviceIdentifier, deviceKey, identityKeyPair, Optional.of(account.getProfileKey().serialize()), verificationCode);
account.setMultiDevice(true);
account.save();
}
verificationCode = verificationCode.replace("-", "");
account.setSignalingKey(KeyUtils.createSignalingKey());
// TODO make unrestricted unidentified access configurable
- accountManager.verifyAccountWithCode(verificationCode, account.getSignalingKey(), account.getSignalProtocolStore().getLocalRegistrationId(), true, pin, null, getSelfUnidentifiedAccessKey(), false);
+ accountManager.verifyAccountWithCode(verificationCode, account.getSignalingKey(), account.getSignalProtocolStore().getLocalRegistrationId(), true, pin, null, getSelfUnidentifiedAccessKey(), false, capabilities);
//accountManager.setGcmId(Optional.of(GoogleCloudMessaging.getInstance(this).register(REGISTRATION_ID)));
account.setRegistered(true);
SignalServiceDataMessage.Reaction reaction = new SignalServiceDataMessage.Reaction(emoji, remove, targetAuthor, targetSentTimestamp);
final SignalServiceDataMessage.Builder messageBuilder = SignalServiceDataMessage.newBuilder()
.withReaction(reaction)
- .withProfileKey(account.getProfileKey());
+ .withProfileKey(account.getProfileKey().serialize());
if (groupId != null) {
SignalServiceGroup group = SignalServiceGroup.newBuilder(SignalServiceGroup.Type.DELIVER)
.withId(groupId)
messageBuilder.withAttachments(attachmentPointers);
}
- messageBuilder.withProfileKey(account.getProfileKey());
+ messageBuilder.withProfileKey(account.getProfileKey().serialize());
sendMessageLegacy(messageBuilder, recipients);
}
SignalServiceDataMessage.Reaction reaction = new SignalServiceDataMessage.Reaction(emoji, remove, targetAuthor, targetSentTimestamp);
final SignalServiceDataMessage.Builder messageBuilder = SignalServiceDataMessage.newBuilder()
.withReaction(reaction)
- .withProfileKey(account.getProfileKey());
+ .withProfileKey(account.getProfileKey().serialize());
sendMessageLegacy(messageBuilder, recipients);
}
}
if (message.getProfileKey().isPresent() && message.getProfileKey().get().length == 32) {
if (source.equals(username)) {
- this.account.setProfileKey(message.getProfileKey().get());
+ try {
+ this.account.setProfileKey(new ProfileKey(message.getProfileKey().get()));
+ } catch (InvalidInputException ignored) {
+ }
}
ContactInfo contact = account.getContactStore().getContact(source);
if (contact == null) {
contact.color = c.getColor().get();
}
if (c.getProfileKey().isPresent()) {
- contact.profileKey = Base64.encodeBytes(c.getProfileKey().get());
+ contact.profileKey = Base64.encodeBytes(c.getProfileKey().get().serialize());
}
if (c.getVerified().isPresent()) {
final VerifiedMessage verifiedMessage = c.getVerified().get();
}
}
- byte[] profileKey = record.profileKey == null ? null : Base64.decode(record.profileKey);
+ ProfileKey profileKey = null;
+ try {
+ profileKey = record.profileKey == null ? null : new ProfileKey(Base64.decode(record.profileKey));
+ } catch (InvalidInputException ignored) {
+ }
out.write(new DeviceContact(record.getAddress(), Optional.fromNullable(record.name),
createContactAvatarAttachment(record.number), Optional.fromNullable(record.color),
Optional.fromNullable(verifiedMessage), Optional.fromNullable(profileKey), record.blocked,
import org.asamk.signal.storage.threads.JsonThreadStore;
import org.asamk.signal.util.IOUtils;
import org.asamk.signal.util.Util;
+import org.signal.zkgroup.InvalidInputException;
+import org.signal.zkgroup.profiles.ProfileKey;
import org.whispersystems.libsignal.IdentityKeyPair;
import org.whispersystems.libsignal.state.PreKeyRecord;
import org.whispersystems.libsignal.state.SignedPreKeyRecord;
private String password;
private String registrationLockPin;
private String signalingKey;
- private byte[] profileKey;
+ private ProfileKey profileKey;
private int preKeyIdOffset;
private int nextSignedPreKeyId;
return account;
}
- public static SignalAccount create(String dataPath, String username, IdentityKeyPair identityKey, int registrationId, byte[] profileKey) throws IOException {
+ public static SignalAccount create(String dataPath, String username, IdentityKeyPair identityKey, int registrationId, ProfileKey profileKey) throws IOException {
IOUtils.createPrivateDirectories(dataPath);
SignalAccount account = new SignalAccount();
return account;
}
- public static SignalAccount createLinkedAccount(String dataPath, String username, String password, int deviceId, IdentityKeyPair identityKey, int registrationId, String signalingKey, byte[] profileKey) throws IOException {
+ public static SignalAccount createLinkedAccount(String dataPath, String username, String password, int deviceId, IdentityKeyPair identityKey, int registrationId, String signalingKey, ProfileKey profileKey) throws IOException {
IOUtils.createPrivateDirectories(dataPath);
SignalAccount account = new SignalAccount();
nextSignedPreKeyId = 0;
}
if (rootNode.has("profileKey")) {
- profileKey = Base64.decode(Util.getNotNullNode(rootNode, "profileKey").asText());
+ try {
+ profileKey = new ProfileKey(Base64.decode(Util.getNotNullNode(rootNode, "profileKey").asText()));
+ } catch (InvalidInputException e) {
+ throw new IOException("Config file contains an invalid profileKey, needs to be base64 encoded array of 32 bytes", e);
+ }
}
signalProtocolStore = jsonProcessor.convertValue(Util.getNotNullNode(rootNode, "axolotlStore"), JsonSignalProtocolStore.class);
.put("signalingKey", signalingKey)
.put("preKeyIdOffset", preKeyIdOffset)
.put("nextSignedPreKeyId", nextSignedPreKeyId)
- .put("profileKey", Base64.encodeBytes(profileKey))
+ .put("profileKey", Base64.encodeBytes(profileKey.serialize()))
.put("registered", registered)
.putPOJO("axolotlStore", signalProtocolStore)
.putPOJO("groupStore", groupStore)
this.signalingKey = signalingKey;
}
- public byte[] getProfileKey() {
+ public ProfileKey getProfileKey() {
return profileKey;
}
- public void setProfileKey(final byte[] profileKey) {
+ public void setProfileKey(final ProfileKey profileKey) {
this.profileKey = profileKey;
}