1 package org
.asamk
.signal
.manager
;
3 import org
.asamk
.signal
.manager
.api
.InvalidDeviceLinkException
;
4 import org
.asamk
.signal
.manager
.util
.Utils
;
5 import org
.signal
.libsignal
.protocol
.InvalidKeyException
;
6 import org
.signal
.libsignal
.protocol
.ecc
.Curve
;
7 import org
.signal
.libsignal
.protocol
.ecc
.ECPublicKey
;
10 import java
.net
.URISyntaxException
;
11 import java
.net
.URLEncoder
;
12 import java
.nio
.charset
.StandardCharsets
;
13 import java
.util
.Base64
;
15 import static org
.whispersystems
.signalservice
.internal
.util
.Util
.isEmpty
;
17 public record DeviceLinkInfo(String deviceIdentifier
, ECPublicKey deviceKey
) {
19 public static DeviceLinkInfo
parseDeviceLinkUri(URI linkUri
) throws InvalidDeviceLinkException
{
20 final var rawQuery
= linkUri
.getRawQuery();
21 if (isEmpty(rawQuery
)) {
22 throw new RuntimeException("Invalid device link uri");
25 var query
= Utils
.getQueryMap(rawQuery
);
26 var deviceIdentifier
= query
.get("uuid");
27 var publicKeyEncoded
= query
.get("pub_key");
29 if (isEmpty(deviceIdentifier
) || isEmpty(publicKeyEncoded
)) {
30 throw new InvalidDeviceLinkException("Invalid device link uri");
33 final byte[] publicKeyBytes
;
35 publicKeyBytes
= Base64
.getDecoder().decode(publicKeyEncoded
);
36 } catch (IllegalArgumentException e
) {
37 throw new InvalidDeviceLinkException("Invalid device link uri", e
);
39 ECPublicKey deviceKey
;
41 deviceKey
= Curve
.decodePoint(publicKeyBytes
, 0);
42 } catch (InvalidKeyException e
) {
43 throw new InvalidDeviceLinkException("Invalid device link", e
);
46 return new DeviceLinkInfo(deviceIdentifier
, deviceKey
);
49 public URI
createDeviceLinkUri() {
50 final var deviceKeyString
= Base64
.getEncoder().encodeToString(deviceKey
.serialize()).replace("=", "");
52 return new URI("sgnl://linkdevice?uuid="
53 + URLEncoder
.encode(deviceIdentifier
, StandardCharsets
.UTF_8
)
55 + URLEncoder
.encode(deviceKeyString
, StandardCharsets
.UTF_8
));
56 } catch (URISyntaxException e
) {
57 throw new AssertionError(e
);