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

Last change on this file since 1434 was 1434, checked in by bln4, 5 years ago

Implementation of ProfileManager. Refactor + additional content for how new profiles are created. The refactoring split out the creation of the default profile from user profiles. Refactoring revealed a long term bug that was causing user profiles to generate with incorrect information. The additional content fixed this bug by introducing the ${USER.NAME} variable, so that the default profile frameset can specify resource locations located in the users resource directory.

org.expeditee.auth.AuthenticatorBrowser
org.expeditee.auth.account.Create
org.expeditee.gui.Browser
org.expeditee.gui.management.ProfileManager
org.expeditee.setting.DirectoryListSetting
org.expeditee.setting.ListSetting
org.expeditee.settings.UserSettings

Implementation of ResourceManager as a core location to get resources from the file system. Also the additional variable ${CURRENT_FRAMESET} to represent the current frameset, so that images can be stored in the directory of the current frameset. This increases portability of framesets.

org.expeditee.gui.FrameIO
org.expeditee.gui.management.ResourceManager
org.expeditee.gui.management.ResourceUtil
Audio:

#NB: Audio used to only operate on a single directory. This has been updated to work in a same way as images. That is: when you ask for a specific resouce, it looks to the user settings to find a sequence of directories to look at in order until it manages to find the desired resource.


There is still need however for a single(ish) source of truth for the .banks and .mastermix file. Therefore these files are now always located in resource-<username>\audio.
org.apollo.agents.MelodySearch
org.apollo.audio.structure.AudioStructureModel
org.apollo.audio.util.MultiTrackPlaybackController
org.apollo.audio.util.SoundDesk
org.apollo.gui.FrameLayoutDaemon
org.apollo.io.AudioPathManager
org.apollo.util.AudioPurger
org.apollo.widgets.FramePlayer
org.apollo.widgets.SampledTrack

Images:

org.expeditee.items.ItemUtils

Frames:

org.expeditee.gui.FrameIO

Fixed a error in the FramePlayer class caused by an incorrect use of toArray().

org.apollo.widgets.FramePlayer


Added several short cut keys to allow for the Play/Pause (Ctrl + P), mute (Ctrl + M) and volume up/down (Ctrl + +/-) when hovering over SampledTrack widgets.

org.apollo.widgets.SampledTrack


Changed the way that Authenticate.login parses the new users profile to be more consistance with other similar places in code.

org.expeditee.auth.account.Authenticate


Encapsulated _body, _surrogateItemsBody and _primaryItemsBody in Frame class. Also changed getBody function to take a boolean flag as to if it should respect the current surrogate mode. If it should then it makes sure that labels have not changed since last time getBody was called.

org.expeditee.gui.Frame

