parent
							
								
									5cd5697aea
								
							
						
					
					
						commit
						7e7e4150e1
					
				@ -2070,7 +2070,8 @@
 | 
				
			|||||||
  "name":"org.whispersystems.signalservice.internal.push.SignalServiceProtos$CallMessage$Opaque",
 | 
					  "name":"org.whispersystems.signalservice.internal.push.SignalServiceProtos$CallMessage$Opaque",
 | 
				
			||||||
  "fields":[
 | 
					  "fields":[
 | 
				
			||||||
    {"name":"bitField0_"}, 
 | 
					    {"name":"bitField0_"}, 
 | 
				
			||||||
    {"name":"data_"}
 | 
					    {"name":"data_"}, 
 | 
				
			||||||
 | 
					    {"name":"urgency_"}
 | 
				
			||||||
  ]}
 | 
					  ]}
 | 
				
			||||||
,
 | 
					,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -2520,6 +2521,15 @@
 | 
				
			|||||||
    {"name":"type_"}
 | 
					    {"name":"type_"}
 | 
				
			||||||
  ]}
 | 
					  ]}
 | 
				
			||||||
,
 | 
					,
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  "name":"org.whispersystems.signalservice.internal.push.SignalServiceProtos$SyncMessage$ViewOnceOpen",
 | 
				
			||||||
 | 
					  "fields":[
 | 
				
			||||||
 | 
					    {"name":"bitField0_"}, 
 | 
				
			||||||
 | 
					    {"name":"senderE164_"}, 
 | 
				
			||||||
 | 
					    {"name":"senderUuid_"}, 
 | 
				
			||||||
 | 
					    {"name":"timestamp_"}
 | 
				
			||||||
 | 
					  ]}
 | 
				
			||||||
 | 
					,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  "name":"org.whispersystems.signalservice.internal.push.SignalServiceProtos$SyncMessage$Viewed",
 | 
					  "name":"org.whispersystems.signalservice.internal.push.SignalServiceProtos$SyncMessage$Viewed",
 | 
				
			||||||
  "fields":[
 | 
					  "fields":[
 | 
				
			||||||
 | 
				
			|||||||
@ -174,6 +174,10 @@ public interface Manager extends Closeable {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    SendMessageResults sendEndSessionMessage(Set<RecipientIdentifier.Single> recipients) throws IOException;
 | 
					    SendMessageResults sendEndSessionMessage(Set<RecipientIdentifier.Single> recipients) throws IOException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void deleteRecipient(RecipientIdentifier.Single recipient) throws IOException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void deleteContact(RecipientIdentifier.Single recipient) throws IOException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void setContactName(
 | 
					    void setContactName(
 | 
				
			||||||
            RecipientIdentifier.Single recipient, String name
 | 
					            RecipientIdentifier.Single recipient, String name
 | 
				
			||||||
    ) throws NotMasterDeviceException, IOException;
 | 
					    ) throws NotMasterDeviceException, IOException;
 | 
				
			||||||
 | 
				
			|||||||
@ -279,13 +279,17 @@ public class ManagerImpl implements Manager {
 | 
				
			|||||||
     *
 | 
					     *
 | 
				
			||||||
     * @param numbers The set of phone number in question
 | 
					     * @param numbers The set of phone number in question
 | 
				
			||||||
     * @return A map of numbers to canonicalized number and uuid. If a number is not registered the uuid is null.
 | 
					     * @return A map of numbers to canonicalized number and uuid. If a number is not registered the uuid is null.
 | 
				
			||||||
     * @throws IOException if its unable to get the contacts to check if they're registered
 | 
					     * @throws IOException if it's unable to get the contacts to check if they're registered
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public Map<String, Pair<String, UUID>> areUsersRegistered(Set<String> numbers) throws IOException {
 | 
					    public Map<String, Pair<String, UUID>> areUsersRegistered(Set<String> numbers) throws IOException {
 | 
				
			||||||
        Map<String, String> canonicalizedNumbers = numbers.stream().collect(Collectors.toMap(n -> n, n -> {
 | 
					        Map<String, String> canonicalizedNumbers = numbers.stream().collect(Collectors.toMap(n -> n, n -> {
 | 
				
			||||||
            try {
 | 
					            try {
 | 
				
			||||||
                return PhoneNumberFormatter.formatNumber(n, account.getAccount());
 | 
					                final var canonicalizedNumber = PhoneNumberFormatter.formatNumber(n, account.getAccount());
 | 
				
			||||||
 | 
					                if (!canonicalizedNumber.equals(n)) {
 | 
				
			||||||
 | 
					                    logger.debug("Normalized number {} to {}.", n, canonicalizedNumber);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                return canonicalizedNumber;
 | 
				
			||||||
            } catch (InvalidNumberException e) {
 | 
					            } catch (InvalidNumberException e) {
 | 
				
			||||||
                return "";
 | 
					                return "";
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -774,6 +778,16 @@ public class ManagerImpl implements Manager {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void deleteRecipient(final RecipientIdentifier.Single recipient) throws IOException {
 | 
				
			||||||
 | 
					        account.removeRecipient(resolveRecipient(recipient));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void deleteContact(final RecipientIdentifier.Single recipient) throws IOException {
 | 
				
			||||||
 | 
					        account.getContactStore().deleteContact(resolveRecipient(recipient));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void setContactName(
 | 
					    public void setContactName(
 | 
				
			||||||
            RecipientIdentifier.Single recipient, String name
 | 
					            RecipientIdentifier.Single recipient, String name
 | 
				
			||||||
 | 
				
			|||||||
@ -2,6 +2,8 @@ package org.asamk.signal.manager.api;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import org.asamk.signal.manager.groups.GroupId;
 | 
					import org.asamk.signal.manager.groups.GroupId;
 | 
				
			||||||
import org.asamk.signal.manager.storage.recipients.RecipientAddress;
 | 
					import org.asamk.signal.manager.storage.recipients.RecipientAddress;
 | 
				
			||||||
 | 
					import org.slf4j.Logger;
 | 
				
			||||||
 | 
					import org.slf4j.LoggerFactory;
 | 
				
			||||||
import org.whispersystems.signalservice.api.util.PhoneNumberFormatter;
 | 
					import org.whispersystems.signalservice.api.util.PhoneNumberFormatter;
 | 
				
			||||||
import org.whispersystems.signalservice.api.util.UuidUtil;
 | 
					import org.whispersystems.signalservice.api.util.UuidUtil;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -18,9 +20,16 @@ public sealed interface RecipientIdentifier {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        static Single fromString(String identifier, String localNumber) throws InvalidNumberException {
 | 
					        static Single fromString(String identifier, String localNumber) throws InvalidNumberException {
 | 
				
			||||||
            try {
 | 
					            try {
 | 
				
			||||||
                return UuidUtil.isUuid(identifier)
 | 
					                if (UuidUtil.isUuid(identifier)) {
 | 
				
			||||||
                        ? new Uuid(UUID.fromString(identifier))
 | 
					                    return new Uuid(UUID.fromString(identifier));
 | 
				
			||||||
                        : new Number(PhoneNumberFormatter.formatNumber(identifier, localNumber));
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                final var normalizedNumber = PhoneNumberFormatter.formatNumber(identifier, localNumber);
 | 
				
			||||||
 | 
					                if (!normalizedNumber.equals(identifier)) {
 | 
				
			||||||
 | 
					                    final Logger logger = LoggerFactory.getLogger(RecipientIdentifier.class);
 | 
				
			||||||
 | 
					                    logger.debug("Normalized number {} to {}.", identifier, normalizedNumber);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                return new Number(normalizedNumber);
 | 
				
			||||||
            } catch (org.whispersystems.signalservice.api.util.InvalidNumberException e) {
 | 
					            } catch (org.whispersystems.signalservice.api.util.InvalidNumberException e) {
 | 
				
			||||||
                throw new InvalidNumberException(e.getMessage(), e);
 | 
					                throw new InvalidNumberException(e.getMessage(), e);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
				
			|||||||
@ -324,6 +324,14 @@ public class SignalAccount implements Closeable {
 | 
				
			|||||||
        senderKeyStore.mergeRecipients(recipientId, toBeMergedRecipientId);
 | 
					        senderKeyStore.mergeRecipients(recipientId, toBeMergedRecipientId);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void removeRecipient(final RecipientId recipientId) {
 | 
				
			||||||
 | 
					        sessionStore.deleteAllSessions(recipientId);
 | 
				
			||||||
 | 
					        identityKeyStore.deleteIdentity(recipientId);
 | 
				
			||||||
 | 
					        messageCache.deleteMessages(recipientId);
 | 
				
			||||||
 | 
					        senderKeyStore.deleteAll(recipientId);
 | 
				
			||||||
 | 
					        recipientStore.deleteRecipientData(recipientId);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static File getFileName(File dataPath, String account) {
 | 
					    public static File getFileName(File dataPath, String account) {
 | 
				
			||||||
        return new File(dataPath, account);
 | 
					        return new File(dataPath, account);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -13,4 +13,6 @@ public interface ContactsStore {
 | 
				
			|||||||
    Contact getContact(RecipientId recipientId);
 | 
					    Contact getContact(RecipientId recipientId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    List<Pair<RecipientId, Contact>> getContacts();
 | 
					    List<Pair<RecipientId, Contact>> getContacts();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void deleteContact(RecipientId recipientId);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -172,6 +172,12 @@ public class IdentityKeyStore implements org.whispersystems.libsignal.state.Iden
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void deleteIdentity(final RecipientId recipientId) {
 | 
				
			||||||
 | 
					        synchronized (cachedIdentities) {
 | 
				
			||||||
 | 
					            deleteIdentityLocked(recipientId);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * @param identifier can be either a serialized uuid or a e164 phone number
 | 
					     * @param identifier can be either a serialized uuid or a e164 phone number
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
 | 
				
			|||||||
@ -71,6 +71,25 @@ public class MessageCache {
 | 
				
			|||||||
        return new CachedMessage(cacheFile);
 | 
					        return new CachedMessage(cacheFile);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void deleteMessages(final RecipientId recipientId) {
 | 
				
			||||||
 | 
					        final var recipientMessageCachePath = getMessageCachePath(recipientId);
 | 
				
			||||||
 | 
					        if (!recipientMessageCachePath.exists()) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (var file : Objects.requireNonNull(recipientMessageCachePath.listFiles())) {
 | 
				
			||||||
 | 
					            if (!file.isFile()) {
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                Files.delete(file.toPath());
 | 
				
			||||||
 | 
					            } catch (IOException e) {
 | 
				
			||||||
 | 
					                logger.warn("Failed to delete cache file “{}”, ignoring: {}", file, e.getMessage());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private File getMessageCachePath(RecipientId recipientId) {
 | 
					    private File getMessageCachePath(RecipientId recipientId) {
 | 
				
			||||||
        if (recipientId == null) {
 | 
					        if (recipientId == null) {
 | 
				
			||||||
            return messageCachePath;
 | 
					            return messageCachePath;
 | 
				
			||||||
 | 
				
			|||||||
@ -220,6 +220,25 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile
 | 
				
			|||||||
                .collect(Collectors.toList());
 | 
					                .collect(Collectors.toList());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void deleteContact(final RecipientId recipientId) {
 | 
				
			||||||
 | 
					        synchronized (recipients) {
 | 
				
			||||||
 | 
					            final var recipient = recipients.get(recipientId);
 | 
				
			||||||
 | 
					            storeRecipientLocked(recipientId, Recipient.newBuilder(recipient).withContact(null).build());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void deleteRecipientData(final RecipientId recipientId) {
 | 
				
			||||||
 | 
					        synchronized (recipients) {
 | 
				
			||||||
 | 
					            final var recipient = recipients.get(recipientId);
 | 
				
			||||||
 | 
					            storeRecipientLocked(recipientId,
 | 
				
			||||||
 | 
					                    Recipient.newBuilder()
 | 
				
			||||||
 | 
					                            .withRecipientId(recipientId)
 | 
				
			||||||
 | 
					                            .withAddress(new RecipientAddress(recipient.getAddress().getUuid().orElse(null)))
 | 
				
			||||||
 | 
					                            .build());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public Profile getProfile(final RecipientId recipientId) {
 | 
					    public Profile getProfile(final RecipientId recipientId) {
 | 
				
			||||||
        final var recipient = getRecipient(recipientId);
 | 
					        final var recipient = getRecipient(recipientId);
 | 
				
			||||||
 | 
				
			|||||||
@ -63,7 +63,7 @@ public class SenderKeyStore implements SignalServiceSenderKeyStore {
 | 
				
			|||||||
        senderKeyRecordStore.deleteAll();
 | 
					        senderKeyRecordStore.deleteAll();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void rotateSenderKeys(RecipientId recipientId) {
 | 
					    public void deleteAll(RecipientId recipientId) {
 | 
				
			||||||
        senderKeySharedStore.deleteAllFor(recipientId);
 | 
					        senderKeySharedStore.deleteAllFor(recipientId);
 | 
				
			||||||
        senderKeyRecordStore.deleteAllFor(recipientId);
 | 
					        senderKeyRecordStore.deleteAllFor(recipientId);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -442,6 +442,15 @@ Specify the new name for this contact.
 | 
				
			|||||||
Set expiration time of messages (seconds).
 | 
					Set expiration time of messages (seconds).
 | 
				
			||||||
To disable expiration set expiration time to 0.
 | 
					To disable expiration set expiration time to 0.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					=== removeContact
 | 
				
			||||||
 | 
					Remove the info of a given contact
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					NUMBER::
 | 
				
			||||||
 | 
					Specify the contact phone number.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*--forget*::
 | 
				
			||||||
 | 
					Delete all data associated with this contact, including identity keys and sessions.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
=== block
 | 
					=== block
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Block the given contacts or groups (no messages will be received).
 | 
					Block the given contacts or groups (no messages will be received).
 | 
				
			||||||
 | 
				
			|||||||
@ -26,6 +26,7 @@ public class Commands {
 | 
				
			|||||||
        addCommand(new QuitGroupCommand());
 | 
					        addCommand(new QuitGroupCommand());
 | 
				
			||||||
        addCommand(new ReceiveCommand());
 | 
					        addCommand(new ReceiveCommand());
 | 
				
			||||||
        addCommand(new RegisterCommand());
 | 
					        addCommand(new RegisterCommand());
 | 
				
			||||||
 | 
					        addCommand(new RemoveContactCommand());
 | 
				
			||||||
        addCommand(new RemoveDeviceCommand());
 | 
					        addCommand(new RemoveDeviceCommand());
 | 
				
			||||||
        addCommand(new RemoteDeleteCommand());
 | 
					        addCommand(new RemoteDeleteCommand());
 | 
				
			||||||
        addCommand(new RemovePinCommand());
 | 
					        addCommand(new RemovePinCommand());
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,49 @@
 | 
				
			|||||||
 | 
					package org.asamk.signal.commands;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import net.sourceforge.argparse4j.impl.Arguments;
 | 
				
			||||||
 | 
					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.manager.Manager;
 | 
				
			||||||
 | 
					import org.asamk.signal.output.OutputWriter;
 | 
				
			||||||
 | 
					import org.asamk.signal.util.CommandUtil;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class RemoveContactCommand implements JsonRpcLocalCommand {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public String getName() {
 | 
				
			||||||
 | 
					        return "removeContact";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void attachToSubparser(final Subparser subparser) {
 | 
				
			||||||
 | 
					        subparser.help("Remove the details of a given contact");
 | 
				
			||||||
 | 
					        subparser.addArgument("recipient").help("Contact number");
 | 
				
			||||||
 | 
					        subparser.addArgument("--forget")
 | 
				
			||||||
 | 
					                .action(Arguments.storeTrue())
 | 
				
			||||||
 | 
					                .help("Delete all data associated with this contact, including identity keys and sessions.");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void handleCommand(
 | 
				
			||||||
 | 
					            final Namespace ns, final Manager m, final OutputWriter outputWriter
 | 
				
			||||||
 | 
					    ) throws CommandException {
 | 
				
			||||||
 | 
					        var recipientString = ns.getString("recipient");
 | 
				
			||||||
 | 
					        var recipient = CommandUtil.getSingleRecipientIdentifier(recipientString, m.getSelfNumber());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var forget = Boolean.TRUE == ns.getBoolean("forget");
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            if (forget) {
 | 
				
			||||||
 | 
					                m.deleteRecipient(recipient);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                m.deleteContact(recipient);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } catch (IOException e) {
 | 
				
			||||||
 | 
					            throw new IOErrorException("Remove contact error: " + e.getMessage(), e);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -381,6 +381,16 @@ public class DbusManagerImpl implements Manager {
 | 
				
			|||||||
        return new SendMessageResults(0, Map.of());
 | 
					        return new SendMessageResults(0, Map.of());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void deleteRecipient(final RecipientIdentifier.Single recipient) throws IOException {
 | 
				
			||||||
 | 
					        throw new UnsupportedOperationException();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void deleteContact(final RecipientIdentifier.Single recipient) throws IOException {
 | 
				
			||||||
 | 
					        throw new UnsupportedOperationException();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void setContactName(
 | 
					    public void setContactName(
 | 
				
			||||||
            final RecipientIdentifier.Single recipient, final String name
 | 
					            final RecipientIdentifier.Single recipient, final String name
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user