]> nmode's Git Repositories - signal-cli/blob - lib/src/main/java/org/asamk/signal/manager/DeviceLinkInfo.java
Add verbose logging for decryption errors of incoming messages
[signal-cli] / lib / src / main / java / org / asamk / signal / manager / DeviceLinkInfo.java
1 package org.asamk.signal.manager;
2
3 import org.asamk.signal.manager.api.InvalidDeviceLinkException;
4 import org.whispersystems.libsignal.InvalidKeyException;
5 import org.whispersystems.libsignal.ecc.Curve;
6 import org.whispersystems.libsignal.ecc.ECPublicKey;
7
8 import java.net.URI;
9 import java.net.URISyntaxException;
10 import java.net.URLDecoder;
11 import java.net.URLEncoder;
12 import java.nio.charset.StandardCharsets;
13 import java.util.Base64;
14 import java.util.HashMap;
15 import java.util.Map;
16
17 import static org.whispersystems.signalservice.internal.util.Util.isEmpty;
18
19 public record DeviceLinkInfo(String deviceIdentifier, ECPublicKey deviceKey) {
20
21 public static DeviceLinkInfo parseDeviceLinkUri(URI linkUri) throws InvalidDeviceLinkException {
22 final var rawQuery = linkUri.getRawQuery();
23 if (isEmpty(rawQuery)) {
24 throw new RuntimeException("Invalid device link uri");
25 }
26
27 var query = getQueryMap(rawQuery);
28 var deviceIdentifier = query.get("uuid");
29 var publicKeyEncoded = query.get("pub_key");
30
31 if (isEmpty(deviceIdentifier) || isEmpty(publicKeyEncoded)) {
32 throw new InvalidDeviceLinkException("Invalid device link uri");
33 }
34
35 final byte[] publicKeyBytes;
36 try {
37 publicKeyBytes = Base64.getDecoder().decode(publicKeyEncoded);
38 } catch (IllegalArgumentException e) {
39 throw new InvalidDeviceLinkException("Invalid device link uri", e);
40 }
41 ECPublicKey deviceKey;
42 try {
43 deviceKey = Curve.decodePoint(publicKeyBytes, 0);
44 } catch (InvalidKeyException e) {
45 throw new InvalidDeviceLinkException("Invalid device link", e);
46 }
47
48 return new DeviceLinkInfo(deviceIdentifier, deviceKey);
49 }
50
51 private static Map<String, String> getQueryMap(String query) {
52 var params = query.split("&");
53 var map = new HashMap<String, String>();
54 for (var param : params) {
55 final var paramParts = param.split("=");
56 var name = URLDecoder.decode(paramParts[0], StandardCharsets.UTF_8);
57 var value = URLDecoder.decode(paramParts[1], StandardCharsets.UTF_8);
58 map.put(name, value);
59 }
60 return map;
61 }
62
63 public URI createDeviceLinkUri() {
64 final var deviceKeyString = Base64.getEncoder().encodeToString(deviceKey.serialize()).replace("=", "");
65 try {
66 return new URI("sgnl://linkdevice?uuid="
67 + URLEncoder.encode(deviceIdentifier, StandardCharsets.UTF_8)
68 + "&pub_key="
69 + URLEncoder.encode(deviceKeyString, StandardCharsets.UTF_8));
70 } catch (URISyntaxException e) {
71 throw new AssertionError(e);
72 }
73 }
74 }