| .. | .. |
|---|
| 1 | +/* |
|---|
| 2 | +* Copyright @ 2013 CurisTEC, S.A.S. All Rights Reserved. |
|---|
| 3 | +*/ |
|---|
| 1 | 4 | package net.curisit.securis.db; |
|---|
| 2 | 5 | |
|---|
| 3 | 6 | import java.io.Serializable; |
|---|
| .. | .. |
|---|
| 21 | 24 | import com.fasterxml.jackson.annotation.JsonProperty; |
|---|
| 22 | 25 | |
|---|
| 23 | 26 | /** |
|---|
| 24 | | - * Entity implementation class for Entity: pack |
|---|
| 25 | | - * |
|---|
| 26 | | - */ |
|---|
| 27 | +* BlockedRequest |
|---|
| 28 | +* <p> |
|---|
| 29 | +* Persistent record marking a request (by hash) as blocked. |
|---|
| 30 | +* Primary key is the SHA-256 of the original request_data. |
|---|
| 31 | +* Useful to avoid replay/duplicate processing. |
|---|
| 32 | +* |
|---|
| 33 | +* Mapping details: |
|---|
| 34 | +* - Table: blocked_request |
|---|
| 35 | +* - PK: hash (SHA-256(request_data)) |
|---|
| 36 | +* - Optional relation 'blockedBy' for auditing. |
|---|
| 37 | +* |
|---|
| 38 | +* @author JRA |
|---|
| 39 | +* Last reviewed by JRA on Oct 7, 2025. |
|---|
| 40 | +*/ |
|---|
| 27 | 41 | @JsonAutoDetect |
|---|
| 28 | 42 | @JsonInclude(Include.NON_NULL) |
|---|
| 29 | 43 | @Entity |
|---|
| .. | .. |
|---|
| 33 | 47 | |
|---|
| 34 | 48 | private static final long serialVersionUID = 1L; |
|---|
| 35 | 49 | |
|---|
| 50 | + /** Unique SHA-256 hash of {@link #requestData}. */ |
|---|
| 36 | 51 | @Id |
|---|
| 37 | 52 | private String hash; |
|---|
| 38 | 53 | |
|---|
| 54 | + /** Original request payload. */ |
|---|
| 39 | 55 | @Column(name = "request_data") |
|---|
| 40 | 56 | @JsonProperty("request_data") |
|---|
| 41 | 57 | private String requestData; |
|---|
| 42 | 58 | |
|---|
| 59 | + /** Server-side creation timestamp. */ |
|---|
| 43 | 60 | @Column(name = "creation_timestamp") |
|---|
| 44 | 61 | @JsonProperty("creation_timestamp") |
|---|
| 45 | 62 | private Date creationTimestamp; |
|---|
| 46 | 63 | |
|---|
| 64 | + /** User who blocked this request (optional, auditing). */ |
|---|
| 47 | 65 | @JsonIgnore |
|---|
| 48 | 66 | @ManyToOne |
|---|
| 49 | 67 | @JoinColumn(name = "blocked_by") |
|---|
| 50 | 68 | private User blockedBy; |
|---|
| 51 | 69 | |
|---|
| 52 | | - public Date getCreationTimestamp() { |
|---|
| 53 | | - return creationTimestamp; |
|---|
| 54 | | - } |
|---|
| 70 | + // --------------------------------------------------------------------- |
|---|
| 71 | + // Getters & setters |
|---|
| 72 | + // --------------------------------------------------------------------- |
|---|
| 55 | 73 | |
|---|
| 56 | | - public void setCreationTimestamp(Date creationTimestamp) { |
|---|
| 57 | | - this.creationTimestamp = creationTimestamp; |
|---|
| 58 | | - } |
|---|
| 74 | + /** |
|---|
| 75 | + * getCreationTimestamp<p> |
|---|
| 76 | + * Get the creation timestamp. |
|---|
| 77 | + * |
|---|
| 78 | + * @return creationTimestamp |
|---|
| 79 | + */ |
|---|
| 80 | + public Date getCreationTimestamp() { return creationTimestamp; } |
|---|
| 59 | 81 | |
|---|
| 82 | + /** |
|---|
| 83 | + * setCreationTimestamp<p> |
|---|
| 84 | + * Set the creation timestamp. |
|---|
| 85 | + * |
|---|
| 86 | + * @param creationTimestamp |
|---|
| 87 | + */ |
|---|
| 88 | + public void setCreationTimestamp(Date creationTimestamp) { this.creationTimestamp = creationTimestamp; } |
|---|
| 89 | + |
|---|
| 90 | + /** |
|---|
| 91 | + * equals<p> |
|---|
| 92 | + * Identity based on primary key (hash). |
|---|
| 93 | + */ |
|---|
| 60 | 94 | @Override |
|---|
| 61 | 95 | public boolean equals(Object obj) { |
|---|
| 62 | | - if (!(obj instanceof BlockedRequest)) |
|---|
| 63 | | - return false; |
|---|
| 96 | + if (!(obj instanceof BlockedRequest)) return false; |
|---|
| 64 | 97 | BlockedRequest other = (BlockedRequest) obj; |
|---|
| 65 | | - return (hash == null && other.hash == null) || hash.equals(other.hash); |
|---|
| 98 | + return (hash == null && other.hash == null) || (hash != null && hash.equals(other.hash)); |
|---|
| 66 | 99 | } |
|---|
| 67 | 100 | |
|---|
| 101 | + /** |
|---|
| 102 | + * hashCode<p> |
|---|
| 103 | + * Hash based on primary key (hash). |
|---|
| 104 | + */ |
|---|
| 68 | 105 | @Override |
|---|
| 69 | | - public int hashCode() { |
|---|
| 106 | + public int hashCode() { return (hash == null ? 0 : hash.hashCode()); } |
|---|
| 70 | 107 | |
|---|
| 71 | | - return (hash == null ? 0 : hash.hashCode()); |
|---|
| 72 | | - } |
|---|
| 108 | + /** |
|---|
| 109 | + * getRequestData<p> |
|---|
| 110 | + * Get the original serialized request data. |
|---|
| 111 | + * |
|---|
| 112 | + * @return requestData |
|---|
| 113 | + */ |
|---|
| 114 | + public String getRequestData() { return requestData; } |
|---|
| 73 | 115 | |
|---|
| 74 | | - public String getRequestData() { |
|---|
| 75 | | - return requestData; |
|---|
| 76 | | - } |
|---|
| 77 | | - |
|---|
| 116 | + /** |
|---|
| 117 | + * setRequestData<p> |
|---|
| 118 | + * Set the original request data and recompute the PK hash immediately. |
|---|
| 119 | + * Hash is computed as SHA-256 over the request string. |
|---|
| 120 | + * |
|---|
| 121 | + * @param requestData |
|---|
| 122 | + */ |
|---|
| 78 | 123 | public void setRequestData(String requestData) { |
|---|
| 79 | 124 | this.requestData = requestData; |
|---|
| 80 | 125 | this.hash = generateHash(this.requestData); |
|---|
| 81 | 126 | } |
|---|
| 82 | 127 | |
|---|
| 83 | | - public User getBlockedBy() { |
|---|
| 84 | | - return blockedBy; |
|---|
| 85 | | - } |
|---|
| 128 | + /** |
|---|
| 129 | + * getBlockedBy<p> |
|---|
| 130 | + * Return the user who blocked this request (if any). |
|---|
| 131 | + * |
|---|
| 132 | + * @return blockedBy |
|---|
| 133 | + */ |
|---|
| 134 | + public User getBlockedBy() { return blockedBy; } |
|---|
| 86 | 135 | |
|---|
| 87 | | - public void setBlockedBy(User blockedBy) { |
|---|
| 88 | | - this.blockedBy = blockedBy; |
|---|
| 89 | | - } |
|---|
| 136 | + /** |
|---|
| 137 | + * setBlockedBy<p> |
|---|
| 138 | + * Set the user who blocked this request. |
|---|
| 139 | + * |
|---|
| 140 | + * @param blockedBy |
|---|
| 141 | + */ |
|---|
| 142 | + public void setBlockedBy(User blockedBy) { this.blockedBy = blockedBy; } |
|---|
| 90 | 143 | |
|---|
| 144 | + // --------------------------------------------------------------------- |
|---|
| 145 | + // Static helpers |
|---|
| 146 | + // --------------------------------------------------------------------- |
|---|
| 147 | + |
|---|
| 148 | + /** |
|---|
| 149 | + * generateHash<p> |
|---|
| 150 | + * Compute the SHA-256 hex string for the given request data. |
|---|
| 151 | + * |
|---|
| 152 | + * @param reqData |
|---|
| 153 | + * @return sha256(reqData) or null if reqData is null |
|---|
| 154 | + */ |
|---|
| 91 | 155 | public static String generateHash(String reqData) { |
|---|
| 92 | 156 | return (reqData != null ? Utils.sha256(reqData) : null); |
|---|
| 93 | 157 | } |
|---|
| 94 | 158 | |
|---|
| 159 | + /** |
|---|
| 160 | + * isRequestBlocked<p> |
|---|
| 161 | + * Check if a request payload is blocked by looking up its hash as the PK. |
|---|
| 162 | + * |
|---|
| 163 | + * @param requestData original payload |
|---|
| 164 | + * @param em JPA entity manager |
|---|
| 165 | + * @return true if an entry exists with the same hash |
|---|
| 166 | + */ |
|---|
| 95 | 167 | public static boolean isRequestBlocked(String requestData, EntityManager em) { |
|---|
| 96 | 168 | String hash = generateHash(requestData); |
|---|
| 97 | 169 | BlockedRequest br = em.find(BlockedRequest.class, hash); |
|---|
| 98 | 170 | return br != null; |
|---|
| 99 | 171 | } |
|---|
| 100 | | - |
|---|
| 101 | 172 | } |
|---|