]> nmode's Git Repositories - signal-cli/blob - lib/src/main/java/org/asamk/signal/manager/api/UsernameLinkUrl.java
Update gradle
[signal-cli] / lib / src / main / java / org / asamk / signal / manager / api / UsernameLinkUrl.java
1 package org.asamk.signal.manager.api;
2
3 import org.signal.core.util.Base64;
4 import org.whispersystems.signalservice.api.push.UsernameLinkComponents;
5 import org.whispersystems.signalservice.api.util.UuidUtil;
6
7 import java.io.IOException;
8 import java.util.Arrays;
9 import java.util.regex.Pattern;
10
11 public final class UsernameLinkUrl {
12
13 private static final Pattern URL_REGEX = Pattern.compile("(https://)?signal.me/?#eu/([a-zA-Z0-9+\\-_/]+)");
14
15 private static final String BASE_URL = "https://signal.me/#eu/";
16
17 private final String url;
18 private final UsernameLinkComponents usernameLinkComponents;
19
20 public static UsernameLinkUrl fromUri(String url) throws InvalidUsernameLinkException {
21 final var matcher = URL_REGEX.matcher(url);
22 if (!matcher.matches()) {
23 throw new InvalidUsernameLinkException("Invalid username link");
24 }
25 final var path = matcher.group(2);
26 final byte[] allBytes;
27 try {
28 allBytes = Base64.decode(path);
29 } catch (IOException e) {
30 throw new InvalidUsernameLinkException("Invalid base64 encoding");
31 }
32
33 if (allBytes.length != 48) {
34 throw new InvalidUsernameLinkException("Invalid username link");
35 }
36
37 final var entropy = Arrays.copyOfRange(allBytes, 0, 32);
38 final var serverId = Arrays.copyOfRange(allBytes, 32, allBytes.length);
39 final var serverIdUuid = UuidUtil.parseOrNull(serverId);
40 if (serverIdUuid == null) {
41 throw new InvalidUsernameLinkException("Invalid serverId");
42 }
43
44 return new UsernameLinkUrl(new UsernameLinkComponents(entropy, serverIdUuid));
45 }
46
47 public UsernameLinkUrl(UsernameLinkComponents usernameLinkComponents) {
48 this.usernameLinkComponents = usernameLinkComponents;
49 this.url = createUrl(usernameLinkComponents);
50 }
51
52 private static String createUrl(UsernameLinkComponents usernameLinkComponents) {
53 final var entropy = usernameLinkComponents.getEntropy();
54 final var serverId = UuidUtil.toByteArray(usernameLinkComponents.getServerId());
55
56 final var combined = new byte[entropy.length + serverId.length];
57 System.arraycopy(entropy, 0, combined, 0, entropy.length);
58 System.arraycopy(serverId, 0, combined, entropy.length, serverId.length);
59
60 final var base64 = Base64.encodeUrlSafeWithoutPadding(combined);
61 return BASE_URL + base64;
62 }
63
64 public String getUrl() {
65 return url;
66 }
67
68 public UsernameLinkComponents getComponents() {
69 return usernameLinkComponents;
70 }
71
72 public static final class InvalidUsernameLinkException extends Exception {
73
74 public InvalidUsernameLinkException(String message) {
75 super(message);
76 }
77
78 public InvalidUsernameLinkException(Throwable cause) {
79 super(cause);
80 }
81 }
82 }