Compare commits

..

No commits in common. "master" and "v0.13.22" have entirely different histories.

108 changed files with 564 additions and 10060 deletions

View File

@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
java: [ '25' ]
java: [ '21', '25' ]
steps:
- uses: actions/checkout@v4
@ -58,8 +58,8 @@ jobs:
- uses: actions/checkout@v4
- uses: graalvm/setup-graalvm@v1
with:
distribution: 'graalvm'
java-version: '25'
version: 'latest'
java-version: '21'
cache: 'gradle'
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Build with Gradle

View File

@ -24,7 +24,7 @@ jobs:
uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: 25
java-version: 21
- name: Checkout repository
uses: actions/checkout@v4

View File

@ -1,32 +1,5 @@
# Changelog
## [Unreleased]
**Attention**: Now requires Java 25
### Breaking changes
- Remove isRegistered method without parameters from Signal dbus interface, which always returned `true`
- Remove `sandbox` value for --service-environment parameter, use `staging` instead
- The `daemon` command now requires at least one channel parameter (`--socket`, `--dbus`, ...) and no longer defaults to dbus
## [0.13.23] - 2026-01-24
Requires libsignal-client version 0.86.12.
### Added
- Add sendPollCreate, sendPollVote, sendPollTerminate commands for polls
- Add updateDevice command to set device name of linked devices
### Changed
- Allow updating contact names from linked devices
### Fixed
- Start multi account mode even if some accounts have authorization failures
## [0.13.22] - 2025-11-14
Requires libsignal-client version 0.86.1.

View File

@ -1,4 +1,4 @@
FROM docker.io/azul/zulu-openjdk:25-jre-headless
FROM docker.io/azul/zulu-openjdk:21-jre-headless
LABEL org.opencontainers.image.source=https://github.com/AsamK/signal-cli
LABEL org.opencontainers.image.description="signal-cli provides an unofficial commandline, dbus and JSON-RPC interface for the Signal messenger."

View File

