From 38c2d0de5d608ccbf3b13624a0d98e9433b11dce Mon Sep 17 00:00:00 2001 From: Dave Date: Tue, 16 Dec 2014 01:01:48 +0200 Subject: [PATCH] Initial commit --- .gitignore | 1 + src/nodash/core/NoConfig.java | 70 ++++++ src/nodash/core/NoCore.java | 82 +++++++ src/nodash/core/NoRegister.java | 6 + src/nodash/core/NoUtil.java | 191 +++++++++++++++ src/nodash/core/spheres/NoByteSetSphere.java | 38 +++ src/nodash/core/spheres/NoHashSphere.java | 77 ++++++ src/nodash/core/spheres/NoSessionSphere.java | 165 +++++++++++++ .../NoByteSetBadDecryptionException.java | 13 ++ .../NoCannotGetInfluenceException.java | 18 ++ src/nodash/exceptions/NoDashException.java | 13 ++ .../exceptions/NoDashFatalException.java | 13 ++ .../exceptions/NoDashSessionBadUUID.java | 13 ++ .../exceptions/NoDashTemporaryError.java | 13 ++ ...nAlreadyAwaitingConfirmationException.java | 5 + .../NoSessionConfirmedException.java | 5 + .../exceptions/NoSessionExpiredException.java | 5 + ...ssionNotAwaitingConfirmationException.java | 5 + .../NoSessionNotChangedException.java | 5 + .../NoUserAlreadyOnlineException.java | 6 + .../exceptions/NoUserNotValidException.java | 13 ++ src/nodash/models/NoAction.java | 9 + src/nodash/models/NoByteSet.java | 12 + src/nodash/models/NoInfluence.java | 70 ++++++ src/nodash/models/NoSession.java | 220 ++++++++++++++++++ src/nodash/models/NoUser.java | 151 ++++++++++++ .../noactiontypes/NoErrorableAction.java | 33 +++ .../noactiontypes/NoHandshakeAction.java | 44 ++++ .../models/noactiontypes/NoSourcedAction.java | 41 ++++ .../noactiontypes/NoTargetedAction.java | 40 ++++ 30 files changed, 1377 insertions(+) create mode 100644 .gitignore create mode 100644 src/nodash/core/NoConfig.java create mode 100644 src/nodash/core/NoCore.java create mode 100644 src/nodash/core/NoRegister.java create mode 100644 src/nodash/core/NoUtil.java create mode 100644 src/nodash/core/spheres/NoByteSetSphere.java create mode 100644 src/nodash/core/spheres/NoHashSphere.java create mode 100644 src/nodash/core/spheres/NoSessionSphere.java create mode 100644 src/nodash/exceptions/NoByteSetBadDecryptionException.java create mode 100644 src/nodash/exceptions/NoCannotGetInfluenceException.java create mode 100644 src/nodash/exceptions/NoDashException.java create mode 100644 src/nodash/exceptions/NoDashFatalException.java create mode 100644 src/nodash/exceptions/NoDashSessionBadUUID.java create mode 100644 src/nodash/exceptions/NoDashTemporaryError.java create mode 100644 src/nodash/exceptions/NoSessionAlreadyAwaitingConfirmationException.java create mode 100644 src/nodash/exceptions/NoSessionConfirmedException.java create mode 100644 src/nodash/exceptions/NoSessionExpiredException.java create mode 100644 src/nodash/exceptions/NoSessionNotAwaitingConfirmationException.java create mode 100644 src/nodash/exceptions/NoSessionNotChangedException.java create mode 100644 src/nodash/exceptions/NoUserAlreadyOnlineException.java create mode 100644 src/nodash/exceptions/NoUserNotValidException.java create mode 100644 src/nodash/models/NoAction.java create mode 100644 src/nodash/models/NoByteSet.java create mode 100644 src/nodash/models/NoInfluence.java create mode 100644 src/nodash/models/NoSession.java create mode 100644 src/nodash/models/NoUser.java create mode 100644 src/nodash/models/noactiontypes/NoErrorableAction.java create mode 100644 src/nodash/models/noactiontypes/NoHandshakeAction.java create mode 100644 src/nodash/models/noactiontypes/NoSourcedAction.java create mode 100644 src/nodash/models/noactiontypes/NoTargetedAction.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ae3c172 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/src/nodash/core/NoConfig.java b/src/nodash/core/NoConfig.java new file mode 100644 index 0000000..9b50c26 --- /dev/null +++ b/src/nodash/core/NoConfig.java @@ -0,0 +1,70 @@ +package nodash.core; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.nio.file.Files; +import java.nio.file.StandardOpenOption; +import java.security.NoSuchAlgorithmException; + +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; + +import nodash.exceptions.NoDashFatalException; + +public class NoConfig implements Serializable { + private static final long serialVersionUID = -8498303909736017075L; + + public static final String CONFIG_FILENAME = "noconfig.cfg"; + + public SecretKey secretKey; + + public boolean saveDatabase = true; + public String databaseFilename = "nodatabase.hash"; + public boolean saveByteSets = false; + public String byteSetFilename = ""; + + public NoConfig() { + try { + KeyGenerator keyGenerator = KeyGenerator.getInstance(NoUtil.CIPHER_KEY_SPEC); + keyGenerator.init(NoUtil.AES_STRENGTH); + this.secretKey = keyGenerator.generateKey(); + } catch (NoSuchAlgorithmException e) { + throw new NoDashFatalException("Value for CIPHER_KEY_SPEC not valid."); + } + } + + public void saveNoConfigToFile(File file) { + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(this); + byte[] data = baos.toByteArray(); + + Files.write(file.toPath(), data, StandardOpenOption.CREATE_NEW); + } catch (IOException e) { + throw new NoDashFatalException("Unable to save config, including generated secret key."); + } + } + + public static NoConfig getNoConfigFromFile(File file) { + try { + byte[] data = Files.readAllBytes(file.toPath()); + ByteArrayInputStream bais = new ByteArrayInputStream(data); + ObjectInputStream ois = new ObjectInputStream(bais); + NoConfig noConfig; + try { + noConfig = (NoConfig) ois.readObject(); + } catch (ClassNotFoundException e) { + throw new NoDashFatalException("Given bytestream does not compile into a configuration object."); + } + return noConfig; + } catch (IOException e) { + throw new NoDashFatalException("Instructed to read config from file but unable to do so."); + } + } +} diff --git a/src/nodash/core/NoCore.java b/src/nodash/core/NoCore.java new file mode 100644 index 0000000..fa6bbbf --- /dev/null +++ b/src/nodash/core/NoCore.java @@ -0,0 +1,82 @@ +package nodash.core; + +import java.io.File; +import java.security.PublicKey; + +import nodash.core.spheres.NoByteSetSphere; +import nodash.core.spheres.NoHashSphere; +import nodash.core.spheres.NoSessionSphere; +import nodash.exceptions.NoDashSessionBadUUID; +import nodash.exceptions.NoSessionAlreadyAwaitingConfirmationException; +import nodash.exceptions.NoSessionConfirmedException; +import nodash.exceptions.NoSessionExpiredException; +import nodash.exceptions.NoSessionNotAwaitingConfirmationException; +import nodash.exceptions.NoSessionNotChangedException; +import nodash.exceptions.NoUserAlreadyOnlineException; +import nodash.exceptions.NoUserNotValidException; +import nodash.models.NoByteSet; +import nodash.models.NoUser; +import nodash.models.NoSession.NoState; + +public final class NoCore { + public static NoConfig config; + + public static void setup() { + File configFile = new File(NoConfig.CONFIG_FILENAME); + if (configFile.exists()) { + config = NoConfig.getNoConfigFromFile(configFile); + } else { + config = new NoConfig(); + config.saveNoConfigToFile(configFile); + } + + NoHashSphere.setup(); + } + + public static byte[] login(byte[] data, char[] password) throws NoUserNotValidException, NoUserAlreadyOnlineException, NoSessionExpiredException { + /* steps 1 through to pre-3 */ + return NoSessionSphere.login(data, password); + } + + public static NoRegister register(NoUser user, char[] password) { + /* Straight to step 4 */ + return NoSessionSphere.registerUser(user, password); + } + + public static NoUser getUser(byte[] cookie) throws NoSessionExpiredException, NoSessionConfirmedException, NoDashSessionBadUUID { + /* Facilitates step 3 + * allow website-side modifications to the NoUser or NoUser inheritant */ + return NoSessionSphere.getUser(cookie); + } + + public static NoState getSessionState(byte[] cookie) throws NoSessionExpiredException, NoSessionConfirmedException, NoDashSessionBadUUID { + /* Facilitates step 3 + * allow front-side to keep track of session state */ + return NoSessionSphere.getState(cookie); + } + + public static byte[] requestSave(byte[] cookie, char[] password) throws NoSessionExpiredException, NoSessionConfirmedException, NoSessionNotChangedException, NoSessionAlreadyAwaitingConfirmationException, NoDashSessionBadUUID { + /* Step 4. Provides a user with the new binary file */ + return NoSessionSphere.save(cookie, password); + } + + public static void confirm(byte[] cookie, char[] password, byte[] data) throws NoSessionExpiredException, NoSessionConfirmedException, NoSessionNotAwaitingConfirmationException, NoUserNotValidException, NoDashSessionBadUUID { + /* Step 5. Assumes the user has re-uploaded the file along with providing the same password. + * Further attempts of getUser or getSessionState will fail with a NoSessionExpiredException*/ + NoSessionSphere.confirm(cookie, password, data); + } + + public static void addByteSet(NoByteSet byteSet, PublicKey publicKey) { + NoByteSetSphere.add(byteSet, publicKey); + } + + public static void shred(byte[] cookie) { + /* 3.2 Hot pull */ + NoSessionSphere.shred(cookie); + } + + public static void triggerPrune() { + NoSessionSphere.prune(); + } + +} \ No newline at end of file diff --git a/src/nodash/core/NoRegister.java b/src/nodash/core/NoRegister.java new file mode 100644 index 0000000..fd59fc2 --- /dev/null +++ b/src/nodash/core/NoRegister.java @@ -0,0 +1,6 @@ +package nodash.core; + +public final class NoRegister { + public byte[] cookie; + public byte[] data; +} \ No newline at end of file diff --git a/src/nodash/core/NoUtil.java b/src/nodash/core/NoUtil.java new file mode 100644 index 0000000..3ca92a1 --- /dev/null +++ b/src/nodash/core/NoUtil.java @@ -0,0 +1,191 @@ +package nodash.core; + +import java.security.InvalidKeyException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.SecretKeySpec; + +import nodash.exceptions.NoDashFatalException; + +public final class NoUtil { + public static final String CIPHER_TYPE = "AES/ECB/PKCS5PADDING"; + public static final String CIPHER_KEY_SPEC = "AES"; + public static final String DIGEST_TYPE = "SHA-512"; + public static final String PBE_TYPE = "PBKDF2WithHmacSHA1"; + public static final String CIPHER_RSA_TYPE = "RSA/ECB/PKCS1PADDING"; + public static final String KEYPAIR_ALGORITHM = "RSA"; + public static final String SECURERANDOM_ALGORITHM = "SHA1PRNG"; + public static final String SECURERANDOM_PROVIDER = "SUN"; + public static final int RSA_STRENGTH = 4096; + public static final int AES_STRENGTH = 256; + public static final byte BLANK_BYTE = 'A'; + + public static char[] bytesToChars(byte[] array) { + char[] result = new char[array.length]; + for (int x=0; x EMPTY_BYTESET_LIST = new ArrayList(0); + + private static ConcurrentHashMap> byteSets = new ConcurrentHashMap>(); + + public static void add(NoByteSet byteSet, PublicKey publicKey) { + if (!NoByteSetSphere.byteSets.containsKey(publicKey)) { + NoByteSetSphere.byteSets.put(publicKey, new ArrayList()); + } + NoByteSetSphere.byteSets.get(publicKey).add(byteSet); + } + + public static void addList(ArrayList byteSetList, PublicKey publicKey) { + if (!NoByteSetSphere.byteSets.containsKey(publicKey)) { + NoByteSetSphere.byteSets.put(publicKey, new ArrayList()); + } + NoByteSetSphere.byteSets.get(publicKey).addAll(byteSetList); + } + + public static ArrayList consume(NoUser user) { + if (NoByteSetSphere.byteSets.containsKey(user.getRSAPublicKey())) { + ArrayList result = NoByteSetSphere.byteSets.get(user.getRSAPublicKey()); + NoByteSetSphere.byteSets.remove(user.getRSAPublicKey()); + return result; + } else { + return NoByteSetSphere.EMPTY_BYTESET_LIST; + } + } +} diff --git a/src/nodash/core/spheres/NoHashSphere.java b/src/nodash/core/spheres/NoHashSphere.java new file mode 100644 index 0000000..2920d52 --- /dev/null +++ b/src/nodash/core/spheres/NoHashSphere.java @@ -0,0 +1,77 @@ +package nodash.core.spheres; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.nio.file.Files; +import java.nio.file.StandardOpenOption; +import java.util.Collections; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import nodash.core.NoCore; +import nodash.exceptions.NoDashFatalException; +import nodash.models.NoUser; + +public final class NoHashSphere { + private static Set database = Collections.newSetFromMap(new ConcurrentHashMap()); + + @SuppressWarnings("unchecked") + public static void setup() { + if (NoCore.config.saveDatabase) { + File file = new File(NoCore.config.databaseFilename); + if (file.exists()) { + try { + byte[] data = Files.readAllBytes(file.toPath()); + ByteArrayInputStream bais = new ByteArrayInputStream(data); + ObjectInputStream ois = new ObjectInputStream(bais); + NoHashSphere.database = (Set) ois.readObject(); + ois.close(); + bais.close(); + } catch (IOException e){ + throw new NoDashFatalException("Unable to load up given database file."); + } catch (ClassNotFoundException e) { + throw new NoDashFatalException("Database file not in a verifiable format."); + } + } + } + } + + public static synchronized void saveToFile() throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(NoHashSphere.database); + byte[] data = baos.toByteArray(); + oos.close(); + baos.close(); + File file = new File(NoCore.config.databaseFilename); + Files.write(file.toPath(), data, StandardOpenOption.CREATE); + } + + public static synchronized void addNewNoUser(NoUser user) throws IOException { + String hash = user.createHashString(); + NoHashSphere.database.add(hash); + NoHashSphere.saveToFile(); + } + + public static synchronized void insertHash(String hash) throws IOException { + NoHashSphere.database.add(hash); + NoHashSphere.saveToFile(); + } + + public static synchronized void removeHash(String hash) throws IOException { + NoHashSphere.database.remove(hash); + NoHashSphere.saveToFile(); + } + + public static synchronized boolean checkHash(String hash) { + return NoHashSphere.database.contains(hash); + } + + public static synchronized int size() { + return NoHashSphere.database.size(); + } +} diff --git a/src/nodash/core/spheres/NoSessionSphere.java b/src/nodash/core/spheres/NoSessionSphere.java new file mode 100644 index 0000000..d072e63 --- /dev/null +++ b/src/nodash/core/spheres/NoSessionSphere.java @@ -0,0 +1,165 @@ +package nodash.core.spheres; + +import java.util.Collections; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +import nodash.core.NoRegister; +import nodash.exceptions.NoByteSetBadDecryptionException; +import nodash.exceptions.NoDashFatalException; +import nodash.exceptions.NoDashSessionBadUUID; +import nodash.exceptions.NoSessionAlreadyAwaitingConfirmationException; +import nodash.exceptions.NoSessionConfirmedException; +import nodash.exceptions.NoSessionExpiredException; +import nodash.exceptions.NoSessionNotAwaitingConfirmationException; +import nodash.exceptions.NoSessionNotChangedException; +import nodash.exceptions.NoUserAlreadyOnlineException; +import nodash.exceptions.NoUserNotValidException; +import nodash.models.NoByteSet; +import nodash.models.NoSession; +import nodash.models.NoUser; +import nodash.models.NoSession.NoState; + +public final class NoSessionSphere { + private static ConcurrentHashMap sessions = new ConcurrentHashMap(); + private static Set originalHashesOnline = Collections.newSetFromMap(new ConcurrentHashMap()); + + public static synchronized void prune() { + for (UUID uuid : NoSessionSphere.sessions.keySet()) { + pruneSingle(uuid); + } + } + + public static void shred(byte[] encryptedUUID) { + try { + UUID uuid = NoSession.decryptUUID(encryptedUUID); + if (NoSessionSphere.sessions.containsKey(uuid)) { + NoSession session = NoSessionSphere.sessions.get(uuid); + NoByteSetSphere.addList(session.incoming, session.current.getRSAPublicKey()); + NoSessionSphere.originalHashesOnline.remove(session.getOriginalHash()); + NoSessionSphere.sessions.remove(uuid); + session = null; + } + } catch (NoDashSessionBadUUID e) { + // Suppress, doesn't matter + } + } + + public static synchronized void pruneSingle(UUID uuid) { + NoSession session = NoSessionSphere.sessions.get(uuid); + try { + session.check(); + } catch (NoSessionExpiredException e) { + /* Resultant from 3.1 and 3.2 */ + NoByteSetSphere.addList(session.incoming, session.current.getRSAPublicKey()); + NoSessionSphere.originalHashesOnline.remove(session.getOriginalHash()); + NoSessionSphere.sessions.remove(uuid); + session = null; + } catch (NoSessionConfirmedException e) { + /* Should be cleaned up at 5.2 */ + } + } + + public static synchronized byte[] login(byte[] data, char[] password) throws NoUserNotValidException, NoUserAlreadyOnlineException, NoSessionExpiredException { + /* 1. Login with byte[] data and byte[] password */ + NoSession session = new NoSession(data, password); + /* 1.1. User currently has an online session, must wait for it to expire. */ + if (originalHashesOnline.contains(session.getOriginalHash())) { + throw new NoUserAlreadyOnlineException(); + } + /* 1.2. User successfully logged in: set up session records. */ + NoSessionSphere.originalHashesOnline.add(session.getOriginalHash()); + NoSessionSphere.sessions.put(session.uuid, session); + + /* 2. Check NoByteSetSphere for incoming Influences */ + session.incoming = NoByteSetSphere.consume(session.current); + for (NoByteSet nbs : session.incoming) { + /* 2.1 Decrypt NoInfluence from NoByteSet, let the current user consume them */ + try { + session.consume(nbs); + } catch (NoByteSetBadDecryptionException e) { + e.printStackTrace(); + } + } /* 2.2 Alternatively, no NoByteSets to consume */ + + try { + session.check(); + } catch (NoSessionConfirmedException e) { + /* Should be impossible to reach */ + throw new NoDashFatalException(e); + } + + /* Will set to 2.1[MODIFIED] or 2.2[IDLE] */ + + /* Precursor to 3.; allow website to associate user session with a cookie. */ + return session.getEncryptedUUID(); + } + + public static NoUser getUser(byte[] encryptedUUID) throws NoDashSessionBadUUID, NoSessionExpiredException, NoSessionConfirmedException { + UUID uuid = NoSession.decryptUUID(encryptedUUID); + if (NoSessionSphere.sessions.containsKey(uuid)) { + NoSessionSphere.pruneSingle(uuid); + return NoSessionSphere.sessions.get(uuid).getNoUser(); + } + throw new NoSessionExpiredException(); + } + + public static NoState getState(byte[] encryptedUUID) throws NoDashSessionBadUUID, NoSessionExpiredException, NoSessionConfirmedException { + UUID uuid = NoSession.decryptUUID(encryptedUUID); + if (NoSessionSphere.sessions.containsKey(uuid)) { + NoSessionSphere.pruneSingle(uuid); + NoSession session = NoSessionSphere.sessions.get(uuid); + return session.getNoState(); + } + throw new NoSessionExpiredException(); + } + + public static synchronized byte[] save(byte[] encryptedUUID, char[] password) throws NoDashSessionBadUUID, NoSessionExpiredException, NoSessionConfirmedException, NoSessionNotChangedException, NoSessionAlreadyAwaitingConfirmationException { + UUID uuid = NoSession.decryptUUID(encryptedUUID); + if (NoSessionSphere.sessions.containsKey(uuid)) { + NoSessionSphere.pruneSingle(uuid); + NoSession session = NoSessionSphere.sessions.get(uuid); + + if (session.getNoState().equals(NoState.IDLE)) { + throw new NoSessionNotChangedException(); + } else if (session.getNoState().equals(NoState.AWAITING_CONFIRMATION)) { + throw new NoSessionAlreadyAwaitingConfirmationException(); + } + return session.initiateSaveAttempt(password); + } + throw new NoSessionExpiredException(); + } + + public static synchronized void confirm(byte[] encryptedUUID, char[] password, byte[] data) throws NoDashSessionBadUUID, NoSessionExpiredException, NoSessionConfirmedException, NoSessionNotAwaitingConfirmationException, NoUserNotValidException { + UUID uuid = NoSession.decryptUUID(encryptedUUID); + if (NoSessionSphere.sessions.containsKey(uuid)) { + NoSessionSphere.pruneSingle(uuid); + NoSession session = NoSessionSphere.sessions.get(uuid); + session.confirmSave(data, password); + return; + } + throw new NoSessionExpiredException(); + } + + public static synchronized NoRegister registerUser(NoUser user, char[] password) { + NoRegister result = new NoRegister(); + NoSession session = new NoSession(user); + NoSessionSphere.sessions.put(session.uuid, session); + result.cookie = session.getEncryptedUUID(); + try { + result.data = NoSessionSphere.save(result.cookie, password); + } catch (NoDashSessionBadUUID e) { + throw new NoDashFatalException("Immediately generated cookie throwing bad cookie error."); + } catch (NoSessionExpiredException e) { + throw new NoDashFatalException("Session expired before it was even returned to client."); + } catch (NoSessionConfirmedException e) { + throw new NoDashFatalException("Session is in confirmed state before it was returned to client."); + } catch (NoSessionNotChangedException e) { + throw new NoDashFatalException("Session claims to be unchanged but user is newly registered."); + } catch (NoSessionAlreadyAwaitingConfirmationException e) { + throw new NoDashFatalException("Session claims to be awaiting confirmation before returning data to the user."); + } + return result; + } +} \ No newline at end of file diff --git a/src/nodash/exceptions/NoByteSetBadDecryptionException.java b/src/nodash/exceptions/NoByteSetBadDecryptionException.java new file mode 100644 index 0000000..4e78af5 --- /dev/null +++ b/src/nodash/exceptions/NoByteSetBadDecryptionException.java @@ -0,0 +1,13 @@ +package nodash.exceptions; + +public class NoByteSetBadDecryptionException extends Exception { + private static final long serialVersionUID = -8579497499272656543L; + + public NoByteSetBadDecryptionException() { + super(); + } + + public NoByteSetBadDecryptionException(Exception e) { + super(e); + } +} diff --git a/src/nodash/exceptions/NoCannotGetInfluenceException.java b/src/nodash/exceptions/NoCannotGetInfluenceException.java new file mode 100644 index 0000000..25d3196 --- /dev/null +++ b/src/nodash/exceptions/NoCannotGetInfluenceException.java @@ -0,0 +1,18 @@ +package nodash.exceptions; + +import nodash.models.NoInfluence; + +public class NoCannotGetInfluenceException extends NoDashException { + private static final long serialVersionUID = 4581361079067540974L; + + private NoInfluence returnable; + + public NoCannotGetInfluenceException(NoInfluence returnable) { + super(); + this.returnable = returnable; + } + + public NoInfluence getResponseInfluence() { + return returnable; + } +} diff --git a/src/nodash/exceptions/NoDashException.java b/src/nodash/exceptions/NoDashException.java new file mode 100644 index 0000000..89b5c1e --- /dev/null +++ b/src/nodash/exceptions/NoDashException.java @@ -0,0 +1,13 @@ +package nodash.exceptions; + +public class NoDashException extends Exception { + private static final long serialVersionUID = -8579497499272656543L; + + public NoDashException() { + super(); + } + + public NoDashException(Exception e) { + super(e); + } +} diff --git a/src/nodash/exceptions/NoDashFatalException.java b/src/nodash/exceptions/NoDashFatalException.java new file mode 100644 index 0000000..b58e260 --- /dev/null +++ b/src/nodash/exceptions/NoDashFatalException.java @@ -0,0 +1,13 @@ +package nodash.exceptions; + +public class NoDashFatalException extends RuntimeException { + private static final long serialVersionUID = -8254102569327237811L; + + public NoDashFatalException(Exception e) { + super(e); + } + + public NoDashFatalException(String string) { + super(string); + } +} diff --git a/src/nodash/exceptions/NoDashSessionBadUUID.java b/src/nodash/exceptions/NoDashSessionBadUUID.java new file mode 100644 index 0000000..b7fe33b --- /dev/null +++ b/src/nodash/exceptions/NoDashSessionBadUUID.java @@ -0,0 +1,13 @@ +package nodash.exceptions; + +public class NoDashSessionBadUUID extends Exception { + private static final long serialVersionUID = -402131397575158344L; + + public NoDashSessionBadUUID() { + super(); + } + + public NoDashSessionBadUUID(Exception e) { + super(e); + } +} diff --git a/src/nodash/exceptions/NoDashTemporaryError.java b/src/nodash/exceptions/NoDashTemporaryError.java new file mode 100644 index 0000000..c88aecb --- /dev/null +++ b/src/nodash/exceptions/NoDashTemporaryError.java @@ -0,0 +1,13 @@ +package nodash.exceptions; + +public class NoDashTemporaryError extends Exception { + private static final long serialVersionUID = 7940405670235375662L; + + public NoDashTemporaryError() { + super(); + } + + public NoDashTemporaryError(Exception e) { + super(e); + } +} diff --git a/src/nodash/exceptions/NoSessionAlreadyAwaitingConfirmationException.java b/src/nodash/exceptions/NoSessionAlreadyAwaitingConfirmationException.java new file mode 100644 index 0000000..564ef7f --- /dev/null +++ b/src/nodash/exceptions/NoSessionAlreadyAwaitingConfirmationException.java @@ -0,0 +1,5 @@ +package nodash.exceptions; + +public class NoSessionAlreadyAwaitingConfirmationException extends NoDashException { + private static final long serialVersionUID = 6046203718016296554L; +} diff --git a/src/nodash/exceptions/NoSessionConfirmedException.java b/src/nodash/exceptions/NoSessionConfirmedException.java new file mode 100644 index 0000000..c0a2e04 --- /dev/null +++ b/src/nodash/exceptions/NoSessionConfirmedException.java @@ -0,0 +1,5 @@ +package nodash.exceptions; + +public class NoSessionConfirmedException extends NoDashException { + private static final long serialVersionUID = -8065331145629402524L; +} diff --git a/src/nodash/exceptions/NoSessionExpiredException.java b/src/nodash/exceptions/NoSessionExpiredException.java new file mode 100644 index 0000000..a6e98c4 --- /dev/null +++ b/src/nodash/exceptions/NoSessionExpiredException.java @@ -0,0 +1,5 @@ +package nodash.exceptions; + +public class NoSessionExpiredException extends NoDashException { + private static final long serialVersionUID = -541733773743173644L; +} diff --git a/src/nodash/exceptions/NoSessionNotAwaitingConfirmationException.java b/src/nodash/exceptions/NoSessionNotAwaitingConfirmationException.java new file mode 100644 index 0000000..7fea548 --- /dev/null +++ b/src/nodash/exceptions/NoSessionNotAwaitingConfirmationException.java @@ -0,0 +1,5 @@ +package nodash.exceptions; + +public class NoSessionNotAwaitingConfirmationException extends NoDashException { + private static final long serialVersionUID = -2563955621281305198L; +} diff --git a/src/nodash/exceptions/NoSessionNotChangedException.java b/src/nodash/exceptions/NoSessionNotChangedException.java new file mode 100644 index 0000000..c763e78 --- /dev/null +++ b/src/nodash/exceptions/NoSessionNotChangedException.java @@ -0,0 +1,5 @@ +package nodash.exceptions; + +public class NoSessionNotChangedException extends NoDashException { + private static final long serialVersionUID = 8049751796255114602L; +} diff --git a/src/nodash/exceptions/NoUserAlreadyOnlineException.java b/src/nodash/exceptions/NoUserAlreadyOnlineException.java new file mode 100644 index 0000000..09abc0b --- /dev/null +++ b/src/nodash/exceptions/NoUserAlreadyOnlineException.java @@ -0,0 +1,6 @@ +package nodash.exceptions; + +public class NoUserAlreadyOnlineException extends NoDashException { + private static final long serialVersionUID = -2922060333175653034L; + +} diff --git a/src/nodash/exceptions/NoUserNotValidException.java b/src/nodash/exceptions/NoUserNotValidException.java new file mode 100644 index 0000000..2415d5e --- /dev/null +++ b/src/nodash/exceptions/NoUserNotValidException.java @@ -0,0 +1,13 @@ +package nodash.exceptions; + +public class NoUserNotValidException extends NoDashException { + private static final long serialVersionUID = -6432604940919299965L; + + public NoUserNotValidException(Exception e) { + super(e); + } + + public NoUserNotValidException() { + + } +} diff --git a/src/nodash/models/NoAction.java b/src/nodash/models/NoAction.java new file mode 100644 index 0000000..da1a2f2 --- /dev/null +++ b/src/nodash/models/NoAction.java @@ -0,0 +1,9 @@ +package nodash.models; + +import java.io.Serializable; + +public abstract class NoAction implements Serializable { + private static final long serialVersionUID = -194752850197321803L; + public abstract void execute(); + public abstract void purge(); +} diff --git a/src/nodash/models/NoByteSet.java b/src/nodash/models/NoByteSet.java new file mode 100644 index 0000000..23a66e4 --- /dev/null +++ b/src/nodash/models/NoByteSet.java @@ -0,0 +1,12 @@ +package nodash.models; + +public final class NoByteSet { + public byte[] key; + public byte[] data; + + public NoByteSet(byte[] key, byte[] data) { + this.key = key; + this.data = data; + } + +} \ No newline at end of file diff --git a/src/nodash/models/NoInfluence.java b/src/nodash/models/NoInfluence.java new file mode 100644 index 0000000..359303e --- /dev/null +++ b/src/nodash/models/NoInfluence.java @@ -0,0 +1,70 @@ +package nodash.models; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; + +import nodash.core.NoUtil; +import nodash.exceptions.NoDashFatalException; + +public abstract class NoInfluence implements Serializable { + private static final long serialVersionUID = -7509462039664862920L; + + public abstract void applyTo(NoUser user); + + public final NoByteSet getByteSet(PublicKey publicKey) { + KeyGenerator keyGen; + try { + keyGen = KeyGenerator.getInstance(NoUtil.CIPHER_KEY_SPEC); + } catch (NoSuchAlgorithmException e) { + throw new NoDashFatalException("Value for CIPHER_KEY_SPEC is not valid."); + } + keyGen.init(NoUtil.AES_STRENGTH); + SecretKey secretKey = keyGen.generateKey(); + System.out.println(secretKey.getClass().toString()); + byte[] key = secretKey.getEncoded(); + byte[] encryptedKey = NoUtil.encryptRSA(key, publicKey); + byte[] data = this.getEncrypted(key); + NoUtil.wipeBytes(key); + return new NoByteSet(encryptedKey, data); + } + + private final byte[] getEncrypted(byte[] key) { + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(this); + byte[] encrypted = NoUtil.encrypt(baos.toByteArray(), key); + oos.close(); + baos.close(); + return encrypted; + } catch (IOException e) { + throw new NoDashFatalException("Unable to write NoInfluence object to byte stream."); + } + } + + public static NoInfluence decrypt(byte[] data, byte[] key) throws IllegalBlockSizeException, BadPaddingException, ClassNotFoundException { + byte[] decrypted = NoUtil.decrypt(data, key); + ByteArrayInputStream bais = new ByteArrayInputStream(decrypted); + try { + ObjectInputStream ois = new ObjectInputStream(bais); + NoInfluence noInfluence = (NoInfluence) ois.readObject(); + ois.close(); + bais.close(); + return noInfluence; + } catch (IOException e) { + throw new NoDashFatalException("Unable to read out provided data stream."); + } + } + +} diff --git a/src/nodash/models/NoSession.java b/src/nodash/models/NoSession.java new file mode 100644 index 0000000..167c23c --- /dev/null +++ b/src/nodash/models/NoSession.java @@ -0,0 +1,220 @@ +package nodash.models; + +import java.io.IOException; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.UUID; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; + +import nodash.core.NoUtil; +import nodash.core.spheres.NoHashSphere; +import nodash.exceptions.NoByteSetBadDecryptionException; +import nodash.exceptions.NoDashFatalException; +import nodash.exceptions.NoDashSessionBadUUID; +import nodash.exceptions.NoSessionConfirmedException; +import nodash.exceptions.NoSessionExpiredException; +import nodash.exceptions.NoSessionNotAwaitingConfirmationException; +import nodash.exceptions.NoUserNotValidException; + +public final class NoSession implements Serializable { + private static final long serialVersionUID = 1814807373427948931L; + + public static final long SESSION_DURATION = 1000 * 60 * 30; //30 minute sessions + public static enum NoState { + IDLE, MODIFIED, AWAITING_CONFIRMATION, CONFIRMED, CLOSED; + }; + + private NoUser original; + private NoState state; + private final long expiry; + private boolean newUserSession; + + public ArrayList incoming; + public NoUser current; + public UUID uuid; + + public NoSession() { + this.state = NoState.IDLE; + this.expiry = System.currentTimeMillis() + NoSession.SESSION_DURATION; + this.uuid = UUID.randomUUID(); + } + + public NoSession(NoUser newUser) { + this(); + this.state = NoState.MODIFIED; + this.original = null; + this.current = newUser; + this.newUserSession = true; + } + + public NoSession(byte[] data, char[] password) throws NoUserNotValidException { + this(); + this.newUserSession = false; + this.state = NoState.IDLE; + char[] passwordDupe = password.clone(); + try { + this.original = NoUser.createUserFromFile(data, password); + if (NoHashSphere.checkHash(this.original.createHashString())) { + this.current = NoUser.createUserFromFile(data, passwordDupe); + this.uuid = UUID.randomUUID(); + NoUtil.wipeBytes(data); + } else { + throw new NoUserNotValidException(); + } + } catch (IOException e) { + throw new NoUserNotValidException(); + } catch (IllegalBlockSizeException e) { + throw new NoUserNotValidException(); + } catch (BadPaddingException e) { + throw new NoUserNotValidException(); + } catch (ClassNotFoundException e) { + throw new NoUserNotValidException(); + } + } + + public void check() throws NoSessionConfirmedException, NoSessionExpiredException { + if (this.state == NoState.CONFIRMED) { + throw new NoSessionConfirmedException(); + } else if (this.state == NoState.CLOSED || System.currentTimeMillis() > this.expiry) { + this.state = NoState.CLOSED; + throw new NoSessionExpiredException(); + } + } + + public NoState touchState() throws NoSessionConfirmedException, NoSessionExpiredException { + this.check(); + if (this.newUserSession) { + if (this.state != NoState.AWAITING_CONFIRMATION) { + this.state = NoState.MODIFIED; + } + } else { + String originalHash = this.original.createHashString(); + String currentHash = this.current.createHashString(); + if (originalHash.equals(currentHash)) { + this.state = NoState.IDLE; + } else if (this.state != NoState.AWAITING_CONFIRMATION) { + this.state = NoState.MODIFIED; + } + } + return this.state; + } + + public byte[] initiateSaveAttempt(char[] password) throws NoSessionConfirmedException, NoSessionExpiredException { + this.touchState(); + this.state = NoState.AWAITING_CONFIRMATION; + byte[] file = this.current.createFile(password); + NoUtil.wipeChars(password); + return file; + } + + public void confirmSave(byte[] confirmData, char[] password) throws NoSessionConfirmedException, NoSessionExpiredException, NoSessionNotAwaitingConfirmationException, NoUserNotValidException { + this.check(); + if (this.state != NoState.AWAITING_CONFIRMATION) { + throw new NoSessionNotAwaitingConfirmationException(); + } + + NoUser confirmed; + try { + confirmed = NoUser.createUserFromFile(confirmData, password); + } catch (IOException e) { + throw new NoUserNotValidException(); + } catch (IllegalBlockSizeException e) { + throw new NoUserNotValidException(); + } catch (BadPaddingException e) { + throw new NoUserNotValidException(); + } catch (ClassNotFoundException e) { + throw new NoUserNotValidException(); + } + + NoUtil.wipeBytes(confirmData); + NoUtil.wipeChars(password); + if (confirmed.createHashString().equals(this.current.createHashString())) { + this.state = NoState.CONFIRMED; + /* 5.2: confirmed! */ + if (!this.newUserSession) { + /* 5.2.1: remove old hash from array */ + try { + NoHashSphere.removeHash(this.original.createHashString()); + } catch (IOException e) { + throw new NoDashFatalException("Unable to remove hash on confirm."); + } + } + /* 5.2.2: add new hash to array */ + try { + NoHashSphere.insertHash(this.current.createHashString()); + } catch (IOException e) { + e.printStackTrace(); + throw new NoDashFatalException("Unable to remove hash on confirm."); + } + + /* 5.2.3: clear influences as they will not need to be re-applied */ + ArrayList actions = this.current.getNoActions(); + this.incoming = null; + this.original = null; + this.current = null; + /* 5.2.4: execute NoActions */ + for (NoAction action : actions) { + /* It is assumed that actions are not long-running tasks + * It is also assumed that actions have the information they need without the user objects */ + action.execute(); + action.purge(); + } + } else { + throw new NoUserNotValidException(); + } + } + + public NoState getNoState() throws NoSessionConfirmedException, NoSessionExpiredException { + this.touchState(); + return this.state; + } + + public NoUser getNoUser() throws NoSessionConfirmedException, NoSessionExpiredException { + this.check(); + return this.current; + } + + public UUID getUUID() { + return this.uuid; + } + + public String getUUIDAsString() { + return this.uuid.toString(); + } + + public byte[] getEncryptedUUID() { + return NoUtil.encrypt(this.uuid.toString().getBytes()); + } + + public String getEncryptedUUIDAsString() { + return new String(this.getEncryptedUUID()); + } + + public byte[] getOriginalHash() { + if (this.original != null) { + return this.original.createHash(); + } else { + return null; + } + } + + public static UUID decryptUUID(byte[] data) throws NoDashSessionBadUUID { + try { + return UUID.fromString(new String(NoUtil.decrypt(data))); + } catch (IllegalBlockSizeException e) { + throw new NoDashSessionBadUUID(); + } catch (BadPaddingException e) { + throw new NoDashSessionBadUUID(); + } + } + + public void consume(NoByteSet byteSet) throws NoByteSetBadDecryptionException { + this.current.consume(byteSet); + } + + public void close() { + this.state = NoState.CLOSED; + } +} diff --git a/src/nodash/models/NoUser.java b/src/nodash/models/NoUser.java new file mode 100644 index 0000000..80e1749 --- /dev/null +++ b/src/nodash/models/NoUser.java @@ -0,0 +1,151 @@ +package nodash.models; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.util.ArrayList; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +import sun.security.rsa.RSAPublicKeyImpl; +import nodash.core.NoUtil; +import nodash.exceptions.NoByteSetBadDecryptionException; + +public class NoUser implements Serializable { + private static final long serialVersionUID = 7132405837081692211L; + private PublicKey publicKey; + private PrivateKey privateKey; + + public int influences; + public int actions; + + private ArrayList outgoing = new ArrayList(); + + public NoUser() { + try { + KeyPairGenerator kpg = KeyPairGenerator.getInstance(NoUtil.KEYPAIR_ALGORITHM); + kpg.initialize(NoUtil.RSA_STRENGTH, SecureRandom.getInstance(NoUtil.SECURERANDOM_ALGORITHM, NoUtil.SECURERANDOM_PROVIDER)); + KeyPair keyPair = kpg.generateKeyPair(); + this.publicKey = keyPair.getPublic(); + this.privateKey = keyPair.getPrivate(); + this.influences = 0; + this.actions = 0; + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (NoSuchProviderException e) { + e.printStackTrace(); + } + } + + public final byte[] createFile(char[] password) { + ArrayList temp = this.outgoing; + try { + this.outgoing = new ArrayList(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(this); + byte[] encrypted = NoUtil.encryptByteArray(baos.toByteArray(), password); + oos.close(); + baos.close(); + return encrypted; + } catch (IOException e) { + e.printStackTrace(); + } finally { + this.outgoing = temp; + } + return null; + } + + public final byte[] createHash() { + ArrayList temp = this.outgoing; + try { + this.outgoing = new ArrayList(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(this); + byte[] userBytes = baos.toByteArray(); + return NoUtil.getHashFromByteArray(userBytes); + } catch (IOException e) { + e.printStackTrace(); + } finally { + this.outgoing = temp; + } + return null; + } + + public final String createHashString() { + return new String(this.createHash()); + } + + public final void consume(NoByteSet byteSet) throws NoByteSetBadDecryptionException { + try { + SecretKey secretKey = new SecretKeySpec(decryptRSA(byteSet.key), NoUtil.CIPHER_KEY_SPEC); + byte[] key = secretKey.getEncoded(); + secretKey = null; + NoInfluence influence = NoInfluence.decrypt(byteSet.data, key); + NoUtil.wipeBytes(key); + + influence.applyTo(this); + this.influences++; + } catch (BadPaddingException e) { + throw new NoByteSetBadDecryptionException(e); + } catch (IllegalBlockSizeException e) { + throw new NoByteSetBadDecryptionException(e); + } catch (ClassNotFoundException e) { + throw new NoByteSetBadDecryptionException(e); + } catch (InvalidKeyException e) { + throw new NoByteSetBadDecryptionException(e); + } + } + + public final void addAction(NoAction action) { + this.outgoing.add(action); + this.actions++; + } + + public final ArrayList getNoActions() { + return this.outgoing; + } + + public final BigInteger getPublicExponent() { + return ((RSAPublicKeyImpl) publicKey).getPublicExponent(); + } + + public final BigInteger getModulus() { + return ((RSAPublicKeyImpl) publicKey).getModulus(); + } + + public final PublicKey getRSAPublicKey() { + return (RSAPublicKeyImpl) this.publicKey; + } + + private final byte[] decryptRSA(byte[] data) throws InvalidKeyException, IllegalBlockSizeException, BadPaddingException { + return NoUtil.decryptRSA(data, this.privateKey); + } + + public static NoUser createUserFromFile(byte[] data, char[] password) throws IllegalBlockSizeException, BadPaddingException, IOException, ClassNotFoundException { + byte[] decrypted = NoUtil.decryptByteArray(data, password); + ByteArrayInputStream bais = new ByteArrayInputStream(decrypted); + ObjectInputStream ois = new ObjectInputStream(bais); + NoUser noUser = (NoUser) ois.readObject(); + ois.close(); + bais.close(); + return noUser; + } + +} \ No newline at end of file diff --git a/src/nodash/models/noactiontypes/NoErrorableAction.java b/src/nodash/models/noactiontypes/NoErrorableAction.java new file mode 100644 index 0000000..5ef66f6 --- /dev/null +++ b/src/nodash/models/noactiontypes/NoErrorableAction.java @@ -0,0 +1,33 @@ +package nodash.models.noactiontypes; + +import java.security.PublicKey; + +import nodash.core.NoCore; +import nodash.exceptions.NoCannotGetInfluenceException; +import nodash.models.NoByteSet; +import nodash.models.NoInfluence; + +public abstract class NoErrorableAction extends NoTargetedAction { + private static final long serialVersionUID = -6077150774349400823L; + + public NoErrorableAction(PublicKey target) { + super(target); + } + + public void execute() { + NoInfluence influence; + try { + influence = this.generateTargetInfluence(); + if (influence != null) { + NoByteSet byteSet = influence.getByteSet(this.target); + NoCore.addByteSet(byteSet, this.target); + } + } catch (NoCannotGetInfluenceException e) { + NoInfluence errorInfluence = e.getResponseInfluence(); + if (errorInfluence != null) { + NoByteSet byteSet = errorInfluence.getByteSet(this.target); + NoCore.addByteSet(byteSet, this.target); + } + } + } +} diff --git a/src/nodash/models/noactiontypes/NoHandshakeAction.java b/src/nodash/models/noactiontypes/NoHandshakeAction.java new file mode 100644 index 0000000..b641101 --- /dev/null +++ b/src/nodash/models/noactiontypes/NoHandshakeAction.java @@ -0,0 +1,44 @@ +package nodash.models.noactiontypes; + +import java.security.PublicKey; + +import nodash.core.NoCore; +import nodash.exceptions.NoCannotGetInfluenceException; +import nodash.models.NoByteSet; +import nodash.models.NoInfluence; + +public abstract class NoHandshakeAction extends NoSourcedAction { + private static final long serialVersionUID = 3195466136587475680L; + + protected abstract NoInfluence generateReturnedInfluence(); + + public NoHandshakeAction(PublicKey target, PublicKey source) { + super(target, source); + } + + public void execute() { + try { + NoInfluence influence = this.generateTargetInfluence(); + if (influence != null) { + NoByteSet byteSet = influence.getByteSet(this.target); + NoCore.addByteSet(byteSet, this.target); + } + + NoInfluence result = this.generateReturnedInfluence(); + if (result != null) { + NoByteSet byteSet = result.getByteSet(this.source); + NoCore.addByteSet(byteSet, this.source); + } + } catch (NoCannotGetInfluenceException e) { + NoInfluence errorInfluence = e.getResponseInfluence(); + if (errorInfluence != null) { + NoByteSet byteSet = errorInfluence.getByteSet(this.source); + NoCore.addByteSet(byteSet, this.source); + } + } + } + + public void purge() { + super.purge(); + } +} diff --git a/src/nodash/models/noactiontypes/NoSourcedAction.java b/src/nodash/models/noactiontypes/NoSourcedAction.java new file mode 100644 index 0000000..c85b5ce --- /dev/null +++ b/src/nodash/models/noactiontypes/NoSourcedAction.java @@ -0,0 +1,41 @@ +package nodash.models.noactiontypes; + +import java.security.PublicKey; + +import nodash.core.NoCore; +import nodash.exceptions.NoCannotGetInfluenceException; +import nodash.models.NoByteSet; +import nodash.models.NoInfluence; + +public abstract class NoSourcedAction extends NoTargetedAction { + private static final long serialVersionUID = -2996690472537380062L; + protected PublicKey source; + protected abstract NoInfluence generateTargetInfluence() throws NoCannotGetInfluenceException; + + public NoSourcedAction(PublicKey target, PublicKey source) { + super(target); + this.source = source; + } + + public void execute() { + NoInfluence influence; + try { + influence = this.generateTargetInfluence(); + if (influence != null) { + NoByteSet byteSet = influence.getByteSet(this.target); + NoCore.addByteSet(byteSet, this.target); + } + } catch (NoCannotGetInfluenceException e) { + NoInfluence errorInfluence = e.getResponseInfluence(); + if (errorInfluence != null) { + NoByteSet byteSet = errorInfluence.getByteSet(this.source); + NoCore.addByteSet(byteSet, this.source); + } + } + } + + public void purge() { + super.purge(); + this.source = null; + } +} diff --git a/src/nodash/models/noactiontypes/NoTargetedAction.java b/src/nodash/models/noactiontypes/NoTargetedAction.java new file mode 100644 index 0000000..844e84a --- /dev/null +++ b/src/nodash/models/noactiontypes/NoTargetedAction.java @@ -0,0 +1,40 @@ +package nodash.models.noactiontypes; + +import java.security.PublicKey; + +import nodash.core.NoCore; +import nodash.exceptions.NoCannotGetInfluenceException; +import nodash.exceptions.NoDashFatalException; +import nodash.models.NoAction; +import nodash.models.NoByteSet; +import nodash.models.NoInfluence; + +public abstract class NoTargetedAction extends NoAction { + private static final long serialVersionUID = -8893381130155149646L; + protected PublicKey target; + + protected abstract NoInfluence generateTargetInfluence() throws NoCannotGetInfluenceException; + + public NoTargetedAction(PublicKey target) { + this.target = target; + } + + public void execute() { + NoInfluence influence; + try { + influence = this.generateTargetInfluence(); + if (influence != null) { + NoByteSet byteSet = influence.getByteSet(this.target); + NoCore.addByteSet(byteSet, this.target); + } + } catch (NoCannotGetInfluenceException e) { + if (e.getResponseInfluence() != null) { + throw new NoDashFatalException("Unsourced action has generated an error with an undeliverable influence."); + } + } + } + + public void purge() { + this.target = null; + } +}