1 package org
.asamk
.signal
.manager
;
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
;
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
;
17 import static org
.whispersystems
.signalservice
.internal
.util
.Util
.isEmpty
;
19 public record DeviceLinkInfo(String deviceIdentifier
, ECPublicKey deviceKey
) {
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");
27 var query
= getQueryMap(rawQuery
);
28 var deviceIdentifier
= query
.get("uuid");
29 var publicKeyEncoded
= query
.get("pub_key");
31 if (isEmpty(deviceIdentifier
) || isEmpty(publicKeyEncoded
)) {
32 throw new InvalidDeviceLinkException("Invalid device link uri");
35 final byte[] publicKeyBytes
;
37 publicKeyBytes
= Base64
.getDecoder().decode(publicKeyEncoded
);
38 } catch (IllegalArgumentException e
) {
39 throw new InvalidDeviceLinkException("Invalid device link uri", e
);
41 ECPublicKey deviceKey
;
43 deviceKey
= Curve
.decodePoint(publicKeyBytes
, 0);
44 } catch (InvalidKeyException e
) {
45 throw new InvalidDeviceLinkException("Invalid device link", e
);
48 return new DeviceLinkInfo(deviceIdentifier
, deviceKey
);
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
);
63 public URI
createDeviceLinkUri() {
64 final var deviceKeyString
= Base64
.getEncoder().encodeToString(deviceKey
.serialize()).replace("=", "");
66 return new URI("sgnl://linkdevice?uuid="
67 + URLEncoder
.encode(deviceIdentifier
, StandardCharsets
.UTF_8
)
69 + URLEncoder
.encode(deviceKeyString
, StandardCharsets
.UTF_8
));
70 } catch (URISyntaxException e
) {
71 throw new AssertionError(e
);