X-Git-Url: https://git.nmode.ca/signal-cli/blobdiff_plain/4a1af0786c938f887a109a17dcc879da21704a8b..bf87fcc652bc37a9843b4dc79f985005452a1c41:/lib/src/main/java/org/asamk/signal/manager/ProvisioningManager.java diff --git a/lib/src/main/java/org/asamk/signal/manager/ProvisioningManager.java b/lib/src/main/java/org/asamk/signal/manager/ProvisioningManager.java index 6445e511..09a329f5 100644 --- a/lib/src/main/java/org/asamk/signal/manager/ProvisioningManager.java +++ b/lib/src/main/java/org/asamk/signal/manager/ProvisioningManager.java @@ -1,208 +1,14 @@ -/* - Copyright (C) 2015-2021 AsamK and contributors - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ package org.asamk.signal.manager; -import org.asamk.signal.manager.config.ServiceConfig; -import org.asamk.signal.manager.config.ServiceEnvironment; -import org.asamk.signal.manager.config.ServiceEnvironmentConfig; -import org.asamk.signal.manager.storage.SignalAccount; -import org.asamk.signal.manager.storage.identities.TrustNewIdentity; -import org.asamk.signal.manager.util.KeyUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.whispersystems.libsignal.IdentityKeyPair; -import org.whispersystems.libsignal.util.KeyHelper; -import org.whispersystems.signalservice.api.SignalServiceAccountManager; -import org.whispersystems.signalservice.api.groupsv2.ClientZkOperations; -import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations; -import org.whispersystems.signalservice.api.push.SignalServiceAddress; -import org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedException; -import org.whispersystems.signalservice.api.util.DeviceNameUtil; -import org.whispersystems.signalservice.internal.util.DynamicCredentialsProvider; +import org.asamk.signal.manager.api.UserAlreadyExistsException; -import java.io.File; import java.io.IOException; import java.net.URI; import java.util.concurrent.TimeoutException; -import java.util.function.Consumer; - -public class ProvisioningManager { - - private final static Logger logger = LoggerFactory.getLogger(ProvisioningManager.class); - - private final PathConfig pathConfig; - private final ServiceEnvironmentConfig serviceEnvironmentConfig; - private final String userAgent; - private final Consumer newManagerListener; - - private final SignalServiceAccountManager accountManager; - private final IdentityKeyPair tempIdentityKey; - private final int registrationId; - private final String password; - - ProvisioningManager( - PathConfig pathConfig, - ServiceEnvironmentConfig serviceEnvironmentConfig, - String userAgent, - final Consumer newManagerListener - ) { - this.pathConfig = pathConfig; - this.serviceEnvironmentConfig = serviceEnvironmentConfig; - this.userAgent = userAgent; - this.newManagerListener = newManagerListener; - - tempIdentityKey = KeyUtils.generateIdentityKeyPair(); - registrationId = KeyHelper.generateRegistrationId(false); - password = KeyUtils.createPassword(); - GroupsV2Operations groupsV2Operations; - try { - groupsV2Operations = new GroupsV2Operations(ClientZkOperations.create(serviceEnvironmentConfig.getSignalServiceConfiguration())); - } catch (Throwable ignored) { - groupsV2Operations = null; - } - accountManager = new SignalServiceAccountManager(serviceEnvironmentConfig.getSignalServiceConfiguration(), - new DynamicCredentialsProvider(null, null, password, SignalServiceAddress.DEFAULT_DEVICE_ID), - userAgent, - groupsV2Operations, - ServiceConfig.AUTOMATIC_NETWORK_RETRY); - } - - public static ProvisioningManager init( - File settingsPath, ServiceEnvironment serviceEnvironment, String userAgent - ) { - return init(settingsPath, serviceEnvironment, userAgent, null); - } - - public static ProvisioningManager init( - File settingsPath, - ServiceEnvironment serviceEnvironment, - String userAgent, - Consumer newManagerListener - ) { - var pathConfig = PathConfig.createDefault(settingsPath); - - final var serviceConfiguration = ServiceConfig.getServiceEnvironmentConfig(serviceEnvironment, userAgent); - - return new ProvisioningManager(pathConfig, serviceConfiguration, userAgent, newManagerListener); - } - - public URI getDeviceLinkUri() throws TimeoutException, IOException { - var deviceUuid = accountManager.getNewDeviceUuid(); - - return new DeviceLinkInfo(deviceUuid, tempIdentityKey.getPublicKey().getPublicKey()).createDeviceLinkUri(); - } - - public String finishDeviceLink(String deviceName) throws IOException, TimeoutException, UserAlreadyExists { - var ret = accountManager.getNewDeviceRegistration(tempIdentityKey); - var number = ret.getNumber(); - - logger.info("Received link information from {}, linking in progress ...", number); - - if (SignalAccount.userExists(pathConfig.dataPath(), number) && !canRelinkExistingAccount(number)) { - throw new UserAlreadyExists(number, SignalAccount.getFileName(pathConfig.dataPath(), number)); - } - - var encryptedDeviceName = deviceName == null - ? null - : DeviceNameUtil.encryptDeviceName(deviceName, ret.getIdentity().getPrivateKey()); - - logger.debug("Finishing new device registration"); - var deviceId = accountManager.finishNewDeviceRegistration(ret.getProvisioningCode(), - false, - true, - registrationId, - encryptedDeviceName); - - // Create new account with the synced identity - var profileKey = ret.getProfileKey() == null ? KeyUtils.createProfileKey() : ret.getProfileKey(); - - SignalAccount account = null; - try { - account = SignalAccount.createOrUpdateLinkedAccount(pathConfig.dataPath(), - number, - ret.getAci(), - password, - encryptedDeviceName, - deviceId, - ret.getIdentity(), - registrationId, - profileKey, - TrustNewIdentity.ON_FIRST_USE); - - ManagerImpl m = null; - try { - m = new ManagerImpl(account, pathConfig, serviceEnvironmentConfig, userAgent); - - logger.debug("Refreshing pre keys"); - try { - m.refreshPreKeys(); - } catch (Exception e) { - logger.error("Failed to refresh pre keys."); - } - - logger.debug("Requesting sync data"); - try { - m.requestAllSyncData(); - } catch (Exception e) { - logger.error( - "Failed to request sync messages from linked device, data can be requested again with `sendSyncRequest`."); - } - - if (newManagerListener != null) { - newManagerListener.accept(m); - m = null; - } - return number; - } finally { - if (m != null) { - m.close(); - } - } - } finally { - if (account != null) { - account.close(); - } - } - } - - private boolean canRelinkExistingAccount(final String number) throws IOException { - final SignalAccount signalAccount; - try { - signalAccount = SignalAccount.load(pathConfig.dataPath(), number, false, TrustNewIdentity.ON_FIRST_USE); - } catch (IOException e) { - logger.debug("Account in use or failed to load.", e); - return false; - } - try (signalAccount) { - if (signalAccount.isMasterDevice()) { - logger.debug("Account is a master device."); - return false; - } +public interface ProvisioningManager { - final var m = new ManagerImpl(signalAccount, pathConfig, serviceEnvironmentConfig, userAgent); - try (m) { - m.checkAccountState(); - } catch (AuthorizationFailedException ignored) { - return true; - } + URI getDeviceLinkUri() throws TimeoutException, IOException; - logger.debug("Account is still successfully linked."); - return false; - } - } + String finishDeviceLink(String deviceName) throws IOException, TimeoutException, UserAlreadyExistsException; }