package org.expeditee.auth.account; import java.io.File; import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.cert.CertificateException; import java.sql.SQLException; import java.util.Base64; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Random; import java.util.function.Consumer; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import org.apollo.io.AudioPathManager; import org.expeditee.agents.ExistingFramesetException; import org.expeditee.agents.InvalidFramesetNameException; import org.expeditee.auth.Actions; import org.expeditee.auth.AuthenticatorBrowser; import org.expeditee.auth.tags.AuthenticationTag; import org.expeditee.core.Colour; import org.expeditee.gui.DisplayController; import org.expeditee.gui.Frame; import org.expeditee.gui.FrameIO; import org.expeditee.gui.MessageBay; import org.expeditee.gui.MessageBay.Progress; import org.expeditee.io.ExpReader; import org.expeditee.items.Item; import org.expeditee.items.PermissionPair; import org.expeditee.items.Text; import org.expeditee.items.UserAppliedPermission; import org.expeditee.setting.GenericSetting; import org.expeditee.setting.Setting; import org.expeditee.setting.TextSetting; import org.expeditee.settings.UserSettings; import org.expeditee.settings.folders.FolderSettings; import org.expeditee.settings.identity.secrets.KeyList; import org.ngikm.cryptography.CryptographyConstants; public class Create implements CryptographyConstants { /** * Create a user account using the specified information in userdata. Creates and stores user keys. * @param userdata Should contain username, password and email. */ public static void createAccount(Map userdata) throws InvalidFramesetNameException, ExistingFramesetException, KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, ClassNotFoundException, IOException, SQLException { // Track progress String message = "Creating new user account..."; int progress = 0; int step = 16; // Extract user details String username = userdata.get(AuthenticationTag.Username); String password = userdata.get(AuthenticationTag.Password); String email = userdata.get(AuthenticationTag.Email); Progress progressBar = MessageBay.displayProgress(message); try { progressBar.UpdateMessage(message + "Generating Keys.", progress += step); } catch (Exception e) { e.printStackTrace(); } DisplayController.refreshBayArea(); // Generate keys // Personal key Random rand = new SecureRandom(); byte[] keyBytes = new byte[16]; rand.nextBytes(keyBytes); SecretKey key = new SecretKeySpec(keyBytes, SymmetricAlgorithm); AuthenticatorBrowser.getInstance().putKey(username, password, key); String personalKey = Base64.getEncoder().encodeToString(key.getEncoded()); // Public and private keys KeyPairGenerator keyGen = KeyPairGenerator.getInstance(AsymmetricAlgorithm); keyGen.initialize(1024); KeyPair keyPair = keyGen.generateKeyPair(); String publicKey = Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded()); String privateKey = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded()); try { progressBar.UpdateMessage(message + "Creating Profile Frameset.", progress += step); } catch (Exception e) { e.printStackTrace(); } DisplayController.refreshBayArea(); // Update in memory settings System.setProperty("user.name", username); UserSettings.UserName.set(username); UserSettings.ProfileName.set(username); UserSettings.setupDefaultFolders(); // Establish the initial settings for the created user. Map initialSettings = new HashMap(); initialSettings.put("settings.identity.secrets.PersonalKey", constructTextSetting("The AES key used to secure your profile frame - do not share with anyone!", "PersonalKey", personalKey)); 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)); initialSettings.put("settings.identity.PublicKey", constructTextSetting("The RSA key used to decrypt things encrypted with your RSA public key.", "PublicKey", publicKey)); initialSettings.put("settings.identity.Email", constructGenericSetting(String.class, "Your public-facing email address.", "Email", email, username)); initialSettings.put("settings.UserSettings.UserName", constructGenericSetting(String.class, "Username", "Username", username, username)); initialSettings.put("settings.UserSettings.ProfileName", constructGenericSetting(String.class, "Profilename", "Profilename", username, username)); initialSettings.put("settings.UserSettings.HomeFrame", constructGenericSetting(String.class, "The home frame", "HomeFrame", username + 1, username)); initialSettings.put("org.expeditee.gui.folders.FolderSettings.FrameDirs", FolderSettings.FrameDirs); initialSettings.put("org.expeditee.gui.folders.FolderSettings.ImageDirs", FolderSettings.ImageDirs); initialSettings.put("org.expeditee.gui.folders.FolderSettings.AudioDirs", FolderSettings.AudioDirs); // Record the credentials frame number Map> notifiers = new HashMap>(); notifiers.put("settings.identity", frame -> { AuthenticatorBrowser.CREDENTIALS_FRAME = frame.getNumber(); frame.addToData("MultiuserCredentials"); Collection textItems = frame.getTextItems(); for (Text t: textItems) { if (t.getText().equals("Secrets")) { t.setPermission(new PermissionPair(UserAppliedPermission.followLinks, UserAppliedPermission.denied)); break; } } }); // Create users profile Frame profile = FrameIO.CreateNewProfile(username, initialSettings, notifiers); int lastNumber = FrameIO.getLastNumber(profile.getFramesetName()); for (int i = 1; i <= lastNumber; i++) { Frame f = FrameIO.LoadFrame(profile.getFramesetName() + i); Text titleItem = f.getTitleItem(); if (i == 1 && titleItem != null) { titleItem.delete(); f.setBackgroundColor(new Colour(1, 1, 0.39f)); } f.setOwner(username); f.getAllItems().stream().forEach(item -> item.setOwner(username)); f.setChanged(true); if (f.getNumber() != AuthenticatorBrowser.CREDENTIALS_FRAME) { f.setEncryptionLabel(AuthenticatorBrowser.PROFILEENCRYPTIONLABEL); } Collection secretsLink = Actions.getByContent(f, "Secrets"); Collection publicKeyItem = Actions.getByContent(f, "PublicKey"); if (!secretsLink.isEmpty() && !publicKeyItem.isEmpty()) { //Then we are on credentials frame f.addToData("MultiuserCredentials"); } Text backupPersonalKey = KeyList.PersonalKey.get(); Text tempPersonalKey = KeyList.PersonalKey.generateText(); tempPersonalKey.setData(personalKey); KeyList.PersonalKey.setSetting(tempPersonalKey); FrameIO.SaveFrame(f); KeyList.PersonalKey.setSetting(backupPersonalKey); } if (AuthenticatorBrowser.CREDENTIALS_FRAME == -1) { System.err.println("authActions::Unable to establish credentials frame for new profile frame. Account creation failed."); return; } try { progressBar.UpdateMessage(message + "Establishing user credentials.", progress += step); } catch (Exception e) { e.printStackTrace(); } DisplayController.refreshBayArea(); // Create credentials File credentialsDir = new File(profile.getFramesetPath() + username + "-credentials"); credentialsDir.mkdir(); // credentials.inf file. String credentialsPath = credentialsDir.getAbsolutePath() + File.separator + "credentials.inf"; File credentialsFile = new File(credentialsPath); credentialsFile.createNewFile(); FileWriter out = new FileWriter(credentialsFile); out.write(AuthenticatorBrowser.CREDENTIALS_FRAME + ".exp"); out.flush(); out.close(); // migrate credentials frame Frame credentialsFrame = FrameIO.LoadFrame(username + AuthenticatorBrowser.CREDENTIALS_FRAME); Path destinationDirectory = Paths.get(credentialsDir.getAbsolutePath()); Path destinationFile = destinationDirectory.resolve(AuthenticatorBrowser.CREDENTIALS_FRAME + ExpReader.EXTENTION); FrameIO.migrateFrame(credentialsFrame, destinationFile); try { progressBar.UpdateMessage(message + "Creating Individual Space.", progress += step); } catch (Exception e) { e.printStackTrace(); } DisplayController.refreshBayArea(); // Copy private resources to personal area Path personalResources = UserSettings.PublicAndPrivateResources ? FrameIO.setupPersonalResources(username) : Paths.get(FrameIO.PARENT_FOLDER); File contactsDir = new File(personalResources.resolve("contacts").toAbsolutePath().toString()); contactsDir.mkdir(); try { progressBar.UpdateMessage(message + "Creating Space For Dead Drops.", progress += step); } catch (Exception e) { e.printStackTrace(); } DisplayController.refreshBayArea(); File deadDropsDir = new File(personalResources.resolve("deaddrops").toAbsolutePath().toString()); deadDropsDir.mkdir(); System.err.println("**** Hardwired call in Apollo's AuthioPathManager"); AudioPathManager.activateAndScanAudioDir(); // **** try { progressBar.UpdateMessage(message + "Done.", 100); } catch (Exception e) { e.printStackTrace(); } DisplayController.refreshBayArea(); } private static TextSetting constructTextSetting(String tooltip, String text, String data) { return new TextSetting(tooltip, text) { @Override public Text generateText() { Text t = new Text(text); t.setData(data); return t; } }; } private static GenericSetting constructGenericSetting(Class type, String tooltip, String name, T value, String frameset) { return new GenericSetting(type, tooltip, name, value) { @Override public Text generateRepresentation(String name, String frameset) { Text t = new Text(name + ": " + value); return t; } }; } }