@ -8,7 +8,7 @@ For registering you need a phone number where you can receive SMS or incoming ca
signal-cli is primarily intended to be used on servers to notify admins of important events.
For this use-case, it has a daemon mode with JSON-RPC interface ([man page](https://github.com/AsamK/signal-cli/blob/master/man/signal-cli-jsonrpc.5.adoc))
and D-BUS interface ([man page](https://github.com/AsamK/signal-cli/blob/master/man/signal-cli-dbus.5.adoc)).
and D-BUS interface ([man page](https://github.com/AsamK/signal-cli/blob/master/man/signal-cli-dbus.5.adoc)) .
For the JSON-RPC interface there's also a simple [example client](https://github.com/AsamK/signal-cli/tree/master/client), written in Rust.
signal-cli needs to be kept up-to-date to keep up with Signal-Server changes.
@ -23,33 +23,24 @@ Windows. There's also a [docker image and some Linux packages](https://github.co
System requirements:
- at least Java Runtime Environment (JRE) 25
- at least Java Runtime Environment (JRE) 21
- native library: libsignal-client
The native libs are bundled for x86_64 Linux (with recent enough glibc), Windows and MacOS. For other
systems/architectures
see: [Provide native lib for libsignal](https://github.com/AsamK/signal-cli/wiki/Provide-native-lib-for-libsignal)
### Install system-wide on Linux [ JVM build ]
### Install system-wide on Linux
See [latest version](https://github.com/AsamK/signal-cli/releases).
```sh
VERSION=$(curl -Ls -o /dev/null -w %{url_effective} https://github.com/AsamK/signal-cli/releases/latest | sed -e 's/^.*\/v//')
curl -L -O https://github.com/AsamK/signal-cli/releases/download/v"${VERSION}"/signal-cli-"${VERSION}".tar.gz
export VERSION=<latest version, format "x.y.z">
wget https://github.com/AsamK/signal-cli/releases/download/v"${VERSION}"/signal-cli-"${VERSION}".tar.gz
sudo tar xf signal-cli-"${VERSION}".tar.gz -C /opt
sudo ln -sf /opt/signal-cli-"${VERSION}"/bin/signal-cli /usr/local/bin/
```
### Install system-wide on Linux [ GraalVM native build ]
```sh
VERSION=$(curl -Ls -o /dev/null -w %{url_effective} https://github.com/AsamK/signal-cli/releases/latest | sed -e 's/^.*\/v//')
curl -L -O https://github.com/AsamK/signal-cli/releases/download/v"${VERSION}"/signal-cli-"${VERSION}"-Linux-native.tar.gz
sudo tar xf signal-cli-"${VERSION}"-Linux-native.tar.gz -C /opt
sudo ln -sf /opt/signal-cli /usr/local/bin/
```
You can find further instructions on the Wiki:
- [Quickstart](https://github.com/AsamK/signal-cli/wiki/Quickstart)

View File

@ -3,17 +3,17 @@ plugins {
application
eclipse
`check-lib-versions`
id("org.graalvm.buildtools.native") version "0.11.4"
id("org.graalvm.buildtools.native") version "0.11.3"
}
allprojects {
group = "org.asamk"
version = "0.14.0-SNAPSHOT"
version = "0.13.22"
}
java {
sourceCompatibility = JavaVersion.VERSION_25
targetCompatibility = JavaVersion.VERSION_25
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
if (!JavaVersion.current().isCompatibleWith(targetCompatibility)) {
toolchain {
@ -39,7 +39,7 @@ graalvmNative {
if (System.getenv("GRAALVM_HOME") == null) {
toolchainDetection.set(true)
javaLauncher.set(javaToolchains.launcherFor {
languageVersion.set(JavaLanguageVersion.of(25))
languageVersion.set(JavaLanguageVersion.of(21))
})
} else {
toolchainDetection.set(false)

View File

@ -7,11 +7,11 @@ plugins {
}
tasks.named<KotlinCompilationTask<KotlinJvmCompilerOptions>>("compileKotlin").configure {
compilerOptions.jvmTarget.set(JvmTarget.JVM_24)
compilerOptions.jvmTarget.set(JvmTarget.JVM_17)
}
java {
targetCompatibility = JavaVersion.VERSION_24
targetCompatibility = JavaVersion.VERSION_17
}
repositories {

View File

@ -1,3 +1,5 @@
@file:Suppress("DEPRECATION")
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
@ -6,7 +8,7 @@ import javax.xml.parsers.DocumentBuilderFactory
class CheckLibVersionsPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.tasks.register("checkLibVersions") {
project.task("checkLibVersions") {
description =
"Find any 3rd party libraries which have released new versions to the central Maven repo since we last upgraded."
doLast {
@ -26,7 +28,7 @@ class CheckLibVersionsPlugin : Plugin<Project> {
try {
val dbf = DocumentBuilderFactory.newInstance()
val db = dbf.newDocumentBuilder()
val doc = db.parse(metaDataUrl)
val doc = db.parse(metaDataUrl);
val newest = doc.getElementsByTagName("latest").item(0).textContent
if (version != newest.toString()) {
println("UPGRADE {\"group\": \"$group\", \"name\": \"$name\", \"current\": \"$version\", \"latest\": \"$newest\"}")

4
client/Cargo.lock generated
View File

@ -119,9 +119,9 @@ checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394"
[[package]]
name = "bytes"
version = "1.11.1"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
[[package]]
name = "cc"

View File

@ -45,9 +45,6 @@
<content_attribute id="social-chat">intense</content_attribute>
</content_rating>
<releases>
<release version="0.13.23" date="2026-01-24">
<url type="details">https://github.com/AsamK/signal-cli/releases/tag/v0.13.23</url>
</release>
<release version="0.13.22" date="2025-11-14">
<url type="details">https://github.com/AsamK/signal-cli/releases/tag/v0.13.22</url>
</release>

View File

@ -121,7 +121,7 @@
},
{
"name":"org.signal.libsignal.net.ChatConnection$ListenerBridge",
"methods":[{"name":"connectionInterrupted","parameterTypes":["java.lang.Throwable"] }, {"name":"onConnectionInterrupted","parameterTypes":["java.lang.Throwable"] }, {"name":"onIncomingMessage","parameterTypes":["byte[]","long","long"] }, {"name":"onQueueEmpty","parameterTypes":[] }, {"name":"onReceivedAlerts","parameterTypes":["java.lang.String[]"] }, {"name":"receivedAlerts","parameterTypes":["java.lang.String[]"] }, {"name":"receivedIncomingMessage","parameterTypes":["byte[]","long","long"] }, {"name":"receivedQueueEmpty","parameterTypes":[] }]
"methods":[{"name":"onConnectionInterrupted","parameterTypes":["java.lang.Throwable"] }, {"name":"onIncomingMessage","parameterTypes":["byte[]","long","long"] }, {"name":"onQueueEmpty","parameterTypes":[] }, {"name":"onReceivedAlerts","parameterTypes":["java.lang.String[]"] }]
},
{
"name":"org.signal.libsignal.net.ChatConnection$Response",
@ -139,14 +139,6 @@
{
"name":"org.signal.libsignal.net.ChatService$ResponseAndDebugInfo"
},
{
"name":"org.signal.libsignal.net.ChatServiceException",
"methods":[{"name":"<init>","parameterTypes":["java.lang.String"] }]
},
{
"name":"org.signal.libsignal.net.ChatServiceInactiveException",
"methods":[{"name":"<init>","parameterTypes":["java.lang.String"] }]
},
{
"name":"org.signal.libsignal.net.DeviceDeregisteredException",
"methods":[{"name":"<init>","parameterTypes":["java.lang.String"] }]
@ -159,10 +151,6 @@
"name":"org.signal.libsignal.net.RetryLaterException",
"methods":[{"name":"<init>","parameterTypes":["long"] }]
},
{
"name":"org.signal.libsignal.net.TransportFailureException",
"methods":[{"name":"<init>","parameterTypes":["java.lang.String"] }]
},
{
"name":"org.signal.libsignal.net.internal.BridgeChatListener"
},

View File

@ -1 +1,26 @@
[{"interfaces":["java.sql.Connection"]},{"interfaces":["org.asamk.Signal"]},{"interfaces":["org.asamk.Signal$Configuration"]},{"interfaces":["org.asamk.Signal$Device"]},{"interfaces":["org.asamk.Signal$Group"]},{"interfaces":["org.asamk.Signal$Identity"]},{"interfaces":["org.asamk.SignalControl"]},{"interfaces":["org.freedesktop.dbus.interfaces.DBus"]}]
[
{
"interfaces":["java.sql.Connection"]
},
{
"interfaces":["org.asamk.Signal"]
},
{
"interfaces":["org.asamk.Signal$Configuration"]
},
{
"interfaces":["org.asamk.Signal$Device"]
},
{
"interfaces":["org.asamk.Signal$Group"]
},
{
"interfaces":["org.asamk.Signal$Identity"]
},
{
"interfaces":["org.asamk.SignalControl"]
},
{
"interfaces":["org.freedesktop.dbus.interfaces.DBus"]
}
]

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,18 +1,18 @@
[versions]
slf4j = "2.0.17"
junit = "6.0.2"
junit = "6.0.1"
[libraries]
bouncycastle = "org.bouncycastle:bcprov-jdk18on:1.83"
bouncycastle = "org.bouncycastle:bcprov-jdk18on:1.82"
jackson-databind = "com.fasterxml.jackson.core:jackson-databind:2.20.1"
argparse4j = "net.sourceforge.argparse4j:argparse4j:0.9.0"
dbusjava = "com.github.hypfvieh:dbus-java-transport-native-unixsocket:5.0.0"
slf4j-api = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" }
slf4j-jul = { module = "org.slf4j:jul-to-slf4j", version.ref = "slf4j" }
logback = "ch.qos.logback:logback-classic:1.5.25"
logback = "ch.qos.logback:logback-classic:1.5.21"
signalservice = "com.github.turasa:signal-service-java:2.15.3_unofficial_136"
sqlite = "org.xerial:sqlite-jdbc:3.51.1.0"
signalservice = "com.github.turasa:signal-service-java:2.15.3_unofficial_134"
sqlite = "org.xerial:sqlite-jdbc:3.51.0.0"
hikari = "com.zaxxer:HikariCP:7.0.2"
junit-jupiter-bom = { module = "org.junit:junit-bom", version.ref = "junit" }
junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit" }

Binary file not shown.

View File

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.0-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.0-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

View File

@ -4,13 +4,11 @@ plugins {
}
java {
sourceCompatibility = JavaVersion.VERSION_25
targetCompatibility = JavaVersion.VERSION_25
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
if (!JavaVersion.current().isCompatibleWith(targetCompatibility)) {
toolchain {
languageVersion.set(JavaLanguageVersion.of(targetCompatibility.majorVersion))
}
toolchain {
languageVersion.set(JavaLanguageVersion.of(21))
}
}

View File

@ -154,8 +154,6 @@ public interface Manager extends Closeable {
List<Device> getLinkedDevices() throws IOException;
void updateLinkedDevice(int deviceId, String name) throws IOException, NotPrimaryDeviceException;
void removeLinkedDevices(int deviceId) throws IOException, NotPrimaryDeviceException;
void addDeviceLink(DeviceLinkUrl linkUri) throws IOException, InvalidDeviceLinkException, NotPrimaryDeviceException, DeviceLimitExceededException;
@ -273,7 +271,7 @@ public interface Manager extends Closeable {
final String nickGivenName,
final String nickFamilyName,
final String note
) throws UnregisteredRecipientException;
) throws NotPrimaryDeviceException, UnregisteredRecipientException;
void setContactsBlocked(
Collection<RecipientIdentifier.Single> recipient,

View File

@ -64,7 +64,7 @@ public class SignalAccountFiles {
return accountsStore.getAllNumbers();
}
public MultiAccountManager initMultiAccountManager() throws IOException {
public MultiAccountManager initMultiAccountManager() throws IOException, AccountCheckException {
final var managerPairs = accountsStore.getAllAccounts().parallelStream().map(a -> {
try {
return new Pair<Manager, Throwable>(initManager(a.number(), a.path()), null);
@ -80,13 +80,12 @@ public class SignalAccountFiles {
for (final var pair : managerPairs) {
if (pair.second() instanceof IOException e) {
throw e;
} else if (pair.second() instanceof AccountCheckException e) {
throw e;
}
}
final var managers = managerPairs.stream()
.filter(p -> p != null && p.first() != null)
.map(Pair::first)
.toList();
final var managers = managerPairs.stream().map(Pair::first).toList();
return new MultiAccountManagerImpl(managers, this);
}
@ -133,7 +132,7 @@ public class SignalAccountFiles {
manager.checkAccountState();
} catch (DeprecatedVersionException e) {
manager.close();
throw new IOException("signal-cli version is too old for the Signal-Server, please update.");
throw new AccountCheckException("signal-cli version is too old for the Signal-Server, please update.");
} catch (IOException e) {
manager.close();
throw new AccountCheckException("Error while checking account " + number + ": " + e.getMessage(), e);

View File

@ -2,7 +2,7 @@ package org.asamk.signal.manager.actions;
import org.asamk.signal.manager.helper.Context;
import org.asamk.signal.manager.storage.recipients.RecipientId;
import org.signal.core.models.ServiceId;
import org.whispersystems.signalservice.api.push.ServiceId;
public class RenewSessionAction implements HandleAction {

View File

@ -1,20 +0,0 @@
package org.asamk.signal.manager.actions;
import org.asamk.signal.manager.helper.Context;
public class RetrieveDeviceNameAction implements HandleAction {
private static final RetrieveDeviceNameAction INSTANCE = new RetrieveDeviceNameAction();
public static RetrieveDeviceNameAction create() {
return INSTANCE;
}
private RetrieveDeviceNameAction() {
}
@Override
public void execute(Context context) throws Throwable {
context.getAccountHelper().refreshDeviceName();
}
}

View File

@ -4,8 +4,8 @@ import org.asamk.signal.manager.groups.GroupLinkPassword;
import org.signal.core.util.Base64;
import org.signal.libsignal.zkgroup.InvalidInputException;
import org.signal.libsignal.zkgroup.groups.GroupMasterKey;
import org.signal.storageservice.storage.protos.groups.GroupInviteLink;
import org.signal.storageservice.storage.protos.groups.local.DecryptedGroup;
import org.signal.storageservice.protos.groups.GroupInviteLink;
import org.signal.storageservice.protos.groups.local.DecryptedGroup;
import java.io.IOException;
import java.net.URI;
@ -52,8 +52,8 @@ public final class GroupInviteLinkUrl {
var bytes = Base64.decode(encoding);
GroupInviteLink groupInviteLink = GroupInviteLink.ADAPTER.decode(bytes);
if (groupInviteLink.contentsV1 != null) {
var groupInviteLinkContentsV1 = groupInviteLink.contentsV1;
if (groupInviteLink.v1Contents != null) {
var groupInviteLinkContentsV1 = groupInviteLink.v1Contents;
var groupMasterKey = new GroupMasterKey(groupInviteLinkContentsV1.groupMasterKey.toByteArray());
var password = GroupLinkPassword.fromBytes(groupInviteLinkContentsV1.inviteLinkPassword.toByteArray());
@ -90,7 +90,7 @@ public final class GroupInviteLinkUrl {
}
private static String createUrl(GroupMasterKey groupMasterKey, GroupLinkPassword password) {
var groupInviteLink = new GroupInviteLink.Builder().contentsV1(new GroupInviteLink.GroupInviteLinkContentsV1.Builder().groupMasterKey(
var groupInviteLink = new GroupInviteLink.Builder().v1Contents(new GroupInviteLink.GroupInviteLinkContentsV1.Builder().groupMasterKey(
ByteString.of(groupMasterKey.serialize()))
.inviteLinkPassword(ByteString.of(password.serialize()))
.build()).build();

View File

@ -3,7 +3,6 @@ package org.asamk.signal.manager.api;
import org.asamk.signal.manager.groups.GroupUtils;
import org.asamk.signal.manager.helper.RecipientAddressResolver;
import org.asamk.signal.manager.storage.recipients.RecipientResolver;
import org.signal.core.models.ServiceId;
import org.signal.libsignal.metadata.ProtocolException;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer;
@ -33,6 +32,7 @@ import org.whispersystems.signalservice.api.messages.multidevice.SentTranscriptM
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
import org.whispersystems.signalservice.api.messages.multidevice.ViewOnceOpenMessage;
import org.whispersystems.signalservice.api.messages.multidevice.ViewedMessage;
import org.whispersystems.signalservice.api.push.ServiceId;
import java.io.File;
import java.io.IOException;

View File

@ -1,6 +1,6 @@
package org.asamk.signal.manager.api;
import org.signal.core.util.UuidUtil;
import org.whispersystems.signalservice.api.util.UuidUtil;
import java.util.Optional;
import java.util.UUID;

View File

@ -1,9 +1,9 @@
package org.asamk.signal.manager.api;
import org.asamk.signal.manager.util.PhoneNumberFormatter;
import org.signal.core.util.UuidUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.util.UuidUtil;
import java.util.UUID;
@ -24,13 +24,13 @@ public sealed interface RecipientIdentifier {
sealed interface Single extends RecipientIdentifier {
static Single fromString(String identifier, String localNumber) throws InvalidNumberException {
if (UuidUtil.INSTANCE.isUuid(identifier)) {
if (UuidUtil.isUuid(identifier)) {
return new Uuid(UUID.fromString(identifier));
}
if (identifier.startsWith("PNI:")) {
final var pni = identifier.substring(4);
if (!UuidUtil.INSTANCE.isUuid(pni)) {
if (!UuidUtil.isUuid(pni)) {
throw new InvalidNumberException("Invalid PNI");
}
return new Pni(UUID.fromString(pni));

View File

@ -1,6 +1,6 @@
package org.asamk.signal.manager.api;
import org.signal.core.util.Hex;
import org.whispersystems.signalservice.internal.util.Hex;
import java.util.Arrays;

View File

@ -1,7 +1,7 @@
package org.asamk.signal.manager.api;
import org.asamk.signal.manager.util.Utils;
import org.signal.core.util.Hex;
import org.whispersystems.signalservice.internal.util.Hex;
import java.io.IOException;
import java.net.URI;

View File

@ -1,8 +1,8 @@
package org.asamk.signal.manager.api;
import org.signal.core.util.Base64;
import org.signal.core.util.UuidUtil;
import org.whispersystems.signalservice.api.push.UsernameLinkComponents;
import org.whispersystems.signalservice.api.util.UuidUtil;
import java.io.IOException;
import java.util.Arrays;
@ -36,7 +36,7 @@ public final class UsernameLinkUrl {
final var entropy = Arrays.copyOfRange(allBytes, 0, 32);
final var serverId = Arrays.copyOfRange(allBytes, 32, allBytes.length);
final var serverIdUuid = UuidUtil.INSTANCE.parseOrNull(serverId);
final var serverIdUuid = UuidUtil.parseOrNull(serverId);
if (serverIdUuid == null) {
throw new InvalidUsernameLinkException("Invalid serverId");
}

View File

@ -1,6 +1,6 @@
package org.asamk.signal.manager.helper;
import org.signal.core.models.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
public interface AccountFileUpdater {

View File

@ -14,8 +14,6 @@ import org.asamk.signal.manager.storage.SignalAccount;
import org.asamk.signal.manager.util.KeyUtils;
import org.asamk.signal.manager.util.NumberVerificationUtils;
import org.asamk.signal.manager.util.Utils;
import org.signal.core.models.ServiceId.ACI;
import org.signal.core.models.ServiceId.PNI;
import org.signal.core.util.Base64;
import org.signal.libsignal.protocol.IdentityKeyPair;
import org.signal.libsignal.protocol.InvalidKeyException;
@ -30,6 +28,8 @@ import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.account.ChangePhoneNumberRequest;
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
import org.whispersystems.signalservice.api.link.LinkedDeviceVerificationCodeResponse;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceId.PNI;
import org.whispersystems.signalservice.api.push.ServiceIdType;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.push.SignedPreKeyEntity;
@ -82,9 +82,16 @@ public class AccountHelper {
}
public void checkAccountState() throws IOException {
if (account.getAci() == null) {
account.setRegistered(false);
throw new IOException("Account without ACI");
if (account.getLastReceiveTimestamp() == 0) {
logger.info("The Signal protocol expects that incoming messages are regularly received.");
} else {
var diffInMilliseconds = System.currentTimeMillis() - account.getLastReceiveTimestamp();
long days = TimeUnit.DAYS.convert(diffInMilliseconds, TimeUnit.MILLISECONDS);
if (days > 7) {
logger.warn(
"Messages have been last received {} days ago. The Signal protocol expects that incoming messages are regularly received.",
days);
}
}
try {
updateAccountAttributes();
@ -93,7 +100,7 @@ public class AccountHelper {
} else {
context.getPreKeyHelper().refreshPreKeysIfNecessary();
}
if (account.getPni() == null) {
if (account.getAci() == null || account.getPni() == null) {
checkWhoAmiI();
}
if (!account.isPrimaryDevice() && account.getPniIdentityKeyPair() == null) {
@ -118,17 +125,6 @@ public class AccountHelper {
account.setRegistered(false);
throw e;
}
if (account.getLastReceiveTimestamp() == 0) {
logger.info("The Signal protocol expects that incoming messages are regularly received.");
} else {
var diffInMilliseconds = System.currentTimeMillis() - account.getLastReceiveTimestamp();
long days = TimeUnit.DAYS.convert(diffInMilliseconds, TimeUnit.MILLISECONDS);
if (days > 7) {
logger.warn(
"Messages have been last received {} days ago. The Signal protocol expects that incoming messages are regularly received.",
days);
}
}
}
public void checkWhoAmiI() throws IOException {
@ -315,7 +311,6 @@ public class AccountHelper {
Utils.mapKeys(pniRegistrationIds, Object::toString))));
});
account.clearSessionId();
final var updatePni = PNI.parseOrThrow(result.first().getPni());
if (updatePni.equals(account.getPni())) {
logger.debug("PNI is unchanged after change number");
@ -522,22 +517,6 @@ public class AccountHelper {
account.setEncryptedDeviceName(encryptedDeviceName);
}
public void setDeviceName(int deviceId, String deviceName) throws IOException {
final var privateKey = account.getAciIdentityKeyPair().getPrivateKey();
final var encryptedDeviceName = DeviceNameUtil.encryptDeviceName(deviceName, privateKey);
handleResponseException(dependencies.getLinkDeviceApi().setDeviceName(encryptedDeviceName, deviceId));
context.getSyncHelper().sendDeviceNameChange(deviceId);
}
public void refreshDeviceName() throws IOException {
final var devices = handleResponseException(dependencies.getLinkDeviceApi().getDevices());
final var deviceId = account.getDeviceId();
final var device = devices.stream().filter(d -> d.id == deviceId).findFirst();
if (device.isPresent()) {
account.setEncryptedDeviceName(device.get().name);
}
}
public void updateAccountAttributes() throws IOException {
handleResponseException(dependencies.getAccountApi().setAccountAttributes(account.getAccountAttributes(null)));
}

View File

@ -28,16 +28,15 @@ import org.asamk.signal.manager.storage.recipients.RecipientId;
import org.asamk.signal.manager.util.AttachmentUtils;
import org.asamk.signal.manager.util.IOUtils;
import org.asamk.signal.manager.util.Utils;
import org.signal.core.models.ServiceId;
import org.signal.libsignal.zkgroup.InvalidInputException;
import org.signal.libsignal.zkgroup.groups.GroupMasterKey;
import org.signal.libsignal.zkgroup.groups.GroupSecretParams;
import org.signal.libsignal.zkgroup.groupsend.GroupSendEndorsementsResponse;
import org.signal.libsignal.zkgroup.profiles.ProfileKey;
import org.signal.storageservice.storage.protos.groups.GroupChangeResponse;
import org.signal.storageservice.storage.protos.groups.local.DecryptedGroup;
import org.signal.storageservice.storage.protos.groups.local.DecryptedGroupChange;
import org.signal.storageservice.storage.protos.groups.local.DecryptedGroupJoinInfo;
import org.signal.storageservice.protos.groups.GroupChangeResponse;
import org.signal.storageservice.protos.groups.local.DecryptedGroup;
import org.signal.storageservice.protos.groups.local.DecryptedGroupChange;
import org.signal.storageservice.protos.groups.local.DecryptedGroupJoinInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupChangeLog;
@ -48,6 +47,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentStre
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
import org.whispersystems.signalservice.api.messages.SignalServiceGroupV2;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.exceptions.ConflictException;
import java.io.IOException;
@ -192,9 +192,9 @@ public class GroupHelper {
final GroupInfoV2 groupInfoV2,
final GroupChangeResponse groupChangeResponse
) {
if (groupChangeResponse.group_send_endorsements_response.size() > 0) {
if (groupChangeResponse.groupSendEndorsementsResponse.size() > 0) {
try {
final var groupSendEndorsementsResponse = new GroupSendEndorsementsResponse(groupChangeResponse.group_send_endorsements_response.toByteArray());
final var groupSendEndorsementsResponse = new GroupSendEndorsementsResponse(groupChangeResponse.groupSendEndorsementsResponse.toByteArray());
updateGroupEndorsements(groupInfoV2.getGroupId(),
groupInfoV2.getMasterKey(),
@ -391,7 +391,7 @@ public class GroupHelper {
.joinGroup(inviteLinkUrl.getGroupMasterKey(), inviteLinkUrl.getPassword(), groupJoinInfo);
final var group = getOrMigrateGroup(inviteLinkUrl.getGroupMasterKey(),
groupJoinInfo.revision + 1,
changeResponse.group_change == null ? null : changeResponse.group_change.encode());
changeResponse.groupChange == null ? null : changeResponse.groupChange.encode());
if (group.getGroup() == null) {
// Only requested member, can't send update to group members
@ -873,10 +873,10 @@ public class GroupHelper {
final var groupChangeResponse = groupGroupChangePair.second();
handleGroupChangeResponse(groupInfoV2, groupChangeResponse);
if (groupChangeResponse.group_change == null) {
if (groupChangeResponse.groupChange == null) {
throw new AssertionError("groupChange is null");
}
var messageBuilder = getGroupUpdateMessageBuilder(groupInfoV2, groupChangeResponse.group_change.encode());
var messageBuilder = getGroupUpdateMessageBuilder(groupInfoV2, groupChangeResponse.groupChange.encode());
return sendGroupMessage(messageBuilder,
groupInfoV2.getMembersIncludingPendingWithout(account.getSelfRecipientId()),
groupInfoV2);
@ -924,10 +924,10 @@ public class GroupHelper {
members.addAll(group.getMembersIncludingPendingWithout(selfRecipientId));
account.getGroupStore().updateGroup(group);
if (groupChangeResponse.group_change == null) {
if (groupChangeResponse.groupChange == null) {
throw new AssertionError("groupChange is null");
}
final var messageBuilder = getGroupUpdateMessageBuilder(group, groupChangeResponse.group_change.encode());
final var messageBuilder = getGroupUpdateMessageBuilder(group, groupChangeResponse.groupChange.encode());
return sendGroupMessage(messageBuilder, members, group);
}

View File

@ -10,10 +10,6 @@ import org.asamk.signal.manager.internal.SignalDependencies;
import org.asamk.signal.manager.storage.groups.GroupInfoV2;
import org.asamk.signal.manager.storage.recipients.RecipientId;
import org.asamk.signal.manager.util.Utils;
import org.signal.core.models.ServiceId;
import org.signal.core.models.ServiceId.ACI;
import org.signal.core.models.ServiceId.PNI;
import org.signal.core.util.UuidUtil;
import org.signal.libsignal.zkgroup.InvalidInputException;
import org.signal.libsignal.zkgroup.VerificationFailedException;
import org.signal.libsignal.zkgroup.auth.AuthCredentialWithPniResponse;
@ -21,15 +17,15 @@ import org.signal.libsignal.zkgroup.groups.GroupMasterKey;
import org.signal.libsignal.zkgroup.groups.GroupSecretParams;
import org.signal.libsignal.zkgroup.groups.UuidCiphertext;
import org.signal.libsignal.zkgroup.profiles.ProfileKey;
import org.signal.storageservice.storage.protos.groups.AccessControl;
import org.signal.storageservice.storage.protos.groups.GroupChange;
import org.signal.storageservice.storage.protos.groups.GroupChangeResponse;
import org.signal.storageservice.storage.protos.groups.Member;
import org.signal.storageservice.storage.protos.groups.local.DecryptedGroup;
import org.signal.storageservice.storage.protos.groups.local.DecryptedGroupChange;
import org.signal.storageservice.storage.protos.groups.local.DecryptedGroupJoinInfo;
import org.signal.storageservice.storage.protos.groups.local.DecryptedMember;
import org.signal.storageservice.storage.protos.groups.local.DecryptedPendingMember;
import org.signal.storageservice.protos.groups.AccessControl;
import org.signal.storageservice.protos.groups.GroupChange;
import org.signal.storageservice.protos.groups.GroupChangeResponse;
import org.signal.storageservice.protos.groups.Member;
import org.signal.storageservice.protos.groups.local.DecryptedGroup;
import org.signal.storageservice.protos.groups.local.DecryptedGroupChange;
import org.signal.storageservice.protos.groups.local.DecryptedGroupJoinInfo;
import org.signal.storageservice.protos.groups.local.DecryptedMember;
import org.signal.storageservice.protos.groups.local.DecryptedPendingMember;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.groupsv2.DecryptChangeVerificationMode;
@ -42,8 +38,12 @@ import org.whispersystems.signalservice.api.groupsv2.GroupsV2AuthorizationString
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations;
import org.whispersystems.signalservice.api.groupsv2.InvalidGroupStateException;
import org.whispersystems.signalservice.api.groupsv2.NotAbleToApplyGroupV2ChangeException;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceId.PNI;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException;
import org.whispersystems.signalservice.api.util.UuidUtil;
import org.whispersystems.signalservice.internal.push.exceptions.NotInGroupException;
import java.io.IOException;
@ -225,7 +225,7 @@ class GroupV2Helper {
change.modifyAvatar(new GroupChange.Actions.ModifyAvatarAction.Builder().avatar(avatarCdnKey).build());
}
change.sourceUserId(getSelfAci().toByteString());
change.sourceServiceId(getSelfAci().toByteString());
return commitChange(groupInfoV2, change);
}
@ -252,7 +252,7 @@ class GroupV2Helper {
final var aci = getSelfAci();
final var change = groupOperations.createModifyGroupMembershipChange(candidates, bannedUuids, aci);
change.sourceUserId(getSelfAci().toByteString());
change.sourceServiceId(getSelfAci().toByteString());
return commitChange(groupInfoV2, change);
}
@ -343,7 +343,7 @@ class GroupV2Helper {
false,
groupInfoV2.getGroup().bannedMembers);
change.sourceUserId(getSelfAci().toByteString());
change.sourceServiceId(getSelfAci().toByteString());
return commitChange(groupInfoV2, change);
}
@ -360,7 +360,7 @@ class GroupV2Helper {
final var change = groupOperations.createUnbanServiceIdsChange(serviceIds);
change.sourceUserId(getSelfAci().toByteString());
change.sourceServiceId(getSelfAci().toByteString());
return commitChange(groupInfoV2, change);
}
@ -436,7 +436,7 @@ class GroupV2Helper {
final GroupsV2Operations.GroupOperations groupOperations = getGroupOperations(groupInfoV2);
final var change = groupOperations.createUpdateProfileKeyCredentialChange(profileKeyCredential);
change.sourceUserId(getSelfAci().toByteString());
change.sourceServiceId(getSelfAci().toByteString());
return commitChange(groupInfoV2, change);
}
@ -459,7 +459,7 @@ class GroupV2Helper {
? groupOperations.createGroupJoinRequest(profileKeyCredential)
: groupOperations.createGroupJoinDirect(profileKeyCredential);
change.sourceUserId(context.getRecipientHelper()
change.sourceServiceId(context.getRecipientHelper()
.resolveSignalServiceAddress(selfRecipientId)
.getServiceId()
.toByteString());
@ -479,7 +479,7 @@ class GroupV2Helper {
final var change = groupOperations.createAcceptInviteChange(profileKeyCredential);
final var aci = context.getRecipientHelper().resolveSignalServiceAddress(selfRecipientId).getServiceId();
change.sourceUserId(aci.toByteString());
change.sourceServiceId(aci.toByteString());
return commitChange(groupInfoV2, change);
}
@ -585,7 +585,7 @@ class GroupV2Helper {
final var groupOperations = dependencies.getGroupsV2Operations().forGroup(groupSecretParams);
final var previousGroupState = groupInfoV2.getGroup();
final var nextRevision = previousGroupState.revision + 1;
final var changeActions = change.version(nextRevision).build();
final var changeActions = change.revision(nextRevision).build();
final DecryptedGroupChange decryptedChange;
final DecryptedGroup decryptedGroupState;
@ -611,7 +611,7 @@ class GroupV2Helper {
GroupLinkPassword password
) throws IOException {
final var nextRevision = currentRevision + 1;
final var changeActions = change.version(nextRevision).build();
final var changeActions = change.revision(nextRevision).build();
return dependencies.getGroupsV2Api()
.patchGroup(changeActions,
@ -621,9 +621,6 @@ class GroupV2Helper {
Pair<ServiceId, ProfileKey> getAuthoritativeProfileKeyFromChange(final DecryptedGroupChange change) {
UUID editor = UuidUtil.fromByteStringOrNull(change.editorServiceIdBytes);
if (editor == null) {
return null;
}
final var editorProfileKeyBytes = Stream.concat(Stream.of(change.newMembers.stream(),
change.promotePendingMembers.stream(),
change.modifiedProfileKeys.stream())

View File

@ -4,7 +4,6 @@ import org.asamk.signal.manager.api.TrustLevel;
import org.asamk.signal.manager.storage.SignalAccount;
import org.asamk.signal.manager.storage.recipients.RecipientId;
import org.asamk.signal.manager.util.Utils;
import org.signal.core.models.ServiceId;
import org.signal.libsignal.protocol.IdentityKey;
import org.signal.libsignal.protocol.fingerprint.Fingerprint;
import org.signal.libsignal.protocol.fingerprint.FingerprintParsingException;
@ -13,6 +12,7 @@ import org.signal.libsignal.protocol.fingerprint.ScannableFingerprint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.messages.SendMessageResult;
import org.whispersystems.signalservice.api.push.ServiceId;
import java.util.Arrays;
import java.util.function.BiFunction;

View File

@ -5,7 +5,6 @@ import org.asamk.signal.manager.actions.HandleAction;
import org.asamk.signal.manager.actions.RefreshPreKeysAction;
import org.asamk.signal.manager.actions.RenewSessionAction;
import org.asamk.signal.manager.actions.ResendMessageAction;
import org.asamk.signal.manager.actions.RetrieveDeviceNameAction;
import org.asamk.signal.manager.actions.RetrieveProfileAction;
import org.asamk.signal.manager.actions.SendGroupInfoAction;
import org.asamk.signal.manager.actions.SendGroupInfoRequestAction;
@ -35,8 +34,6 @@ import org.asamk.signal.manager.storage.groups.GroupInfoV1;
import org.asamk.signal.manager.storage.recipients.RecipientAddress;
import org.asamk.signal.manager.storage.recipients.RecipientId;
import org.asamk.signal.manager.storage.stickers.StickerPack;
import org.signal.core.models.ServiceId;
import org.signal.core.models.ServiceId.ACI;
import org.signal.libsignal.metadata.ProtocolInvalidKeyException;
import org.signal.libsignal.metadata.ProtocolInvalidKeyIdException;
import org.signal.libsignal.metadata.ProtocolInvalidMessageException;
@ -65,6 +62,8 @@ import org.whispersystems.signalservice.api.messages.SignalServiceReceiptMessage
import org.whispersystems.signalservice.api.messages.SignalServiceStoryMessage;
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
import org.whispersystems.signalservice.api.messages.multidevice.StickerPackOperationMessage;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceIdType;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.internal.push.Envelope;
@ -634,12 +633,6 @@ public final class IncomingMessageHandler {
context.getAccountHelper().handlePniChangeNumberMessage(pniChangeNumber, updatedPni);
}
}
if (syncMessage.getDeviceNameChange().isPresent()) {
final var deviceNameChange = syncMessage.getDeviceNameChange().get();
if (deviceNameChange.deviceId != null && deviceNameChange.deviceId == account.getDeviceId()) {
actions.add(RetrieveDeviceNameAction.create());
}
}
return actions;
}

View File

@ -1,9 +1,9 @@
package org.asamk.signal.manager.helper;
import org.asamk.signal.manager.api.IncorrectPinException;
import org.signal.core.models.MasterKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.kbs.MasterKey;
import org.whispersystems.signalservice.api.svr.SecureValueRecovery;
import org.whispersystems.signalservice.internal.push.AuthCredentials;
import org.whispersystems.signalservice.internal.push.LockedException;

View File

@ -9,11 +9,11 @@ import org.asamk.signal.manager.jobs.CleanOldPreKeysJob;
import org.asamk.signal.manager.storage.SignalAccount;
import org.asamk.signal.manager.storage.messageCache.CachedMessage;
import org.asamk.signal.manager.storage.recipients.RecipientAddress;
import org.signal.core.models.ServiceId;
import org.signal.core.models.ServiceId.ACI;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.websocket.SignalWebSocket;
import org.whispersystems.signalservice.api.websocket.WebSocketConnectionState;
import org.whispersystems.signalservice.api.websocket.WebSocketUnavailableException;

View File

@ -6,14 +6,14 @@ import org.asamk.signal.manager.api.UsernameLinkUrl;
import org.asamk.signal.manager.internal.SignalDependencies;
import org.asamk.signal.manager.storage.SignalAccount;
import org.asamk.signal.manager.storage.recipients.RecipientId;
import org.signal.core.models.ServiceId;
import org.signal.core.models.ServiceId.ACI;
import org.signal.core.models.ServiceId.PNI;
import org.signal.libsignal.usernames.BaseUsernameException;
import org.signal.libsignal.usernames.Username;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.cds.CdsiV2Service;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceId.PNI;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.push.exceptions.CdsiInvalidArgumentException;
import org.whispersystems.signalservice.api.push.exceptions.CdsiInvalidTokenException;

View File

@ -15,7 +15,6 @@ import org.asamk.signal.manager.storage.groups.GroupInfo;
import org.asamk.signal.manager.storage.groups.GroupInfoV2;
import org.asamk.signal.manager.storage.recipients.RecipientId;
import org.asamk.signal.manager.storage.sendLog.MessageSendLogEntry;
import org.signal.core.models.ServiceId.ACI;
import org.signal.libsignal.protocol.InvalidKeyException;
import org.signal.libsignal.protocol.InvalidRegistrationIdException;
import org.signal.libsignal.protocol.NoSessionException;
@ -39,6 +38,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceTypingMessage;
import org.whispersystems.signalservice.api.messages.multidevice.SentTranscriptMessage;
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
import org.whispersystems.signalservice.api.push.DistributionId;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.push.exceptions.NotFoundException;
import org.whispersystems.signalservice.api.push.exceptions.ProofRequiredException;

View File

@ -7,10 +7,10 @@ import org.asamk.signal.manager.storage.SignalAccount;
import org.asamk.signal.manager.storage.stickerPacks.JsonStickerPack;
import org.asamk.signal.manager.storage.stickers.StickerPack;
import org.asamk.signal.manager.util.IOUtils;
import org.signal.core.util.Hex;
import org.signal.libsignal.protocol.InvalidMessageException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.internal.util.Hex;
import java.io.IOException;
import java.util.HashSet;

View File

@ -14,7 +14,6 @@ import org.asamk.signal.manager.syncStorage.StorageSyncModels;
import org.asamk.signal.manager.syncStorage.StorageSyncValidations;
import org.asamk.signal.manager.syncStorage.WriteOperationResult;
import org.asamk.signal.manager.util.KeyUtils;
import org.signal.core.models.storageservice.StorageKey;
import org.signal.core.util.SetUtil;
import org.signal.libsignal.protocol.InvalidKeyException;
import org.slf4j.Logger;
@ -24,6 +23,7 @@ import org.whispersystems.signalservice.api.storage.RecordIkm;
import org.whispersystems.signalservice.api.storage.SignalStorageManifest;
import org.whispersystems.signalservice.api.storage.SignalStorageRecord;
import org.whispersystems.signalservice.api.storage.StorageId;
import org.whispersystems.signalservice.api.storage.StorageKey;
import org.whispersystems.signalservice.api.storage.StorageRecordConvertersKt;
import org.whispersystems.signalservice.api.storage.StorageServiceRepository;
import org.whispersystems.signalservice.api.storage.StorageServiceRepository.ManifestIfDifferentVersionResult;

View File

@ -12,7 +12,6 @@ import org.asamk.signal.manager.storage.stickers.StickerPack;
import org.asamk.signal.manager.util.IOUtils;
import org.asamk.signal.manager.util.MimeUtils;
import org.jetbrains.annotations.NotNull;
import org.signal.core.models.ServiceId;
import org.signal.libsignal.protocol.IdentityKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -37,6 +36,7 @@ import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSy
import org.whispersystems.signalservice.api.messages.multidevice.StickerPackOperationMessage;
import org.whispersystems.signalservice.api.messages.multidevice.VerifiedMessage;
import org.whispersystems.signalservice.api.messages.multidevice.ViewedMessage;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.internal.push.SyncMessage;
@ -52,8 +52,6 @@ import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import okio.ByteString;
public class SyncHelper {
private static final Logger logger = LoggerFactory.getLogger(SyncHelper.class);
@ -408,11 +406,6 @@ public class SyncHelper {
return context.getSendHelper().sendSyncMessage(SignalServiceSyncMessage.forMessageRequestResponse(response));
}
public SendMessageResult sendDeviceNameChange(final int deviceId) {
final var deviceNameChange = new SyncMessage.DeviceNameChange(deviceId, ByteString.EMPTY);
return context.getSendHelper().sendSyncMessage(SignalServiceSyncMessage.forDeviceNameChange(deviceNameChange));
}
private SendMessageResult requestSyncData(final SyncMessage.Request.Type type) {
var r = new SyncMessage.Request.Builder().type(type).build();
var message = SignalServiceSyncMessage.forRequest(new RequestMessage(r));

View File

@ -2,7 +2,7 @@ package org.asamk.signal.manager.internal;
import org.asamk.signal.manager.helper.AccountFileUpdater;
import org.asamk.signal.manager.storage.accounts.AccountsStore;
import org.signal.core.models.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
public class AccountFileUpdaterImpl implements AccountFileUpdater {

View File

@ -20,7 +20,7 @@ public class JobExecutor implements AutoCloseable {
public JobExecutor(final Context context) {
this.context = context;
this.executorService = Executors.newVirtualThreadPerTaskExecutor();
this.executorService = Executors.newCachedThreadPool();
}
public void enqueueJob(Job job) {

View File

@ -91,11 +91,7 @@ import org.asamk.signal.manager.util.KeyUtils;
import org.asamk.signal.manager.util.MimeUtils;
import org.asamk.signal.manager.util.PhoneNumberFormatter;
import org.asamk.signal.manager.util.StickerUtils;
import org.signal.core.models.ServiceId;
import org.signal.core.models.ServiceId.ACI;
import org.signal.core.models.ServiceId.PNI;
import org.signal.core.util.Base64;
import org.signal.core.util.Hex;
import org.signal.libsignal.protocol.InvalidMessageException;
import org.signal.libsignal.usernames.BaseUsernameException;
import org.slf4j.Logger;
@ -106,12 +102,16 @@ import org.whispersystems.signalservice.api.messages.SignalServicePreview;
import org.whispersystems.signalservice.api.messages.SignalServiceReceiptMessage;
import org.whispersystems.signalservice.api.messages.SignalServiceTypingMessage;
import org.whispersystems.signalservice.api.messages.multidevice.DeviceInfo;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceId.PNI;
import org.whispersystems.signalservice.api.push.ServiceIdType;
import org.whispersystems.signalservice.api.push.exceptions.CdsiResourceExhaustedException;
import org.whispersystems.signalservice.api.push.exceptions.UsernameMalformedException;
import org.whispersystems.signalservice.api.push.exceptions.UsernameTakenException;
import org.whispersystems.signalservice.api.util.DeviceNameUtil;
import org.whispersystems.signalservice.api.util.StreamDetails;
import org.whispersystems.signalservice.internal.util.Hex;
import org.whispersystems.signalservice.internal.util.Util;
import java.io.ByteArrayInputStream;
@ -157,7 +157,7 @@ public class ManagerImpl implements Manager {
private final SignalDependencies dependencies;
private final Context context;
private final ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
private final ExecutorService executor = Executors.newCachedThreadPool();
private Thread receiveThread;
private boolean isReceivingSynchronous;
@ -487,21 +487,6 @@ public class ManagerImpl implements Manager {
}).toList();
}
@Override
public void updateLinkedDevice(
final int deviceId,
final String name
) throws IOException, NotPrimaryDeviceException {
if (deviceId == account.getDeviceId()) {
context.getAccountHelper().setDeviceName(name);
} else {
if (!account.isPrimaryDevice()) {
throw new NotPrimaryDeviceException();
}
context.getAccountHelper().setDeviceName(deviceId, name);
}
}
private Long getPlaintextCreatedAt(DeviceInfo d) {
final var DECRYPTION_INFO = "deviceCreatedAt";
var identityKey = account.getAciIdentityKeyPair().getPrivateKey();
@ -1153,7 +1138,10 @@ public class ManagerImpl implements Manager {
final String nickGivenName,
final String nickFamilyName,
final String note
) throws UnregisteredRecipientException {
) throws NotPrimaryDeviceException, UnregisteredRecipientException {
if (!account.isPrimaryDevice()) {
throw new NotPrimaryDeviceException();
}
context.getContactHelper()
.setContactName(context.getRecipientHelper().resolveRecipient(recipient),
givenName,

View File

@ -33,14 +33,14 @@ import org.asamk.signal.manager.helper.PinHelper;
import org.asamk.signal.manager.storage.SignalAccount;
import org.asamk.signal.manager.util.KeyUtils;
import org.asamk.signal.manager.util.NumberVerificationUtils;
import org.signal.core.models.MasterKey;
import org.signal.core.models.ServiceId.ACI;
import org.signal.core.models.ServiceId.PNI;
import org.signal.libsignal.usernames.BaseUsernameException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.account.PreKeyCollection;
import org.whispersystems.signalservice.api.kbs.MasterKey;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceId.PNI;
import org.whispersystems.signalservice.api.push.ServiceIdType;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.push.exceptions.AlreadyVerifiedException;

View File

@ -2,10 +2,10 @@ package org.asamk.signal.manager.jobs;
import org.asamk.signal.manager.api.StickerPackId;
import org.asamk.signal.manager.helper.Context;
import org.signal.core.util.Hex;
import org.signal.libsignal.protocol.InvalidMessageException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.internal.util.Hex;
import java.io.IOException;

View File

@ -16,11 +16,11 @@ import org.asamk.signal.manager.storage.senderKeys.SenderKeyRecordStore;
import org.asamk.signal.manager.storage.senderKeys.SenderKeySharedStore;
import org.asamk.signal.manager.storage.sessions.SessionStore;
import org.asamk.signal.manager.storage.stickers.StickerStore;
import org.signal.core.models.ServiceId;
import org.signal.core.models.ServiceId.ACI;
import org.signal.core.util.UuidUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.util.UuidUtil;
import java.io.File;
import java.sql.Connection;
@ -646,10 +646,9 @@ public class AccountDatabase extends Database {
try (final var preparedStatement = connection.prepareStatement(sql)) {
try (var result = Utils.executeQueryForStream(preparedStatement, (resultSet) -> {
final var pni = Optional.ofNullable(resultSet.getBytes("pni"))
.map(UuidUtil.INSTANCE::parseOrNull)
.map(UuidUtil::parseOrNull)
.map(ServiceId.PNI::from);
final var serviceIdUuid = Optional.ofNullable(resultSet.getBytes("uuid"))
.map(UuidUtil.INSTANCE::parseOrNull);
final var serviceIdUuid = Optional.ofNullable(resultSet.getBytes("uuid")).map(UuidUtil::parseOrNull);
final var serviceId = serviceIdUuid.isPresent() && pni.isPresent() && serviceIdUuid.get()
.equals(pni.get().getRawUuid())
? pni.<ServiceId>map(p -> p)

View File

@ -53,14 +53,6 @@ import org.asamk.signal.manager.storage.stickers.StickerStore;
import org.asamk.signal.manager.storage.threads.LegacyJsonThreadStore;
import org.asamk.signal.manager.util.IOUtils;
import org.asamk.signal.manager.util.KeyUtils;
import org.signal.core.models.AccountEntropyPool;
import org.signal.core.models.MasterKey;
import org.signal.core.models.ServiceId;
import org.signal.core.models.ServiceId.ACI;
import org.signal.core.models.ServiceId.PNI;
import org.signal.core.models.backup.MediaRootBackupKey;
import org.signal.core.models.storageservice.StorageKey;
import org.signal.core.util.UuidUtil;
import org.signal.libsignal.protocol.IdentityKeyPair;
import org.signal.libsignal.protocol.InvalidMessageException;
import org.signal.libsignal.protocol.SignalProtocolAddress;
@ -73,16 +65,24 @@ import org.signal.libsignal.zkgroup.InvalidInputException;
import org.signal.libsignal.zkgroup.profiles.ProfileKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.AccountEntropyPool;
import org.whispersystems.signalservice.api.SignalServiceAccountDataStore;
import org.whispersystems.signalservice.api.SignalServiceDataStore;
import org.whispersystems.signalservice.api.account.AccountAttributes;
import org.whispersystems.signalservice.api.account.PreKeyCollection;
import org.whispersystems.signalservice.api.backup.MediaRootBackupKey;
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccess;
import org.whispersystems.signalservice.api.kbs.MasterKey;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceId.PNI;
import org.whispersystems.signalservice.api.push.ServiceIdType;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.push.UsernameLinkComponents;
import org.whispersystems.signalservice.api.storage.SignalStorageManifest;
import org.whispersystems.signalservice.api.storage.StorageKey;
import org.whispersystems.signalservice.api.util.CredentialsProvider;
import org.whispersystems.signalservice.api.util.UuidUtil;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@ -376,7 +376,6 @@ public class SignalAccount implements Closeable {
trustSelfIdentity(ServiceIdType.ACI);
trustSelfIdentity(ServiceIdType.PNI);
getKeyValueStore().storeEntry(lastRecipientsRefresh, null);
clearSessionId();
}
public void initDatabase() {
@ -962,7 +961,7 @@ public class SignalAccount implements Closeable {
continue;
}
try {
if (UuidUtil.INSTANCE.isUuid(thread.id) || thread.id.startsWith("+")) {
if (UuidUtil.isUuid(thread.id) || thread.id.startsWith("+")) {
final var recipientId = getRecipientResolver().resolveRecipient(thread.id);
var contact = getContactStore().getContact(recipientId);
if (contact != null) {
@ -1486,12 +1485,6 @@ public class SignalAccount implements Closeable {
keyValueStore.storeEntry(verificationSessionId, sessionId);
}
public void clearSessionId() {
final var keyValueStore = getKeyValueStore();
keyValueStore.storeEntry(verificationSessionNumber, null);
keyValueStore.storeEntry(verificationSessionId, null);
}
public void setEncryptedDeviceName(final String encryptedDeviceName) {
this.encryptedDeviceName = encryptedDeviceName;
save();

View File

@ -10,11 +10,11 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.asamk.signal.manager.storage.recipients.RecipientAddress;
import org.signal.core.models.ServiceId;
import org.signal.core.util.UuidUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.ServiceIdType;
import org.whispersystems.signalservice.api.util.UuidUtil;
import java.io.InvalidObjectException;
import java.sql.PreparedStatement;
@ -57,7 +57,7 @@ public class Utils {
}
public static RecipientAddress getRecipientAddressFromLegacyIdentifier(final String identifier) {
if (UuidUtil.INSTANCE.isUuid(identifier)) {
if (UuidUtil.isUuid(identifier)) {
return new RecipientAddress(ServiceId.parseOrThrow(identifier));
} else {
return new RecipientAddress(Optional.empty(), Optional.of(identifier));

View File

@ -8,9 +8,9 @@ import org.asamk.signal.manager.api.ServiceEnvironment;
import org.asamk.signal.manager.storage.SignalAccount;
import org.asamk.signal.manager.storage.Utils;
import org.asamk.signal.manager.util.IOUtils;
import org.signal.core.models.ServiceId.ACI;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

View File

@ -4,7 +4,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.asamk.signal.manager.storage.recipients.RecipientAddress;
import org.signal.core.models.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import java.util.UUID;

View File

@ -6,13 +6,13 @@ import org.asamk.signal.manager.api.GroupPermission;
import org.asamk.signal.manager.storage.recipients.RecipientAddress;
import org.asamk.signal.manager.storage.recipients.RecipientId;
import org.asamk.signal.manager.storage.recipients.RecipientResolver;
import org.signal.core.models.ServiceId;
import org.signal.libsignal.zkgroup.groups.GroupMasterKey;
import org.signal.storageservice.storage.protos.groups.AccessControl;
import org.signal.storageservice.storage.protos.groups.Member;
import org.signal.storageservice.storage.protos.groups.local.DecryptedGroup;
import org.signal.storageservice.storage.protos.groups.local.EnabledState;
import org.signal.storageservice.protos.groups.AccessControl;
import org.signal.storageservice.protos.groups.Member;
import org.signal.storageservice.protos.groups.local.DecryptedGroup;
import org.signal.storageservice.protos.groups.local.EnabledState;
import org.whispersystems.signalservice.api.push.DistributionId;
import org.whispersystems.signalservice.api.push.ServiceId;
import java.util.Set;
import java.util.stream.Collectors;

View File

@ -11,16 +11,16 @@ import org.asamk.signal.manager.storage.recipients.RecipientId;
import org.asamk.signal.manager.storage.recipients.RecipientIdCreator;
import org.asamk.signal.manager.storage.recipients.RecipientResolver;
import org.asamk.signal.manager.util.KeyUtils;
import org.signal.core.util.UuidUtil;
import org.signal.libsignal.zkgroup.InvalidInputException;
import org.signal.libsignal.zkgroup.groups.GroupMasterKey;
import org.signal.libsignal.zkgroup.groups.GroupSecretParams;
import org.signal.libsignal.zkgroup.groupsend.GroupSendEndorsement;
import org.signal.storageservice.storage.protos.groups.local.DecryptedGroup;
import org.signal.storageservice.protos.groups.local.DecryptedGroup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.push.DistributionId;
import org.whispersystems.signalservice.api.storage.StorageId;
import org.whispersystems.signalservice.api.util.UuidUtil;
import java.io.IOException;
import java.sql.Connection;

View File

@ -12,14 +12,14 @@ import org.asamk.signal.manager.api.GroupIdV1;
import org.asamk.signal.manager.api.GroupIdV2;
import org.asamk.signal.manager.storage.recipients.RecipientAddress;
import org.asamk.signal.manager.storage.recipients.RecipientResolver;
import org.signal.core.models.ServiceId;
import org.signal.core.util.Hex;
import org.signal.libsignal.zkgroup.InvalidInputException;
import org.signal.libsignal.zkgroup.groups.GroupMasterKey;
import org.signal.storageservice.storage.protos.groups.local.DecryptedGroup;
import org.signal.storageservice.protos.groups.local.DecryptedGroup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.push.DistributionId;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.internal.util.Hex;
import java.io.File;
import java.io.FileInputStream;

View File

@ -1,8 +1,8 @@
package org.asamk.signal.manager.storage.identities;
import org.asamk.signal.manager.api.TrustLevel;
import org.signal.core.models.ServiceId;
import org.signal.libsignal.protocol.IdentityKey;
import org.whispersystems.signalservice.api.push.ServiceId;
public class IdentityInfo {

View File

@ -5,13 +5,13 @@ import org.asamk.signal.manager.api.TrustNewIdentity;
import org.asamk.signal.manager.storage.Database;
import org.asamk.signal.manager.storage.Utils;
import org.asamk.signal.manager.storage.recipients.RecipientStore;
import org.signal.core.models.ServiceId;
import org.signal.libsignal.protocol.IdentityKey;
import org.signal.libsignal.protocol.InvalidKeyException;
import org.signal.libsignal.protocol.state.IdentityKeyStore.Direction;
import org.signal.libsignal.protocol.state.IdentityKeyStore.IdentityChange;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.push.ServiceId;
import java.sql.Connection;
import java.sql.ResultSet;

View File

@ -9,9 +9,9 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import org.asamk.signal.manager.storage.recipients.RecipientAddress;
import org.signal.core.models.ServiceId;
import org.signal.libsignal.zkgroup.InvalidInputException;
import org.signal.libsignal.zkgroup.profiles.ProfileKey;
import org.whispersystems.signalservice.api.push.ServiceId;
import java.io.IOException;
import java.util.ArrayList;

View File

@ -8,13 +8,13 @@ import com.fasterxml.jackson.databind.JsonNode;
import org.asamk.signal.manager.api.TrustLevel;
import org.asamk.signal.manager.storage.Utils;
import org.asamk.signal.manager.storage.recipients.RecipientAddress;
import org.signal.core.models.ServiceId.ACI;
import org.signal.core.util.UuidUtil;
import org.signal.libsignal.protocol.IdentityKey;
import org.signal.libsignal.protocol.IdentityKeyPair;
import org.signal.libsignal.protocol.InvalidKeyException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.util.UuidUtil;
import java.io.IOException;
import java.util.ArrayList;
@ -99,7 +99,7 @@ public class LegacyJsonIdentityKeyStore {
for (var trustedKey : trustedKeysNode) {
var trustedKeyName = trustedKey.hasNonNull("name") ? trustedKey.get("name").asText() : null;
if (UuidUtil.INSTANCE.isUuid(trustedKeyName)) {
if (UuidUtil.isUuid(trustedKeyName)) {
// Ignore identities that were incorrectly created with UUIDs as name
continue;
}

View File

@ -7,8 +7,8 @@ import com.fasterxml.jackson.databind.JsonNode;
import org.asamk.signal.manager.storage.Utils;
import org.asamk.signal.manager.storage.recipients.RecipientAddress;
import org.signal.core.models.ServiceId.ACI;
import org.signal.core.util.UuidUtil;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.util.UuidUtil;
import java.io.IOException;
import java.util.ArrayList;
@ -41,7 +41,7 @@ public class LegacyJsonSessionStore {
if (node.isArray()) {
for (var session : node) {
var sessionName = session.hasNonNull("name") ? session.get("name").asText() : null;
if (UuidUtil.INSTANCE.isUuid(sessionName)) {
if (UuidUtil.isUuid(sessionName)) {
// Ignore sessions that were incorrectly created with UUIDs as name
continue;
}

View File

@ -7,7 +7,7 @@ import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import org.signal.core.models.ServiceId;
import org.whispersystems.signalservice.api.push.ServiceId;
import java.io.IOException;
import java.util.ArrayList;

View File

@ -3,12 +3,12 @@ package org.asamk.signal.manager.storage.recipients;
import org.asamk.signal.manager.api.Contact;
import org.asamk.signal.manager.api.Profile;
import org.asamk.signal.manager.storage.Utils;
import org.signal.core.models.ServiceId;
import org.signal.libsignal.zkgroup.InvalidInputException;
import org.signal.libsignal.zkgroup.profiles.ExpiringProfileKeyCredential;
import org.signal.libsignal.zkgroup.profiles.ProfileKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.push.ServiceId;
import java.io.File;
import java.io.FileInputStream;

View File

@ -1,8 +1,8 @@
package org.asamk.signal.manager.storage.recipients;
import org.signal.core.models.ServiceId;
import org.signal.core.models.ServiceId.ACI;
import org.signal.core.models.ServiceId.PNI;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceId.PNI;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import java.util.Optional;

View File

@ -1,6 +1,6 @@
package org.asamk.signal.manager.storage.recipients;
import org.signal.core.models.ServiceId;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import java.util.function.Supplier;

View File

@ -10,14 +10,14 @@ import org.asamk.signal.manager.storage.Utils;
import org.asamk.signal.manager.storage.contacts.ContactsStore;
import org.asamk.signal.manager.storage.profiles.ProfileStore;
import org.asamk.signal.manager.util.KeyUtils;
import org.signal.core.models.ServiceId;
import org.signal.core.models.ServiceId.ACI;
import org.signal.core.models.ServiceId.PNI;
import org.signal.libsignal.zkgroup.InvalidInputException;
import org.signal.libsignal.zkgroup.profiles.ExpiringProfileKeyCredential;
import org.signal.libsignal.zkgroup.profiles.ProfileKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceId.PNI;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.storage.StorageId;

View File

@ -1,7 +1,7 @@
package org.asamk.signal.manager.storage.recipients;
import org.signal.core.models.ServiceId.ACI;
import org.signal.core.models.ServiceId.PNI;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceId.PNI;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import java.util.Optional;

View File

@ -4,13 +4,13 @@ import org.asamk.signal.manager.api.GroupId;
import org.asamk.signal.manager.groups.GroupUtils;
import org.asamk.signal.manager.storage.Database;
import org.asamk.signal.manager.storage.Utils;
import org.signal.core.models.ServiceId;
import org.signal.libsignal.zkgroup.InvalidInputException;
import org.signal.libsignal.zkgroup.groups.GroupMasterKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.crypto.ContentHint;
import org.whispersystems.signalservice.api.messages.SendMessageResult;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.internal.push.Content;
import java.io.IOException;

View File

@ -3,14 +3,14 @@ package org.asamk.signal.manager.storage.senderKeys;
import org.asamk.signal.manager.api.Pair;
import org.asamk.signal.manager.storage.Database;
import org.asamk.signal.manager.storage.Utils;
import org.signal.core.models.ServiceId;
import org.signal.core.util.UuidUtil;
import org.signal.libsignal.protocol.InvalidMessageException;
import org.signal.libsignal.protocol.SignalProtocolAddress;
import org.signal.libsignal.protocol.groups.state.SenderKeyRecord;
import org.signal.libsignal.protocol.groups.state.SenderKeyStore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.util.UuidUtil;
import java.sql.Connection;
import java.sql.ResultSet;

View File

@ -2,12 +2,12 @@ package org.asamk.signal.manager.storage.senderKeys;
import org.asamk.signal.manager.storage.Database;
import org.asamk.signal.manager.storage.Utils;
import org.signal.core.models.ServiceId;
import org.signal.core.util.UuidUtil;
import org.signal.libsignal.protocol.SignalProtocolAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.push.DistributionId;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.util.UuidUtil;
import java.sql.Connection;
import java.sql.ResultSet;

View File

@ -2,11 +2,11 @@ package org.asamk.signal.manager.storage.senderKeys;
import org.asamk.signal.manager.api.Pair;
import org.asamk.signal.manager.storage.Database;
import org.signal.core.models.ServiceId;
import org.signal.libsignal.protocol.SignalProtocolAddress;
import org.signal.libsignal.protocol.groups.state.SenderKeyRecord;
import org.whispersystems.signalservice.api.SignalServiceSenderKeyStore;
import org.whispersystems.signalservice.api.push.DistributionId;
import org.whispersystems.signalservice.api.push.ServiceId;
import java.util.Collection;
import java.util.Map;

View File

@ -3,7 +3,6 @@ package org.asamk.signal.manager.storage.sessions;
import org.asamk.signal.manager.api.Pair;
import org.asamk.signal.manager.storage.Database;
import org.asamk.signal.manager.storage.Utils;
import org.signal.core.models.ServiceId;
import org.signal.libsignal.protocol.NoSessionException;
import org.signal.libsignal.protocol.SignalProtocolAddress;
import org.signal.libsignal.protocol.ecc.ECPublicKey;
@ -11,6 +10,7 @@ import org.signal.libsignal.protocol.state.SessionRecord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.SignalServiceSessionStore;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.ServiceIdType;
import java.sql.Connection;

View File

@ -5,8 +5,8 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import org.asamk.signal.manager.api.StickerPackId;
import org.asamk.signal.manager.util.IOUtils;
import org.asamk.signal.manager.util.Utils;
import org.signal.core.util.Hex;
import org.whispersystems.signalservice.api.util.StreamDetails;
import org.whispersystems.signalservice.internal.util.Hex;
import java.io.BufferedWriter;
import java.io.File;

View File

@ -5,7 +5,6 @@ import org.asamk.signal.manager.internal.JobExecutor;
import org.asamk.signal.manager.jobs.DownloadProfileAvatarJob;
import org.asamk.signal.manager.storage.SignalAccount;
import org.asamk.signal.manager.util.KeyUtils;
import org.signal.core.util.UuidUtil;
import org.signal.libsignal.zkgroup.InvalidInputException;
import org.signal.libsignal.zkgroup.profiles.ProfileKey;
import org.slf4j.Logger;
@ -14,6 +13,7 @@ import org.whispersystems.signalservice.api.push.UsernameLinkComponents;
import org.whispersystems.signalservice.api.storage.IAPSubscriptionId;
import org.whispersystems.signalservice.api.storage.SignalAccountRecord;
import org.whispersystems.signalservice.api.storage.StorageId;
import org.whispersystems.signalservice.api.util.UuidUtil;
import org.whispersystems.signalservice.internal.storage.protos.AccountRecord;
import org.whispersystems.signalservice.internal.storage.protos.OptionalBool;

View File

@ -8,14 +8,14 @@ import org.asamk.signal.manager.jobs.RefreshRecipientsJob;
import org.asamk.signal.manager.storage.SignalAccount;
import org.asamk.signal.manager.storage.recipients.RecipientAddress;
import org.asamk.signal.manager.util.KeyUtils;
import org.signal.core.models.ServiceId.ACI;
import org.signal.core.models.ServiceId.PNI;
import org.signal.libsignal.protocol.IdentityKey;
import org.signal.libsignal.protocol.InvalidKeyException;
import org.signal.libsignal.zkgroup.InvalidInputException;
import org.signal.libsignal.zkgroup.profiles.ProfileKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceId.PNI;
import org.whispersystems.signalservice.api.storage.SignalContactRecord;
import org.whispersystems.signalservice.api.storage.StorageId;
import org.whispersystems.signalservice.internal.storage.protos.ContactRecord;
@ -63,8 +63,8 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor<Signal
@Override
protected boolean isInvalid(SignalContactRecord remoteRecord) {
final var remote = remoteRecord.getProto();
final var aci = ACI.parseOrNull(remote.aci, remote.aciBinary);
final var pni = PNI.parseOrNull(remote.pni, remote.pniBinary);
final var aci = ACI.parseOrNull(remote.aci);
final var pni = PNI.parseOrNull(remote.pni);
final var e164 = nullIfEmpty(remote.e164);
boolean hasAci = aci != null && aci.isValid();
boolean hasPni = pni != null && pni.isValid();
@ -129,7 +129,7 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor<Signal
identityKey = local.identityKey.size() > 0 ? local.identityKey : ByteString.EMPTY;
}
if ((!local.aci.isEmpty() || local.aciBinary.size() > 0)
if (!local.aci.isEmpty()
&& local.identityKey.size() > 0
&& remote.identityKey.size() > 0
&& !local.identityKey.equals(remote.identityKey)) {
@ -327,8 +327,8 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor<Signal
}
private static RecipientAddress getRecipientAddress(final ContactRecord contactRecord) {
return new RecipientAddress(ACI.parseOrNull(contactRecord.aci, contactRecord.aciBinary),
PNI.parseOrNull(contactRecord.pni, contactRecord.pniBinary),
return new RecipientAddress(ACI.parseOrNull(contactRecord.aci),
PNI.parseOrNull(contactRecord.pni),
nullIfEmpty(contactRecord.e164),
nullIfEmpty(contactRecord.username));
}

View File

@ -1,6 +1,5 @@
package org.asamk.signal.manager.syncStorage;
import org.asamk.signal.manager.api.Contact;
import org.asamk.signal.manager.api.PhoneNumberSharingMode;
import org.asamk.signal.manager.api.TrustLevel;
import org.asamk.signal.manager.storage.configuration.ConfigurationStore;
@ -8,14 +7,14 @@ import org.asamk.signal.manager.storage.groups.GroupInfoV1;
import org.asamk.signal.manager.storage.groups.GroupInfoV2;
import org.asamk.signal.manager.storage.identities.IdentityInfo;
import org.asamk.signal.manager.storage.recipients.Recipient;
import org.signal.core.models.ServiceId.ACI;
import org.signal.core.models.ServiceId.PNI;
import org.signal.core.util.UuidUtil;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceId.PNI;
import org.whispersystems.signalservice.api.push.UsernameLinkComponents;
import org.whispersystems.signalservice.api.storage.SignalAccountRecord;
import org.whispersystems.signalservice.api.storage.SignalContactRecord;
import org.whispersystems.signalservice.api.storage.SignalGroupV1Record;
import org.whispersystems.signalservice.api.storage.SignalGroupV2Record;
import org.whispersystems.signalservice.api.util.UuidUtil;
import org.whispersystems.signalservice.internal.storage.protos.AccountRecord;
import org.whispersystems.signalservice.internal.storage.protos.AccountRecord.UsernameLink;
import org.whispersystems.signalservice.internal.storage.protos.ContactRecord;
@ -33,9 +32,6 @@ import static org.signal.core.util.StringExtensionsKt.emptyIfNull;
public final class StorageSyncModels {
private final static boolean useBinaryId = false;
private final static boolean useStringId = true;
private StorageSyncModels() {
}
@ -93,19 +89,13 @@ public final class StorageSyncModels {
public static ContactRecord localToRemoteRecord(Recipient recipient, IdentityInfo identity) {
final var address = recipient.getAddress();
final var builder = SignalContactRecord.Companion.newBuilder(recipient.getStorageRecord())
.aci(address.aci().map(ACI::toString).orElse(""))
.e164(address.number().orElse(""))
.pni(address.pni().map(PNI::toStringWithoutPrefix).orElse(""))
.username(address.username().orElse(""))
.profileKey(recipient.getProfileKey() == null
? ByteString.EMPTY
: ByteString.of(recipient.getProfileKey().serialize()));
if (useBinaryId) {
builder.aciBinary(address.aci().map(ACI::toByteString).orElse(ByteString.EMPTY))
.pniBinary(address.pni().map(PNI::toByteString).orElse(ByteString.EMPTY));
}
if (useStringId) {
builder.aci(address.aci().map(ACI::toString).orElse(""))
.pni(address.pni().map(PNI::toStringWithoutPrefix).orElse(""));
}
if (recipient.getProfile() != null) {
builder.givenName(emptyIfNull(recipient.getProfile().getGivenName()))
.familyName(emptyIfNull(recipient.getProfile().getFamilyName()));
@ -114,7 +104,10 @@ public final class StorageSyncModels {
builder.systemGivenName(emptyIfNull(recipient.getContact().givenName()))
.systemFamilyName(emptyIfNull(recipient.getContact().familyName()))
.systemNickname(emptyIfNull(recipient.getContact().nickName()))
.nickname(getNicknameRemoteRecord(recipient.getContact()))
.nickname(new ContactRecord.Name.Builder().given(emptyIfNull(recipient.getContact()
.nickNameGivenName()))
.family(emptyIfNull(recipient.getContact().nickNameFamilyName()))
.build())
.note(emptyIfNull(recipient.getContact().note()))
.blocked(recipient.getContact().isBlocked())
.whitelisted(recipient.getContact().isProfileSharingEnabled())
@ -133,15 +126,6 @@ public final class StorageSyncModels {
return builder.build();
}
private static ContactRecord.Name getNicknameRemoteRecord(final Contact contact) {
final var given = emptyIfNull(contact.nickNameGivenName());
final var family = emptyIfNull(contact.nickNameFamilyName());
if (given.isEmpty() && family.isEmpty()) {
return null;
}
return new ContactRecord.Name.Builder().given(given).family(family).build();
}
public static GroupV1Record localToRemoteRecord(GroupInfoV1 group) {
final var builder = SignalGroupV1Record.Companion.newBuilder(group.getStorageRecord());
builder.id(ByteString.of(group.getGroupId().serialize()));

View File

@ -1,12 +1,12 @@
package org.asamk.signal.manager.syncStorage;
import org.asamk.signal.manager.storage.recipients.RecipientAddress;
import org.signal.core.models.ServiceId.ACI;
import org.signal.core.models.ServiceId.PNI;
import org.signal.core.util.Base64;
import org.signal.core.util.SetUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceId.PNI;
import org.whispersystems.signalservice.api.storage.SignalStorageManifest;
import org.whispersystems.signalservice.api.storage.SignalStorageRecord;
import org.whispersystems.signalservice.api.storage.StorageId;

View File

@ -1,7 +1,6 @@
package org.asamk.signal.manager.util;
import org.asamk.signal.manager.storage.SignalAccount;
import org.signal.core.models.backup.MediaRootBackupKey;
import org.signal.libsignal.protocol.IdentityKey;
import org.signal.libsignal.protocol.IdentityKeyPair;
import org.signal.libsignal.protocol.InvalidKeyException;
@ -15,6 +14,7 @@ import org.signal.libsignal.protocol.state.SignedPreKeyRecord;
import org.signal.libsignal.zkgroup.InvalidInputException;
import org.signal.libsignal.zkgroup.profiles.ProfileKey;
import org.whispersystems.signalservice.api.account.PreKeyCollection;
import org.whispersystems.signalservice.api.backup.MediaRootBackupKey;
import java.security.SecureRandom;
import java.util.ArrayList;

View File

@ -1,11 +1,11 @@
package org.asamk.signal.manager.util;
import org.signal.core.models.ServiceId;
import org.signal.core.util.UuidUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.util.UuidUtil;
import org.whispersystems.signalservice.internal.push.Envelope;
import java.io.DataInputStream;

View File

@ -9,9 +9,9 @@ import org.asamk.signal.manager.api.PinLockedException;
import org.asamk.signal.manager.api.RateLimitException;
import org.asamk.signal.manager.api.VerificationMethodNotAvailableException;
import org.asamk.signal.manager.helper.PinHelper;
import org.signal.core.models.MasterKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.kbs.MasterKey;
import org.whispersystems.signalservice.api.push.exceptions.ChallengeRequiredException;
import org.whispersystems.signalservice.api.push.exceptions.NoSuchSessionException;
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException;

View File

@ -1,7 +1,6 @@
package org.asamk.signal.manager.util;
import org.asamk.signal.manager.api.Pair;
import org.signal.core.models.ServiceId;
import org.signal.libsignal.net.BadRequestError;
import org.signal.libsignal.net.RequestResult;
import org.signal.libsignal.protocol.IdentityKey;
@ -11,6 +10,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.NetworkResult;
import org.whispersystems.signalservice.api.NetworkResultUtil;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.util.StreamDetails;
import java.io.ByteArrayInputStream;
@ -160,10 +160,9 @@ public class Utils {
return NetworkResultUtil.toBasicLegacy(response);
}
@SuppressWarnings("unchecked")
public static <T, E extends BadRequestError> T handleResponseException(final RequestResult<T, E> result) throws IOException {
if (result instanceof RequestResult.Success<?> success) {
return ((RequestResult.Success<T>) success).getResult();
if (result instanceof RequestResult.Success) {
return ((RequestResult.Success<T>) result).getResult();
} else if (result instanceof RequestResult.ApplicationError e) {
final var cause = e.getCause();
switch (cause) {

View File

@ -3,8 +3,8 @@ package org.asamk.signal.manager.storage.recipients;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.signal.core.models.ServiceId.ACI;
import org.signal.core.models.ServiceId.PNI;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceId.PNI;
import java.util.Arrays;
import java.util.HashSet;

View File

@ -285,7 +285,7 @@ In json mode this is outputted as a list of objects.
One or more numbers to check.
[--username [USERNAME ...]]::
One or more usernames or username links to check.
One or more usernames to check.
=== send
@ -385,89 +385,6 @@ Clear session state and send end session message.
*--edit-timestamp*::
Specify the timestamp of a previous message with the recipient or group to send an edited message.
=== sendPollCreate
Send a poll create message to another user or group.
RECIPIENT::
Specify the recipients.
*--note-to-self*::
Send the message to self.
*--notify-self*::
If self is part of recipients/groups send a normal message, not a sync message.
*-g* GROUP, *--group-id* GROUP::
Specify the recipient group ID in base64 encoding.
*-u* USERNAME, *--username* USERNAME::
Specify the recipient username or username link.
*-q* QUESTION, *--question* QUESTION::
Specify the poll question.
*--no-multi*::
Allow only one option to be selected by each recipient.
By default, recipients can select multiple options.
*-o* OPTION [OPTION ...], *--option* OPTION [OPTION ...]*::
The options for the poll.
=== sendPollVote
Send a poll vote message to another user or group, to vote on a previously created vote.
RECIPIENT::
Specify the recipients.
*--note-to-self*::
Send the message to self.
*--notify-self*::
If self is part of recipients/groups send a normal message, not a sync message.
*-g* GROUP, *--group-id* GROUP::
Specify the recipient group ID in base64 encoding.
*-u* USERNAME, *--username* USERNAME::
Specify the recipient username or username link.
*--poll-author* POLL_AUTHOR::
Specify the number or uuid of the author of the poll message.
*--poll-timestamp* POLL_TIMESTAMP::
Specify the timestamp of the original poll create message.
*-o* [OPTION [OPTION ...]], *--option* [OPTION [OPTION ...]]::
The option indexes of the poll to vote for.
For none multi polls, only one option may be specified.
*--vote-count: VOTE_COUNT::
Specify the number of this vote (increase by one for every time you vote).
=== sendPollTerminate
Send a poll terminate message to another user or group, to close on a previously created vote.
RECIPIENT::
Specify the recipients.
*--note-to-self*::
Send the message to self.
*--notify-self*::
If self is part of recipients/groups send a normal message, not a sync message.
*-g* GROUP, *--group-id* GROUP::
Specify the recipient group ID in base64 encoding.
*-u* USERNAME, *--username* USERNAME::
Specify the recipient username or username link.
*--poll-timestamp* POLL_TIMESTAMP::
Specify the timestamp of the original poll create message.
=== sendMessageRequestResponse
Send response to a message request to linked devices.
@ -759,7 +676,6 @@ If the contact doesn't exist yet, it will be added.
RECIPIENT::
Specify the recipient.
Use "u:" prefix to specify a username or username link.
*--given-name* GIVEN_NAME, *--name* NAME::
New system given name.
@ -1000,9 +916,6 @@ signal-cli -a ACCOUNT verify CODE
Send a message to one or more recipients::
signal-cli -a ACCOUNT send -m "This is a message" [RECIPIENT [RECIPIENT ...]] [-a [ATTACHMENT [ATTACHMENT ...]]]
Send a message to a username (or username link)::
signal-cli -a ACCOUNT send u:someusername.000 -m "This is a message"
Pipe the message content from another process::
uname -a | signal-cli -a ACCOUNT send --message-from-stdin [RECIPIENT [RECIPIENT ...]]

View File

@ -32,7 +32,7 @@ fi
run() {
# To update graalvm config, set GRAALVM_HOME, e.g:
# export GRAALVM_HOME=/usr/lib/jvm/java-25-graalvm
# export GRAALVM_HOME=/usr/lib/jvm/java-21-graalvm
if [ ! -z "$GRAALVM_HOME" ]; then
export JAVA_HOME=$GRAALVM_HOME
export SIGNAL_CLI_OPTS="-agentlib:native-image-agent=config-merge-dir=graalvm-config-dir-${SIGNAL_CLI_AGENT_ID}/"

View File

@ -1,14 +1,7 @@
dependencyResolutionManagement {
repositories {
mavenCentral()
mavenLocal()
maven {
name = "SignalBuildArtifacts"
url = uri("https://build-artifacts.signal.org/libraries/maven/")
content {
includeGroupByRegex("org\\.signal.*")
}
}
mavenCentral()
}
}

View File

@ -143,6 +143,9 @@ public interface Signal extends DBusInterface {
String avatar
) throws Error.AttachmentInvalid, Error.Failure, Error.InvalidNumber, Error.GroupNotFound, Error.InvalidGroupId;
@Deprecated
boolean isRegistered() throws Error.Failure, Error.InvalidNumber;
boolean isRegistered(String number) throws Error.Failure, Error.InvalidNumber;
List<Boolean> isRegistered(List<String> numbers) throws Error.Failure, Error.InvalidNumber;

View File

@ -291,6 +291,8 @@ public class App {
commandHandler.handleMultiLocalCommand(command, multiAccountManager);
} catch (IOException e) {
throw new IOErrorException("Failed to load local accounts file", e);
} catch (AccountCheckException e) {
throw new UnexpectedErrorException("Failed to load account file", e);
}
}

View File

@ -13,4 +13,10 @@ public enum ServiceEnvironmentCli {
return "staging";
}
},
@Deprecated SANDBOX {
@Override
public String toString() {
return "sandbox";
}
},
}

View File

@ -3,13 +3,12 @@ package org.asamk.signal.commands;
import org.asamk.signal.OutputType;
import java.util.List;
import java.util.SequencedCollection;
public interface Command {
String getName();
default SequencedCollection<OutputType> getSupportedOutputTypes() {
default List<OutputType> getSupportedOutputTypes() {
return List.of(OutputType.PLAIN_TEXT);
}
}

View File

@ -58,7 +58,6 @@ public class Commands {
addCommand(new UpdateAccountCommand());
addCommand(new UpdateConfigurationCommand());
addCommand(new UpdateContactCommand());
addCommand(new UpdateDeviceCommand());
addCommand(new UpdateGroupCommand());
addCommand(new UpdateProfileCommand());
addCommand(new UploadStickerPackCommand());

View File

@ -10,7 +10,6 @@ import org.asamk.signal.ReceiveMessageHandler;
import org.asamk.signal.Shutdown;
import org.asamk.signal.commands.exceptions.CommandException;
import org.asamk.signal.commands.exceptions.IOErrorException;
import org.asamk.signal.commands.exceptions.UserErrorException;
import org.asamk.signal.dbus.DbusHandler;
import org.asamk.signal.http.HttpServerHandler;
import org.asamk.signal.json.JsonReceiveMessageHandler;
@ -32,7 +31,6 @@ import java.nio.channels.Channel;
import java.nio.channels.ServerSocketChannel;
import java.util.ArrayList;
import java.util.List;
import java.util.SequencedCollection;
import static org.asamk.signal.util.CommandUtil.getReceiveConfig;
@ -88,7 +86,7 @@ public class DaemonCommand implements MultiLocalCommand, LocalCommand {
}
@Override
public SequencedCollection<OutputType> getSupportedOutputTypes() {
public List<OutputType> getSupportedOutputTypes() {
return List.of(OutputType.PLAIN_TEXT, OutputType.JSON);
}
@ -203,7 +201,9 @@ public class DaemonCommand implements MultiLocalCommand, LocalCommand {
&& tcpAddress == null
&& httpAddress == null
&& inheritedChannel == null) {
throw new UserErrorException("At least one channel parameter is required, e.g. --socket or --dbus.");
logger.warn(
"Running daemon command without explicit mode is deprecated. Use 'daemon --dbus' to use the dbus interface.");
daemonHandler.runDbus(false, DbusConfig.getBusname());
}
}

View File

@ -16,7 +16,6 @@ import org.asamk.signal.output.JsonWriter;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.SequencedCollection;
public class DeleteLocalAccountDataCommand implements RegistrationCommand, JsonRpcRegistrationCommand<Map<String, Object>> {
@ -55,7 +54,7 @@ public class DeleteLocalAccountDataCommand implements RegistrationCommand, JsonR
}
@Override
public SequencedCollection<OutputType> getSupportedOutputTypes() {
public List<OutputType> getSupportedOutputTypes() {
return List.of(OutputType.PLAIN_TEXT, OutputType.JSON);
}

View File

@ -5,7 +5,6 @@ import com.fasterxml.jackson.core.type.TypeReference;
import org.asamk.signal.OutputType;
import java.util.List;
import java.util.SequencedCollection;
public interface JsonRpcCommand<T> extends Command {
@ -13,7 +12,7 @@ public interface JsonRpcCommand<T> extends Command {
return null;
}
default SequencedCollection<OutputType> getSupportedOutputTypes() {
default List<OutputType> getSupportedOutputTypes() {
return List.of(OutputType.JSON);
}
}

View File

@ -21,7 +21,6 @@ import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.nio.channels.Channels;
import java.util.List;
import java.util.SequencedCollection;
import java.util.function.Supplier;
import static org.asamk.signal.util.CommandUtil.getReceiveConfig;
@ -54,7 +53,7 @@ public class JsonRpcDispatcherCommand implements LocalCommand, MultiLocalCommand
}
@Override
public SequencedCollection<OutputType> getSupportedOutputTypes() {
public List<OutputType> getSupportedOutputTypes() {
return List.of(OutputType.JSON);
}

View File

@ -11,7 +11,6 @@ import org.asamk.signal.output.JsonWriter;
import java.util.List;
import java.util.Map;
import java.util.SequencedCollection;
public interface JsonRpcLocalCommand extends JsonRpcSingleCommand<Map<String, Object>>, LocalCommand {
@ -24,7 +23,7 @@ public interface JsonRpcLocalCommand extends JsonRpcSingleCommand<Map<String, Ob
handleCommand(commandNamespace, m, jsonWriter);
}
default SequencedCollection<OutputType> getSupportedOutputTypes() {
default List<OutputType> getSupportedOutputTypes() {
return List.of(OutputType.PLAIN_TEXT, OutputType.JSON);
}
}

View File

@ -11,7 +11,6 @@ import org.asamk.signal.output.JsonWriter;
import java.util.List;
import java.util.Map;
import java.util.SequencedCollection;
public interface JsonRpcMultiLocalCommand extends JsonRpcMultiCommand<Map<String, Object>>, MultiLocalCommand {
@ -28,7 +27,7 @@ public interface JsonRpcMultiLocalCommand extends JsonRpcMultiCommand<Map<String
handleCommand(commandNamespace, c, jsonWriter);
}
default SequencedCollection<OutputType> getSupportedOutputTypes() {
default List<OutputType> getSupportedOutputTypes() {
return List.of(OutputType.PLAIN_TEXT, OutputType.JSON);
}
}

View File

@ -27,7 +27,6 @@ import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.SequencedCollection;
public class ReceiveCommand implements LocalCommand, JsonRpcSingleCommand<ReceiveCommand.ReceiveParams> {
@ -61,7 +60,7 @@ public class ReceiveCommand implements LocalCommand, JsonRpcSingleCommand<Receiv
}
@Override
public SequencedCollection<OutputType> getSupportedOutputTypes() {
public List<OutputType> getSupportedOutputTypes() {
return List.of(OutputType.PLAIN_TEXT, OutputType.JSON);
}

View File

@ -21,7 +21,6 @@ import org.asamk.signal.util.CommandUtil;
import java.io.IOException;
import java.util.List;
import java.util.SequencedCollection;
public class RegisterCommand implements RegistrationCommand, JsonRpcRegistrationCommand<RegisterCommand.RegistrationParams> {
@ -58,7 +57,7 @@ public class RegisterCommand implements RegistrationCommand, JsonRpcRegistration
}
@Override
public SequencedCollection<OutputType> getSupportedOutputTypes() {
public List<OutputType> getSupportedOutputTypes() {
return List.of(OutputType.PLAIN_TEXT, OutputType.JSON);
}

View File

@ -7,6 +7,7 @@ import org.asamk.signal.commands.exceptions.CommandException;
import org.asamk.signal.commands.exceptions.IOErrorException;
import org.asamk.signal.commands.exceptions.UserErrorException;
import org.asamk.signal.manager.Manager;
import org.asamk.signal.manager.api.NotPrimaryDeviceException;
import org.asamk.signal.manager.api.UnregisteredRecipientException;
import org.asamk.signal.output.OutputWriter;
import org.asamk.signal.util.CommandUtil;
@ -62,6 +63,8 @@ public class UpdateContactCommand implements JsonRpcLocalCommand {
m.setContactName(recipient, givenName, familyName, nickGivenName, nickFamilyName, note);
} catch (IOException e) {
throw new IOErrorException("Update contact error: " + e.getMessage(), e);
} catch (NotPrimaryDeviceException e) {
throw new UserErrorException("This command doesn't work on linked devices.");
} catch (UnregisteredRecipientException e) {
throw new UserErrorException("The user " + e.getSender().getIdentifier() + " is not registered.");
}

View File

@ -1,50 +0,0 @@
package org.asamk.signal.commands;
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
import org.asamk.signal.commands.exceptions.CommandException;
import org.asamk.signal.commands.exceptions.IOErrorException;
import org.asamk.signal.commands.exceptions.UserErrorException;
import org.asamk.signal.manager.Manager;
import org.asamk.signal.manager.api.NotPrimaryDeviceException;
import org.asamk.signal.output.OutputWriter;
import java.io.IOException;
public class UpdateDeviceCommand implements JsonRpcLocalCommand {
@Override
public String getName() {
return "updateDevice";
}
@Override
public void attachToSubparser(final Subparser subparser) {
subparser.help("Update a linked device.");
subparser.addArgument("-d", "--device-id", "--deviceId")
.type(int.class)
.required(true)
.help("Specify the device you want to update. Use listDevices to see the deviceIds.");
subparser.addArgument("-n", "--device-name")
.required(true)
.help("Specify a name to describe the given device.");
}
@Override
public void handleCommand(
final Namespace ns,
final Manager m,
final OutputWriter outputWriter
) throws CommandException {
try {
final var deviceId = ns.getInt("device-id");
final var deviceName = ns.getString("device-name");
m.updateLinkedDevice(deviceId, deviceName);
} catch (NotPrimaryDeviceException e) {
throw new UserErrorException("This command doesn't work on linked devices.");
} catch (IOException e) {
throw new IOErrorException("Error while updating device: " + e.getMessage(), e);
}
}
}

Some files were not shown because too many files have changed in this diff Show More