diff --git a/src/main/java/com/baloise/confluence/digitalsignature/Signature.java b/src/main/java/com/baloise/confluence/digitalsignature/Signature.java index 6929c16..e084eed 100644 --- a/src/main/java/com/baloise/confluence/digitalsignature/Signature.java +++ b/src/main/java/com/baloise/confluence/digitalsignature/Signature.java @@ -1,175 +1,203 @@ package com.baloise.confluence.digitalsignature; -import com.atlassian.bandana.BandanaManager; -import com.google.common.collect.Sets; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; +import static org.apache.commons.codec.digest.DigestUtils.sha256Hex; import java.io.Serializable; -import java.util.*; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +public class Signature implements Serializable, Cloneable { + + private static final long serialVersionUID = 1L; + + private String key = ""; + private String hash = ""; + private long pageId; + private String title = ""; + private String body = ""; + private long maxSignatures = -1; + private long visibilityLimit = -1; + private Map signatures = new HashMap<>(); + private Set missingSignatures = new TreeSet<>(); + private Set notified = new TreeSet<>(); + + public Signature() { + } -import static com.atlassian.confluence.setup.bandana.ConfluenceBandanaContext.GLOBAL_CONTEXT; -import static org.apache.commons.codec.digest.DigestUtils.sha256Hex; + public Signature(long pageId, String body, String title) { + this.pageId = pageId; + this.body = body; + this.title = title == null ? "" : title; + hash = sha256Hex(pageId + ":" + title + ":" + body); + key = "signature." + hash; + } + + public static boolean isPetitionMode(Set userGroups) { + return userGroups != null && userGroups.size() == 1 && userGroups.iterator().next().trim().equals("*"); + } + + public String getHash() { + if (hash == null) { + hash = getKey().replace("signature.", ""); + } + return hash; + } + + public void setHash(String hash) { + this.hash = hash; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getProtectedKey() { + return "protected." + getHash(); + } + + public long getPageId() { + return pageId; + } -@Slf4j -@Getter -@Setter -@NoArgsConstructor -public class Signature implements Serializable { - public static final Gson GSON = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ssz").create(); - private static final long serialVersionUID = 1L; - private String key = ""; - private String hash = ""; - private long pageId; - private String title = ""; - private String body = ""; - private long maxSignatures = -1; - private long visibilityLimit = -1; - private Map signatures = new HashMap<>(); - private Set missingSignatures = new TreeSet<>(); - private Set notify = new TreeSet<>(); - - public Signature(long pageId, String body, String title) { - this.pageId = pageId; - this.body = body; - this.title = title == null ? "" : title; - this.hash = sha256Hex(pageId + ":" + title + ":" + body); - this.key = "signature." + hash; - } - - public static boolean isPetitionMode(Set userGroups) { - return userGroups != null - && userGroups.size() == 1 - && userGroups.iterator().next().trim().equals("*"); - } - - static Signature deserialize(String serialization) { - return GSON.fromJson(serialization, Signature.class); - } - - public static Signature fromBandana(BandanaManager mgr, String key) { - if (mgr.getKeys(GLOBAL_CONTEXT) == null - || !Sets.newHashSet(mgr.getKeys(GLOBAL_CONTEXT)).contains(key)) { - return null; - } - - Object value = mgr.getValue(GLOBAL_CONTEXT, key); - - if (value == null) { - throw new IllegalArgumentException("Value is null in Bandana???"); - } - - if (value instanceof Signature) { - // required for downward compatibility - update for next time. - Signature signature = (Signature) value; - toBandana(mgr, key, signature); - return signature; - } - - if (value instanceof String) { - try { - return deserialize((String) value); - } catch (Exception e) { - log.error("Could not deserialize String value from Bandana", e); - return null; - } - } - - throw new IllegalArgumentException(String.format("Could not deserialize %s value from Bandana. Please clear the plugin-cache and reboot confluence. (https://github.com/baloise/digital-signature/issues/82)", value)); - } - - public static void toBandana(BandanaManager mgr, String key, Signature sig) { - mgr.setValue(GLOBAL_CONTEXT, key, sig.serialize()); - } - - public static void toBandana(BandanaManager mgr, Signature sig) { - toBandana(mgr, sig.getKey(), sig); - } - - String serialize() { - return GSON.toJson(this, Signature.class); - } - - public String getHash() { - if (hash == null) { - hash = getKey().replace("signature.", ""); - } - return hash; - } - - public String getProtectedKey() { - return "protected." + getHash(); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((key == null) ? 0 : key.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - - return Objects.equals(key, ((Signature) obj).key); - } - - public Signature withNotified(Set notified) { - this.notify = notified; - return this; - } - - public Signature withMaxSignatures(long maxSignatures) { - this.maxSignatures = maxSignatures; - return this; - } - - public Signature withVisibilityLimit(long visibilityLimit) { - this.visibilityLimit = visibilityLimit; - return this; - } + public void setPageId(long pageId) { + this.pageId = pageId; + } - public boolean hasSigned(String userName) { - return signatures.containsKey(userName); - } + public String getBody() { + return body; + } - public boolean isPetitionMode() { - return isPetitionMode(getMissingSignatures()); - } + public void setBody(String body) { + this.body = body; + } - public boolean sign(String userName) { - if (!isMaxSignaturesReached() && !isPetitionMode() && !getMissingSignatures().remove(userName)) { - return false; + public Map getSignatures() { + return signatures; } - getSignatures().put(userName, new Date()); - return true; - } + public void setSignatures(Map signatures) { + this.signatures = signatures; + } + + public Set getMissingSignatures() { + return missingSignatures; + } + + public void setMissingSignatures(Set missingSignatures) { + this.missingSignatures = missingSignatures; + } + + public long getVisibilityLimit() { + return visibilityLimit; + } + + public void setVisibilityLimit(long visibilityLimit) { + this.visibilityLimit = visibilityLimit; + } + + public long getMaxSignatures() { + return maxSignatures; + } + + public void setMaxSignatures(long maxSignatures) { + this.maxSignatures = maxSignatures; + } - public boolean isMaxSignaturesReached() { - return maxSignatures > -1 && maxSignatures <= getSignatures().size(); - } - - public boolean isSignatureMissing(String userName) { - return !isMaxSignaturesReached() && !hasSigned(userName) && isSignatory(userName); - } - - public boolean isSignatory(String userName) { - return isPetitionMode() || getMissingSignatures().contains(userName); - } - - public boolean hasMissingSignatures() { - return !isMaxSignaturesReached() && (isPetitionMode() || !getMissingSignatures().isEmpty()); - } + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public Set getNotify() { + return notified; + } + + public void setNotify(Set notify) { + this.notified = notify; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((key == null) ? 0 : key.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Signature other = (Signature) obj; + if (key == null) { + return other.key == null; + } else return key.equals(other.key); + } + + public Signature withNotified(Set notified) { + this.notified = notified; + return this; + } + + public Signature withMaxSignatures(long maxSignatures) { + this.maxSignatures = maxSignatures; + return this; + } + + public Signature withVisibilityLimit(long visibilityLimit) { + this.visibilityLimit = visibilityLimit; + return this; + } + + public boolean hasSigned(String userName) { + return signatures.containsKey(userName); + } + + public boolean isPetitionMode() { + return isPetitionMode(getMissingSignatures()); + } + + public boolean sign(String userName) { + if (!isMaxSignaturesReached() && !isPetitionMode() && !getMissingSignatures().remove(userName)) { + return false; + } else { + getSignatures().put(userName, new Date()); + return true; + } + } + + public boolean isMaxSignaturesReached() { + return maxSignatures > -1 && maxSignatures <= getSignatures().size(); + } + + public boolean isSignatureMissing(String userName) { + return !isMaxSignaturesReached() && !hasSigned(userName) && isSignatory(userName); + } + + public boolean isSignatory(String userName) { + return isPetitionMode() || getMissingSignatures().contains(userName); + } + + public boolean hasMissingSignatures() { + return !isMaxSignaturesReached() && (isPetitionMode() || !getMissingSignatures().isEmpty()); + } + + @Override + public Signature clone() throws CloneNotSupportedException{ + return (Signature) super.clone(); + } } diff --git a/src/main/java/com/baloise/confluence/digitalsignature/Signature2.java b/src/main/java/com/baloise/confluence/digitalsignature/Signature2.java new file mode 100644 index 0000000..e57dfad --- /dev/null +++ b/src/main/java/com/baloise/confluence/digitalsignature/Signature2.java @@ -0,0 +1,180 @@ +package com.baloise.confluence.digitalsignature; + +import com.atlassian.bandana.BandanaManager; +import com.google.common.collect.Sets; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + +import java.io.Serializable; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.TreeSet; + +import static com.atlassian.confluence.setup.bandana.ConfluenceBandanaContext.GLOBAL_CONTEXT; +import static org.apache.commons.codec.digest.DigestUtils.sha256Hex; + +@Slf4j +@Getter +@Setter +@NoArgsConstructor +public class Signature2 implements Serializable { + public static final Gson GSON = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ssz").create(); + private static final long serialVersionUID = 1L; + private String key = ""; + private String hash = ""; + private long pageId; + private String title = ""; + private String body = ""; + private long maxSignatures = -1; + private long visibilityLimit = -1; + private Map signatures = new HashMap<>(); + private Set missingSignatures = new TreeSet<>(); + private Set notify = new TreeSet<>(); + + public Signature2(long pageId, String body, String title) { + this.pageId = pageId; + this.body = body; + this.title = title == null ? "" : title; + this.hash = sha256Hex(pageId + ":" + title + ":" + body); + this.key = "signature." + hash; + } + + public static boolean isPetitionMode(Set userGroups) { + return userGroups != null + && userGroups.size() == 1 + && userGroups.iterator().next().trim().equals("*"); + } + + static Signature2 deserialize(String serialization) { + return GSON.fromJson(serialization, Signature2.class); + } + + public static Signature2 fromBandana(BandanaManager mgr, String key) { + if (mgr.getKeys(GLOBAL_CONTEXT) == null + || !Sets.newHashSet(mgr.getKeys(GLOBAL_CONTEXT)).contains(key)) { + return null; + } + + Object value = mgr.getValue(GLOBAL_CONTEXT, key); + + if (value == null) { + throw new IllegalArgumentException("Value is null in Bandana???"); + } + + if (value instanceof Signature2) { + // required for downward compatibility - update for next time. + Signature2 signature = (Signature2) value; + toBandana(mgr, key, signature); + return signature; + } + + if (value instanceof String) { + try { + return deserialize((String) value); + } catch (Exception e) { + log.error("Could not deserialize String value from Bandana", e); + return null; + } + } + + throw new IllegalArgumentException(String.format("Could not deserialize %s value from Bandana. Please clear the plugin-cache and reboot confluence. (https://github.com/baloise/digital-signature/issues/82)", value)); + } + + public static void toBandana(BandanaManager mgr, String key, Signature2 sig) { + mgr.setValue(GLOBAL_CONTEXT, key, sig.serialize()); + } + + public static void toBandana(BandanaManager mgr, Signature2 sig) { + toBandana(mgr, sig.getKey(), sig); + } + + String serialize() { + return GSON.toJson(this, Signature2.class); + } + + public String getHash() { + if (hash == null) { + hash = getKey().replace("signature.", ""); + } + return hash; + } + + public String getProtectedKey() { + return "protected." + getHash(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((key == null) ? 0 : key.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + + return Objects.equals(key, ((Signature2) obj).key); + } + + public Signature2 withNotified(Set notified) { + this.notify = notified; + return this; + } + + public Signature2 withMaxSignatures(long maxSignatures) { + this.maxSignatures = maxSignatures; + return this; + } + + public Signature2 withVisibilityLimit(long visibilityLimit) { + this.visibilityLimit = visibilityLimit; + return this; + } + + public boolean hasSigned(String userName) { + return signatures.containsKey(userName); + } + + public boolean isPetitionMode() { + return isPetitionMode(getMissingSignatures()); + } + + public boolean sign(String userName) { + if (!isMaxSignaturesReached() && !isPetitionMode() && !getMissingSignatures().remove(userName)) { + return false; + } + + getSignatures().put(userName, new Date()); + return true; + } + + public boolean isMaxSignaturesReached() { + return maxSignatures > -1 && maxSignatures <= getSignatures().size(); + } + + public boolean isSignatureMissing(String userName) { + return !isMaxSignaturesReached() && !hasSigned(userName) && isSignatory(userName); + } + + public boolean isSignatory(String userName) { + return isPetitionMode() || getMissingSignatures().contains(userName); + } + + public boolean hasMissingSignatures() { + return !isMaxSignaturesReached() && (isPetitionMode() || !getMissingSignatures().isEmpty()); + } +}