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

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

Removed reliance of System.getProperty("user.name") by introducing some functions and a variable to Browser to be used instead. All previous occurrences of System.getProperty("user.name") now use these functions.

At the time, introduced new piping into various functions related to the creation and management of profile frames that distinguished between a profile name and a user name. This allows functions to be more specific about what is being used. For example, when modifying the users profile frames (in the profiles directory) that users profile name can be used instead of naming the variable 'username'. This distinction is important because while username's can end with numbers, profile names cannot and therefore get an 'A' on the end.

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