package org.expeditee.encryption.items.surrogates; import java.util.ArrayList; import java.util.Arrays; import java.util.Base64; import java.util.Collection; import java.util.List; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; import org.expeditee.gui.ItemsList; import org.expeditee.gui.MessageBay; import org.expeditee.items.Item; import org.expeditee.items.Text; import org.expeditee.settings.identity.secrets.KeyList; public class Label { private static List userLabels = new ArrayList(); private static List labelsInfo = new ArrayList(); private static int surrogateStep = 0; private static boolean isInSurrogateMode = false; private static boolean isUnprivileged = false; public static LabelInfo getLabel(String labelName) { // Maintain the local cache of user labels ensureUserLabels(); int indexOfLabel = userLabels.indexOf(labelName); if (indexOfLabel == -1) { //A label by the specified name does not exist. return unableToFindLabelResult(labelName); } else { //A label by the specified name is in the local cache and can be used. LabelInfo labelResult = labelsInfo.get(indexOfLabel); return labelResult; } } public static List progressSurrogateMode(ItemsList context) { // Maintain the local cache of user labels ensureUserLabels(); List ret; List localLabels = getLabelsFromContext(context); if (userLabels.isEmpty() || localLabels.isEmpty()) { // If either the labels in the context are empty or the user // has no labels then we are not able to enter surrogate mode. return userLabels; } ArrayList intersection = new ArrayList(userLabels); intersection.retainAll(localLabels); if (!isInSurrogateMode) { isInSurrogateMode = true; // Priming surrogate step to become zero in the loop below. surrogateStep = -1; } // We are already in surrogate mode, progress it. int index = surrogateStep + 1; boolean found = false; while (index < userLabels.size()) { String surrogateMode = userLabels.get(index); if (intersection.contains(surrogateMode)) { found = true; break; } index++; } if (found) { isUnprivileged = false; surrogateStep = index; String chosenSurrogateMode = userLabels.get(surrogateStep); ret = Arrays.asList(chosenSurrogateMode); } else { if (surrogateStep >= userLabels.size()) { surrogateStep = 0; isInSurrogateMode = false; isUnprivileged = false; ret = intersection; } else { ret = new ArrayList(); surrogateStep = index; isUnprivileged = true; } } return ret; } public static void resetSurrogateMode() { // Maintain the local cache of user labels ensureUserLabels(); surrogateStep = 0; isInSurrogateMode = false; } public static List getAccessibleLabelsNames(ItemsList itemsList) { // Maintain the local cache of user labels ensureUserLabels(); if (isInSurrogateMode) { if (isUnprivileged) { return new ArrayList(); } else { return Arrays.asList(userLabels.get(surrogateStep)); } } else { return getLabelsFromContext(itemsList); } } private static void ensureUserLabels() { List userSettingsLabelNames = KeyList.getLabelsNameOnly(); boolean hasNoKeys = userLabels.isEmpty() && userSettingsLabelNames.isEmpty(); boolean hasNotChanged = userLabels.equals(userSettingsLabelNames) || hasNoKeys; if (hasNotChanged) { return; } // Deal with the fact that the position of our current surrogate mode // might have moved in the users list of labels. if (userLabels.size() > surrogateStep) { String surrogateMode = userLabels.get(surrogateStep); int newIndexOfSurrogateMode = userSettingsLabelNames.indexOf(surrogateMode); if (newIndexOfSurrogateMode >= 0) { surrogateStep = newIndexOfSurrogateMode; } else { surrogateStep = 0; isInSurrogateMode = false; MessageBay.displayMessage("You have lost access to the encryption label " + surrogateMode + ". Dropping out of surrogate mode."); } } // (Re)Initialise the userLabels list and labelResultsCache. userLabels.clear(); labelsInfo.clear(); Text[] userSettings = KeyList.UserLabels.get(); for (Text userSetting: userSettings) { String labelName = userSetting.getName(); List data = userSetting.getData(); if (data == null || data.isEmpty()) { continue; } // Extract the data and check if we have a full or partial key. String dataEntry = data.get(0); if (dataEntry.contains("{")) { userLabels.add(labelName); LabelInfo labelInfo = new LabelInfo(LabelResult.SuccessResolveLabelToPartialKey, labelName, null); labelsInfo.add(labelInfo); } else { userLabels.add(labelName); byte[] key = Base64.getDecoder().decode(dataEntry); LabelInfo labelInfo = new LabelInfo(LabelResult.SuccessResolveLabelToKey, labelName, key); labelsInfo.add(labelInfo); } } } private static List getLabelsFromContext(ItemsList context) { Predicate hasEncryptionLabel = item -> item.getEncryptionLabel() != null && !item.getEncryptionLabel().isEmpty(); Collection local = new ItemsList(context).underlying(); Stream itemsWithLabel = local.stream().filter(hasEncryptionLabel); Stream labels = itemsWithLabel.map(item -> item.getEncryptionLabel()).distinct(); return labels.collect(Collectors.toList()); } private static LabelInfo unableToFindLabelResult(String label) { LabelInfo info = new LabelInfo(LabelResult.ErrorUnableToFindLabel, label, null); return info; } public static class LabelInfo { public byte[] key; public String name; public LabelResult type; public LabelInfo(LabelResult type, String name, byte[] key) { this.type = type; this.name = name; this.key = key; } public boolean is(LabelResult type) { return this.type == type; } public String toString() { switch(type) { case SuccessResolveLabelToKey: return "Resolved label to key: " + Base64.getEncoder().encodeToString(key); case SuccessResolveLabelToPartialKey: return "Resolved label to slice of a key: " + Base64.getEncoder().encodeToString(key); case ErrorUnableToFindSecretsFrame: return "Unable to find your Secrets Frame."; case ErrorUnableToFindLabel: return "Unable to resolve label to encrypt/decrypt frame. Label: " + name; case ErrorForbiddenLabel: return "Whilst you have the key for label " + name + " ; you are not allowed to use it."; } String message = "Was the list of possible enum results updated without nessasary changes to the toString() function?"; throw new IllegalArgumentException(message); } } public enum LabelResult { SuccessResolveLabelToKey, SuccessResolveLabelToPartialKey, ErrorUnableToFindSecretsFrame, ErrorUnableToFindLabel, ErrorForbiddenLabel; } }