Update dependencies

updateProfile can now only update both name and avatar at the same time,
as the upstream API has changed.
This commit is contained in:
AsamK 2020-08-09 13:00:29 +02:00
parent 6b02b1076c
commit e6c1e03e21
6 changed files with 42 additions and 64 deletions

View file

@ -17,10 +17,10 @@ repositories {
} }
dependencies { dependencies {
implementation 'com.github.turasa:signal-service-java:2.15.3_unofficial_11' implementation 'com.github.turasa:signal-service-java:2.15.3_unofficial_12'
implementation 'org.bouncycastle:bcprov-jdk15on:1.66' implementation 'org.bouncycastle:bcprov-jdk15on:1.66'
implementation 'net.sourceforge.argparse4j:argparse4j:0.8.1' implementation 'net.sourceforge.argparse4j:argparse4j:0.8.1'
implementation 'com.github.hypfvieh:dbus-java:3.2.2' implementation 'com.github.hypfvieh:dbus-java:3.2.3'
implementation 'org.slf4j:slf4j-nop:1.7.30' implementation 'org.slf4j:slf4j-nop:1.7.30'
} }

View file

@ -227,7 +227,7 @@ Specify the safety number of the key, only use this option if you have verified
=== updateProfile === updateProfile
Update the name and/or avatar image visible by message recipients for the current users. Update the name and avatar image visible by message recipients for the current users.
The profile is stored encrypted on the Signal servers. The profile is stored encrypted on the Signal servers.
The decryption key is sent with every outgoing messages (excluding group messages). The decryption key is sent with every outgoing messages (excluding group messages).

View file