File size: 13.3 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.setupDefaultFolders();
93
94 Frame profile;
95 try {
96 profile = createNewProfile(username, email, personalKey, privateKey, publicKey);
97 } catch (InvalidFramesetNameException | ExistingFramesetException e) {
98 return CreateResult.ErrorNewProfile;
99 }
100
101 if (AuthenticatorBrowser.CREDENTIALS_FRAME == -1) {
102 return CreateResult.ErrorCredentialsFrame;
103 }
104
105 progress = progress(message + "Establishing user credentials.", progress, step, progressBar);
106
107 // Create credentials
108 boolean success = setupCredentialsFrameAndINFs(username, profile);
109 if (!success) {
110 return CreateResult.ErrorIODuringCredentialsFrameSetup;
111 }
112
113 progress = progress(message + "Creating Individual Space.", progress, step, progressBar);
114
115 // Copy private resources to personal area
116 Path personalResources = createPersonalArea(username);
117
118 progress = progress(message + "Creating Space For Dead Drops.", progress, step, progressBar);
119
120 createDeaddropsArea(personalResources);
121
122 System.err.println("**** Hardwired call in Apollo's AuthioPathManager");
123 AudioPathManager.activateAndScanAudioDirs(); // ****
124
125 progress = progress(message + "Done.", progress, step, progressBar);
126
127 return CreateResult.SuccessCreateAccount;
128 }
129
130 public enum CreateResult {
131 SuccessCreateAccount ("Account created."),
132 SuccessAlternativeAccount ("Alternative access to account established."),
133 ErrorSymmetricKey ("An error occured while trying to generate your personal key."),
134 ErrorAsymmetricKeys ("An error occured while trying to generate asymmetric keys."),
135 ErrorNewProfile ("An error occured while creating the profile frames."),
136 ErrorCredentialsFrame ("Unable to establish credentials frame for new profile frame."),
137 ErrorIODuringCredentialsFrameSetup ("An error occured during the setup of the new users credentials frame.");
138
139 private String message = null;
140
141 private CreateResult(String message) {
142 this.message = message;
143 }
144
145 public String toString() {
146 return message;
147 }
148 }
149
150 private static int progress(String message, int progress, int step, Progress progressBar) {
151 try {
152 progressBar.UpdateMessage(message, progress += step);
153 } catch (Exception e) {
154 e.printStackTrace();
155 }
156 DisplayController.refreshBayArea();
157 return progress;
158 }
159
160 private static void createDeaddropsArea(Path personalResources) {
161 File deadDropsDir = new File(personalResources.resolve("deaddrops").toAbsolutePath().toString());
162 deadDropsDir.mkdir();
163 }
164
165 private static Path createPersonalArea(String username) {
166 Path personalResources = UserSettings.PublicAndPrivateResources ? FrameIO.setupPersonalResources(username) : Paths.get(FrameIO.PARENT_FOLDER);
167
168 File contactsDir = new File(personalResources.resolve("contacts").toAbsolutePath().toString());
169 contactsDir.mkdir();
170 return personalResources;
171 }
172
173 private static boolean setupCredentialsFrameAndINFs(String username, Frame profile) {
174 try {
175 File credentialsDir = new File(profile.getFramesetPath() + username + "-credentials");
176 credentialsDir.mkdir();
177 // credentials.inf file.
178 String credentialsPath = credentialsDir.getAbsolutePath() + File.separator + "credentials.inf";
179 File credentialsFile = new File(credentialsPath);
180 credentialsFile.createNewFile();
181 FileWriter out = new FileWriter(credentialsFile);
182 out.write(AuthenticatorBrowser.CREDENTIALS_FRAME + ".exp");
183 out.flush();
184 out.close();
185 // migrate credentials frame
186 Frame credentialsFrame = FrameIO.LoadFrame(username + AuthenticatorBrowser.CREDENTIALS_FRAME);
187 Path destinationDirectory = Paths.get(credentialsDir.getAbsolutePath());
188 Path destinationFile = destinationDirectory.resolve(AuthenticatorBrowser.CREDENTIALS_FRAME + ExpReader.EXTENTION);
189 FrameIO.migrateFrame(credentialsFrame, destinationFile);
190 // pwcolleagues.inf file.
191 File pwColleaguesFile = Paths.get(FrameIO.PROFILE_PATH).resolve(username).resolve("pwcolleagues.inf").toFile();
192 pwColleaguesFile.createNewFile();
193 out = new FileWriter(pwColleaguesFile);
194 out.write(AuthenticatorBrowser.PASSWORD_RECOVERY_FRAME + ".exp");
195 out.flush();
196 out.close();
197 return true;
198 } catch (IOException e) {
199 return false;
200 }
201 }
202
203 private static Frame createNewProfile(String username, String email, String personalKey, String privateKey,
204 String publicKey) throws InvalidFramesetNameException, ExistingFramesetException {
205 // Establish the initial settings for the created user.
206 Map<String, Setting> initialSettings = new HashMap<String, Setting>();
207 initialSettings.put("settings.identity.secrets.PersonalKey", constructTextSetting("The AES key used to secure your profile frame - do not share with anyone!", "PersonalKey", personalKey));
208 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));
209 initialSettings.put("settings.identity.PublicKey", constructTextSetting("The RSA key used to decrypt things encrypted with your RSA public key.", "PublicKey", publicKey));
210 initialSettings.put("settings.identity.Email", constructGenericSetting(String.class, "Your public-facing email address.", "Email", email, username));
211 initialSettings.put("settings.UserSettings.UserName", constructGenericSetting(String.class, "UserName", "UserName", username, username));
212 initialSettings.put("settings.UserSettings.ProfileName", constructGenericSetting(String.class, "ProfileName", "ProfileName", username, username));
213 initialSettings.put("settings.UserSettings.HomeFrame", constructGenericSetting(String.class, "The home frame", "HomeFrame", username + 1, username));
214 initialSettings.put("org.expeditee.gui.folders.FolderSettings.FrameDirs", FolderSettings.FrameDirs);
215 initialSettings.put("org.expeditee.gui.folders.FolderSettings.ImageDirs", FolderSettings.ImageDirs);
216 initialSettings.put("org.expeditee.gui.folders.FolderSettings.AudioDirs", FolderSettings.AudioDirs);
217
218 // Record the credentials frame number and password colleagues frame
219 Map<String, Consumer<Frame>> notifiers = new HashMap<String, Consumer<Frame>>();
220 notifiers.put("settings.identity", frame -> {
221 AuthenticatorBrowser.CREDENTIALS_FRAME = frame.getNumber();
222 frame.addToData("MultiuserCredentials");
223 Collection<Text> textItems = frame.getTextItems();
224 for (Text t: textItems) {
225 if (t.getText().equals("Secrets")) {
226 t.setPermission(new PermissionTriple(UserAppliedPermission.followLinks, UserAppliedPermission.denied, UserAppliedPermission.denied));
227 break;
228 }
229 }
230 });
231 notifiers.put("settings.identity.passwordrecovery", frame -> {
232 frame.addToData("PasswordColleagues");
233 AuthenticatorBrowser.PASSWORD_RECOVERY_FRAME = frame.getNumber();
234 });
235 notifiers.put("settings.identity.secrets", frame -> {
236 frame.addToData("SecretsFrame");
237 AuthenticatorBrowser.SECRETS_FRAME = frame.getNumber();
238 });
239
240 // Create users profile
241 Frame profile = FrameIO.CreateNewProfile(username, initialSettings, notifiers);
242 int lastNumber = FrameIO.getLastNumber(profile.getFramesetName());
243 for (int i = 1; i <= lastNumber; i++) {
244 Frame f = FrameIO.LoadFrame(profile.getFramesetName() + i);
245 Text titleItem = f.getTitleItem();
246 if (i == 1 && titleItem != null) {
247 titleItem.delete();
248 f.setBackgroundColor(new Colour(1, 1, 0.39f));
249 }
250 f.setOwner(username);
251 f.getAllItems().stream().forEach(item -> item.setOwner(username));
252 f.setChanged(true);
253 if (f.getNumber() != AuthenticatorBrowser.CREDENTIALS_FRAME &&
254 f.getNumber() != AuthenticatorBrowser.PASSWORD_RECOVERY_FRAME) {
255 f.setEncryptionLabel(AuthenticatorBrowser.PROFILEENCRYPTIONLABEL);
256 }
257 Collection<Item> secretsLink = Actions.getByContent(f, "Secrets");
258 Collection<Item> publicKeyItem = Actions.getByContent(f, "PublicKey");
259 if (!secretsLink.isEmpty() && !publicKeyItem.isEmpty()) {
260 //Then we are on credentials frame
261 f.addToData("MultiuserCredentials");
262 }
263 Text backupPersonalKey = KeyList.PersonalKey.get();
264 Text tempPersonalKey = KeyList.PersonalKey.generateText();
265 tempPersonalKey.setData(personalKey);
266 KeyList.PersonalKey.setSetting(tempPersonalKey);
267 FrameIO.SaveFrame(f);
268 KeyList.PersonalKey.setSetting(backupPersonalKey);
269 }
270 return profile;
271 }
272
273 private static String generatePersonalKey(String username, String password) {
274 try {
275 Random rand = new SecureRandom();
276 byte[] keyBytes = new byte[16];
277 rand.nextBytes(keyBytes);
278 SecretKey key = new SecretKeySpec(keyBytes, SymmetricAlgorithm);
279 AuthenticatorBrowser.getInstance().putKey(username, password, key);
280 String personalKey = Base64.getEncoder().encodeToString(key.getEncoded());
281 return personalKey;
282 } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | ClassNotFoundException
283 | IOException | SQLException e) {
284 return null;
285 }
286 }
287
288 private static String[] generateAsymmetricKeys() {
289 try {
290 KeyPairGenerator keyGen = KeyPairGenerator.getInstance(AsymmetricAlgorithm);
291 keyGen.initialize(1024);
292 KeyPair keyPair = keyGen.generateKeyPair();
293 String publicKey = Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
294 String privateKey = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());
295 return new String[] { privateKey, publicKey };
296 } catch (NoSuchAlgorithmException e) {
297 return null;
298 }
299 }
300
301 private static TextSetting constructTextSetting(String tooltip, String text, String data) {
302 return new TextSetting(tooltip, text) {
303 @Override
304 public Text generateText() {
305 Text t = new Text(text);
306 t.setData(data);
307 return t;
308 }
309 };
310 }
311
312 private static <T> GenericSetting<T> constructGenericSetting(Class<T> type, String tooltip, String name, T value, String frameset) {
313 return new GenericSetting<T>(type, tooltip, name, value) {
314 @Override
315 public Text generateRepresentation(String name, String frameset) {
316 Text t = new Text(name + ": " + value);
317 return t;
318 }
319 };
320 }
321}
Note: See TracBrowser for help on using the repository browser.