]> nmode's Git Repositories - signal-cli/blob - src/main/java/org/asamk/signal/dbus/DbusSignalControlImpl.java
d8465d2678acb227493e1054b5f8af8b146c8380
[signal-cli] / src / main / java / org / asamk / signal / dbus / DbusSignalControlImpl.java
1 package org.asamk.signal.dbus;
2
3 import org.asamk.SignalControl;
4 import org.asamk.signal.BaseConfig;
5 import org.asamk.signal.DbusConfig;
6 import org.asamk.signal.manager.Manager;
7 import org.asamk.signal.manager.MultiAccountManager;
8 import org.asamk.signal.manager.ProvisioningManager;
9 import org.asamk.signal.manager.RegistrationManager;
10 import org.asamk.signal.manager.api.CaptchaRequiredException;
11 import org.asamk.signal.manager.api.IncorrectPinException;
12 import org.asamk.signal.manager.api.NonNormalizedPhoneNumberException;
13 import org.asamk.signal.manager.api.PinLockedException;
14 import org.asamk.signal.manager.api.RateLimitException;
15 import org.asamk.signal.manager.api.UserAlreadyExistsException;
16 import org.asamk.signal.manager.api.VerificationMethoNotAvailableException;
17 import org.freedesktop.dbus.DBusPath;
18 import org.slf4j.Logger;
19 import org.slf4j.LoggerFactory;
20
21 import java.io.IOException;
22 import java.net.URI;
23 import java.net.URISyntaxException;
24 import java.nio.channels.OverlappingFileLockException;
25 import java.util.List;
26 import java.util.concurrent.TimeoutException;
27
28 public class DbusSignalControlImpl implements org.asamk.SignalControl {
29
30 private static final Logger logger = LoggerFactory.getLogger(DbusSignalControlImpl.class);
31 private final MultiAccountManager c;
32
33 private final String objectPath;
34
35 public DbusSignalControlImpl(final MultiAccountManager c, final String objectPath) {
36 this.c = c;
37 this.objectPath = objectPath;
38 }
39
40 @Override
41 public boolean isRemote() {
42 return false;
43 }
44
45 @Override
46 public String getObjectPath() {
47 return objectPath;
48 }
49
50 @Override
51 public void register(
52 final String number, final boolean voiceVerification
53 ) throws Error.Failure, Error.InvalidNumber {
54 registerWithCaptcha(number, voiceVerification, null);
55 }
56
57 @Override
58 public void registerWithCaptcha(
59 final String number, final boolean voiceVerification, final String captcha
60 ) throws Error.Failure, Error.InvalidNumber {
61 if (!Manager.isValidNumber(number, null)) {
62 throw new SignalControl.Error.InvalidNumber(
63 "Invalid account (phone number), make sure you include the country code.");
64 }
65 try (final RegistrationManager registrationManager = c.getNewRegistrationManager(number)) {
66 registrationManager.register(voiceVerification, captcha);
67 } catch (RateLimitException e) {
68 String message = "Rate limit reached";
69 throw new SignalControl.Error.Failure(message);
70 } catch (CaptchaRequiredException e) {
71 String message = captcha == null ? "Captcha required for verification." : "Invalid captcha given.";
72 throw new SignalControl.Error.RequiresCaptcha(message);
73 } catch (NonNormalizedPhoneNumberException e) {
74 throw new Error.InvalidNumber(e.getMessage());
75 } catch (OverlappingFileLockException e) {
76 throw new SignalControl.Error.Failure("Account is already in use");
77 } catch (IOException | VerificationMethoNotAvailableException e) {
78 throw new SignalControl.Error.Failure(e.getClass().getSimpleName() + " " + e.getMessage());
79 }
80 }
81
82 @Override
83 public void verify(final String number, final String verificationCode) throws Error.Failure, Error.InvalidNumber {
84 verifyWithPin(number, verificationCode, null);
85 }
86
87 @Override
88 public void verifyWithPin(
89 final String number, final String verificationCode, final String pin
90 ) throws Error.Failure, Error.InvalidNumber {
91 try (final RegistrationManager registrationManager = c.getNewRegistrationManager(number)) {
92 registrationManager.verifyAccount(verificationCode, pin);
93 } catch (OverlappingFileLockException e) {
94 throw new SignalControl.Error.Failure("Account is already in use");
95 } catch (IOException e) {
96 throw new SignalControl.Error.Failure(e.getClass().getSimpleName() + " " + e.getMessage());
97 } catch (PinLockedException e) {
98 throw new Error.Failure(
99 "Verification failed! This number is locked with a pin. Hours remaining until reset: "
100 + (e.getTimeRemaining() / 1000 / 60 / 60));
101 } catch (IncorrectPinException e) {
102 throw new Error.Failure("Verification failed! Invalid pin, tries remaining: " + e.getTriesRemaining());
103 }
104 }
105
106 @Override
107 public String link(final String newDeviceName) throws Error.Failure {
108 final URI deviceLinkUri;
109 try {
110 deviceLinkUri = c.getNewProvisioningDeviceLinkUri();
111 } catch (TimeoutException | IOException e) {
112 throw new SignalControl.Error.Failure(e.getClass().getSimpleName() + " " + e.getMessage());
113 }
114 Thread.ofPlatform().name("dbus-link").start(() -> {
115 final ProvisioningManager provisioningManager = c.getProvisioningManagerFor(deviceLinkUri);
116 try {
117 provisioningManager.finishDeviceLink(newDeviceName);
118 } catch (IOException | TimeoutException | UserAlreadyExistsException e) {
119 logger.warn("Failed to finish linking", e);
120 }
121 });
122 return deviceLinkUri.toString();
123 }
124
125 @Override
126 public String startLink() throws Error.Failure {
127 try {
128 final URI deviceLinkUri = c.getNewProvisioningDeviceLinkUri();
129 return deviceLinkUri.toString();
130 } catch (TimeoutException | IOException e) {
131 throw new SignalControl.Error.Failure(e.getClass().getSimpleName() + " " + e.getMessage());
132 }
133 }
134
135 @Override
136 public String finishLink(String deviceLinkUri, final String newDeviceName) throws Error.Failure {
137 try {
138 final var provisioningManager = c.getProvisioningManagerFor(new URI(deviceLinkUri));
139 return provisioningManager.finishDeviceLink(newDeviceName);
140 } catch (TimeoutException | IOException | UserAlreadyExistsException | URISyntaxException e) {
141 throw new SignalControl.Error.Failure(e.getClass().getSimpleName() + " " + e.getMessage());
142 }
143 }
144
145 @Override
146 public String version() {
147 return BaseConfig.PROJECT_VERSION;
148 }
149
150 @Override
151 public List<DBusPath> listAccounts() {
152 return c.getAccountNumbers().stream().map(u -> new DBusPath(DbusConfig.getObjectPath(u))).toList();
153 }
154
155 @Override
156 public DBusPath getAccount(final String number) {
157 return new DBusPath(DbusConfig.getObjectPath(number));
158 }
159 }