@ -200,7 +200,7 @@ public class ReceiveMessageHandler implements Manager.ReceiveMessageHandler {
SignalServiceCallMessage callMessage = content.getCallMessage().get(); SignalServiceCallMessage callMessage = content.getCallMessage().get();
if (callMessage.getAnswerMessage().isPresent()) { if (callMessage.getAnswerMessage().isPresent()) {
AnswerMessage answerMessage = callMessage.getAnswerMessage().get(); AnswerMessage answerMessage = callMessage.getAnswerMessage().get();
System.out.println("Answer message: " + answerMessage.getId() + ": " + answerMessage.getDescription()); System.out.println("Answer message: " + answerMessage.getId() + ": " + answerMessage.getSdp());
} }
if (callMessage.getBusyMessage().isPresent()) { if (callMessage.getBusyMessage().isPresent()) {
BusyMessage busyMessage = callMessage.getBusyMessage().get(); BusyMessage busyMessage = callMessage.getBusyMessage().get();
@ -218,7 +218,7 @@ public class ReceiveMessageHandler implements Manager.ReceiveMessageHandler {
} }
if (callMessage.getOfferMessage().isPresent()) { if (callMessage.getOfferMessage().isPresent()) {
OfferMessage offerMessage = callMessage.getOfferMessage().get(); OfferMessage offerMessage = callMessage.getOfferMessage().get();
System.out.println("Offer message: " + offerMessage.getId() + ": " + offerMessage.getDescription()); System.out.println("Offer message: " + offerMessage.getId() + ": " + offerMessage.getSdp());
} }
} }
if (content.getReceiptMessage().isPresent()) { if (content.getReceiptMessage().isPresent()) {

View file

@ -14,16 +14,18 @@ public class UpdateProfileCommand implements LocalCommand {
@Override @Override
public void attachToSubparser(final Subparser subparser) { public void attachToSubparser(final Subparser subparser) {
final MutuallyExclusiveGroup avatarOptions = subparser.addMutuallyExclusiveGroup(); final MutuallyExclusiveGroup avatarOptions = subparser.addMutuallyExclusiveGroup()
.required(true);
avatarOptions.addArgument("--avatar") avatarOptions.addArgument("--avatar")
.help("Path to new profile avatar"); .help("Path to new profile avatar");
avatarOptions.addArgument("--remove-avatar") avatarOptions.addArgument("--remove-avatar")
.action(Arguments.storeTrue()); .action(Arguments.storeTrue());
subparser.addArgument("--name") subparser.addArgument("--name")
.required(true)
.help("New profile name"); .help("New profile name");
subparser.help("Set a name and/or avatar image for the user profile"); subparser.help("Set a name and avatar image for the user profile");
} }
@Override @Override
@ -34,38 +36,15 @@ public class UpdateProfileCommand implements LocalCommand {
} }
String name = ns.getString("name"); String name = ns.getString("name");
if (name != null) {
try {
m.setProfileName(name);
} catch (IOException e) {
System.err.println("UpdateAccount error: " + e.getMessage());
return 3;
}
}
String avatarPath = ns.getString("avatar"); String avatarPath = ns.getString("avatar");
if (avatarPath != null) {
File avatarFile = new File(avatarPath);
try {
m.setProfileAvatar(avatarFile);
} catch (IOException e) {
System.err.println("UpdateAccount error: " + e.getMessage());
return 3;
}
}
boolean removeAvatar = ns.getBoolean("remove_avatar"); boolean removeAvatar = ns.getBoolean("remove_avatar");
if (removeAvatar) { try {
try { File avatarFile = removeAvatar ? null : new File(avatarPath);
m.removeProfileAvatar(); m.setProfile(name, avatarFile);
} catch (IOException e) { } catch (IOException e) {
System.err.println("UpdateAccount error: " + e.getMessage()); System.err.println("UpdateAccount error: " + e.getMessage());
return 3; return 3;
}
} }
return 0; return 0;

View file

@ -38,7 +38,6 @@ import org.signal.libsignal.metadata.ProtocolUntrustedIdentityException;
import org.signal.libsignal.metadata.SelfSendException; import org.signal.libsignal.metadata.SelfSendException;
import org.signal.libsignal.metadata.certificate.InvalidCertificateException; import org.signal.libsignal.metadata.certificate.InvalidCertificateException;
import org.signal.zkgroup.InvalidInputException; import org.signal.zkgroup.InvalidInputException;
import org.signal.zkgroup.VerificationFailedException;
import org.signal.zkgroup.profiles.ClientZkProfileOperations; import org.signal.zkgroup.profiles.ClientZkProfileOperations;
import org.signal.zkgroup.profiles.ProfileKey; import org.signal.zkgroup.profiles.ProfileKey;
import org.whispersystems.libsignal.IdentityKey; import org.whispersystems.libsignal.IdentityKey;
@ -135,6 +134,8 @@ import java.util.Locale;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -288,18 +289,10 @@ public class Manager implements Closeable {
accountManager.setAccountAttributes(account.getSignalingKey(), account.getSignalProtocolStore().getLocalRegistrationId(), true, account.getRegistrationLockPin(), account.getRegistrationLock(), getSelfUnidentifiedAccessKey(), false, ServiceConfig.capabilities); accountManager.setAccountAttributes(account.getSignalingKey(), account.getSignalProtocolStore().getLocalRegistrationId(), true, account.getRegistrationLockPin(), account.getRegistrationLock(), getSelfUnidentifiedAccessKey(), false, ServiceConfig.capabilities);
} }
public void setProfileName(String name) throws IOException { public void setProfile(String name, File avatar) throws IOException {
accountManager.setProfileName(account.getProfileKey(), name); try (final StreamDetails streamDetails = avatar == null ? null : Utils.createStreamDetailsFromFile(avatar)) {
} accountManager.setVersionedProfile(account.getUuid(), account.getProfileKey(), name, streamDetails);
}
public void setProfileAvatar(File avatar) throws IOException {
final StreamDetails streamDetails = Utils.createStreamDetailsFromFile(avatar);
accountManager.setProfileAvatar(account.getProfileKey(), streamDetails);
streamDetails.getStream().close();
}
public void removeProfileAvatar() throws IOException {
accountManager.setProfileAvatar(account.getProfileKey(), null);
} }
public void unregister() throws IOException { public void unregister() throws IOException {
@ -421,8 +414,9 @@ public class Manager implements Closeable {
// TODO implement ZkGroup support // TODO implement ZkGroup support
final ClientZkProfileOperations clientZkProfileOperations = null; final ClientZkProfileOperations clientZkProfileOperations = null;
final boolean attachmentsV3 = false; final boolean attachmentsV3 = false;
final ExecutorService executor = null;
return new SignalServiceMessageSender(serviceConfiguration, account.getUuid(), account.getUsername(), account.getPassword(), return new SignalServiceMessageSender(serviceConfiguration, account.getUuid(), account.getUsername(), account.getPassword(),
account.getDeviceId(), account.getSignalProtocolStore(), userAgent, account.isMultiDevice(), attachmentsV3, Optional.fromNullable(messagePipe), Optional.fromNullable(unidentifiedMessagePipe), Optional.absent(), clientZkProfileOperations); account.getDeviceId(), account.getSignalProtocolStore(), userAgent, account.isMultiDevice(), attachmentsV3, Optional.fromNullable(messagePipe), Optional.fromNullable(unidentifiedMessagePipe), Optional.absent(), clientZkProfileOperations, executor);
} }
private SignalServiceProfile getEncryptedRecipientProfile(SignalServiceAddress address, Optional<UnidentifiedAccess> unidentifiedAccess) throws IOException { private SignalServiceProfile getEncryptedRecipientProfile(SignalServiceAddress address, Optional<UnidentifiedAccess> unidentifiedAccess) throws IOException {
@ -431,16 +425,16 @@ public class Manager implements Closeable {
if (pipe != null) { if (pipe != null) {
try { try {
return pipe.getProfile(address, Optional.absent(), unidentifiedAccess, SignalServiceProfile.RequestType.PROFILE).getProfile(); return pipe.getProfile(address, Optional.absent(), unidentifiedAccess, SignalServiceProfile.RequestType.PROFILE).get(10, TimeUnit.SECONDS).getProfile();
} catch (IOException ignored) { } catch (IOException | InterruptedException | ExecutionException | TimeoutException ignored) {
} }
} }
SignalServiceMessageReceiver receiver = getMessageReceiver(); SignalServiceMessageReceiver receiver = getMessageReceiver();
try { try {
return receiver.retrieveProfile(address, Optional.absent(), unidentifiedAccess, SignalServiceProfile.RequestType.PROFILE).getProfile(); return receiver.retrieveProfile(address, Optional.absent(), unidentifiedAccess, SignalServiceProfile.RequestType.PROFILE).get(10, TimeUnit.SECONDS).getProfile();
} catch (VerificationFailedException e) { } catch (InterruptedException | ExecutionException | TimeoutException e) {
throw new AssertionError(e); throw new IOException("Failed to retrieve profile", e);
} }
} }

View file

@ -75,13 +75,13 @@ class Utils {
InputStream attachmentStream = new FileInputStream(attachmentFile); InputStream attachmentStream = new FileInputStream(attachmentFile);
final long attachmentSize = attachmentFile.length(); final long attachmentSize = attachmentFile.length();
final String mime = getFileMimeType(attachmentFile); final String mime = getFileMimeType(attachmentFile);
// TODO mabybe add a parameter to set the voiceNote, preview, width, height and caption option // TODO mabybe add a parameter to set the voiceNote, borderless, preview, width, height and caption option
final long uploadTimestamp = System.currentTimeMillis(); final long uploadTimestamp = System.currentTimeMillis();
Optional<byte[]> preview = Optional.absent(); Optional<byte[]> preview = Optional.absent();
Optional<String> caption = Optional.absent(); Optional<String> caption = Optional.absent();
Optional<String> blurHash = Optional.absent(); Optional<String> blurHash = Optional.absent();
final Optional<ResumableUploadSpec> resumableUploadSpec = Optional.absent(); final Optional<ResumableUploadSpec> resumableUploadSpec = Optional.absent();
return new SignalServiceAttachmentStream(attachmentStream, mime, attachmentSize, Optional.of(attachmentFile.getName()), false, preview, 0, 0, uploadTimestamp, caption, blurHash, null, null, resumableUploadSpec); return new SignalServiceAttachmentStream(attachmentStream, mime, attachmentSize, Optional.of(attachmentFile.getName()), false, false, preview, 0, 0, uploadTimestamp, caption, blurHash, null, null, resumableUploadSpec);
} }
static StreamDetails createStreamDetailsFromFile(File file) throws IOException { static StreamDetails createStreamDetailsFromFile(File file) throws IOException {
@ -152,7 +152,7 @@ class Utils {
try (FileInputStream f = new FileInputStream(file)) { try (FileInputStream f = new FileInputStream(file)) {
DataInputStream in = new DataInputStream(f); DataInputStream in = new DataInputStream(f);
int version = in.readInt(); int version = in.readInt();
if (version > 3) { if (version > 4) {
return null; return null;
} }
int type = in.readInt(); int type = in.readInt();
@ -179,26 +179,30 @@ class Utils {
legacyMessage = new byte[legacyMessageLen]; legacyMessage = new byte[legacyMessageLen];
in.readFully(legacyMessage); in.readFully(legacyMessage);
} }
long serverTimestamp = 0; long serverReceivedTimestamp = 0;
String uuid = null; String uuid = null;
if (version == 2) { if (version >= 2) {
serverTimestamp = in.readLong(); serverReceivedTimestamp = in.readLong();
uuid = in.readUTF(); uuid = in.readUTF();
if ("".equals(uuid)) { if ("".equals(uuid)) {
uuid = null; uuid = null;
} }
} }
long serverDeliveredTimestamp = 0;
if (version >= 4) {
serverDeliveredTimestamp = in.readLong();
}
Optional<SignalServiceAddress> addressOptional = sourceUuid == null && source.isEmpty() Optional<SignalServiceAddress> addressOptional = sourceUuid == null && source.isEmpty()
? Optional.absent() ? Optional.absent()
: Optional.of(new SignalServiceAddress(sourceUuid, source)); : Optional.of(new SignalServiceAddress(sourceUuid, source));
return new SignalServiceEnvelope(type, addressOptional, sourceDevice, timestamp, legacyMessage, content, serverTimestamp, uuid); return new SignalServiceEnvelope(type, addressOptional, sourceDevice, timestamp, legacyMessage, content, serverReceivedTimestamp, serverDeliveredTimestamp, uuid);
} }
} }
static void storeEnvelope(SignalServiceEnvelope envelope, File file) throws IOException { static void storeEnvelope(SignalServiceEnvelope envelope, File file) throws IOException {
try (FileOutputStream f = new FileOutputStream(file)) { try (FileOutputStream f = new FileOutputStream(file)) {
try (DataOutputStream out = new DataOutputStream(f)) { try (DataOutputStream out = new DataOutputStream(f)) {
out.writeInt(3); // version out.writeInt(4); // version
out.writeInt(envelope.getType()); out.writeInt(envelope.getType());
out.writeUTF(envelope.getSourceE164().isPresent() ? envelope.getSourceE164().get() : ""); out.writeUTF(envelope.getSourceE164().isPresent() ? envelope.getSourceE164().get() : "");
out.writeUTF(envelope.getSourceUuid().isPresent() ? envelope.getSourceUuid().get() : ""); out.writeUTF(envelope.getSourceUuid().isPresent() ? envelope.getSourceUuid().get() : "");
@ -216,9 +220,10 @@ class Utils {
} else { } else {
out.writeInt(0); out.writeInt(0);
} }
out.writeLong(envelope.getServerTimestamp()); out.writeLong(envelope.getServerReceivedTimestamp());
String uuid = envelope.getUuid(); String uuid = envelope.getUuid();
out.writeUTF(uuid == null ? "" : uuid); out.writeUTF(uuid == null ? "" : uuid);
out.writeLong(envelope.getServerDeliveredTimestamp());
} }
} }
} }