|
1 |
| -package xyz.srnyx.javautilities.objects; |
| 1 | +package xyz.srnyx.javautilities.objects.encryptor; |
2 | 2 |
|
3 | 3 | import org.jetbrains.annotations.NotNull;
|
4 | 4 | import org.jetbrains.annotations.Nullable;
|
5 | 5 |
|
6 | 6 | import xyz.srnyx.javautilities.manipulation.Mapper;
|
| 7 | +import xyz.srnyx.javautilities.objects.encryptor.exceptions.TokenExpiredException; |
| 8 | +import xyz.srnyx.javautilities.objects.encryptor.exceptions.TokenInvalidException; |
| 9 | +import xyz.srnyx.javautilities.objects.encryptor.exceptions.TokenTamperedException; |
7 | 10 |
|
8 | 11 | import javax.crypto.Mac;
|
9 | 12 | import javax.crypto.spec.SecretKeySpec;
|
@@ -94,32 +97,36 @@ public String encrypt(@NotNull Object value) {
|
94 | 97 | /**
|
95 | 98 | * Decrypts a token by verifying its signature and timestamp
|
96 | 99 | *
|
97 |
| - * @param token the token to decrypt |
| 100 | + * @param token the token to decrypt |
98 | 101 | *
|
99 |
| - * @return the original value if the token is valid and not expired, otherwise {@code null} |
| 102 | + * @return the original value if the token is valid and not expired, otherwise {@code null} |
| 103 | + * |
| 104 | + * @throws TokenInvalidException if the token is invalid |
| 105 | + * @throws TokenExpiredException if the token has expired |
| 106 | + * @throws TokenTamperedException if the token has been tampered with |
100 | 107 | */
|
101 | 108 | @Nullable
|
102 |
| - public String decrypt(@NotNull String token) { |
| 109 | + public String decrypt(@NotNull String token) throws TokenInvalidException, TokenExpiredException, TokenTamperedException { |
103 | 110 | // Decode token
|
104 | 111 | final String decoded = new String(Base64.getUrlDecoder().decode(token), StandardCharsets.UTF_8);
|
105 | 112 | final String[] parts = decoded.split(":");
|
106 |
| - if (parts.length != 3) return null; |
| 113 | + if (parts.length != 3) throw new TokenInvalidException("Token does not have 3 parts"); |
107 | 114 |
|
108 | 115 | // Get casted value and timestamp
|
109 | 116 | final String value = parts[0];
|
110 |
| - if (value == null) return null; |
| 117 | + if (value == null) throw new TokenInvalidException("Value is null"); |
111 | 118 | final Optional<Long> timestamp = Mapper.toLong(parts[1]);
|
112 |
| - if (!timestamp.isPresent()) return null; |
| 119 | + if (!timestamp.isPresent()) throw new TokenInvalidException("Timestamp is not a valid long"); |
113 | 120 |
|
114 | 121 | // Check age
|
115 |
| - if (maxAge != null && System.currentTimeMillis() - timestamp.get() > maxAge.toMillis()) return null; // Expired |
| 122 | + if (maxAge != null && System.currentTimeMillis() - timestamp.get() > maxAge.toMillis()) throw new TokenExpiredException(); |
116 | 123 |
|
117 | 124 | // Recompute signature
|
118 | 125 | final String payload = parts[0] + ":" + parts[1];
|
119 | 126 | final byte[] expectedSig = getSignature(payload);
|
120 | 127 | if (expectedSig == null) return null; // Should never happen
|
121 | 128 | final byte[] actualSig = Base64.getUrlDecoder().decode(parts[2]);
|
122 |
| - if (!Arrays.equals(expectedSig, actualSig)) return null; // Tampered |
| 129 | + if (!Arrays.equals(expectedSig, actualSig)) throw new TokenTamperedException(); |
123 | 130 |
|
124 | 131 | return value;
|
125 | 132 | }
|
|
0 commit comments