]> nmode's Git Repositories - signal-cli/blob - src/main/java/cli/Manager.java
b745988b5b1ee945c9ae223d10e30f75dc90f63a
[signal-cli] / src / main / java / cli / Manager.java
1 /**
2 * Copyright (C) 2015 AsamK
3 * <p>
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 * <p>
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 * <p>
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17 package cli;
18
19 import org.apache.commons.io.IOUtils;
20 import org.json.JSONObject;
21 import org.whispersystems.libaxolotl.IdentityKeyPair;
22 import org.whispersystems.libaxolotl.InvalidKeyException;
23 import org.whispersystems.libaxolotl.InvalidVersionException;
24 import org.whispersystems.libaxolotl.state.PreKeyRecord;
25 import org.whispersystems.libaxolotl.state.SignedPreKeyRecord;
26 import org.whispersystems.libaxolotl.util.KeyHelper;
27 import org.whispersystems.libaxolotl.util.Medium;
28 import org.whispersystems.libaxolotl.util.guava.Optional;
29 import org.whispersystems.textsecure.api.TextSecureAccountManager;
30 import org.whispersystems.textsecure.api.TextSecureMessagePipe;
31 import org.whispersystems.textsecure.api.TextSecureMessageReceiver;
32 import org.whispersystems.textsecure.api.TextSecureMessageSender;
33 import org.whispersystems.textsecure.api.crypto.TextSecureCipher;
34 import org.whispersystems.textsecure.api.messages.TextSecureContent;
35 import org.whispersystems.textsecure.api.messages.TextSecureEnvelope;
36 import org.whispersystems.textsecure.api.push.TextSecureAddress;
37 import org.whispersystems.textsecure.api.push.TrustStore;
38
39 import java.io.*;
40 import java.util.List;
41 import java.util.concurrent.TimeUnit;
42 import java.util.concurrent.TimeoutException;
43
44 public class Manager {
45 private final static String URL = "https://textsecure-service.whispersystems.org";
46 private final static TrustStore TRUST_STORE = new WhisperTrustStore();
47
48 private final static String settingsPath = System.getProperty("user.home") + "/.config/textsecure";
49
50 private String username;
51 private String password;
52 private String signalingKey;
53
54 private boolean registered = false;
55
56 private JsonAxolotlStore axolotlStore;
57 TextSecureAccountManager accountManager;
58
59 public Manager(String username) {
60 this.username = username;
61 }
62
63 private String getFileName() {
64 String path = settingsPath + "/data";
65 new File(path).mkdirs();
66 return path + "/" + username;
67 }
68
69 public boolean userExists() {
70 File f = new File(getFileName());
71 if (!f.exists() || f.isDirectory()) {
72 return false;
73 }
74 return true;
75 }
76
77 public boolean userHasKeys() {
78 return axolotlStore != null;
79 }
80
81 public void load() throws IOException, InvalidKeyException {
82 JSONObject in = new JSONObject(IOUtils.toString(new FileInputStream(getFileName())));
83 username = in.getString("username");
84 password = in.getString("password");
85 if (in.has("signalingKey")) {
86 signalingKey = in.getString("signalingKey");
87 }
88 axolotlStore = new JsonAxolotlStore(in.getJSONObject("axolotlStore"));
89 registered = in.getBoolean("registered");
90 accountManager = new TextSecureAccountManager(URL, TRUST_STORE, username, password);
91 }
92
93 public void save() {
94 String out = new JSONObject().put("username", username)
95 .put("password", password)
96 .put("signalingKey", signalingKey)
97 .put("axolotlStore", axolotlStore.getJson())
98 .put("registered", registered).toString();
99 try {
100 OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(getFileName()));
101 writer.write(out);
102 writer.flush();
103 writer.close();
104 } catch (Exception e) {
105 System.out.println("Saving file error: " + e.getMessage());
106 return;
107 }
108 }
109
110 public void createNewIdentity() {
111 IdentityKeyPair identityKey = KeyHelper.generateIdentityKeyPair();
112 int registrationId = KeyHelper.generateRegistrationId(false);
113 axolotlStore = new JsonAxolotlStore(identityKey, registrationId);
114 registered = false;
115 }
116
117 public boolean isRegistered() {
118 return registered;
119 }
120
121 public void register(boolean voiceVerication) throws IOException {
122 password = Util.getSecret(18);
123
124 accountManager = new TextSecureAccountManager(URL, TRUST_STORE, username, password);
125
126 if (voiceVerication)
127 accountManager.requestVoiceVerificationCode();
128 else
129 accountManager.requestSmsVerificationCode();
130
131 registered = false;
132 }
133
134 public void verifyAccount(String verificationCode) throws IOException {
135 verificationCode = verificationCode.replace("-", "");
136 signalingKey = Util.getSecret(52);
137 accountManager.verifyAccount(verificationCode, signalingKey, false, axolotlStore.getLocalRegistrationId());
138
139 //accountManager.setGcmId(Optional.of(GoogleCloudMessaging.getInstance(this).register(REGISTRATION_ID)));
140 registered = true;
141
142 int start = 0;
143 List<PreKeyRecord> oneTimePreKeys = KeyHelper.generatePreKeys(start, 100);
144 for (int i = start; i < oneTimePreKeys.size(); i++) {
145 axolotlStore.storePreKey(i, oneTimePreKeys.get(i));
146 }
147
148 PreKeyRecord lastResortKey = KeyHelper.generateLastResortPreKey();
149 axolotlStore.storePreKey(Medium.MAX_VALUE, lastResortKey);
150
151 int signedPreKeyId = 0;
152 SignedPreKeyRecord signedPreKeyRecord;
153 try {
154 signedPreKeyRecord = KeyHelper.generateSignedPreKey(axolotlStore.getIdentityKeyPair(), signedPreKeyId);
155 axolotlStore.storeSignedPreKey(signedPreKeyId, signedPreKeyRecord);
156 } catch (InvalidKeyException e) {
157 // Should really not happen
158 System.out.println("invalid key");
159 return;
160 }
161 accountManager.setPreKeys(axolotlStore.getIdentityKeyPair().getPublicKey(), lastResortKey, signedPreKeyRecord, oneTimePreKeys);
162 }
163
164 public TextSecureMessageSender getMessageSender() {
165 return new TextSecureMessageSender(URL, TRUST_STORE, username, password,
166 axolotlStore, Optional.<TextSecureMessageSender.EventListener>absent());
167 }
168
169 public TextSecureContent receiveMessage() throws IOException, InvalidVersionException {
170 TextSecureMessageReceiver messageReceiver = new TextSecureMessageReceiver(URL, TRUST_STORE, username, password, signalingKey);
171 TextSecureMessagePipe messagePipe = null;
172
173 try {
174 messagePipe = messageReceiver.createMessagePipe();
175
176 TextSecureEnvelope envelope;
177 try {
178 envelope = messagePipe.read(5, TimeUnit.SECONDS);
179 } catch (TimeoutException e) {
180 return null;
181 }
182 TextSecureCipher cipher = new TextSecureCipher(new TextSecureAddress(username), axolotlStore);
183 TextSecureContent message = null;
184 try {
185 message = cipher.decrypt(envelope);
186 } catch (Exception e) {
187 // TODO handle all exceptions
188 e.printStackTrace();
189 }
190 return message;
191 } finally {
192 if (messagePipe != null)
193 messagePipe.shutdown();
194 }
195 }
196 }