source: trunk/src/org/expeditee/auth/account/Create.java@ 1474

Last change on this file since 1474 was 1474, checked in by bnemhaus, 4 years ago

Added FrameIO.Mail to the default paths populated on profile frames. With more time this could be done better; as per comment in UserSettings::appendDefaultFolders

File size: 13.6 KB
Line 
1package org.expeditee.auth.account;
2
3import java.io.File;
4import java.io.FileWriter;
5import java.io.IOException;
6import java.nio.file.Path;
7import java.nio.file.Paths;
8import java.security.KeyPair;
9import java.security.KeyPairGenerator;
10import java.security.KeyStoreException;
11import java.security.NoSuchAlgorithmException;
12import java.security.SecureRandom;
13import java.security.cert.CertificateException;
14import java.sql.SQLException;
15import java.util.Base64;
16import java.util.Collection;
17import java.util.HashMap;
18import java.util.Map;
19import java.util.Random;
20import java.util.function.Consumer;
21
22import javax.crypto.SecretKey;
23import javax.crypto.spec.SecretKeySpec;
24
25import org.apollo.io.AudioPathManager;
26import org.expeditee.agents.ExistingFramesetException;
27import org.expeditee.agents.InvalidFramesetNameException;
28import org.expeditee.auth.Actions;
29import org.expeditee.auth.AuthenticatorBrowser;
30import org.expeditee.auth.tags.AuthenticationTag;
31import org.expeditee.core.Colour;
32import org.expeditee.encryption.CryptographyConstants;
33import org.expeditee.gui.DisplayController;
34import org.expeditee.gui.Frame;
35import org.expeditee.gui.FrameIO;
36import org.expeditee.gui.MessageBay;
37import org.expeditee.gui.MessageBay.Progress;
38import org.expeditee.gui.management.ProfileManager;
39import org.expeditee.io.ExpReader;
40import org.expeditee.items.Item;
41import org.expeditee.items.PermissionTriple;
42import org.expeditee.items.Text;
43import org.expeditee.items.UserAppliedPermission;
44import org.expeditee.setting.GenericSetting;
45import org.expeditee.setting.Setting;
46import org.expeditee.setting.TextSetting;
47import org.expeditee.settings.UserSettings;
48import org.expeditee.settings.folders.FolderSettings;
49import org.expeditee.settings.identity.secrets.KeyList;
50
51public class Create implements CryptographyConstants {
52
53 /**
54 * Create a user account using the specified information in userdata. Creates and stores user keys.
55 * @param userdata Should contain username, password and email.
56 */
57 public static CreateResult createAccount(Map<AuthenticationTag, String> userdata) {
58 // Track progress
59 String message = "Creating new user account...";
60 int progress = 0;
61 int step = 16;
62
63 // Extract user details
64 String username = userdata.get(AuthenticationTag.Username);
65 String password = userdata.get(AuthenticationTag.Password);
66 String email = userdata.get(AuthenticationTag.Email);
67
68 Progress progressBar = MessageBay.displayProgress(message);
69 progress = progress(message + "Generating Keys.", progress, step, progressBar);
70
71 // Generate keys
72 // Personal key
73 String personalKey = generatePersonalKey(username, password);
74 if (personalKey == null) {
75 return CreateResult.ErrorSymmetricKey;
76 }
77 // Public and private keys
78 String[] keys = generateAsymmetricKeys();
79 if (keys == null) {
80 return CreateResult.ErrorAsymmetricKeys;
81 }
82 String privateKey = keys[0];
83 String publicKey = keys[1];
84
85 progress = progress(message + "Creating Profile Frameset.", progress, step, progressBar);
86
87 // Update in memory settings
88 ProfileManager.ensureDefaultProfile();
89 System.setProperty("user.name", username);
90 UserSettings.UserName.set(username);
91 //UserSettings.ProfileName.set(username);
92 UserSettings.ProfileName.set(FrameIO.ConvertToValidFramesetName(username));
93 UserSettings.setupDefaultFolders();
94
95 Frame profile;
96 try {
97 profile = createNewProfile(username, email, personalKey, privateKey, publicKey);
98 } catch (InvalidFramesetNameException | ExistingFramesetException e) {
99 return CreateResult.ErrorNewProfile;
100 }
101
102 if (AuthenticatorBrowser.CREDENTIALS_FRAME == -1) {
103 return CreateResult.ErrorCredentialsFrame;
104 }
105
106 progress = progress(message + "Establishing user credentials.", progress, step, progressBar);
107
108 // Create credentials
109 boolean success = setupCredentialsFrameAndINFs(username, profile);
110 if (!success) {
111 return CreateResult.ErrorIODuringCredentialsFrameSetup;
112 }
113
114 progress = progress(message + "Creating Individual Space.", progress, step, progressBar);
115
116 // Copy private resources to personal area
117 Path personalResources = createPersonalArea(username);
118
119 progress = progress(message + "Creating Space For Dead Drops.", progress, step, progressBar);
120
121 createDeaddropsArea(personalResources);
122
123 System.err.println("**** Hardwired call in Apollo's AuthioPathManager");
124 AudioPathManager.activateAndScanAudioDirs(); // ****
125
126 progress = progress(message + "Done.", progress, step, progressBar);
127
128 return CreateResult.SuccessCreateAccount;
129 }
130
131 public enum CreateResult {
132 SuccessCreateAccount ("Account created."),
133 SuccessAlternativeAccount ("Alternative access to account established."),
134 ErrorSymmetricKey ("An error occured while trying to generate your personal key."),
135 ErrorAsymmetricKeys ("An error occured while trying to generate asymmetric keys."),
136 ErrorNewProfile ("An error occured while creating the profile frames."),
137 ErrorCredentialsFrame ("Unable to establish credentials frame for new profile frame."),
138 ErrorIODuringCredentialsFrameSetup ("An error occured during the setup of the new users credentials frame.");
139
140 private String message = null;
141
142 private CreateResult(String message) {
143 this.message = message;
144 }
145
146 public String toString() {
147 return message;
148 }
149 }
150
151 private static int progress(String message, int progress, int step, Progress progressBar) {
152 try {
153 progressBar.UpdateMessage(message, progress += step);
154 } catch (Exception e) {
155 e.printStackTrace();
156 }
157 DisplayController.refreshBayArea();
158 return progress;
159 }
160
161 private static void createDeaddropsArea(Path personalResources) {
162 File deadDropsDir = new File(personalResources.resolve("deaddrops").toAbsolutePath().toString());
163 deadDropsDir.mkdir();
164 }
165
166 private static Path createPersonalArea(String username) {
167 Path personalResources = UserSettings.PublicAndPrivateResources ? FrameIO.setupPersonalResources(username) : Paths.get(FrameIO.PARENT_FOLDER);
168
169 File contactsDir = new File(personalResources.resolve("contacts").toAbsolutePath().toString());
170 contactsDir.mkdir();
171 return personalResources;
172 }
173
174 private static boolean setupCredentialsFrameAndINFs(String username, Frame profile) {
175 try {
176 File credentialsDir = new File(profile.getFramesetPath() + username + "-credentials");
177 credentialsDir.mkdir();
178 // credentials.inf file.
179 String credentialsPath = credentialsDir.getAbsolutePath() + File.separator + "credentials.inf";
180 File credentialsFile = new File(credentialsPath);
181 credentialsFile.createNewFile();
182 FileWriter out = new FileWriter(credentialsFile);
183 out.write(AuthenticatorBrowser.CREDENTIALS_FRAME + ".exp");
184 out.flush();
185 out.close();
186 // migrate credentials frame
187 Frame credentialsFrame = FrameIO.LoadFrame(username + AuthenticatorBrowser.CREDENTIALS_FRAME);
188 Path destinationDirectory = Paths.get(credentialsDir.getAbsolutePath());
189 Path destinationFile = destinationDirectory.resolve(AuthenticatorBrowser.CREDENTIALS_FRAME + ExpReader.EXTENTION);
190 FrameIO.migrateFrame(credentialsFrame, destinationFile);
191 // pwcolleagues.inf file.
192 File pwColleaguesFile = Paths.get(FrameIO.PROFILE_PATH).resolve(username).resolve("pwcolleagues.inf").toFile();
193 pwColleaguesFile.createNewFile();
194 out = new FileWriter(pwColleaguesFile);
195 out.write(AuthenticatorBrowser.PASSWORD_RECOVERY_FRAME + ".exp");
196 out.flush();
197 out.close();
198 return true;
199 } catch (IOException e) {
200 return false;
201 }
202 }
203
204 private static Frame createNewProfile(String username, String email, String personalKey, String privateKey,
205 String publicKey) throws InvalidFramesetNameException, ExistingFramesetException {
206 // Establish the initial settings for the created user.
207 Map<String, Setting> initialSettings = new HashMap<String, Setting>();
208 initialSettings.put("settings.identity.secrets.PersonalKey", constructTextSetting("The AES key used to secure your profile frame - do not share with anyone!", "PersonalKey", personalKey));
209 initialSettings.put("settings.identity.secrets.PrivateKey", constructTextSetting("The RSA key used to decrypt things encrypted with your RSA public key - do not share with anyone!", "PrivateKey", privateKey));
210 initialSettings.put("settings.identity.PublicKey", constructTextSetting("The RSA key used to decrypt things encrypted with your RSA public key.", "PublicKey", publicKey));
211 initialSettings.put("settings.identity.Email", constructGenericSetting(String.class, "Your public-facing email address.", "Email", email, username));
212 initialSettings.put("settings.UserSettings.UserName", constructGenericSetting(String.class, "UserName", "UserName", username, username));
213 initialSettings.put("settings.UserSettings.ProfileName", constructGenericSetting(String.class, "ProfileName", "ProfileName", username, username));
214 initialSettings.put("settings.UserSettings.HomeFrame", constructGenericSetting(String.class, "The home frame", "HomeFrame", username + 1, username));
215 //String resourcesPrivateUserPath = FrameIO.PARENT_FOLDER + "resources-" + UserSettings.UserName.get() + File.separator;
216 //FolderSettings.FrameDirs.addAbsoluteDir(resourcesPrivateUserPath + "messages" + File.separator);
217 //initialSettings.put("org.expeditee.gui.folders.FolderSettings.FrameDirs", FolderSettings.FrameDirs);
218 //initialSettings.put("org.expeditee.gui.folders.FolderSettings.ImageDirs", FolderSettings.ImageDirs);
219 //initialSettings.put("org.expeditee.gui.folders.FolderSettings.AudioDirs", FolderSettings.AudioDirs);
220
221 // Record the credentials frame number and password colleagues frame
222 Map<String, Consumer<Frame>> notifiers = new HashMap<String, Consumer<Frame>>();
223 notifiers.put("settings.identity", frame -> {
224 AuthenticatorBrowser.CREDENTIALS_FRAME = frame.getNumber();
225 frame.addToData("MultiuserCredentials");
226 Collection<Text> textItems = frame.getTextItems();
227 for (Text t: textItems) {
228 if (t.getText().equals("Secrets")) {
229 t.setPermission(new PermissionTriple(UserAppliedPermission.followLinks, UserAppliedPermission.denied, UserAppliedPermission.denied));
230 break;
231 }
232 }
233 });
234 notifiers.put("settings.identity.passwordrecovery", frame -> {
235 frame.addToData("PasswordColleagues");
236 AuthenticatorBrowser.PASSWORD_RECOVERY_FRAME = frame.getNumber();
237 });
238 notifiers.put("settings.identity.secrets", frame -> {
239 frame.addToData("SecretsFrame");
240 AuthenticatorBrowser.SECRETS_FRAME = frame.getNumber();
241 });
242
243 // Create users profile
244 Frame profile = FrameIO.CreateNewProfile(username, initialSettings, notifiers);
245 int lastNumber = FrameIO.getLastNumber(profile.getFramesetName());
246 for (int i = 1; i <= lastNumber; i++) {
247 Frame f = FrameIO.LoadFrame(profile.getFramesetName() + i);
248 Text titleItem = f.getTitleItem();
249 if (i == 1 && titleItem != null) {
250 titleItem.delete();
251 f.setBackgroundColor(new Colour(1, 1, 0.39f));
252 }
253 f.setOwner(username);
254 f.getAllItems().stream().forEach(item -> item.setOwner(username));
255 f.setChanged(true);
256 if (f.getNumber() != AuthenticatorBrowser.CREDENTIALS_FRAME &&
257 f.getNumber() != AuthenticatorBrowser.PASSWORD_RECOVERY_FRAME) {
258 f.setEncryptionLabel(AuthenticatorBrowser.PROFILEENCRYPTIONLABEL);
259 }
260 Collection<Item> secretsLink = Actions.getByContent(f, "Secrets");
261 Collection<Item> publicKeyItem = Actions.getByContent(f, "PublicKey");
262 if (!secretsLink.isEmpty() && !publicKeyItem.isEmpty()) {
263 //Then we are on credentials frame
264 f.addToData("MultiuserCredentials");
265 }
266 Text backupPersonalKey = KeyList.PersonalKey.get();
267 Text tempPersonalKey = KeyList.PersonalKey.generateText();
268 tempPersonalKey.setData(personalKey);
269 KeyList.PersonalKey.setSetting(tempPersonalKey);
270 FrameIO.SaveFrame(f);
271 KeyList.PersonalKey.setSetting(backupPersonalKey);
272 }
273 return profile;
274 }
275
276 private static String generatePersonalKey(String username, String password) {
277 try {
278 Random rand = new SecureRandom();
279 byte[] keyBytes = new byte[16];
280 rand.nextBytes(keyBytes);
281 SecretKey key = new SecretKeySpec(keyBytes, SymmetricAlgorithm);
282 AuthenticatorBrowser.getInstance().putKey(username, password, key);
283 String personalKey = Base64.getEncoder().encodeToString(key.getEncoded());
284 return personalKey;
285 } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | ClassNotFoundException
286 | IOException | SQLException e) {
287 return null;
288 }
289 }
290
291 private static String[] generateAsymmetricKeys() {
292 try {
293 KeyPairGenerator keyGen = KeyPairGenerator.getInstance(AsymmetricAlgorithm);
294 keyGen.initialize(1024);
295 KeyPair keyPair = keyGen.generateKeyPair();
296 String publicKey = Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
297 String privateKey = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());
298 return new String[] { privateKey, publicKey };
299 } catch (NoSuchAlgorithmException e) {
300 return null;
301 }
302 }
303
304 private static TextSetting constructTextSetting(String tooltip, String text, String data) {
305 return new TextSetting(tooltip, text) {
306 @Override
307 public Text generateText() {
308 Text t = new Text(text);
309 t.setData(data);
310 return t;
311 }
312 };
313 }
314
315 private static <T> GenericSetting<T> constructGenericSetting(Class<T> type, String tooltip, String name, T value, String frameset) {
316 return new GenericSetting<T>(type, tooltip, name, value) {
317 @Override
318 public Text generateRepresentation(String name, String frameset) {
319 Text t = new Text(name + ": " + value);
320 return t;
321 }
322 };
323 }
324}
Note: See TracBrowser for help on using the repository browser.