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