mirror of
https://github.com/AsamK/signal-cli
synced 2025-08-29 02:20:39 +00:00
Add sticker pack url to list output
This commit is contained in:
parent
99eef05084
commit
8a5f98dac6
10 changed files with 133 additions and 44 deletions
|
@ -444,7 +444,8 @@
|
||||||
{"name":"installed","parameterTypes":[] },
|
{"name":"installed","parameterTypes":[] },
|
||||||
{"name":"packId","parameterTypes":[] },
|
{"name":"packId","parameterTypes":[] },
|
||||||
{"name":"stickers","parameterTypes":[] },
|
{"name":"stickers","parameterTypes":[] },
|
||||||
{"name":"title","parameterTypes":[] }
|
{"name":"title","parameterTypes":[] },
|
||||||
|
{"name":"url","parameterTypes":[] }
|
||||||
]}
|
]}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,18 +1,16 @@
|
||||||
package org.asamk.signal.manager;
|
package org.asamk.signal.manager;
|
||||||
|
|
||||||
import org.asamk.signal.manager.api.InvalidDeviceLinkException;
|
import org.asamk.signal.manager.api.InvalidDeviceLinkException;
|
||||||
|
import org.asamk.signal.manager.util.Utils;
|
||||||
import org.whispersystems.libsignal.InvalidKeyException;
|
import org.whispersystems.libsignal.InvalidKeyException;
|
||||||
import org.whispersystems.libsignal.ecc.Curve;
|
import org.whispersystems.libsignal.ecc.Curve;
|
||||||
import org.whispersystems.libsignal.ecc.ECPublicKey;
|
import org.whispersystems.libsignal.ecc.ECPublicKey;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.net.URLDecoder;
|
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import static org.whispersystems.signalservice.internal.util.Util.isEmpty;
|
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");
|
throw new RuntimeException("Invalid device link uri");
|
||||||
}
|
}
|
||||||
|
|
||||||
var query = getQueryMap(rawQuery);
|
var query = Utils.getQueryMap(rawQuery);
|
||||||
var deviceIdentifier = query.get("uuid");
|
var deviceIdentifier = query.get("uuid");
|
||||||
var publicKeyEncoded = query.get("pub_key");
|
var publicKeyEncoded = query.get("pub_key");
|
||||||
|
|
||||||
|
@ -48,18 +46,6 @@ public record DeviceLinkInfo(String deviceIdentifier, ECPublicKey deviceKey) {
|
||||||
return new DeviceLinkInfo(deviceIdentifier, deviceKey);
|
return new DeviceLinkInfo(deviceIdentifier, deviceKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<String, String> getQueryMap(String query) {
|
|
||||||
var params = query.split("&");
|
|
||||||
var map = new HashMap<String, String>();
|
|
||||||
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() {
|
public URI createDeviceLinkUri() {
|
||||||
final var deviceKeyString = Base64.getEncoder().encodeToString(deviceKey.serialize()).replace("=", "");
|
final var deviceKeyString = Base64.getEncoder().encodeToString(deviceKey.serialize()).replace("=", "");
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -14,6 +14,7 @@ import org.asamk.signal.manager.api.RecipientIdentifier;
|
||||||
import org.asamk.signal.manager.api.SendGroupMessageResults;
|
import org.asamk.signal.manager.api.SendGroupMessageResults;
|
||||||
import org.asamk.signal.manager.api.SendMessageResults;
|
import org.asamk.signal.manager.api.SendMessageResults;
|
||||||
import org.asamk.signal.manager.api.StickerPack;
|
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.TypingAction;
|
||||||
import org.asamk.signal.manager.api.UnregisteredRecipientException;
|
import org.asamk.signal.manager.api.UnregisteredRecipientException;
|
||||||
import org.asamk.signal.manager.api.UpdateGroup;
|
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
|
* @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
|
* @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<StickerPack> getStickerPacks();
|
List<StickerPack> getStickerPacks();
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ import org.asamk.signal.manager.api.SendMessageResult;
|
||||||
import org.asamk.signal.manager.api.SendMessageResults;
|
import org.asamk.signal.manager.api.SendMessageResults;
|
||||||
import org.asamk.signal.manager.api.StickerPack;
|
import org.asamk.signal.manager.api.StickerPack;
|
||||||
import org.asamk.signal.manager.api.StickerPackId;
|
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.TypingAction;
|
||||||
import org.asamk.signal.manager.api.UnregisteredRecipientException;
|
import org.asamk.signal.manager.api.UnregisteredRecipientException;
|
||||||
import org.asamk.signal.manager.api.UpdateGroup;
|
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.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
|
||||||
import java.net.URLEncoder;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -658,7 +656,7 @@ public class ManagerImpl implements Manager {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public URI uploadStickerPack(File path) throws IOException, StickerPackInvalidException {
|
public StickerPackUrl uploadStickerPack(File path) throws IOException, StickerPackInvalidException {
|
||||||
var manifest = StickerUtils.getSignalServiceStickerManifestUpload(path);
|
var manifest = StickerUtils.getSignalServiceStickerManifestUpload(path);
|
||||||
|
|
||||||
var messageSender = dependencies.getMessageSender();
|
var messageSender = dependencies.getMessageSender();
|
||||||
|
@ -670,17 +668,7 @@ public class ManagerImpl implements Manager {
|
||||||
var sticker = new Sticker(packId, packKey);
|
var sticker = new Sticker(packId, packKey);
|
||||||
account.getStickerStore().updateSticker(sticker);
|
account.getStickerStore().updateSticker(sticker);
|
||||||
|
|
||||||
try {
|
return new StickerPackUrl(packId, packKey);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -691,7 +679,7 @@ public class ManagerImpl implements Manager {
|
||||||
try {
|
try {
|
||||||
final var manifest = stickerPackStore.retrieveManifest(pack.getPackId());
|
final var manifest = stickerPackStore.retrieveManifest(pack.getPackId());
|
||||||
return new StickerPack(pack.getPackId(),
|
return new StickerPack(pack.getPackId(),
|
||||||
pack.getPackKey(),
|
new StickerPackUrl(pack.getPackId(), pack.getPackKey()),
|
||||||
pack.isInstalled(),
|
pack.isInstalled(),
|
||||||
manifest.title(),
|
manifest.title(),
|
||||||
manifest.author(),
|
manifest.author(),
|
||||||
|
|
|
@ -5,7 +5,7 @@ import java.util.Optional;
|
||||||
|
|
||||||
public record StickerPack(
|
public record StickerPack(
|
||||||
StickerPackId packId,
|
StickerPackId packId,
|
||||||
byte[] packKey,
|
StickerPackUrl url,
|
||||||
boolean installed,
|
boolean installed,
|
||||||
String title,
|
String title,
|
||||||
String author,
|
String author,
|
||||||
|
@ -14,7 +14,7 @@ public record StickerPack(
|
||||||
) {
|
) {
|
||||||
|
|
||||||
public StickerPack(final StickerPackId packId, final byte[] packKey, final boolean installed) {
|
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) {}
|
public record Sticker(int id, String emoji, String contentType) {}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,8 +14,12 @@ import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URLConnection;
|
import java.net.URLConnection;
|
||||||
|
import java.net.URLDecoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Spliterator;
|
import java.util.Spliterator;
|
||||||
import java.util.Spliterators;
|
import java.util.Spliterators;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
|
@ -106,4 +110,16 @@ public class Utils {
|
||||||
}
|
}
|
||||||
}, leftStream.isParallel() || rightStream.isParallel());
|
}, leftStream.isParallel() || rightStream.isParallel());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Map<String, String> getQueryMap(String query) {
|
||||||
|
var params = query.split("&");
|
||||||
|
var map = new HashMap<String, String>();
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,21 +35,29 @@ public class ListStickerPacksCommand implements JsonRpcLocalCommand {
|
||||||
jsonWriter.write(jsonStickerPacks);
|
jsonWriter.write(jsonStickerPacks);
|
||||||
} else if (outputWriter instanceof PlainTextWriter plainTextWriter) {
|
} else if (outputWriter instanceof PlainTextWriter plainTextWriter) {
|
||||||
for (final var sticker : stickerPacks) {
|
for (final var sticker : stickerPacks) {
|
||||||
plainTextWriter.println("Pack {}: “{}” by “{}” has {} stickers",
|
plainTextWriter.println("Pack {}: “{}” by “{}” has {} stickers. {}",
|
||||||
Hex.toStringCondensed(sticker.packId().serialize()),
|
Hex.toStringCondensed(sticker.packId().serialize()),
|
||||||
sticker.title(),
|
sticker.title(),
|
||||||
sticker.author(),
|
sticker.author(),
|
||||||
sticker.stickers().size());
|
sticker.stickers().size(),
|
||||||
|
sticker.url().getUrl());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private record JsonStickerPack(
|
private record JsonStickerPack(
|
||||||
String packId, boolean installed, String title, String author, JsonSticker cover, List<JsonSticker> stickers
|
String packId,
|
||||||
|
String url,
|
||||||
|
boolean installed,
|
||||||
|
String title,
|
||||||
|
String author,
|
||||||
|
JsonSticker cover,
|
||||||
|
List<JsonSticker> stickers
|
||||||
) {
|
) {
|
||||||
|
|
||||||
JsonStickerPack(StickerPack stickerPack) {
|
JsonStickerPack(StickerPack stickerPack) {
|
||||||
this(Hex.toStringCondensed(stickerPack.packId().serialize()),
|
this(Hex.toStringCondensed(stickerPack.packId().serialize()),
|
||||||
|
stickerPack.url().getUrl().toString(),
|
||||||
stickerPack.installed(),
|
stickerPack.installed(),
|
||||||
stickerPack.title(),
|
stickerPack.title(),
|
||||||
stickerPack.author(),
|
stickerPack.author(),
|
||||||
|
|
|
@ -43,10 +43,10 @@ public class UploadStickerPackCommand implements JsonRpcLocalCommand {
|
||||||
try {
|
try {
|
||||||
var url = m.uploadStickerPack(path);
|
var url = m.uploadStickerPack(path);
|
||||||
if (outputWriter instanceof PlainTextWriter writer) {
|
if (outputWriter instanceof PlainTextWriter writer) {
|
||||||
writer.println("{}", url);
|
writer.println("{}", url.getUrl());
|
||||||
} else {
|
} else {
|
||||||
final var writer = (JsonWriter) outputWriter;
|
final var writer = (JsonWriter) outputWriter;
|
||||||
writer.write(Map.of("url", url));
|
writer.write(Map.of("url", url.getUrl()));
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new IOErrorException("Upload error (maybe image size too large):" + e.getMessage(), e);
|
throw new IOErrorException("Upload error (maybe image size too large):" + e.getMessage(), e);
|
||||||
|
|
|
@ -19,6 +19,7 @@ import org.asamk.signal.manager.api.RecipientIdentifier;
|
||||||
import org.asamk.signal.manager.api.SendGroupMessageResults;
|
import org.asamk.signal.manager.api.SendGroupMessageResults;
|
||||||
import org.asamk.signal.manager.api.SendMessageResults;
|
import org.asamk.signal.manager.api.SendMessageResults;
|
||||||
import org.asamk.signal.manager.api.StickerPack;
|
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.TypingAction;
|
||||||
import org.asamk.signal.manager.api.UpdateGroup;
|
import org.asamk.signal.manager.api.UpdateGroup;
|
||||||
import org.asamk.signal.manager.groups.GroupId;
|
import org.asamk.signal.manager.groups.GroupId;
|
||||||
|
@ -436,10 +437,10 @@ public class DbusManagerImpl implements Manager {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public URI uploadStickerPack(final File path) throws IOException, StickerPackInvalidException {
|
public StickerPackUrl uploadStickerPack(final File path) throws IOException, StickerPackInvalidException {
|
||||||
try {
|
try {
|
||||||
return new URI(signal.uploadStickerPack(path.getPath()));
|
return StickerPackUrl.fromUri(new URI(signal.uploadStickerPack(path.getPath())));
|
||||||
} catch (URISyntaxException e) {
|
} catch (URISyntaxException | StickerPackUrl.InvalidStickerPackLinkException e) {
|
||||||
throw new AssertionError(e);
|
throw new AssertionError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue