}
dependencies {
- api("com.github.turasa:signal-service-java:2.15.3_unofficial_20")
+ api("com.github.turasa:signal-service-java:2.15.3_unofficial_21")
implementation("com.google.protobuf:protobuf-javalite:3.10.0")
implementation("org.bouncycastle:bcprov-jdk15on:1.68")
implementation("org.slf4j:slf4j-api:1.7.30")
*/
package org.asamk.signal.manager;
+import org.asamk.signal.manager.api.Device;
import org.asamk.signal.manager.config.ServiceConfig;
import org.asamk.signal.manager.config.ServiceEnvironment;
import org.asamk.signal.manager.config.ServiceEnvironmentConfig;
import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroup;
import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroupsInputStream;
import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroupsOutputStream;
-import org.whispersystems.signalservice.api.messages.multidevice.DeviceInfo;
import org.whispersystems.signalservice.api.messages.multidevice.RequestMessage;
import org.whispersystems.signalservice.api.messages.multidevice.SentTranscriptMessage;
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.push.exceptions.MissingConfigurationException;
import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
+import org.whispersystems.signalservice.api.util.DeviceNameUtil;
import org.whispersystems.signalservice.api.util.InvalidNumberException;
import org.whispersystems.signalservice.api.util.PhoneNumberFormatter;
import org.whispersystems.signalservice.api.util.SleepTimer;
}
public void updateAccountAttributes() throws IOException {
- accountManager.setAccountAttributes(account.getDeviceName(),
+ accountManager.setAccountAttributes(account.getEncryptedDeviceName(),
null,
account.getLocalRegistrationId(),
true,
account.setRegistered(false);
}
- public List<DeviceInfo> getLinkedDevices() throws IOException {
+ public List<Device> getLinkedDevices() throws IOException {
var devices = accountManager.getDevices();
account.setMultiDevice(devices.size() > 1);
- return devices;
+ var identityKey = account.getIdentityKeyPair().getPrivateKey();
+ return devices.stream().map(d -> {
+ String deviceName = d.getName();
+ if (deviceName != null) {
+ try {
+ deviceName = DeviceNameUtil.decryptDeviceName(deviceName, identityKey);
+ } catch (IOException e) {
+ logger.debug("Failed to decrypt device name, maybe plain text?", e);
+ }
+ }
+ return new Device(d.getId(), deviceName, d.getCreated(), d.getLastSeen());
+ }).collect(Collectors.toList());
}
public void removeLinkedDevices(int deviceId) throws IOException {
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.util.DeviceNameUtil;
import org.whispersystems.signalservice.api.util.SleepTimer;
import org.whispersystems.signalservice.api.util.UptimeSleepTimer;
import org.whispersystems.signalservice.internal.util.DynamicCredentialsProvider;
private final String userAgent;
private final SignalServiceAccountManager accountManager;
- private final IdentityKeyPair identityKey;
+ private final IdentityKeyPair tempIdentityKey;
private final int registrationId;
private final String password;
this.serviceEnvironmentConfig = serviceEnvironmentConfig;
this.userAgent = userAgent;
- identityKey = KeyUtils.generateIdentityKeyPair();
+ tempIdentityKey = KeyUtils.generateIdentityKeyPair();
registrationId = KeyHelper.generateRegistrationId(false);
password = KeyUtils.createPassword();
final SleepTimer timer = new UptimeSleepTimer();
public URI getDeviceLinkUri() throws TimeoutException, IOException {
var deviceUuid = accountManager.getNewDeviceUuid();
- return new DeviceLinkInfo(deviceUuid, identityKey.getPublicKey().getPublicKey()).createDeviceLinkUri();
+ return new DeviceLinkInfo(deviceUuid, tempIdentityKey.getPublicKey().getPublicKey()).createDeviceLinkUri();
}
public Manager finishDeviceLink(String deviceName) throws IOException, TimeoutException, UserAlreadyExists {
- var ret = accountManager.getNewDeviceRegistration(identityKey);
+ var ret = accountManager.getNewDeviceRegistration(tempIdentityKey);
var number = ret.getNumber();
if (SignalAccount.userExists(pathConfig.getDataPath(), number)) {
throw new UserAlreadyExists(number, SignalAccount.getFileName(pathConfig.getDataPath(), number));
}
+ var encryptedDeviceName = deviceName == null
+ ? null
+ : DeviceNameUtil.encryptDeviceName(deviceName, ret.getIdentity().getPrivateKey());
+
var deviceId = accountManager.finishNewDeviceRegistration(ret.getProvisioningCode(),
false,
true,
registrationId,
- deviceName);
+ encryptedDeviceName);
// Create new account with the synced identity
var profileKey = ret.getProfileKey() == null ? KeyUtils.createProfileKey() : ret.getProfileKey();
number,
ret.getUuid(),
password,
- deviceName,
+ encryptedDeviceName,
deviceId,
ret.getIdentity(),
registrationId,
--- /dev/null
+package org.asamk.signal.manager.api;
+
+public class Device {
+
+ private final long id;
+ private final String name;
+ private final long created;
+ private final long lastSeen;
+
+ public Device(long id, String name, long created, long lastSeen) {
+ this.id = id;
+ this.name = name;
+ this.created = created;
+ this.lastSeen = lastSeen;
+ }
+
+ public long getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public long getCreated() {
+ return created;
+ }
+
+ public long getLastSeen() {
+ return lastSeen;
+ }
+}
private String username;
private UUID uuid;
- private String deviceName;
+ private String encryptedDeviceName;
private int deviceId = SignalServiceAddress.DEFAULT_DEVICE_ID;
private boolean isMultiDevice = false;
private String password;
String username,
UUID uuid,
String password,
- String deviceName,
+ String encryptedDeviceName,
int deviceId,
IdentityKeyPair identityKey,
int registrationId,
account.uuid = uuid;
account.password = password;
account.profileKey = profileKey;
- account.deviceName = deviceName;
+ account.encryptedDeviceName = encryptedDeviceName;
account.deviceId = deviceId;
account.initStores(dataPath, identityKey, registrationId);
}
}
if (rootNode.hasNonNull("deviceName")) {
- deviceName = rootNode.get("deviceName").asText();
+ encryptedDeviceName = rootNode.get("deviceName").asText();
}
if (rootNode.hasNonNull("deviceId")) {
deviceId = rootNode.get("deviceId").asInt();
rootNode.put("version", CURRENT_STORAGE_VERSION)
.put("username", username)
.put("uuid", uuid == null ? null : uuid.toString())
- .put("deviceName", deviceName)
+ .put("deviceName", encryptedDeviceName)
.put("deviceId", deviceId)
.put("isMultiDevice", isMultiDevice)
.put("password", password)
return recipientStore.resolveRecipientTrusted(getSelfAddress());
}
- public String getDeviceName() {
- return deviceName;
+ public String getEncryptedDeviceName() {
+ return encryptedDeviceName;
}
public int getDeviceId() {
public void finishRegistration(final UUID uuid, final MasterKey masterKey, final String pin) {
this.pinMasterKey = masterKey;
- this.deviceName = null;
+ this.encryptedDeviceName = null;
this.deviceId = SignalServiceAddress.DEFAULT_DEVICE_ID;
this.isMultiDevice = false;
this.registered = true;
import org.asamk.signal.commands.exceptions.CommandException;
import org.asamk.signal.commands.exceptions.IOErrorException;
import org.asamk.signal.manager.Manager;
+import org.asamk.signal.manager.api.Device;
import org.asamk.signal.util.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.whispersystems.signalservice.api.messages.multidevice.DeviceInfo;
import java.io.IOException;
import java.util.List;
public void handleCommand(final Namespace ns, final Manager m) throws CommandException {
final var writer = new PlainTextWriterImpl(System.out);
- List<DeviceInfo> devices;
+ List<Device> devices;
try {
devices = m.getLinkedDevices();
} catch (IOException e) {