import org.whispersystems.libsignal.ecc.Curve;
import org.whispersystems.libsignal.ecc.ECKeyPair;
import org.whispersystems.libsignal.ecc.ECPublicKey;
+import org.whispersystems.libsignal.fingerprint.Fingerprint;
+import org.whispersystems.libsignal.fingerprint.NumericFingerprintGenerator;
import org.whispersystems.libsignal.state.PreKeyRecord;
import org.whispersystems.libsignal.state.SignedPreKeyRecord;
import org.whispersystems.libsignal.util.KeyHelper;
private FileChannel fileChannel;
private FileLock lock;
- private final ObjectMapper jsonProcessot = new ObjectMapper();
+ private final ObjectMapper jsonProcessor = new ObjectMapper();
private String username;
private int deviceId = SignalServiceAddress.DEFAULT_DEVICE_ID;
private String password;
this.attachmentsPath = this.settingsPath + "/attachments";
this.avatarsPath = this.settingsPath + "/avatars";
- jsonProcessot.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE); // disable autodetect
- jsonProcessot.enable(SerializationFeature.INDENT_OUTPUT); // for pretty print, you can disable it.
- jsonProcessot.enable(SerializationFeature.WRITE_NULL_MAP_VALUES);
- jsonProcessot.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
- jsonProcessot.disable(JsonParser.Feature.AUTO_CLOSE_SOURCE);
- jsonProcessot.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
+ jsonProcessor.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE); // disable autodetect
+ jsonProcessor.enable(SerializationFeature.INDENT_OUTPUT); // for pretty print, you can disable it.
+ jsonProcessor.enable(SerializationFeature.WRITE_NULL_MAP_VALUES);
+ jsonProcessor.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
+ jsonProcessor.disable(JsonParser.Feature.AUTO_CLOSE_SOURCE);
+ jsonProcessor.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
}
public String getUsername() {
return username;
}
+ private IdentityKey getIdentity() {
+ return signalProtocolStore.getIdentityKeyPair().getPublicKey();
+ }
+
public int getDeviceId() {
return deviceId;
}
}
}
- public void load() throws IOException, InvalidKeyException {
+ public void init() throws IOException {
+ load();
+
+ migrateLegacyConfigs();
+
+ accountManager = new SignalServiceAccountManager(URL, TRUST_STORE, username, password, deviceId, USER_AGENT);
+ try {
+ if (registered && accountManager.getPreKeysCount() < PREKEY_MINIMUM_COUNT) {
+ refreshPreKeys();
+ save();
+ }
+ } catch (AuthorizationFailedException e) {
+ System.err.println("Authorization failed, was the number registered elsewhere?");
+ }
+ }
+
+ private void load() throws IOException {
openFileChannel();
- JsonNode rootNode = jsonProcessot.readTree(Channels.newInputStream(fileChannel));
+ JsonNode rootNode = jsonProcessor.readTree(Channels.newInputStream(fileChannel));
JsonNode node = rootNode.get("deviceId");
if (node != null) {
} else {
nextSignedPreKeyId = 0;
}
- signalProtocolStore = jsonProcessot.convertValue(getNotNullNode(rootNode, "axolotlStore"), JsonSignalProtocolStore.class);
+ signalProtocolStore = jsonProcessor.convertValue(getNotNullNode(rootNode, "axolotlStore"), JsonSignalProtocolStore.class);
registered = getNotNullNode(rootNode, "registered").asBoolean();
JsonNode groupStoreNode = rootNode.get("groupStore");
if (groupStoreNode != null) {
- groupStore = jsonProcessot.convertValue(groupStoreNode, JsonGroupStore.class);
+ groupStore = jsonProcessor.convertValue(groupStoreNode, JsonGroupStore.class);
}
if (groupStore == null) {
groupStore = new JsonGroupStore();
}
+
+ JsonNode contactStoreNode = rootNode.get("contactStore");
+ if (contactStoreNode != null) {
+ contactStore = jsonProcessor.convertValue(contactStoreNode, JsonContactsStore.class);
+ }
+ if (contactStore == null) {
+ contactStore = new JsonContactsStore();
+ }
+ }
+
+ private void migrateLegacyConfigs() {
// Copy group avatars that were previously stored in the attachments folder
// to the new avatar folder
- if (groupStore.groupsWithLegacyAvatarId.size() > 0) {
- for (GroupInfo g : groupStore.groupsWithLegacyAvatarId) {
+ if (JsonGroupStore.groupsWithLegacyAvatarId.size() > 0) {
+ for (GroupInfo g : JsonGroupStore.groupsWithLegacyAvatarId) {
File avatarFile = getGroupAvatarFile(g.groupId);
File attachmentFile = getAttachmentFile(g.getAvatarId());
if (!avatarFile.exists() && attachmentFile.exists()) {
}
}
}
- groupStore.groupsWithLegacyAvatarId.clear();
+ JsonGroupStore.groupsWithLegacyAvatarId.clear();
save();
}
-
- JsonNode contactStoreNode = rootNode.get("contactStore");
- if (contactStoreNode != null) {
- contactStore = jsonProcessot.convertValue(contactStoreNode, JsonContactsStore.class);
- }
- if (contactStore == null) {
- contactStore = new JsonContactsStore();
- }
-
- accountManager = new SignalServiceAccountManager(URL, TRUST_STORE, username, password, deviceId, USER_AGENT);
- try {
- if (registered && accountManager.getPreKeysCount() < PREKEY_MINIMUM_COUNT) {
- refreshPreKeys();
- save();
- }
- } catch (AuthorizationFailedException e) {
- System.err.println("Authorization failed, was the number registered elsewhere?");
- }
}
private void save() {
if (username == null) {
return;
}
- ObjectNode rootNode = jsonProcessot.createObjectNode();
+ ObjectNode rootNode = jsonProcessor.createObjectNode();
rootNode.put("username", username)
.put("deviceId", deviceId)
.put("password", password)
try {
openFileChannel();
fileChannel.position(0);
- jsonProcessot.writeValue(Channels.newOutputStream(fileChannel), rootNode);
+ jsonProcessor.writeValue(Channels.newOutputStream(fileChannel), rootNode);
fileChannel.truncate(fileChannel.position());
fileChannel.force(false);
} catch (Exception e) {
DeviceContactsInputStream s = new DeviceContactsInputStream(retrieveAttachmentAsStream(syncMessage.getContacts().get().asPointer()));
DeviceContact c;
while ((c = s.read()) != null) {
- ContactInfo contact = new ContactInfo();
- contact.number = c.getNumber();
+ ContactInfo contact = contactStore.getContact(c.getNumber());
+ if (contact == null) {
+ contact = new ContactInfo();
+ contact.number = c.getNumber();
+ }
if (c.getName().isPresent()) {
contact.name = c.getName().get();
}
return false;
}
+ /**
+ * Trust this the identity with this safety number
+ *
+ * @param name username of the identity
+ * @param safetyNumber Safety number
+ */
+ public boolean trustIdentityVerifiedSafetyNumber(String name, String safetyNumber) {
+ List<JsonIdentityKeyStore.Identity> ids = signalProtocolStore.getIdentities(name);
+ if (ids == null) {
+ return false;
+ }
+ for (JsonIdentityKeyStore.Identity id : ids) {
+ if (!safetyNumber.equals(computeSafetyNumber(name, id.identityKey))) {
+ continue;
+ }
+
+ signalProtocolStore.saveIdentity(name, id.identityKey, TrustLevel.TRUSTED_VERIFIED);
+ save();
+ return true;
+ }
+ return false;
+ }
+
/**
* Trust all keys of this identity without verification
*
save();
return true;
}
+
+ public String computeSafetyNumber(String theirUsername, IdentityKey theirIdentityKey) {
+ Fingerprint fingerprint = new NumericFingerprintGenerator(5200).createFor(username, getIdentity(), theirUsername, theirIdentityKey);
+ return fingerprint.getDisplayableFingerprint().getDisplayText();
+ }
}