]> nmode's Git Repositories - signal-cli/blob - lib/src/main/java/org/asamk/signal/manager/groups/GroupInviteLinkUrl.java
Remove dead code and fix inspection issues
[signal-cli] / lib / src / main / java / org / asamk / signal / manager / groups / GroupInviteLinkUrl.java
1 package org.asamk.signal.manager.groups;
2
3 import com.google.protobuf.ByteString;
4
5 import org.signal.storageservice.protos.groups.GroupInviteLink;
6 import org.signal.storageservice.protos.groups.local.DecryptedGroup;
7 import org.signal.zkgroup.InvalidInputException;
8 import org.signal.zkgroup.groups.GroupMasterKey;
9 import org.whispersystems.util.Base64UrlSafe;
10
11 import java.io.IOException;
12 import java.net.URI;
13 import java.net.URISyntaxException;
14
15 public final class GroupInviteLinkUrl {
16
17 private static final String GROUP_URL_HOST = "signal.group";
18 private static final String GROUP_URL_PREFIX = "https://" + GROUP_URL_HOST + "/#";
19
20 private final GroupMasterKey groupMasterKey;
21 private final GroupLinkPassword password;
22 private final String url;
23
24 public static GroupInviteLinkUrl forGroup(GroupMasterKey groupMasterKey, DecryptedGroup group) {
25 return new GroupInviteLinkUrl(groupMasterKey,
26 GroupLinkPassword.fromBytes(group.getInviteLinkPassword().toByteArray()));
27 }
28
29 /**
30 * @return null iff not a group url.
31 * @throws InvalidGroupLinkException If group url, but cannot be parsed.
32 */
33 public static GroupInviteLinkUrl fromUri(String urlString) throws InvalidGroupLinkException, UnknownGroupLinkVersionException {
34 var uri = getGroupUrl(urlString);
35
36 if (uri == null) {
37 return null;
38 }
39
40 try {
41 if (!"/".equals(uri.getPath()) && uri.getPath().length() > 0) {
42 throw new InvalidGroupLinkException("No path was expected in uri");
43 }
44
45 var encoding = uri.getFragment();
46
47 if (encoding == null || encoding.length() == 0) {
48 throw new InvalidGroupLinkException("No reference was in the uri");
49 }
50
51 var bytes = Base64UrlSafe.decodePaddingAgnostic(encoding);
52 var groupInviteLink = GroupInviteLink.parseFrom(bytes);
53
54 switch (groupInviteLink.getContentsCase()) {
55 case V1CONTENTS -> {
56 var groupInviteLinkContentsV1 = groupInviteLink.getV1Contents();
57 var groupMasterKey = new GroupMasterKey(groupInviteLinkContentsV1.getGroupMasterKey()
58 .toByteArray());
59 var password = GroupLinkPassword.fromBytes(groupInviteLinkContentsV1.getInviteLinkPassword()
60 .toByteArray());
61
62 return new GroupInviteLinkUrl(groupMasterKey, password);
63 }
64 default -> throw new UnknownGroupLinkVersionException("Url contains no known group link content");
65 }
66 } catch (InvalidInputException | IOException e) {
67 throw new InvalidGroupLinkException(e);
68 }
69 }
70
71 /**
72 * @return {@link URI} if the host name matches.
73 */
74 private static URI getGroupUrl(String urlString) {
75 try {
76 var url = new URI(urlString);
77
78 if (!"https".equalsIgnoreCase(url.getScheme()) && !"sgnl".equalsIgnoreCase(url.getScheme())) {
79 return null;
80 }
81
82 return GROUP_URL_HOST.equalsIgnoreCase(url.getHost()) ? url : null;
83 } catch (URISyntaxException e) {
84 return null;
85 }
86 }
87
88 private GroupInviteLinkUrl(GroupMasterKey groupMasterKey, GroupLinkPassword password) {
89 this.groupMasterKey = groupMasterKey;
90 this.password = password;
91 this.url = createUrl(groupMasterKey, password);
92 }
93
94 private static String createUrl(GroupMasterKey groupMasterKey, GroupLinkPassword password) {
95 var groupInviteLink = GroupInviteLink.newBuilder()
96 .setV1Contents(GroupInviteLink.GroupInviteLinkContentsV1.newBuilder()
97 .setGroupMasterKey(ByteString.copyFrom(groupMasterKey.serialize()))
98 .setInviteLinkPassword(ByteString.copyFrom(password.serialize())))
99 .build();
100
101 var encoding = Base64UrlSafe.encodeBytesWithoutPadding(groupInviteLink.toByteArray());
102
103 return GROUP_URL_PREFIX + encoding;
104 }
105
106 public String getUrl() {
107 return url;
108 }
109
110 public GroupMasterKey getGroupMasterKey() {
111 return groupMasterKey;
112 }
113
114 public GroupLinkPassword getPassword() {
115 return password;
116 }
117
118 public final static class InvalidGroupLinkException extends Exception {
119
120 public InvalidGroupLinkException(String message) {
121 super(message);
122 }
123
124 public InvalidGroupLinkException(Throwable cause) {
125 super(cause);
126 }
127 }
128
129 public final static class UnknownGroupLinkVersionException extends Exception {
130
131 public UnknownGroupLinkVersionException(String message) {
132 super(message);
133 }
134 }
135 }