+ public URI getDeviceLinkUri() throws TimeoutException, IOException {
+ password = Util.getSecret(18);
+
+ accountManager = new SignalServiceAccountManager(URL, TRUST_STORE, username, password, USER_AGENT);
+ String uuid = accountManager.getNewDeviceUuid();
+
+ registered = false;
+ try {
+ return new URI("tsdevice:/?uuid=" + URLEncoder.encode(uuid, "utf-8") + "&pub_key=" + URLEncoder.encode(Base64.encodeBytesWithoutPadding(signalProtocolStore.getIdentityKeyPair().getPublicKey().serialize()), "utf-8"));
+ } catch (URISyntaxException e) {
+ // Shouldn't happen
+ return null;
+ }
+ }
+
+ public void finishDeviceLink(String deviceName) throws IOException, InvalidKeyException, TimeoutException, UserAlreadyExists {
+ signalingKey = Util.getSecret(52);
+ SignalServiceAccountManager.NewDeviceRegistrationReturn ret = accountManager.finishNewDeviceRegistration(signalProtocolStore.getIdentityKeyPair(), signalingKey, false, true, signalProtocolStore.getLocalRegistrationId(), deviceName);
+ deviceId = ret.getDeviceId();
+ username = ret.getNumber();
+ // TODO do this check before actually registering
+ if (userExists()) {
+ throw new UserAlreadyExists(username, getFileName());
+ }
+ signalProtocolStore = new JsonSignalProtocolStore(ret.getIdentity(), signalProtocolStore.getLocalRegistrationId());
+
+ registered = true;
+ refreshPreKeys();
+
+ requestSyncGroups();
+ requestSyncContacts();
+
+ save();
+ }
+
+
+ public static Map<String, String> getQueryMap(String query) {
+ String[] params = query.split("&");
+ Map<String, String> map = new HashMap<>();
+ for (String param : params) {
+ String name = null;
+ try {
+ name = URLDecoder.decode(param.split("=")[0], "utf-8");
+ } catch (UnsupportedEncodingException e) {
+ // Impossible
+ }
+ String value = null;
+ try {
+ value = URLDecoder.decode(param.split("=")[1], "utf-8");
+ } catch (UnsupportedEncodingException e) {
+ // Impossible
+ }
+ map.put(name, value);
+ }
+ return map;
+ }
+
+ public void addDeviceLink(URI linkUri) throws IOException, InvalidKeyException {
+ Map<String, String> query = getQueryMap(linkUri.getQuery());
+ String deviceIdentifier = query.get("uuid");
+ String publicKeyEncoded = query.get("pub_key");
+
+ if (TextUtils.isEmpty(deviceIdentifier) || TextUtils.isEmpty(publicKeyEncoded)) {
+ throw new RuntimeException("Invalid device link uri");
+ }
+
+ ECPublicKey deviceKey = Curve.decodePoint(Base64.decode(publicKeyEncoded), 0);
+
+ addDeviceLink(deviceIdentifier, deviceKey);
+ }
+
+ private void addDeviceLink(String deviceIdentifier, ECPublicKey deviceKey) throws IOException, InvalidKeyException {
+ IdentityKeyPair identityKeyPair = signalProtocolStore.getIdentityKeyPair();
+ String verificationCode = accountManager.getNewDeviceVerificationCode();
+
+ accountManager.addDevice(deviceIdentifier, deviceKey, identityKeyPair, verificationCode);
+ }
+