From: AsamK Date: Mon, 3 Jan 2022 17:50:27 +0000 (+0100) Subject: Add sticker pack url to list output X-Git-Tag: v0.10.1~6 X-Git-Url: https://git.nmode.ca/signal-cli/commitdiff_plain/8a5f98dac68e008ee35f8b7f252e1fb17699fcb4?ds=inline Add sticker pack url to list output --- diff --git a/graalvm-config-dir/reflect-config.json b/graalvm-config-dir/reflect-config.json index 68af8ab4..a9065791 100644 --- a/graalvm-config-dir/reflect-config.json +++ b/graalvm-config-dir/reflect-config.json @@ -444,7 +444,8 @@ {"name":"installed","parameterTypes":[] }, {"name":"packId","parameterTypes":[] }, {"name":"stickers","parameterTypes":[] }, - {"name":"title","parameterTypes":[] } + {"name":"title","parameterTypes":[] }, + {"name":"url","parameterTypes":[] } ]} , { diff --git a/lib/src/main/java/org/asamk/signal/manager/DeviceLinkInfo.java b/lib/src/main/java/org/asamk/signal/manager/DeviceLinkInfo.java index ca6e305c..7c15131e 100644 --- a/lib/src/main/java/org/asamk/signal/manager/DeviceLinkInfo.java +++ b/lib/src/main/java/org/asamk/signal/manager/DeviceLinkInfo.java @@ -1,18 +1,16 @@ package org.asamk.signal.manager; import org.asamk.signal.manager.api.InvalidDeviceLinkException; +import org.asamk.signal.manager.util.Utils; import org.whispersystems.libsignal.InvalidKeyException; import org.whispersystems.libsignal.ecc.Curve; import org.whispersystems.libsignal.ecc.ECPublicKey; import java.net.URI; import java.net.URISyntaxException; -import java.net.URLDecoder; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.Base64; -import java.util.HashMap; -import java.util.Map; import static org.whispersystems.signalservice.internal.util.Util.isEmpty; @@ -24,7 +22,7 @@ public record DeviceLinkInfo(String deviceIdentifier, ECPublicKey deviceKey) { throw new RuntimeException("Invalid device link uri"); } - var query = getQueryMap(rawQuery); + var query = Utils.getQueryMap(rawQuery); var deviceIdentifier = query.get("uuid"); var publicKeyEncoded = query.get("pub_key"); @@ -48,18 +46,6 @@ public record DeviceLinkInfo(String deviceIdentifier, ECPublicKey deviceKey) { return new DeviceLinkInfo(deviceIdentifier, deviceKey); } - private static Map getQueryMap(String query) { - var params = query.split("&"); - var map = new HashMap(); - for (var param : params) { - final var paramParts = param.split("="); - var name = URLDecoder.decode(paramParts[0], StandardCharsets.UTF_8); - var value = URLDecoder.decode(paramParts[1], StandardCharsets.UTF_8); - map.put(name, value); - } - return map; - } - public URI createDeviceLinkUri() { final var deviceKeyString = Base64.getEncoder().encodeToString(deviceKey.serialize()).replace("=", ""); try { diff --git a/lib/src/main/java/org/asamk/signal/manager/Manager.java b/lib/src/main/java/org/asamk/signal/manager/Manager.java index 7e39909f..b33116f4 100644 --- a/lib/src/main/java/org/asamk/signal/manager/Manager.java +++ b/lib/src/main/java/org/asamk/signal/manager/Manager.java @@ -14,6 +14,7 @@ import org.asamk.signal.manager.api.RecipientIdentifier; import org.asamk.signal.manager.api.SendGroupMessageResults; import org.asamk.signal.manager.api.SendMessageResults; import org.asamk.signal.manager.api.StickerPack; +import org.asamk.signal.manager.api.StickerPackUrl; import org.asamk.signal.manager.api.TypingAction; import org.asamk.signal.manager.api.UnregisteredRecipientException; import org.asamk.signal.manager.api.UpdateGroup; @@ -220,7 +221,7 @@ public interface Manager extends Closeable { * @param path Path can be a path to a manifest.json file or to a zip file that contains a manifest.json file * @return if successful, returns the URL to install the sticker pack in the signal app */ - URI uploadStickerPack(File path) throws IOException, StickerPackInvalidException; + StickerPackUrl uploadStickerPack(File path) throws IOException, StickerPackInvalidException; List getStickerPacks(); diff --git a/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java b/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java index fbcf1b48..a19caa7a 100644 --- a/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java +++ b/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java @@ -31,6 +31,7 @@ import org.asamk.signal.manager.api.SendMessageResult; import org.asamk.signal.manager.api.SendMessageResults; import org.asamk.signal.manager.api.StickerPack; import org.asamk.signal.manager.api.StickerPackId; +import org.asamk.signal.manager.api.StickerPackUrl; import org.asamk.signal.manager.api.TypingAction; import org.asamk.signal.manager.api.UnregisteredRecipientException; import org.asamk.signal.manager.api.UpdateGroup; @@ -70,9 +71,6 @@ import org.whispersystems.signalservice.internal.util.Util; import java.io.File; import java.io.IOException; import java.net.URI; -import java.net.URISyntaxException; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; import java.time.Duration; import java.util.ArrayList; import java.util.HashMap; @@ -658,7 +656,7 @@ public class ManagerImpl implements Manager { } @Override - public URI uploadStickerPack(File path) throws IOException, StickerPackInvalidException { + public StickerPackUrl uploadStickerPack(File path) throws IOException, StickerPackInvalidException { var manifest = StickerUtils.getSignalServiceStickerManifestUpload(path); var messageSender = dependencies.getMessageSender(); @@ -670,17 +668,7 @@ public class ManagerImpl implements Manager { var sticker = new Sticker(packId, packKey); account.getStickerStore().updateSticker(sticker); - try { - return new URI("https", - "signal.art", - "/addstickers/", - "pack_id=" - + URLEncoder.encode(Hex.toStringCondensed(packId.serialize()), StandardCharsets.UTF_8) - + "&pack_key=" - + URLEncoder.encode(Hex.toStringCondensed(packKey), StandardCharsets.UTF_8)); - } catch (URISyntaxException e) { - throw new AssertionError(e); - } + return new StickerPackUrl(packId, packKey); } @Override @@ -691,7 +679,7 @@ public class ManagerImpl implements Manager { try { final var manifest = stickerPackStore.retrieveManifest(pack.getPackId()); return new StickerPack(pack.getPackId(), - pack.getPackKey(), + new StickerPackUrl(pack.getPackId(), pack.getPackKey()), pack.isInstalled(), manifest.title(), manifest.author(), diff --git a/lib/src/main/java/org/asamk/signal/manager/api/StickerPack.java b/lib/src/main/java/org/asamk/signal/manager/api/StickerPack.java index e051a961..f6d092d9 100644 --- a/lib/src/main/java/org/asamk/signal/manager/api/StickerPack.java +++ b/lib/src/main/java/org/asamk/signal/manager/api/StickerPack.java @@ -5,7 +5,7 @@ import java.util.Optional; public record StickerPack( StickerPackId packId, - byte[] packKey, + StickerPackUrl url, boolean installed, String title, String author, @@ -14,7 +14,7 @@ public record StickerPack( ) { public StickerPack(final StickerPackId packId, final byte[] packKey, final boolean installed) { - this(packId, packKey, installed, "", "", Optional.empty(), List.of()); + this(packId, new StickerPackUrl(packId, packKey), installed, "", "", Optional.empty(), List.of()); } public record Sticker(int id, String emoji, String contentType) {} diff --git a/lib/src/main/java/org/asamk/signal/manager/api/StickerPackUrl.java b/lib/src/main/java/org/asamk/signal/manager/api/StickerPackUrl.java new file mode 100644 index 00000000..d018ac39 --- /dev/null +++ b/lib/src/main/java/org/asamk/signal/manager/api/StickerPackUrl.java @@ -0,0 +1,88 @@ +package org.asamk.signal.manager.api; + +import org.asamk.signal.manager.util.Utils; +import org.whispersystems.signalservice.internal.util.Hex; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +import static org.whispersystems.signalservice.internal.util.Util.isEmpty; + +public final class StickerPackUrl { + + private final StickerPackId packId; + private final byte[] packKey; + + /** + * @throws InvalidStickerPackLinkException If url cannot be parsed. + */ + public static StickerPackUrl fromUri(URI uri) throws InvalidStickerPackLinkException { + final var rawQuery = uri.getRawFragment(); + if (isEmpty(rawQuery)) { + throw new RuntimeException("Invalid sticker pack uri"); + } + + var query = Utils.getQueryMap(rawQuery); + var packIdString = query.get("pack_id"); + var packKeyString = query.get("pack_key"); + + if (isEmpty(packIdString) || isEmpty(packKeyString)) { + throw new InvalidStickerPackLinkException("Incomplete sticker pack uri"); + } + + StickerPackId packId; + try { + packId = StickerPackId.deserialize(Hex.fromStringCondensed(packIdString)); + } catch (IOException e) { + throw new InvalidStickerPackLinkException("Invalid sticker pack", e); + } + final byte[] packKey; + try { + packKey = Hex.fromStringCondensed(packKeyString); + } catch (IOException e) { + throw new InvalidStickerPackLinkException("Invalid sticker pack uri", e); + } + return new StickerPackUrl(packId, packKey); + } + + public StickerPackUrl(final StickerPackId packId, final byte[] packKey) { + this.packId = packId; + this.packKey = packKey; + } + + public URI getUrl() { + try { + return new URI("https", + "signal.art", + "/addstickers/", + "pack_id=" + + URLEncoder.encode(Hex.toStringCondensed(packId.serialize()), StandardCharsets.UTF_8) + + "&pack_key=" + + URLEncoder.encode(Hex.toStringCondensed(packKey), StandardCharsets.UTF_8)); + } catch (URISyntaxException e) { + throw new AssertionError(e); + } + } + + public StickerPackId getPackId() { + return packId; + } + + public byte[] getPackKey() { + return packKey; + } + + public final static class InvalidStickerPackLinkException extends Exception { + + public InvalidStickerPackLinkException(String message) { + super(message); + } + + public InvalidStickerPackLinkException(final String message, final Throwable cause) { + super(message, cause); + } + } +} diff --git a/lib/src/main/java/org/asamk/signal/manager/util/Utils.java b/lib/src/main/java/org/asamk/signal/manager/util/Utils.java index 05de2c86..c255eb43 100644 --- a/lib/src/main/java/org/asamk/signal/manager/util/Utils.java +++ b/lib/src/main/java/org/asamk/signal/manager/util/Utils.java @@ -14,8 +14,12 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URLConnection; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.util.HashMap; import java.util.Locale; +import java.util.Map; import java.util.Spliterator; import java.util.Spliterators; import java.util.function.BiFunction; @@ -106,4 +110,16 @@ public class Utils { } }, leftStream.isParallel() || rightStream.isParallel()); } + + public static Map getQueryMap(String query) { + var params = query.split("&"); + var map = new HashMap(); + for (var param : params) { + final var paramParts = param.split("="); + var name = URLDecoder.decode(paramParts[0], StandardCharsets.UTF_8); + var value = URLDecoder.decode(paramParts[1], StandardCharsets.UTF_8); + map.put(name, value); + } + return map; + } } diff --git a/src/main/java/org/asamk/signal/commands/ListStickerPacksCommand.java b/src/main/java/org/asamk/signal/commands/ListStickerPacksCommand.java index fa61e753..53f3f352 100644 --- a/src/main/java/org/asamk/signal/commands/ListStickerPacksCommand.java +++ b/src/main/java/org/asamk/signal/commands/ListStickerPacksCommand.java @@ -35,21 +35,29 @@ public class ListStickerPacksCommand implements JsonRpcLocalCommand { jsonWriter.write(jsonStickerPacks); } else if (outputWriter instanceof PlainTextWriter plainTextWriter) { for (final var sticker : stickerPacks) { - plainTextWriter.println("Pack {}: “{}” by “{}” has {} stickers", + plainTextWriter.println("Pack {}: “{}” by “{}” has {} stickers. {}", Hex.toStringCondensed(sticker.packId().serialize()), sticker.title(), sticker.author(), - sticker.stickers().size()); + sticker.stickers().size(), + sticker.url().getUrl()); } } } private record JsonStickerPack( - String packId, boolean installed, String title, String author, JsonSticker cover, List stickers + String packId, + String url, + boolean installed, + String title, + String author, + JsonSticker cover, + List stickers ) { JsonStickerPack(StickerPack stickerPack) { this(Hex.toStringCondensed(stickerPack.packId().serialize()), + stickerPack.url().getUrl().toString(), stickerPack.installed(), stickerPack.title(), stickerPack.author(), diff --git a/src/main/java/org/asamk/signal/commands/UploadStickerPackCommand.java b/src/main/java/org/asamk/signal/commands/UploadStickerPackCommand.java index 0fc75aee..b70d9e0d 100644 --- a/src/main/java/org/asamk/signal/commands/UploadStickerPackCommand.java +++ b/src/main/java/org/asamk/signal/commands/UploadStickerPackCommand.java @@ -43,10 +43,10 @@ public class UploadStickerPackCommand implements JsonRpcLocalCommand { try { var url = m.uploadStickerPack(path); if (outputWriter instanceof PlainTextWriter writer) { - writer.println("{}", url); + writer.println("{}", url.getUrl()); } else { final var writer = (JsonWriter) outputWriter; - writer.write(Map.of("url", url)); + writer.write(Map.of("url", url.getUrl())); } } catch (IOException e) { throw new IOErrorException("Upload error (maybe image size too large):" + e.getMessage(), e); diff --git a/src/main/java/org/asamk/signal/dbus/DbusManagerImpl.java b/src/main/java/org/asamk/signal/dbus/DbusManagerImpl.java index 345a385a..3e3af300 100644 --- a/src/main/java/org/asamk/signal/dbus/DbusManagerImpl.java +++ b/src/main/java/org/asamk/signal/dbus/DbusManagerImpl.java @@ -19,6 +19,7 @@ import org.asamk.signal.manager.api.RecipientIdentifier; import org.asamk.signal.manager.api.SendGroupMessageResults; import org.asamk.signal.manager.api.SendMessageResults; import org.asamk.signal.manager.api.StickerPack; +import org.asamk.signal.manager.api.StickerPackUrl; import org.asamk.signal.manager.api.TypingAction; import org.asamk.signal.manager.api.UpdateGroup; import org.asamk.signal.manager.groups.GroupId; @@ -436,10 +437,10 @@ public class DbusManagerImpl implements Manager { } @Override - public URI uploadStickerPack(final File path) throws IOException, StickerPackInvalidException { + public StickerPackUrl uploadStickerPack(final File path) throws IOException, StickerPackInvalidException { try { - return new URI(signal.uploadStickerPack(path.getPath())); - } catch (URISyntaxException e) { + return StickerPackUrl.fromUri(new URI(signal.uploadStickerPack(path.getPath()))); + } catch (URISyntaxException | StickerPackUrl.InvalidStickerPackLinkException e) { throw new AssertionError(e); } }