Merge pull request #15 from CodeCraftersCN/dev/v1.1.0

Upgrade to v1.1.0
This commit is contained in:
Zihlu Wang
2023-09-19 14:19:32 +08:00
committed by GitHub
64 changed files with 1041 additions and 672 deletions
+1 -1
View File
@@ -27,7 +27,7 @@ A module for generating globally unique IDs. It includes a facade interface and
<span style="font-size: 14px;">_[Learn more](https://github.com/CodeCraftersCN/jdevkit/webcal/README.md)_</span>
The module `webcal` is a Java library that facilitates the generation and resolution of iCalendar content for web-based calendar applications. It provides a flexible and easy-to-use API for creating web calendars with customizable settings and events.
The module `webcal` is a Java library that facilitates the generation and resolution of iCalendar content for web-based calendar applications. It provides a flexible and easy-to-use API for creating web calendars with customisable settings and events.
With the `webcal` module, developers can easily integrate calendar functionality into web applications, enabling users to view, add, and manage events in a structured and standardized format. It is designed to simplify calendar-related tasks and enhance the overall user experience when dealing with calendar data on the web.
+1 -1
View File
@@ -23,7 +23,7 @@
<parent>
<groupId>cn.org.codecrafters</groupId>
<artifactId>jdevkit</artifactId>
<version>1.0.1</version>
<version>1.1.0</version>
</parent>
<artifactId>devkit-core</artifactId>
@@ -18,31 +18,23 @@
package cn.org.codecrafters.devkit.core.exceptions;
/**
* NotImplementedException - Custom Runtime Exception
* <p>
* The {@code NotImplementedException} class is a custom runtime exception
* that represents a situation where a particular method or functionality is
* not implemented or is currently unavailable in the codebase. It extends the
* standard {@code RuntimeException} class, making it an unchecked exception.
*
* not implemented or is currently unavailable in the codebase.
* <p>
* This exception is typically thrown when developers need to indicate that a
* specific part of the code is incomplete or requires further implementation.
* It serves as a placeholder to highlight unfinished sections of the
* application during development and testing phases.
*
* <p>
* Usage Example:
*
* <pre>
* public void someMethod() {
* // Some code...
* throw new NotImplementedException("""
* This feature will be implemented in a future release.
* """);
* This feature will be implemented in a future release.""");
* }
* </pre>
*
* <b>Contact</b>
* <ul>
* <li>
@@ -55,7 +47,7 @@ package cn.org.codecrafters.devkit.core.exceptions;
* </ul>
*
* @author Zihlu Wang
* @version 1.0.0
* @version 1.1.0
* @see RuntimeException
* @since 1.0.0
*/
@@ -16,7 +16,7 @@
*/
/**
* Commonly used exceptions will be used in JDevKit.
* This package contains commonly used exceptions will be used in JDevKit.
*
* @author Zihlu Wang
* @since 1.0.0
@@ -16,19 +16,16 @@
*/
/**
* This package is a part of JDevKit, an open-source Java Development Kit that
* provides a set of convenient tools to streamline code development and
* enhance productivity. This package serves as the core package containing
* This package is the core part of JDevKit, an open-source Java Development
* Kit that provides a set of convenient tools to streamline code development
* and enhance productivity. This package serves as the core package containing
* common exceptions that are used throughout the entire JDevKit project.
*
* <p>
* JDevKit is designed to be modular, and other specific feature modules within
* the library may rely on these exceptions from the core package.
*
* <p>
* For more information and the latest version of JDevKit, please visit our
* website <a href="https://codecrafters.org.cn">codecrafters.org.cn</a>.
*
* <p>
* <b>Contact</b>
* <ul>
@@ -19,8 +19,8 @@
* This package is the main part of JDevKit, an open-source Java class library
* that provides a set of convenient tools to streamline code development and
* enhance productivity. This package serves as the root package for several
* modules, containing devkit-core, guid and dev-utils module.
*
* modules, containing {@code devkit-core}, {@code guid} and {@code dev-utils}
* module.
* <p>
* For more information and the latest version of JDevKit, please visit our
* website <a href="https://codecrafters.org.cn">codecrafters.org.cn</a>.
+1 -1
View File
@@ -6,7 +6,7 @@
<parent>
<groupId>cn.org.codecrafters</groupId>
<artifactId>jdevkit</artifactId>
<version>1.0.1</version>
<version>1.1.0</version>
</parent>
<artifactId>devkit-utils</artifactId>
@@ -0,0 +1,136 @@
/*
* Copyright (C) 2023 CodeCraftersCN.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.org.codecrafters.devkit.utils;
import lombok.extern.slf4j.Slf4j;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Objects;
import java.util.UUID;
/**
* {@link AesUtil} can help you encrypt and decrypt data with specified secret
* by AES algorithm.
*
* @author hubin@baomidou
* @version 1.1.0
* @since 1.1.0
*/
@Slf4j
public final class AesUtil {
private AesUtil() {
}
private static final String AES = "AES";
private static final String AES_CBC_CIPHER = "AES/CBC/PKCS5Padding";
/**
* Encrypts the data using the AES algorithm with the given secret.
*
* @param data the data to be encrypted
* @param secret the secret to encrypt the data
* @return the encryption result or {@code null} if encryption failed
*/
public static byte[] encrypt(byte[] data, byte[] secret) {
try {
var secretKeySpec = new SecretKeySpec(new SecretKeySpec(secret, AES).getEncoded(), AES);
var cipher = Cipher.getInstance(AES_CBC_CIPHER);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, new IvParameterSpec(secret));
return cipher.doFinal(data);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | UnsupportedOperationException |
InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException |
BadPaddingException exception) {
log.error(exception.getMessage());
for (var stackTraceElement : exception.getStackTrace()) {
log.error("{}", stackTraceElement.toString());
}
}
return null;
}
/**
* Decrypts the data using the AES algorithm with the given secret.
*
* @param data the data to be decrypted
* @param secret the secret to encrypt the data
* @return the decryption result or {@code null} if decryption failed
*/
public static byte[] decrypt(byte[] data, byte[] secret) {
try {
var secretKeySpec = new SecretKeySpec(new SecretKeySpec(secret, AES).getEncoded(), AES);
var cipher = Cipher.getInstance(AES_CBC_CIPHER);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, new IvParameterSpec(secret));
return cipher.doFinal(data);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | UnsupportedOperationException |
InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException |
BadPaddingException exception) {
log.error(exception.getMessage());
for (var stackTraceElement : exception.getStackTrace()) {
log.error("{}", stackTraceElement.toString());
}
}
return null;
}
/**
* Encrypts the data using the AES algorithm with the given secret.
*
* @param data the data to be encrypted
* @param secret the secret to encrypt the data
* @return the encryption result or {@code null} if encryption failed
*/
public static String encrypt(String data, String secret) {
return Base64.getEncoder().encodeToString(encrypt(data.getBytes(StandardCharsets.UTF_8), secret.getBytes(StandardCharsets.UTF_8)));
}
/**
* Decrypts the data using the AES algorithm with the given secret.
*
* @param data the data to be decrypted
* @param secret the secret to encrypt the data
* @return the decryption result or {@code null} if decryption failed
*/
public static String decrypt(String data, String secret) {
return new String(Objects.requireNonNull(
decrypt(Base64.getDecoder().decode(data.getBytes()),
secret.getBytes(StandardCharsets.UTF_8)))
);
}
/**
* Generates 16 characters-long random secret.
*
* @return the generated secure secret
*/
public static String generateRandomSecret() {
return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 16);
}
}
@@ -20,20 +20,18 @@ package cn.org.codecrafters.devkit.utils;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Objects;
/**
* <p>
* The {@code Base64Util} class provides static methods to encode and decode
* strings using Base64 encoding. It utilizes the {@link Base64} class from the
* The {@link Base64Util} class provides static methods to encode and decode
* strings with Base64 encoding. It utilizes the {@link Base64} class from the
* Java standard library for performing the encoding and decoding operations.
* This utility class offers convenient methods to encode and decode strings
* with different character sets.
*
* <p>
* This class is designed as a final class with a private constructor to
* prevent instantiation. All methods in this class are static, allowing easy
* access to the Base64 encoding and decoding functionality.
*
* <p>
* Example usage:
* <pre>
@@ -47,19 +45,45 @@ import java.util.Base64;
* String decoded = Base64Util.decode(encoded);
* System.out.println("Decoded string: " + decoded);
* </pre>
*
* <p>
* <b>Note:</b> This utility class uses the default charset (UTF-8) if no
* specific charset is provided. It is recommended to specify the charset
* explicitly to ensure consistent encoding and decoding.
*
*
* @author Zihlu Wang
* @version 1.0.0
* @version 1.1.0
* @since 1.0.0
*/
public final class Base64Util {
private static Base64.Encoder encoder;
private static Base64.Decoder decoder;
/**
* Ensure that there is only one Base64 Encoder.
*
* @return the {@link Base64.Encoder} instance
*/
private static Base64.Encoder getEncoder() {
if (Objects.isNull(encoder)) {
encoder = Base64.getEncoder();
}
return encoder;
}
/**
* Ensure that there is only one Base64 Encoder.
*
* @return the {@link Base64.Encoder} instance
*/
private static Base64.Decoder getDecoder() {
if (Objects.isNull(decoder)) {
decoder = Base64.getDecoder();
}
return decoder;
}
/**
* Private constructor to prevent instantiation of the class.
*/
@@ -74,8 +98,7 @@ public final class Base64Util {
* @return the Base64 encoded string
*/
public static String encode(String value, Charset charset) {
var encoder = Base64.getEncoder();
var encoded = encoder.encode(value.getBytes(charset));
var encoded = getEncoder().encode(value.getBytes(charset));
return new String(encoded);
}
@@ -98,8 +121,7 @@ public final class Base64Util {
* @return the decoded string
*/
public static String decode(String value, Charset charset) {
var decoder = Base64.getDecoder();
var decoded = decoder.decode(value.getBytes(charset));
var decoded = getDecoder().decode(value.getBytes(charset));
return new String(decoded);
}
@@ -23,29 +23,24 @@ import java.util.function.BooleanSupplier;
import java.util.function.Supplier;
/**
* The {@link BranchUtil} class provides static methods to simplify conditional
* logic in Java development by leveraging lambda expressions. It offers
* convenient methods to replace verbose {@code if...else} statements with more
* concise and expressive functional constructs.
* <p>
* The BranchUtil class provides static methods to simplify conditional logic
* in Java development by leveraging lambda expressions. It offers convenient
* methods to replace verbose if...else statements with more concise and
* expressive functional constructs.
*
*
* <p>
* Developers can use the methods in this utility class to streamline their
* code, enhance readability, and promote a more functional style of
* programming when dealing with branching logic and conditional statements.
*
*
* Developers can use methods in this utility class to streamline their code,
* enhance readability, and promote a more functional style of programming when
* dealing with branching logic and conditional statements.
* <p>
* <b>Example:</b>
* <pre>
* // If you want to simplify an if (exp1 || exp2), you can use the
* // following code:
* var r1 = BranchUtil.or(1 == 1, 2 == 1)
* String r1 = BranchUtil.or(1 == 1, 2 == 1)
* .handle(() -> "1 is equal to 1 or 2 is equal to 1.");
*
* // If you have an else branch, you can use the following code:
* var r2 = BranchUtil.or(1 == 1, 2 == 1)
* String r2 = BranchUtil.or(1 == 1, 2 == 1)
* .handle(() -> "1 is equal to 1 or 2 is equal to 1.",
* () -> "1 is not equal to 1 and 2 is not equal to 1.");
*
@@ -67,7 +62,6 @@ import java.util.function.Supplier;
* // do something
* });
* </pre>
*
* <p>
* <b>Note:</b>
* The {@link #and(Boolean...)} and {@link #or(Boolean...)} methods accept any
@@ -75,7 +69,7 @@ import java.util.function.Supplier;
*
* @param <T> the type of the result to be handled by the methods
* @author Zihlu Wang
* @version 1.0.0
* @version 1.1.0
* @see java.util.function.Supplier
* @see java.util.function.BooleanSupplier
* @see java.lang.Runnable
@@ -164,15 +158,12 @@ public final class BranchUtil<T> {
}
/**
* <p>
* Handles the result of the boolean expressions by executing the
* appropriate handler based on the result.
*
* <p>
* If the result is {@code true}, the {@code ifHandler} is executed. If the
* result is {@code false} and an {@code elseHandler} is provided, it is
* executed.
*
* <p>
* Returns the result of the executed handler.
*
@@ -181,7 +172,8 @@ public final class BranchUtil<T> {
* @param elseHandler the handler to be executed if the result is
* {@code false} (optional)
* @return the result of the executed handler, or {@code null} if no
* {@code elseHandler} is provided
* {@code elseHandler} is provided and the result of the evaluation is
* {@code false}
*/
public T handle(Supplier<T> ifHandler, Supplier<T> elseHandler) {
if (this.result && Objects.nonNull(ifHandler)) {
@@ -196,26 +188,23 @@ public final class BranchUtil<T> {
}
/**
* <p>
* Handles the result of the boolean expressions by executing the provided
* handler if the result is {@code true}.
*
* <p>
* Returns the result of the executed handler.
*
* @param ifHandler the handler to be executed if the result is
* {@code true}
* @return the result of the executed handler
* @return the result of the executed handler, or {@code null} if result of
* evaluation is {@code false}
*/
public T handle(Supplier<T> ifHandler) {
return handle(ifHandler, null);
}
/**
* <p>
* Handles the result of the boolean expressions by executing the
* appropriate handler based on the result.
*
* <p>
* If the result is {@code true}, the {@code ifHandler} is executed. If the
* result is {@code false} and an {@code elseHandler} is provided, it is
@@ -17,6 +17,8 @@
package cn.org.codecrafters.devkit.utils;
import lombok.Getter;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Objects;
@@ -24,19 +26,12 @@ import java.util.function.BiFunction;
import java.util.function.Function;
/**
* <p>
* Utility class for chained high-precision calculations using BigDecimal.
*
*
* <p>
* The ChainedCalcUtil class provides a convenient way to perform chained
* high-precision calculations using BigDecimal. It allows users to perform
* mathematical operations such as addition, subtraction, multiplication,
* and division with customizable precision and scale. By using this utility
* class, developers can achieve accurate results and avoid precision loss
* in their calculations.
*
*
* The {@code ChainedCalcUtil} class provides a convenient way to perform
* chained high-precision calculations using {@link BigDecimal}. It allows
* users to perform mathematical operations such as addition, subtraction,
* multiplication, and division with customisable precision and scale. By using
* this utility class, developers can achieve accurate results and avoid
* precision loss in their calculations.
* <p>
* <b>Usage:</b>
* <pre>
@@ -84,26 +79,31 @@ import java.util.function.Function;
* .getValue(2);
* </pre>
* The above expressions perform various mathematical calculations using the
* ChainedCalcUtil class.
*
* {@code ChainedCalcUtil} class.
* <p>
* <b>Note:</b>
* The ChainedCalcUtil class internally uses BigDecimal to handle
* high-precision calculations. It is important to note that BigDecimal
* operations can be memory-intensive and may have performance implications
* for extremely large numbers or complex calculations.
* The {@code ChainedCalcUtil} class internally uses {@link BigDecimal} to
* handle high-precision calculations. It is important to note that {@link
* BigDecimal} operations can be memory-intensive and may have performance
* implications for extremely large numbers or complex calculations.
*
* @author sunzsh
* @version 1.0.0
* @version 1.1.0
* @see java.math.BigDecimal
* @since 9 Jul 2023
* @since 1.0.0
*/
@Getter
public final class ChainedCalcUtil {
/**
* -- GETTER --
* Returns the current value as a BigDecimal.
*/
private BigDecimal value;
/**
* Creates a ChainedCalcUtil instance with the specified initial value.
* Creates a {@code ChainedCalcUtil} instance with the specified initial
* value.
*
* @param value the initial value for the calculation
*/
@@ -115,7 +115,7 @@ public final class ChainedCalcUtil {
* Starts a chained calculation with the specified initial value.
*
* @param value the initial value for the calculation
* @return a ChainedCalcUtil instance for performing chained calculations
* @return a {@code ChainedCalcUtil} instance for performing chained calculations
*/
public static ChainedCalcUtil startWith(Number value) {
return new ChainedCalcUtil(value);
@@ -125,7 +125,7 @@ public final class ChainedCalcUtil {
* Adds the specified value to the current value.
*
* @param other the value to be added
* @return a ChainedCalcUtil instance with the updated value
* @return a {@code ChainedCalcUtil} instance with the updated value
*/
public ChainedCalcUtil add(Number other) {
return operator(BigDecimal::add, other);
@@ -137,7 +137,7 @@ public final class ChainedCalcUtil {
*
* @param other the value to be added
* @param beforeOperateScale the scale to be applied before the operation
* @return a ChainedCalcUtil instance with the updated value
* @return a {@code ChainedCalcUtil} instance with the updated value
*/
public ChainedCalcUtil add(Number other, Integer beforeOperateScale) {
return operator(BigDecimal::add, other, beforeOperateScale);
@@ -147,7 +147,7 @@ public final class ChainedCalcUtil {
* Subtracts the specified value from the current value.
*
* @param other the value to be subtracted
* @return a ChainedCalcUtil instance with the updated value
* @return a {@code ChainedCalcUtil} instance with the updated value
*/
public ChainedCalcUtil subtract(Number other) {
return operator(BigDecimal::subtract, other);
@@ -159,7 +159,7 @@ public final class ChainedCalcUtil {
*
* @param other the value to be subtracted
* @param beforeOperateScale the scale to be applied before the operation
* @return a ChainedCalcUtil instance with the updated value
* @return a {@code ChainedCalcUtil} instance with the updated value
*/
public ChainedCalcUtil subtract(Number other, Integer beforeOperateScale) {
return operator(BigDecimal::subtract, other, beforeOperateScale);
@@ -169,7 +169,7 @@ public final class ChainedCalcUtil {
* Multiplies the current value by the specified value.
*
* @param other the value to be multiplied by
* @return a ChainedCalcUtil instance with the updated value
* @return a {@code ChainedCalcUtil} instance with the updated value
*/
public ChainedCalcUtil multiply(Number other) {
return operator(BigDecimal::multiply, other);
@@ -181,7 +181,7 @@ public final class ChainedCalcUtil {
*
* @param other the value to be multiplied by
* @param beforeOperateScale the scale to be applied before the operation
* @return a ChainedCalcUtil instance with the updated value
* @return a {@code ChainedCalcUtil} instance with the updated value
*/
public ChainedCalcUtil multiply(Number other, Integer beforeOperateScale) {
return operator(BigDecimal::multiply, other, beforeOperateScale);
@@ -191,7 +191,7 @@ public final class ChainedCalcUtil {
* Divides the current value by the specified value.
*
* @param other the value to divide by
* @return a ChainedCalcUtil instance with the updated value
* @return a {@code ChainedCalcUtil} instance with the updated value
*/
public ChainedCalcUtil divide(Number other) {
return operator(BigDecimal::divide, other);
@@ -203,7 +203,7 @@ public final class ChainedCalcUtil {
*
* @param other the value to divide by
* @param beforeOperateScale the scale to be applied before the operation
* @return a ChainedCalcUtil instance with the updated value
* @return a {@code ChainedCalcUtil} instance with the updated value
*/
public ChainedCalcUtil divide(Number other, Integer beforeOperateScale) {
return operator(BigDecimal::divide, other, beforeOperateScale);
@@ -214,7 +214,7 @@ public final class ChainedCalcUtil {
*
* @param other the value to divide by
* @param scale the scale for the result
* @return a ChainedCalcUtil instance with the updated value
* @return a {@code ChainedCalcUtil} instance with the updated value
*/
public ChainedCalcUtil divideWithScale(Number other, Integer scale) {
return baseOperator(otherValue ->
@@ -228,63 +228,54 @@ public final class ChainedCalcUtil {
* @param other the value to divide by
* @param scale the scale for the result
* @param beforeOperateScale the scale to be applied before the operation
* @return a ChainedCalcUtil instance with the updated value
* @return a {@code ChainedCalcUtil} instance with the updated value
*/
public ChainedCalcUtil divideWithScale(Number other, Integer scale, Integer beforeOperateScale) {
return baseOperator(otherValue -> this.value.divide(otherValue, scale, RoundingMode.HALF_UP), other, beforeOperateScale);
}
/**
* Returns the current value as a BigDecimal.
*
* @return the current value as a BigDecimal
*/
public BigDecimal getValue() {
return value;
}
/**
* Returns the current value as a BigDecimal with the specified scale.
* Returns the current value as a {@link BigDecimal} with the specified scale.
*
* @param scale the scale for the result
* @return the current value as a BigDecimal with the specified scale
* @return the current value as a {@link BigDecimal} with the specified scale
*/
public BigDecimal getValue(int scale) {
return value.setScale(scale, RoundingMode.HALF_UP);
}
/**
* Returns the current value as a Double.
* Returns the current value as a {@link Double}.
*
* @return the current value as a Double
* @return the current value as a {@link Double}
*/
public Double getDouble() {
return getValue().doubleValue();
}
/**
* Returns the current value as a Double with the specified scale.
* Returns the current value as a {@link Double} with the specified scale.
*
* @param scale the scale for the result
* @return the current value as a Double with the specified scale
* @return the current value as a {@link Double} with the specified scale
*/
public Double getDouble(int scale) {
return getValue(scale).doubleValue();
}
/**
* Returns the current value as a Long.
* Returns the current value as a {@link Long}.
*
* @return the current value as a Long
* @return the current value as a {@link Long}
*/
public Long getLong() {
return getValue().longValue();
}
/**
* Returns the current value as an Integer.
* Returns the current value as an {@link Integer}.
*
* @return the current value as an Integer
* @return the current value as an {@link Integer}
*/
public Integer getInteger() {
return getValue().intValue();
@@ -340,7 +331,7 @@ public final class ChainedCalcUtil {
}
/**
* Converts the specified value to a BigDecimal.
* Converts the specified value to a {@link BigDecimal}.
*
* @param value the value to convert
* @param scale the scale to apply to the resulting BigDecimal, or null if
@@ -25,15 +25,10 @@ import java.util.Objects;
import java.util.Optional;
/**
* <p>
* Utility class for performing hash operations on strings.
*
* <p>
* The HashUtil class provides convenient methods for calculating various hash
* functions on strings, including MD2, MD5, SHA-1, SHA-224, SHA-256, SHA-384,
* and SHA-512. It allows developers to easily obtain the hash value of a given
* string using different algorithms.
*
* The {@code HashUtil} class provides convenient methods for calculating
* various hash functions on strings, including MD2, MD5, SHA-1, SHA-224,
* SHA-256, SHA-384, and SHA-512. It allows developers to easily obtain the
* hash value of a given string using different algorithms.
* <p>
* Example usage:
* <pre>
@@ -58,9 +53,8 @@ import java.util.Optional;
* // Perform SHA-512 hash operation
* String sha512Hash = HashUtil.sha512("someString");
* </pre>
* The above examples demonstrate how to use the HashUtil class to calculate
* hash values for a given string using different algorithms.
*
* The above examples demonstrate how to use the {@code HashUtil} class to
* calculate hash values for a given string using different algorithms.
* <p>
* <b>Note:</b>
* The hash functions provided by the HashUtil class are one-way hash
@@ -69,7 +63,7 @@ import java.util.Optional;
* password storage, but they should not be used for encryption purposes.
*
* @author Zihlu Wang
* @version 1.0.0
* @version 1.1.0
* @see java.security.MessageDigest
* @since 1.0.0
*/
@@ -121,7 +115,7 @@ public final class HashUtil {
* Calculates the MD2 hash value of the specified string using the given
* charset.
*
* @param value the string to calculate the MD2 hash value for
* @param value the string to calculate with the MD2 algorithm
* @param charset the charset to use for encoding the string (default is
* UTF-8 if null)
* @return the MD2 hash value as a hexadecimal string
@@ -135,7 +129,7 @@ public final class HashUtil {
* Calculates the MD2 hash value of the specified string using the UTF-8
* charset.
*
* @param value the string to calculate the MD2 hash value for
* @param value the string to calculate with the MD2 algorithm
* @return the MD2 hash value as a hexadecimal string
*/
public static String md2(String value) {
@@ -146,7 +140,7 @@ public final class HashUtil {
* Calculates the MD5 hash value of the specified string using the given
* charset.
*
* @param value the string to calculate the MD5 hash value for
* @param value the string to calculate with the MD5 algorithm
* @param charset the charset to use for encoding the string (default is
* UTF-8 if null)
* @return the MD5 hash value as a hexadecimal string
@@ -160,7 +154,7 @@ public final class HashUtil {
* Calculates the MD5 hash value of the specified string using the UTF-8
* charset.
*
* @param value the string to calculate the MD5 hash value for
* @param value the string to calculate with the MD5 algorithm
* @return the MD5 hash value as a hexadecimal string
*/
public static String md5(String value) {
@@ -171,7 +165,7 @@ public final class HashUtil {
* Calculates the SHA-1 hash value of the specified string using the given
* charset.
*
* @param value the string to calculate the SHA-1 hash value for
* @param value the string to calculate with the SHA-1 algorithm
* @param charset the charset to use for encoding the string (default is
* UTF-8 if null)
* @return the SHA-1 hash value as a hexadecimal string
@@ -185,7 +179,7 @@ public final class HashUtil {
* Calculates the SHA-1 hash value of the specified string using the UTF-8
* charset.
*
* @param value the string to calculate the SHA-1 hash value for
* @param value the string to calculate with the SHA-1 algorithm
* @return the SHA-1 hash value as a hexadecimal string
*/
public static String sha1(String value) {
@@ -196,7 +190,7 @@ public final class HashUtil {
* Calculates the SHA-224 hash value of the specified string using the
* given charset.
*
* @param value the string to calculate the SHA-224 hash value for
* @param value the string to calculate with the SHA-225 algorithm
* @param charset the charset to use for encoding the string (default is
* UTF-8 if null)
* @return the SHA-224 hash value as a hexadecimal string
@@ -210,7 +204,7 @@ public final class HashUtil {
* Calculates the SHA-224 hash value of the specified string using the
* UTF-8 charset.
*
* @param value the string to calculate the SHA-224 hash value for
* @param value the string to calculate with the SHA-224 algorithm
* @return the SHA-224 hash value as a hexadecimal string
*/
public static String sha224(String value) {
@@ -221,7 +215,7 @@ public final class HashUtil {
* Calculates the SHA-256 hash value of the specified string using the
* given charset.
*
* @param value the string to calculate the SHA-256 hash value for
* @param value the string to calculate with the SHA-256 algorithm
* @param charset the charset to use for encoding the string (default is
* UTF-8 if null)
* @return the SHA-256 hash value as a hexadecimal string
@@ -235,7 +229,7 @@ public final class HashUtil {
* Calculates the SHA-256 hash value of the specified string using the
* UTF-8 charset.
*
* @param value the string to calculate the SHA-256 hash value for
* @param value the string to calculate with the SHA-256 algorithm
* @return the SHA-256 hash value as a hexadecimal string
*/
public static String sha256(String value) {
@@ -246,7 +240,7 @@ public final class HashUtil {
* Calculates the SHA-384 hash value of the specified string using the
* given charset.
*
* @param value the string to calculate the SHA-384 hash value for
* @param value the string to calculate with the SHA-384 algorithm
* @param charset the charset to use for encoding the string (default is
* UTF-8 if null)
* @return the SHA-384 hash value as a hexadecimal string
@@ -260,7 +254,7 @@ public final class HashUtil {
* Calculates the SHA-384 hash value of the specified string using the
* UTF-8 charset.
*
* @param value the string to calculate the SHA-384 hash value for
* @param value the string to calculate with the SHA-384 algorithm
* @return the SHA-384 hash value as a hexadecimal string
*/
public static String sha384(String value) {
@@ -271,7 +265,7 @@ public final class HashUtil {
* Calculates the SHA-512 hash value of the specified string using the
* given charset.
*
* @param value the string to calculate the SHA-384 hash value for
* @param value the string to calculate with the SHA-512 algorithm
* @param charset the charset to use for encoding the string (default is
* UTF-8 if null)
* @return the SHA-512 hash value as a hexadecimal string
@@ -285,7 +279,7 @@ public final class HashUtil {
* Calculates the SHA-512 hash value of the specified string using the
* UTF-8 charset.
*
* @param value the string to calculate the SHA-384 hash value for
* @param value the string to calculate with the SHA-512 algorithm
* @return the SHA-512 hash value as a hexadecimal string
*/
public static String sha512(String value) {
@@ -24,17 +24,15 @@ import java.util.HashMap;
import java.util.Map;
/**
* <p>
* MapUtil is a utility class that provides methods for converting objects to
* maps and maps to objects.
*
* {@code MapUtil} is a utility class that provides methods for converting
* objects to maps and maps to objects.
* <p>
* It also provides methods for getting and setting field values using
* reflection.
*
* @author Zihlu Wang
* @version 1.0.0
* @since 16 Jul 2023
* @version 1.1.0
* @since 1.0.0
*/
@Slf4j
public final class MapUtil {
@@ -180,6 +178,22 @@ public final class MapUtil {
method.invoke(obj, fieldValue);
}
/**
* Casts the specified value to the required type.
*
* @param value the value to be cast
* @param requiredType the type to which the value should be cast
* @param <T> the type to which the value should be cast
* @return the cast value, or null if the value cannot be cast to the
* required type
*/
public static <T> T cast(Object value, Class<T> requiredType) {
if (requiredType.isInstance(value)) {
return requiredType.cast(value);
}
return null;
}
/**
* Constructs a method name based on the given prefix and field name.
*
@@ -205,20 +219,4 @@ public final class MapUtil {
return String.valueOf(obj);
}
}
/**
* Casts the specified value to the required type.
*
* @param value the value to be casted
* @param requiredType the type to which the value should be casted
* @param <T> the type to which the value should be casted
* @return the casted value, or null if the value cannot be casted to the
* required type
*/
public static <T> T cast(Object value, Class<T> requiredType) {
if (requiredType.isInstance(value)) {
return requiredType.cast(value);
}
return null;
}
}
+1 -1
View File
@@ -23,7 +23,7 @@
<parent>
<groupId>cn.org.codecrafters</groupId>
<artifactId>jdevkit</artifactId>
<version>1.0.1</version>
<version>1.1.0</version>
</parent>
<artifactId>guid</artifactId>
@@ -18,17 +18,14 @@
package cn.org.codecrafters.guid;
/**
* <p>
* The {@code GuidCreator} is a generic interface for generating globally unique
* identifiers (GUIDs) of a specific type.
*
* <p>
* The type of ID is determined by the class implementing this interface.
*
*
* @param <IdType> this represents the type of the Global Unique Identifier
* @author Zihlu Wang
* @version 1.0.0
* @version 1.1.0
* @since 1.0.0
*/
public interface GuidCreator<IdType> {
@@ -20,35 +20,31 @@ package cn.org.codecrafters.guid;
import cn.org.codecrafters.guid.exceptions.TimingException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
/**
* <p>
* SnowflakeGuidCreator - GUID generator based on the Snowflake algorithm.
*
* <p>
* The SnowflakeGuidCreator generates unique identifiers using the Snowflake
* algorithm, which combines a timestamp, worker ID, and data center ID to
* create 64-bit long integers. The bit distribution for the generated IDs is
* as follows:
* The {@code SnowflakeGuidCreator} generates unique identifiers using the
* Snowflake algorithm, which combines a timestamp, worker ID, and data centre
* ID to create 64-bit long integers. The bit distribution for the generated
* IDs is as follows:
* <ul>
* <li>1 bit for sign</li>
* <li>41 bits for timestamp (in milliseconds)</li>
* <li>5 bits for data center ID</li>
* <li>5 bits for data centre ID</li>
* <li>5 bits for worker ID</li>
* <li>12 bits for sequence number (per millisecond)</li>
* </ul>
*
* <p>
* When initializing the SnowflakeGuidCreator, you must provide the worker ID
* and data center ID, ensuring they are within the valid range defined by the
* bit size. The generator maintains an internal sequence number that
* increments for IDs generated within the same millisecond. If the system
* When initializing a {@link SnowflakeGuidCreator}, you must provide the
* worker ID and data centre ID, ensuring they are within the valid range
* defined by the bit size. The generator maintains an internal sequence number
* that increments for IDs generated within the same millisecond. If the system
* clock moves backward, an exception is thrown to prevent generating IDs with
* repeated timestamps.
*
* @author Zihlu Wang
* @version 1.0.0
* @version 1.1.0
* @since 1.0.0
*/
public final class SnowflakeGuidCreator implements GuidCreator<Long> {
@@ -71,7 +67,7 @@ public final class SnowflakeGuidCreator implements GuidCreator<Long> {
private final long workerIdBits = 5L;
/**
* The number of bits reserved for the data center ID.
* The number of bits reserved for the data centre ID.
*/
private final long dataCentreIdBits = 5L;
@@ -81,7 +77,7 @@ public final class SnowflakeGuidCreator implements GuidCreator<Long> {
private final long workerId;
/**
* The data center ID assigned to this generator.
* The data centre ID assigned to this generator.
*/
private final long dataCentreId;
@@ -97,28 +93,28 @@ public final class SnowflakeGuidCreator implements GuidCreator<Long> {
/**
* Constructs a SnowflakeGuidGenerator with the default start epoch and
* custom worker ID, data center ID.
* custom worker ID, data centre ID.
*
* @param workerId the worker ID (between 0 and 31).
* @param dataCentreId the data center ID (between 0 and 31).
* @param dataCentreId the data centre ID (between 0 and 31)
* @param workerId the worker ID (between 0 and 31)
*/
public SnowflakeGuidCreator(long workerId, long dataCentreId) {
this(workerId, dataCentreId, DEFAULT_CUSTOM_EPOCH);
public SnowflakeGuidCreator(long dataCentreId, long workerId) {
this(dataCentreId, workerId, DEFAULT_CUSTOM_EPOCH);
}
/**
* Constructs a SnowflakeGuidGenerator with a custom epoch, worker ID, and
* data center ID.
* data centre ID.
*
* @param dataCentreId the data centre ID (between 0 and 31)
* @param workerId the worker ID (between 0 and 31)
* @param startEpoch the custom epoch timestamp (in milliseconds) to
* start generating IDs from
* @param workerId the worker ID (between 0 and 31)
* @param dataCentreId the data center ID (between 0 and 31)
* @throws IllegalArgumentException if the start epoch is greater than the
* current timestamp, or if the worker ID
* or data center ID is out of range
* or data centre ID is out of range
*/
public SnowflakeGuidCreator(long workerId, long dataCentreId, long startEpoch) {
public SnowflakeGuidCreator(long dataCentreId, long workerId, long startEpoch) {
if (startEpoch > currentTimestamp()) {
throw new IllegalArgumentException("Start Epoch can not be greater than current timestamp!");
}
@@ -206,7 +202,7 @@ public final class SnowflakeGuidCreator implements GuidCreator<Long> {
* @return the current timestamp
*/
private long currentTimestamp() {
return LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli();
return LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
}
}
@@ -18,28 +18,14 @@
package cn.org.codecrafters.guid.exceptions;
/**
* <p>
* The TimingException class represents an exception that is thrown when there
* is an error related to time sequence.
*
* <p>
* This class extends the RuntimeException class, which means that instances of
* TimingException do not need to be declared in a method or constructor's
* throws clause.
*
* The {@code TimingException} class represents an exception that is thrown
* when there is an error related to time sequence.
* <p>
* Instances of TimingException can be created with or without a message and a
* cause. The message provides a description of the exception, while the cause
* represents the underlying cause of the exception and provides additional
* information about the error.
*
* <p>
* TimingException is typically used to handle exceptions related to timing,
* such as timeouts or synchronization issues. It is a subclass of
* RuntimeException, which means it is an unchecked exception and does not need
* to be caught or declared.
*
*
* @author Zihlu Wang
* @since 1.0.0
*/
@@ -54,9 +40,9 @@ public class TimingException extends RuntimeException {
/**
* A custom exception that is thrown when there is an issue with timing or
* scheduling with customized error message.
* scheduling with customised error message.
*
* @param message customized message
* @param message customised message
*/
public TimingException(String message) {
super(message);
@@ -64,9 +50,9 @@ public class TimingException extends RuntimeException {
/**
* A custom exception that is thrown when there is an issue with timing or
* scheduling with customized error message.
* scheduling with customised error message.
*
* @param message customized message
* @param message customised message
* @param cause the cause of this exception
*/
public TimingException(String message, Throwable cause) {
@@ -75,7 +61,7 @@ public class TimingException extends RuntimeException {
/**
* A custom exception that is thrown when there is an issue with timing or
* scheduling with customized error message.
* scheduling with customised error message.
*
* @param cause the cause of this exception
*/
@@ -16,17 +16,14 @@
*/
/**
* <p>
* This package contains the custom exception classes related to GUID
* generation. These exceptions are thrown when there are issues or errors
* during the generation or processing of global unique identifiers (GUIDs).
*
* <p>
* The main exception class in this package is {@link
* cn.org.codecrafters.guid.exceptions.TimingException}, which is a runtime
* exception and serves as the base exception for all other custom exceptions
* related to GUID generation.
*
* <p>
* Custom exceptions in this package provide specific information about the
* type of error that occurred during GUID generation, making it easier for
@@ -34,7 +31,6 @@
* GUIDs. They are designed to enhance the robustness and reliability of the
* GUID generation process by providing clear and meaningful error messages to
* the developers.
*
* <p>
* Developers using the GUID generation module should be aware of the possible
* exceptions that can be thrown and handle them appropriately to ensure smooth
@@ -16,15 +16,12 @@
*/
/**
* <p>
* The package provides a set of tools for generating globally unique
* identifiers (GUIDs).
*
* <p>
* The goal of this library is to provide an efficient, reliable way to
* generate globally unique identifiers without requiring any specific
* environment or configuration.
*
* <p>
* Key features include:
* <ul>
+2 -1
View File
@@ -29,7 +29,7 @@
<groupId>cn.org.codecrafters</groupId>
<artifactId>jdevkit</artifactId>
<version>1.0.1</version>
<version>1.1.0</version>
<inceptionYear>2023</inceptionYear>
<packaging>pom</packaging>
@@ -42,6 +42,7 @@
<module>simple-jwt-authzero</module>
<module>simple-jwt-jjwt</module>
<module>simple-jwt-spring-boot-starter</module>
<module>property-guard-spring-boot-starter</module>
</modules>
<organization>
@@ -0,0 +1,97 @@
# Property Guard
## Introduction
This feature is designed to protect the security of configurations and data, to a certain extent, to control the flow of developers leading to the leakage of sensitive information.
## Prerequisites
This whole `JDevKit` is developed by **JDK 17**, which means you have to use JDK 17 for better experience. Except this, this module is designed for Spring Boot framework, so you have to install Spring Boot (v3) in your application.
## Installation
### If you are using `Maven`
It is quite simple to install this module by `Maven`. The only thing you need to do is find your `pom.xml` file in the project, then find the `<dependencies>` node in the `<project>` node, and add the following codes to `<dependencies>` node:
```xml
<dependency>
<groupId>cn.org.codecrafters</groupId>
<artifactId>property-guard-spring-boot-starter</artifactId>
<version>${property-guard-spring-boot-starter.version}</version>
</dependency>
```
And run `mvn dependency:get` in your project root folder(i.e., if your `pom.xml` is located at `/path/to/your/project/pom.xml`, then your current work folder should be `/path/to/your/project`), then `Maven` will automatically download the `jar` archive from `Maven Central Repository`. This could be **MUCH EASIER** if you are using IDE(i.e., IntelliJ IDEA), the only thing you need to do is click the refresh button of `Maven`.
If you are restricted using the Internet, and have to make `Maven` offline, you could follow the following steps.
1. Download the `jar` file from any place you can get and transfer the `jar` files to your work computer.
2. Move the `jar` files to your local `Maven` Repository as the path of `/path/to/maven_local_repo/cn/org/codecrafters/property-guard-spring-boot-starter/`.
### If you are using `Gradle`
Add this module to your project with `Gradle` is much easier than doing so with `Maven`.
Find `build.gradle` in the needed project, and add the following code to the `dependencies` closure in the build script:
```groovy
implementation 'cn.org.codecrafters:property-guard-spring-boot-starter:${property-guard-spring-boot-starter.version}'
```
### If you are not using `Maven` or `Gradle`
1. Download the `jar` file from the Internet.
2. Create a folder in your project and name it as a name you like(i.e., for me, I prefer `vendor`).
3. Put the `jar` file to the folder you just created in Step 2.
4. Add this folder to your project `classpath`.
## Usage
First, you need a 16-bit-long secret. If you don't have a good way to get a secret, you could consider using our `cn.org.codecrafters.devkit.utils.AesUtil` or `cn.org.codecrafters.simplejwt.SecretCreator` to create a secret.
For example:
```java
import cn.org.codecrafters.devkit.utils.AesUtil;
import cn.org.codecrafters.simplejwt.SecretCreator;
class GenerateRandomKeySample {
public static void main(String[] args) {
var secret1 = AesUtil.generateRandomSecret();
var secret2 = SecretCreator.createSecret(16, true, true, true);
}
}
```
Then, remember this secret and encrypt the configuration properties that are required high security. For example:
```java
import cn.org.codecrafters.devkit.utils.AesUtil;
class EncryptSample {
public static void main(String[] args) {
var dataNeedEncryption = "Sample Value";
var key = "3856faef0d2d4f33";
var encryptedData = AesUtil.encrypt(dataNeedEncryption, key);
}
}
```
After that, copy the encrypted data to `application.properties` or `application.yml`.
For `yml`:
```yaml
app:
sample-configuration: pe:t4YBfv8M9ZmTzWgTi2gJqg== # "pe:" is the prefix that declare that this property is encrypted.
```
For `properties`:
```properties
app.sample-configuration=pe:t4YBfv8M9ZmTzWgTi2gJqg==
```
## Contact
If you have any suggestions, ideas, don't hesitate contacting us via [GitHub Issues](https://github.com/CodeCraftersCN/jdevkit/issues/new) or [Discord Community](https://discord.gg/NQK9tjcBB8).
If you face any bugs while using our library and you are able to fix any bugs in our library, we would be happy to accept pull requests from you on [GitHub](https://github.com/CodeCraftersCN/jdevkit/compare).
@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (C) 2023 CodeCraftersCN.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.org.codecrafters</groupId>
<artifactId>jdevkit</artifactId>
<version>1.1.0</version>
</parent>
<artifactId>property-guard-spring-boot-starter</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>cn.org.codecrafters</groupId>
<artifactId>devkit-utils</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,111 @@
/*
* Copyright (C) 2023 CodeCraftersCN.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.org.codecrafters.propertyguard.autoconfiguration;
import cn.org.codecrafters.devkit.utils.AesUtil;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.boot.env.OriginTrackedMapPropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.SimpleCommandLinePropertySource;
import java.util.HashMap;
import java.util.Optional;
/**
* {@code PropertyGuard} is a utility class designed for encrypting
* configuration properties in Spring Boot applications.
* <p>
* Spring Boot applications often need to store sensitive configuration details
* such as database passwords, API keys, etc. To ensure that these sensitive
* pieces of information are not exposed to the public, developers can utilize
* the {@code PropertyGuard} class to encrypt and store them within
* configuration files.
* <p>
* <b>Usage</b>
* You need a 16-char long secret for encrypting a configuration property. You
* can get this secret on your own, or use the helper utility class by the
* following code:
* <pre>{@code
* var secret = AesUtil.generateRandomSecret(); // Let's presume the result is
* // "3856faef0d2d4f33"
* }</pre>
* <p>
* Then, in {@code application.yml} or {@code application.properties}, change
* the original value from plain text to encrypted value with the prefix
* "<code>pg:</code>".
* <pre>
* # original
* app.example-properties=Sample Value
*
* # encrypted with key 3856faef0d2d4f33
* app.example-properties=pg:t4YBfv8M9ZmTzWgTi2gJqg==
* </pre>
* After that, before running, you need to add the command line arguments
* "pg.key" as the following codes: {@code --pg.key=<the secret>}.
* <p>
* This class is extracted from <a href="https://baomidou.com/pages/e0a5ce/"
* >MyBatis-Plus</a>.
*
* @author hubin@baomidou
* @version 1.1.0
* @see EnvironmentPostProcessor
* @since 1.1.0 (3.3.2 of MyBatis-Plus)
*/
public class PropertyGuard implements EnvironmentPostProcessor {
private final String PREFIX = "pg";
/**
* Process the encryption environment variables.
*
* @param environment the environment to post-process
* @param application the application to which the environment belongs
*/
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
// Get the key for encryption from command line.
var encryptionKey = "";
for (var ps : environment.getPropertySources()) {
if (ps instanceof SimpleCommandLinePropertySource source) {
encryptionKey = source.getProperty("%s.key".formatted(PREFIX));
break;
}
}
if (Optional.ofNullable(encryptionKey).map((key) -> !key.isEmpty()).orElse(false)) {
var map = new HashMap<String, Object>();
for (var propertySources : environment.getPropertySources()) {
if (propertySources instanceof OriginTrackedMapPropertySource source) {
for (var name : source.getPropertyNames()) {
if (source.getProperty(name) instanceof String str) {
if (str.startsWith("%s:".formatted(PREFIX))) {
map.put(name, AesUtil.decrypt(str.substring(3), encryptionKey));
}
}
}
}
}
// Put the decrypted data into environment variables, and made them at top-level.
if (!map.isEmpty()) {
environment.getPropertySources().addFirst(new MapPropertySource("custom-encrypt", map));
}
}
}
}
@@ -0,0 +1 @@
org.springframework.boot.env.EnvironmentPostProcessor=cn.org.codecrafters.propertyguard.autoconfiguration.PropertyGuard
+1 -1
View File
@@ -23,7 +23,7 @@
<parent>
<groupId>cn.org.codecrafters</groupId>
<artifactId>jdevkit</artifactId>
<version>1.0.1</version>
<version>1.1.0</version>
</parent>
<artifactId>simple-jwt-authzero</artifactId>
@@ -39,19 +39,16 @@ import java.time.ZoneId;
import java.util.*;
/**
* <p>
* The {@code AuthzeroTokenResolver} class is an implementation of the {@link
* cn.org.codecrafters.simplejwt.TokenResolver} interface. It uses the {@code
* com.auth0:java-jwt} library to handle JSON Web Token (JWT) resolution. This
* resolver provides functionality to create, extract, verify, and renew JWT
* tokens using various algorithms and custom payload data.
*
* <p>
* <b>Dependencies:</b>
* This implementation relies on the {@code com.auth0:java-jwt} library. Please
* ensure you have added this library as a dependency to your project before
* using this resolver.
*
* <p>
* <b>Usage:</b>
* To use the {@code AuthzeroTokenResolver}, first, create an instance of this
@@ -63,11 +60,9 @@ import java.util.*;
* "Token Issuer",
* "Token Secret");
* }</pre>
*
* <p>
* Then, you can utilize the various methods provided by this resolver to
* handle JWT tokens:
*
* <pre>{@code
* // Creating a new JWT token
* String token =
@@ -84,7 +79,6 @@ import java.util.*;
* String renewedToken =
* tokenResolver.renew(token, Duration.ofMinutes(30), customPayloads);
* }</pre>
*
* <p>
* <b>Note:</b>
* It is essential to configure the appropriate algorithms, secret, and issuer
@@ -93,7 +87,7 @@ import java.util.*;
* correctly configured in your project's dependencies.
*
* @author Zihlu Wang
* @version 1.0.0
* @version 1.1.0
* @see GuidCreator
* @see Algorithm
* @see JWTVerifier
@@ -128,11 +122,11 @@ public class AuthzeroTokenResolver implements TokenResolver<DecodedJWT> {
private final AuthzeroTokenResolverConfig config = AuthzeroTokenResolverConfig.getInstance();
/**
* Creates a new instance of AuthzeroTokenResolver with the provided
* configurations.
* Creates a new instance of {@code AuthzeroTokenResolver} with the
* provided configurations.
*
* @param jtiCreator the GuidCreator used for generating unique identifiers
* for "jti" claim in JWT tokens
* @param jtiCreator the {@link GuidCreator} used for generating unique
* identifiers for "jti" claim in JWT tokens
* @param algorithm the algorithm used for signing and verifying JWT
* tokens
* @param issuer the issuer claim value to be included in JWT tokens
@@ -157,8 +151,8 @@ public class AuthzeroTokenResolver implements TokenResolver<DecodedJWT> {
}
/**
* Creates a new instance of AuthzeroTokenResolver with the provided
* configurations and a simple UUID GuidCreator.
* Creates a new instance of {@link AuthzeroTokenResolver} with the
* provided configurations and a simple UUID GuidCreator.
*
* @param algorithm the algorithm used for signing and verifying JWT tokens
* @param issuer the issuer claim value to be included in JWT tokens
@@ -174,7 +168,7 @@ public class AuthzeroTokenResolver implements TokenResolver<DecodedJWT> {
log.warn("The provided secret which owns {} characters is too weak. Please consider replacing it with a stronger one.", secret.length());
}
this.jtiCreator = (GuidCreator<UUID>) UUID::randomUUID;
this.jtiCreator = UUID::randomUUID;
this.algorithm = config
.getAlgorithm(algorithm)
.apply(secret);
@@ -183,8 +177,9 @@ public class AuthzeroTokenResolver implements TokenResolver<DecodedJWT> {
}
/**
* Creates a new instance of AuthzeroTokenResolver with the provided
* configurations, HMAC256 algorithm and a simple UUID GuidCreator.
* Creates a new instance of {@link AuthzeroTokenResolver} with the
* provided configurations, HMAC256 algorithm and a simple
* UUID GuidCreator.
*
* @param issuer the issuer claim value to be included in JWT tokens
* @param secret the secret used for HMAC-based algorithms (HS256,
@@ -199,7 +194,7 @@ public class AuthzeroTokenResolver implements TokenResolver<DecodedJWT> {
log.warn("The provided secret which owns {} characters is too weak. Please consider replacing it with a stronger one.", secret.length());
}
this.jtiCreator = (GuidCreator<UUID>) UUID::randomUUID;
this.jtiCreator = UUID::randomUUID;
this.algorithm = config
.getAlgorithm(TokenAlgorithm.HS256)
.apply(secret);
@@ -208,15 +203,16 @@ public class AuthzeroTokenResolver implements TokenResolver<DecodedJWT> {
}
/**
* Creates a new instance of AuthzeroTokenResolver with the provided
* configurations, HMAC256 algorithm and a simple UUID GuidCreator.
* Creates a new instance of {@link AuthzeroTokenResolver} with the
* provided configurations, HMAC256 algorithm and a simple
* UUID GuidCreator.
*
* @param issuer the issuer claim value to be included in JWT tokens
*/
public AuthzeroTokenResolver(String issuer) {
var secret = SecretCreator.createSecret(32, true, true, true);
this.jtiCreator = (GuidCreator<UUID>) UUID::randomUUID;
this.jtiCreator = UUID::randomUUID;
this.algorithm = config
.getAlgorithm(TokenAlgorithm.HS256)
.apply(secret);
@@ -283,8 +279,7 @@ public class AuthzeroTokenResolver implements TokenResolver<DecodedJWT> {
builder.withClaim(name, v);
} else {
log.warn("""
Unable to determine the type of field {}, converting it to a string now.
""", name);
Unable to determine the type of field {}, converting it to a string now.""", name);
builder.withClaim(name, value.toString());
}
} else {
@@ -293,16 +288,13 @@ public class AuthzeroTokenResolver implements TokenResolver<DecodedJWT> {
}
/**
* <p>
* Builds the custom claims of the JSON Web Token (JWT) using the provided
* Map of claims and adds them to the JWTCreator.Builder.
* <p>
* <p>
* This method is used to add custom claims to the JWT. It takes a Map of
* claims, where each entry represents a custom claim name (key) and its
* corresponding value (value). The custom claims will be added to the JWT
* using the JWTCreator.Builder.
* <p>
*
* @param claims a Map containing the custom claims to be added to the JWT
* @param builder the JWTCreator.Builder instance to which the custom
@@ -317,9 +309,7 @@ public class AuthzeroTokenResolver implements TokenResolver<DecodedJWT> {
}
/**
* <p>
* Finish creating a token.
*
* <p>
* This is the final step of create a token, to sign this token.
*
@@ -331,7 +321,7 @@ public class AuthzeroTokenResolver implements TokenResolver<DecodedJWT> {
}
/**
* Creates a new token with the specified expiration time, subject, and
* Creates a new token with the specified expiration duration, subject, and
* audience.
*
* @param expireAfter the duration after which the token will expire
@@ -394,7 +384,7 @@ public class AuthzeroTokenResolver implements TokenResolver<DecodedJWT> {
// Build Claims
addClaim(builder, field.getName(), field.get(payload));
} catch (IllegalAccessException e) {
log.error("Cannot access field %s!".formatted(field.getName()));
log.error("Cannot access field {}!", field.getName());
}
}
@@ -402,10 +392,10 @@ public class AuthzeroTokenResolver implements TokenResolver<DecodedJWT> {
}
/**
* Resolves the given token into a DecodedJWT object.
* Resolves the given token into a {@link DecodedJWT} object.
*
* @param token the token to be resolved
* @return a ResolvedToken object
* @return a {@link DecodedJWT} object
*/
@Override
public DecodedJWT resolve(String token) {
@@ -456,9 +446,9 @@ public class AuthzeroTokenResolver implements TokenResolver<DecodedJWT> {
return bean;
} catch (NoSuchMethodException e) {
log.error("Unable to find a no-argument constructor declaration for class %s.".formatted(targetType.getCanonicalName()));
log.error("Unable to find a no-argument constructor declaration for class {}.", targetType.getCanonicalName());
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
log.error("Unable to create a new instance of class %s.".formatted(targetType.getCanonicalName()));
log.error("Unable to create a new instance of class {}.", targetType.getCanonicalName());
}
return null;
}
@@ -482,7 +472,7 @@ public class AuthzeroTokenResolver implements TokenResolver<DecodedJWT> {
/**
* Renews the given expired token with the specified custom payload data.
*
* @param oldToken the expired token to be renewed
* @param oldToken the expiring token to be renewed
* @param payload the custom payload data to be included in the renewed
* token
* @return the renewed token as a {@code String}
@@ -496,7 +486,7 @@ public class AuthzeroTokenResolver implements TokenResolver<DecodedJWT> {
* Renews the given expired token with the new specified strongly-typed
* payload data.
*
* @param oldToken the expired token to be renewed
* @param oldToken the expiring token to be renewed
* @param payload the strongly-typed payload data to be included in the
* renewed token
* @return the renewed token as a {@code String}
@@ -518,7 +508,7 @@ public class AuthzeroTokenResolver implements TokenResolver<DecodedJWT> {
* @param oldToken the expired token to be renewed
* @param payload the strongly-typed payload data to be included in the
* renewed token
* @return the renewed token as a {@code String}
* @return the renewed token as a {@link String}
*/
@Override
public <T extends TokenPayload> String renew(String oldToken, T payload) {
@@ -17,6 +17,8 @@
package cn.org.codecrafters.simplejwt.authzero.config;
import cn.org.codecrafters.simplejwt.TokenResolver;
import cn.org.codecrafters.simplejwt.authzero.AuthzeroTokenResolver;
import cn.org.codecrafters.simplejwt.config.TokenResolverConfig;
import cn.org.codecrafters.simplejwt.constants.TokenAlgorithm;
import cn.org.codecrafters.simplejwt.exceptions.UnsupportedAlgorithmException;
@@ -29,72 +31,65 @@ import java.util.Optional;
import java.util.function.Function;
/**
* The AuthzeroTokenResolverConfig class provides the configuration for the
* AuthzeroTokenResolver.
* The {@code AuthzeroTokenResolverConfig} class provides the configuration for
* the {@link AuthzeroTokenResolver}.
* <p>
* This configuration class is used to establish the mapping between the
* standard TokenAlgorithm defined within the AuthzeroTokenResolver facade and
* the specific algorithms used by the Auth0 Java JWT library, which is the
* underlying library used by AuthzeroTokenResolver to handle JSON Web Tokens
* (JWTs).
*
* This configuration is used to establish the mapping between the standard
* {@link TokenAlgorithm} defined within the {@link AuthzeroTokenResolver}
* facade and the specific algorithms used by the {@code com.auth0:java-jwt}
* library, which is the underlying library used by {@link
* AuthzeroTokenResolver} to handle JSON Web Tokens (JWTs).
* <p>
* <b>Algorithm Mapping:</b>
* The AuthzeroTokenResolverConfig class allows specifying the relationship
* between the standard TokenAlgorithm instances supported by
* AuthzeroTokenResolver and the corresponding algorithms used by the
* com.auth0:java-jwt library. The mapping is achieved using a Map, where the
* keys are the standard TokenAlgorithm instances, and the values represent the
* algorithm functions used by Auth0 Java JWT library for each corresponding
* key.
*
* The {@code AuthzeroTokenResolverConfig} allows specifying the relationship
* between the standard {@link TokenAlgorithm} instances supported by
* {@link AuthzeroTokenResolver} and the corresponding algorithms used by the
* {@code com.auth0:java-jwt} library. The mapping is achieved using a Map,
* where the keys are the standard TokenAlgorithm instances, and the values
* represent the algorithm functions used by Auth0 Java JWT library for each
* corresponding key.
* <p>
* <b>Note:</b>
* The provided algorithm mapping should be consistent with the actual
* algorithms supported and used by the Auth0 Java JWT library. It is crucial
* to ensure that the mapping is accurate to enable proper token validation
* and processing within the AuthzeroTokenResolver.
* algorithms supported and used by the {@code com.auth0:java-jwt} library. It
* is crucial to ensure that the mapping is accurate to enable proper token
* validation and processing within the {@link AuthzeroTokenResolver}.
*
* @author Zihlu Wang
* @version 1.0.0
* @version 1.1.0
* @since 1.0.0
*/
public final class AuthzeroTokenResolverConfig implements TokenResolverConfig<Function<String, Algorithm>> {
/**
* <p>
* Constructs a new instance of AuthzeroTokenResolverConfig.
*
* Constructs a new instance of {@code AuthzeroTokenResolverConfig}.
* <p>
* The constructor is set as private to enforce the singleton pattern for
* this configuration class. Instances of AuthzeroTokenResolverConfig
* should be obtained through the {@link #getInstance()} method.
* this configuration class. Instances of
* {@code AuthzeroTokenResolverConfig} should be obtained through the
* {@link #getInstance()} method.
*/
private AuthzeroTokenResolverConfig() {
}
/**
* <p>
* The singleton instance of AuthzeroTokenResolverConfig.
*
* The singleton instance of {@code AuthzeroTokenResolverConfig}.
* <p>
* This instance is used to ensure that only one instance of
* AuthzeroTokenResolverConfig is created and shared throughout the
* application. The singleton pattern is implemented to provide centralized
* {@code AuthzeroTokenResolverConfig} is created and shared throughout the
* application. The singleton pattern is implemented to provide centralised
* configuration and avoid redundant object creation.
*/
private static AuthzeroTokenResolverConfig instance;
/**
* <p>
* The supported algorithms and their corresponding algorithm functions.
*
* <p>
* This map stores the supported algorithms as keys and their corresponding
* algorithm functions as values. The algorithm functions represent the
* functions used by the Auth0 Java JWT library to handle the specific
* algorithms. The mapping is used to provide proper algorithm resolution
* and processing within the AuthzeroTokenResolver.
* functions used by the {@code com.auth0:java-jwt} library to handle the
* specific algorithms. The mapping is used to provide proper algorithm
* resolution and processing within the {@link AuthzeroTokenResolver}.
*/
private static final Map<TokenAlgorithm, Function<String, Algorithm>> SUPPORTED_ALGORITHMS = new HashMap<>() {{
put(TokenAlgorithm.HS256, Algorithm::HMAC256);
@@ -103,14 +98,14 @@ public final class AuthzeroTokenResolverConfig implements TokenResolverConfig<Fu
}};
/**
* Gets the instance of AuthzeroTokenResolverConfig.
* Gets the instance of {@code AuthzeroTokenResolverConfig}.
* <p>
* This method returns the singleton instance of
* AuthzeroTokenResolverConfig. If the instance is not yet created, it will
* create a new instance and return it. Otherwise, it returns the existing
* instance.
* {@code AuthzeroTokenResolverConfig}. If the instance is not yet created,
* it will create a new instance and return it. Otherwise, it returns the
* existing instance.
*
* @return the instance of AuthzeroTokenResolverConfig
* @return the instance of {@code AuthzeroTokenResolverConfig}
*/
public static AuthzeroTokenResolverConfig getInstance() {
if (Objects.isNull(instance)) {
@@ -121,20 +116,20 @@ public final class AuthzeroTokenResolverConfig implements TokenResolverConfig<Fu
}
/**
* <p>
* Gets the algorithm function corresponding to the specified
* TokenAlgorithm.
*
* {@link TokenAlgorithm}.
* <p>
* This method returns the algorithm function associated with the given
* TokenAlgorithm. The provided TokenAlgorithm represents the specific
* algorithm for which the corresponding algorithm function is required.
* The returned AlgorithmFunction represents the function implementation
* that can be used by the TokenResolver to handle the specific algorithm.
* {@link TokenAlgorithm}. The provided {@link TokenAlgorithm} represents
* the specific algorithm for which the corresponding algorithm function
* is required. The returned Algorithm Function represents the function
* implementation that can be used by the {@link TokenResolver} to handle
* the specific algorithm.
*
* @param algorithm the TokenAlgorithm for which the algorithm function is
* required
* @return the algorithm function associated with the given TokenAlgorithm
* @param algorithm the {@link TokenAlgorithm} for which the algorithm
* function isrequired
* @return the algorithm function associated with the given {@link
* TokenAlgorithm}
* @throws UnsupportedAlgorithmException if the given {@code algorithm} is
* not supported by this
* implementation
@@ -16,17 +16,14 @@
*/
/**
* <p>
* The package {@code cn.org.codecrafters.simplejwt.authzero.config} contains
* configuration classes related to the {@link
* cn.org.codecrafters.simplejwt.authzero.AuthzeroTokenResolver}
* implementation.
*
* <p>
* The classes in this package provide configuration options and settings for
* the {@link cn.org.codecrafters.simplejwt.authzero.AuthzeroTokenResolver},
* which is used for resolving JSON Web Tokens (JWT) using the Auth0 library.
*
* <p>
* The {@link
* cn.org.codecrafters.simplejwt.authzero.config.AuthzeroTokenResolverConfig}
@@ -37,7 +34,6 @@
* JWT algorithms. It enables developers to specify and customize the
* algorithm functions according to the chosen JWT algorithm and the library
* being used.
*
* <p>
* The configuration options in this package help developers integrate and
* configure the {@link
@@ -45,13 +41,12 @@
* into their Spring Boot applications. Developers can fine-tune the token
* resolution process and customize algorithm handling to align with their
* specific requirements and desired level of security.
*
* <p>
* It is recommended to explore the classes in this package to understand how
* to configure and use the {@link
* cn.org.codecrafters.simplejwt.authzero.AuthzeroTokenResolver} effectively
* in the Spring Boot environment to handle JWT authentication and
* authorization securely and efficiently.
* authorisation securely and efficiently.
*
* @since 1.0.0
*/
@@ -19,11 +19,10 @@
* This package contains classes related to the integration of the {@code
* com.auth0:java-jwt} library in the Simple JWT project. {@code
* com.auth0:java-jwt} is a powerful and widely-used Identity as a Service
* (IDaaS) platform that provides secure authentication and authorization
* (IDaaS) platform that provides secure authentication and authorisation
* solutions for web and mobile applications. The classes in this package
* provide the necessary functionality to handle JSON Web Tokens (JWTs) using
* the {@code com.auth0:java-jwt} library.
*
* <p>
* The main class in this package is the {@link
* cn.org.codecrafters.simplejwt.authzero.AuthzeroTokenResolver}, which
@@ -33,22 +32,22 @@
* {@code com.auth0:java-jwt} library. Developers can use this class as the
* main token resolver in the Simple JWT project when integrating {@code
* com.auth0:java-jwt} as the JWT management library.
*
* <p>
* The {@code AuthzeroTokenResolver} relies on the {@code com.auth0:java-jwt}
* library to handle the underlying JWT operations, including token creation,
* validation, and extraction. It utilizes the {@code com.auth0:java-jwt}
* {@code Algorithm} class to define and use different algorithms for JWT
* signing and verification.
*
* The {@link cn.org.codecrafters.simplejwt.authzero.AuthzeroTokenResolver}
* relies on the {@code com.auth0:java-jwt} library to handle the underlying
* JWT operations, including token creation, validation, and extraction. It
* utilizes the {@code com.auth0:java-jwt} {@link
* com.auth0.jwt.algorithms.Algorithm} class to define and use different
* algorithms for JWT signing and verification.
* <p>
* To use the {@code AuthzeroTokenResolver}, developers must provide the
* necessary configurations and dependencies, such as the {@code GuidCreator}
* for generating unique JWT IDs (JTI), the supported algorithm function, the
* issuer name, and the secret key used for token signing and validation. The
* {@code AuthzeroTokenResolverConfig} class provides a convenient way to
* configure these dependencies.
*
* To use the {@link
* cn.org.codecrafters.simplejwt.authzero.AuthzeroTokenResolver}, developers
* must provide the necessary configurations and dependencies, such as the
* {@link cn.org.codecrafters.guid.GuidCreator} for generating unique JWT IDs
* (JTI), the supported algorithm function, the issuer name, and the secret key
* used for token signing and validation. The {@link
* cn.org.codecrafters.simplejwt.authzero.config.AuthzeroTokenResolverConfig}
* class provides a convenient way to configure these dependencies.
* <p>
* Developers using the {@code com.auth0:java-jwt} integration should be
* familiar with the concepts and usage of the {@code com.auth0:java-jwt}
+1 -1
View File
@@ -23,7 +23,7 @@
<parent>
<groupId>cn.org.codecrafters</groupId>
<artifactId>jdevkit</artifactId>
<version>1.0.1</version>
<version>1.1.0</version>
</parent>
<artifactId>simple-jwt-facade</artifactId>
@@ -22,12 +22,12 @@ import cn.org.codecrafters.simplejwt.exceptions.WeakSecretException;
import java.util.Random;
/**
* SecretCreator is a utility class that provides methods to generate secure
* secret strings. The generated secrets can be used as cryptographic keys or
* passwords for various security-sensitive purposes.
* {@code SecretCreator} is a utility class that provides methods to generate
* secure secret strings. The generated secrets can be used as cryptographic
* keys or passwords for various security-sensitive purposes.
*
* @author Zihlu Wang
* @version 1.0.0
* @version 1.1.0
* @since 1.0.0
*/
public final class SecretCreator {
@@ -83,24 +83,23 @@ public final class SecretCreator {
if (length < 32) {
throw new WeakSecretException("""
The requested secret, which is only %d characters long, is too weak. \
Please replace it with a stronger secret.
""".formatted(length));
Please replace it with a stronger secret.""".formatted(length));
}
final var randomizer = new Random();
final var randomiser = new Random();
var charset = new StringBuilder(LOWERCASE_CHARACTERS);
if (isContainCapital) charset.append(UPPERCASE_CHARACTERS);
if (isContainDigital) charset.append(DIGITS);
if (isContainSpecialSign) charset.append(SPECIAL_SIGNS);
var password = new StringBuilder();
var secretBuilder = new StringBuilder();
var charsetSize = charset.length();
for (var i = 0; i < length; ++i) {
password.append(charset.charAt(randomizer.nextInt(charsetSize)));
secretBuilder.append(charset.charAt(randomiser.nextInt(charsetSize)));
}
return password.toString();
return secretBuilder.toString();
}
/**
@@ -115,6 +114,7 @@ public final class SecretCreator {
* @return the generated secure secret
* @throws WeakSecretException if the requested secret length is less than
* 32 characters
* @see #createSecret(int, boolean, boolean, boolean)
*/
public static String createSecret(int length,
boolean isContainCapital,
@@ -132,6 +132,7 @@ public final class SecretCreator {
* @return the generated secure secret
* @throws WeakSecretException if the requested secret length is less than
* 32 characters
* @see #createSecret(int, boolean, boolean, boolean)
*/
public static String createSecret(int length,
boolean isContainCapital) {
@@ -146,6 +147,7 @@ public final class SecretCreator {
* @return the generated secure secret
* @throws WeakSecretException if the requested secret length is less than
* 32 characters
* @see #createSecret(int, boolean, boolean, boolean)
*/
public static String createSecret(int length) {
return createSecret(length, false, false, false);
@@ -20,21 +20,15 @@ package cn.org.codecrafters.simplejwt;
import java.util.Map;
/**
* <p>
* TokenPayload - Interface for JWT Payload Data Classes.
*
* <p>
* The {@code TokenPayload} interface is used to mark a data class as suitable
* {@code TokenPayload} interface is used to mark a data class as suitable
* for being used as the payload in a JSON Web Token (JWT). Any class
* implementing this interface can be used to represent the payload data that
* will be included in a JWT.
*
* <p>
* Implementing this interface indicates that the data class contains
* information that needs to be securely transmitted and verified as part of a
* JWT. The payload typically contains claims or attributes that provide
* additional information about the JWT subject or context.
*
* <p>
* <b>Usage:</b>
* To use a class as a JWT payload, simply implement the {@code TokenPayload}
@@ -45,8 +39,9 @@ import java.util.Map;
* }
* </pre>
*
* @author Zihlu Wang
* @version 1.1.0
* @since 1.0.0
* @version 1.0.0
*/
public interface TokenPayload {
@@ -22,25 +22,21 @@ import java.time.Duration;
import java.util.Map;
/**
* <p>
* The {@code TokenResolver} interface defines methods for creating,
* extracting, and renewing tokens, particularly JSON Web Tokens (JWTs). It
* provides a set of methods to generate tokens with various payload
* configurations, extract payload from tokens, and renew expired tokens.
*
* {@code TokenResolver} defines methods for creating, extracting, and
* renewing tokens, particularly JSON Web Tokens (JWTs). It provides a set of
* methods to generate tokens with various payload configurations, extract
* payload from tokens, and renew expired tokens.
* <p>
* <b>Token Creation:</b>
* The interface provides overloaded methods for creating tokens with different
* payload configurations, including expiration time, audience, subject, and
* custom payload data. Clients can choose the appropriate method based on
* their specific token requirements.
*
* <p>
* <b>Token Extraction:</b>
* The interface includes methods to extract payload information from a given
* token. Clients can use these methods to obtain the payload data encoded in
* the token.
*
* <p>
* <b>Token Renewal:</b>
* The interface also offers methods for token renewal. Clients can renew an
@@ -50,7 +46,7 @@ import java.util.Map;
* @param <ResolvedTokenType> the type of the result obtained by the
* third-party library when parsing JWTs
* @author Zihlu Wang
* @version 1.0.0
* @version 1.1.0
* @since 1.0.0
*/
public interface TokenResolver<ResolvedTokenType> {
@@ -23,14 +23,12 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation {@code ExcludeFromPayload} is used to mark a property of a data
* class that should be excluded from being automatically injected into the
* JSON Web Token (JWT) payload during token generation. When a property is
* annotated by this annotation, it will not be included in the JWT payloads.
* <p>
* This annotation is used to mark a property of a data class that should be
* excluded from being automatically injected into the JSON Web Token (JWT)
* payload during token generation. When a property is annotated with this
* annotation, it will not be included as part of the JWT payload.
*
*
* <p><b>Usage:</b>
* <b>Usage:</b>
* To exclude a property from the JWT payload, annotate the property with
* {@code @ExcludeFromPayload}:
*
@@ -45,14 +43,15 @@ import java.lang.annotation.Target;
* // Getters and setters...
* }
* }</pre>
*
* <p><b>Note:</b>
* This annotation should be used only on properties that are not intended to
* <p>
* <b>Note:</b>
* This annotation should be used on properties that are not intended to
* be included in the JWT payload due to their sensitive nature or for other
* reasons. It is important to carefully choose which properties are excluded
* from the payload to ensure the JWT remains secure and efficient.
* reasons only. It is important to carefully choose which properties are
* excluded from the payload to ensure the JWT remains secure and efficient.
*
* @version 1.0.0
* @author Zihlu Wang
* @version 1.1.0
* @since 1.0.0
*/
@Retention(RetentionPolicy.RUNTIME)
@@ -22,7 +22,6 @@
* properties of a data class to exclude them from being included as part
* of the JWT payload.
*
* @version 1.0.0
* @since 1.0.0
*/
package cn.org.codecrafters.simplejwt.annotations;
@@ -17,21 +17,21 @@
package cn.org.codecrafters.simplejwt.config;
import cn.org.codecrafters.simplejwt.TokenResolver;
import cn.org.codecrafters.simplejwt.constants.TokenAlgorithm;
/**
* <p>
* The TokenResolverConfig interface provides a mechanism to configure a
* TokenResolver with algorithm functions.
*
* The {@code TokenResolverConfig} provides a mechanism to configure a
* {@link TokenResolver} with algorithm functions.
* <p>
* This generic interface is used to define the configuration details for a
* TokenResolver that utilizes algorithm functions. The interface allows for
* specifying algorithm functions corresponding to different TokenAlgorithm
* instances supported by the TokenResolver implementation.
* {@link TokenResolver} that utilizes algorithm functions. The interface
* allows for specifying algorithm functions corresponding to different {@link
* TokenAlgorithm} instances supported by the {@link TokenResolver}
* implementation.
*
* @param <Algo> the type representing algorithm functions used by the
* {@code TokenResolver}
* {@link TokenResolver}
* @author Zihlu Wang
* @version 1.0.0
* @since 1.0.0
@@ -39,18 +39,20 @@ import cn.org.codecrafters.simplejwt.constants.TokenAlgorithm;
public interface TokenResolverConfig<Algo> {
/**
* Gets the algorithm function corresponding to the specified
* TokenAlgorithm.
* Gets the algorithm function corresponding to the specified {@link
* TokenAlgorithm}.
* <p>
* This method returns the algorithm function associated with the given
* TokenAlgorithm. The provided TokenAlgorithm represents the specific
* algorithm for which the corresponding algorithm function is required.
* The returned AlgorithmFunction represents the function implementation
* that can be used by the TokenResolver to handle the specific algorithm.
* {@link TokenAlgorithm}. The provided TokenAlgorithm represents the
* specific algorithm for which the corresponding algorithm function is
* required. The returned {@code Algo} represents the function
* implementation that can be used by the {@link TokenResolver} to handle
* the specific algorithm.
*
* @param algorithm the TokenAlgorithm for which the algorithm function is
* required
* @return the algorithm function associated with the given TokenAlgorithm
* @param algorithm the {@link TokenAlgorithm} for which the algorithm
* function is required
* @return the algorithm function associated with the given {@link
* TokenAlgorithm}
*/
Algo getAlgorithm(TokenAlgorithm algorithm);
@@ -16,17 +16,16 @@
*/
/**
* <p>
* The classes in this package provide configuration options and settings for
* the Simple JWT library. They are used to customize the behavior of the
* library and allow developers to fine-tune various aspects of JWT generation
* and validation.
*
* the {@code cn.org.codecrafters:simple-jwt-facade} library. They are used
* to customize the behavior of the library and allow developers to fine-tune
* various aspects of JWT generation and validation.
* <p>
* Other configuration classes may be added in the future to support additional
* customization options and features. Developers using the Simple JWT library
* should be familiar with the available configuration options to ensure proper
* integration and usage of the library.
* customisation options and features. Developers using the
* {@code cn.org.codecrafters:simple-jwt-facade} library should be familiar
* with the available configuration options to ensure proper integration and
* usage of the library.
*
* @since 1.0.0
*/
@@ -23,8 +23,8 @@ import java.util.List;
* The {@code PredefinedKeys} class contains constants for standard JSON Web Token (JWT) claims. These constants
* represent the names of the standard claims that can be included in a JWT payload. Developers can use these constants
* when working with JWTs to ensure consistent naming of the claims.
*
* <p>The class provides the following standard JWT claim constants:
* <p>
* The class provides the following standard JWT claim constants:
* <ul>
* <li>{@link #ISSUER}: Represents the "iss" (Issuer) claim.</li>
* <li>{@link #SUBJECT}: Represents the "sub" (Subject) claim.</li>
@@ -34,13 +34,15 @@ import java.util.List;
* <li>{@link #ISSUED_AT}: Represents the "iat" (Issued At) claim.</li>
* <li>{@link #JWT_ID}: Represents the "jti" (JWT ID) claim.</li>
* </ul>
*
* <p>The class also contains a list of all the standard claim constants, accessible via the {@link #KEYS} field. This
* <p>
* The class also contains a list of all the standard claim constants, accessible via the {@link #KEYS} field. This
* list can be useful for iterating through all the standard claims or checking for the presence of specific claims.
*
* <p>Note: This class is final and cannot be instantiated. It only serves as a utility class to hold the standard JWT
* <p>
* Note: This class is final and cannot be instantiated. It only serves as a utility class to hold the standard JWT
* claim constants.
*
* @author Zihlu Wang
* @version 1.1.0
* @since 1.0.0
*/
public final class PredefinedKeys {
@@ -86,11 +88,13 @@ public final class PredefinedKeys {
public static final List<String> KEYS = List.of(ISSUER, SUBJECT, AUDIENCE, EXPIRATION_TIME, NOT_BEFORE, ISSUED_AT, JWT_ID);
/**
* Private constructor to prevent instantiation of the {@code PredefinedKeys} class.
* This class is intended to be used as a utility class with only static constants and methods.
* Private constructor to prevent instantiation of the
* {@code PredefinedKeys} class.
* <p>
* This class is intended to be used as a utility class with only static
* constants and methods.
*/
private PredefinedKeys() {
// Private constructor to prevent instantiation
}
}
@@ -25,9 +25,8 @@ import lombok.Getter;
* cryptographic algorithms to be used for secure token generation and
* validation. This enum provides a list of supported algorithms to ensure
* consistent usage and avoid potential security issues.
*
* <p><b>Supported Algorithms:</b>
* This enum includes the following supported algorithms:
* <p>
* <b>Supported Algorithms:</b>
* <ul>
* <li>{@link TokenAlgorithm#HS256}: HMAC SHA-256</li>
* <li>{@link TokenAlgorithm#HS384}: HMAC SHA-384</li>
@@ -40,7 +39,8 @@ import lombok.Getter;
* <li>{@link TokenAlgorithm#ES512}: ECDSA with SHA-512</li>
* </ul>
*
* @version 1.0.0
* @author Zihlu Wang
* @version 1.1.0
* @since 1.0.0
*/
@Getter
@@ -22,6 +22,5 @@
* configuration parameters.
*
* @since 1.0.0
* @version 1.0.0
*/
package cn.org.codecrafters.simplejwt.constants;
@@ -18,30 +18,34 @@
package cn.org.codecrafters.simplejwt.exceptions;
/**
* This {@code UnsupportedAlgorithmException} represents the given
* algorithm is not supported by {@link
* cn.org.codecrafters.simplejwt.TokenResolver} yet.
* <p>
* This {@code UnsupportedAlgorithmException} is to indicates that the given
* algorithm is not supported by TokenResolver yet.
*
* <p>
* To support a specified algorithm, you could
*
* If you want the supports to an unsupported algorithm, you could
* <ul>
* <li>Commit an issue at GitHub Issues or;</li>
* <li>Communicate with us on Discord Community.</li>
* </ul>
*
* @author Zihlu Wang
* @version 1.1.0
* @since 1.0.0
*/
public class UnsupportedAlgorithmException extends RuntimeException {
/**
* Constructs a new runtime exception with {@code null} as its detail
* message. The cause is not initialized, and may subsequently be
* initialized by a call to {@link #initCause}.
* Constructs a new {@code UnsupportedAlgorithmException} with {@code null}
* as its detail message. The cause is not initialized, and may
* subsequently be initialized by a call to {@link #initCause}.
*/
public UnsupportedAlgorithmException() {
}
/**
* Constructs a new runtime exception with the specified detail message.
* The cause is not initialized, and may subsequently be initialized by a
* call to {@link #initCause}.
* Constructs a new {@code UnsupportedAlgorithmException} with the
* specified detail message. The cause is not initialized, and may
* subsequently be initialized by a call to {@link #initCause}.
*
* @param message the detail message. The detail message is saved for
* later retrieval by the {@link #getMessage()} method.
@@ -51,14 +55,8 @@ public class UnsupportedAlgorithmException extends RuntimeException {
}
/**
* <p>
* Constructs a new runtime exception with the specified detail message and
* cause.
*
* <p>Note that the detail message associated with
* {@code cause} is <i>not</i> automatically incorporated in
* this runtime exception's detail message.
*
* Constructs a new {@code UnsupportedAlgorithmException} with the
* specified detail message and cause.
*
* @param message the detail message (which is saved for later retrieval
* by the {@link #getMessage()} method).
@@ -73,11 +71,12 @@ public class UnsupportedAlgorithmException extends RuntimeException {
}
/**
* Constructs a new runtime exception with the specified cause and a
* detail message of {@code (cause==null ? null : cause.toString())}
* (which typically contains the class and detail message of
* {@code cause}). This constructor is useful for runtime exceptions
* that are little more than wrappers for other throwables.
* Constructs a new {@code UnsupportedAlgorithmException} with the
* specified cause and a detail message of
* {@code (cause==null ? null : cause.toString())} (which typically
* contains the class and detail message of {@code cause}). This
* constructor is useful for runtime exceptions that are little more
* than wrappers for other throwable.
*
* @param cause the cause (which is saved for later retrieval by the
* {@link #getCause()} method). (A {@code null} value is
@@ -90,18 +89,17 @@ public class UnsupportedAlgorithmException extends RuntimeException {
}
/**
* Constructs a new runtime exception with the specified detail
* message, cause, suppression enabled or disabled, and writable
* stack trace enabled or disabled.
* Constructs a new {@code UnsupportedAlgorithmException} with the
* specified detail message, cause, suppression enabled or disabled, and
* writable stack trace enabled or disabled.
*
* @param message the detail message.
* @param cause the cause. (A {@code null} value is permitted,
* and indicates that the cause is nonexistent or unknown.)
* @param enableSuppression whether or not suppression is enabled
* or disabled
* @param writableStackTrace whether or not the stack trace should
* be writable
* @since 1.7
* @param cause the cause (A {@code null} value is permitted,
* and indicates that the cause is nonexistent or
* unknown.)
* @param enableSuppression whether suppression is enabled or disabled
* @param writableStackTrace whether the stack trace should be writable
* @since 1.0.0
*/
public UnsupportedAlgorithmException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
@@ -18,14 +18,21 @@
package cn.org.codecrafters.simplejwt.exceptions;
/**
* WeakSecretException
* {@code WeakSecretException} represents that your secret is too weak to be
* used in signing JWTs.
* <p>
* {@code WeakSecretException} will only appears that if you are using the
* implementation module {@code cn.org.codecrafters:simple-jwt-jjwt} due to
* it is implemented by {@code io.jsonwebtoken:jjwt}.
*
* @author Zihlu Wang
* @version 1.1.0
* @since 1.0.0
*/
public class WeakSecretException extends RuntimeException {
/**
* Constructs a new runtime exception with {@code null} as its
* Constructs a new {@code WeakSecretException} with {@code null} as its
* detail message. The cause is not initialized, and may subsequently be
* initialized by a call to {@link #initCause}.
*/
@@ -33,9 +40,9 @@ public class WeakSecretException extends RuntimeException {
}
/**
* Constructs a new runtime exception with the specified detail message.
* The cause is not initialized, and may subsequently be initialized by a
* call to {@link #initCause}.
* Constructs a new {@code WeakSecretException} with the specified detail
* message. The cause is not initialized, and may subsequently be
* initialized by a call to {@link #initCause}.
*
* @param message the detail message. The detail message is saved for
* later retrieval by the {@link #getMessage()} method.
@@ -45,10 +52,11 @@ public class WeakSecretException extends RuntimeException {
}
/**
* Constructs a new runtime exception with the specified detail message and
* cause. <p>Note that the detail message associated with
* {@code cause} is <i>not</i> automatically incorporated in
* this runtime exception's detail message.
* Constructs a new {@code WeakSecretException} with the specified detail
* message and cause.
* <p>
* Note that the detail message associated with {@code cause} is <i>not</i>
* automatically incorporated in this runtime exception's detail message.
*
* @param message the detail message (which is saved for later retrieval
* by the {@link #getMessage()} method).
@@ -56,42 +64,41 @@ public class WeakSecretException extends RuntimeException {
* {@link #getCause()} method). (A {@code null} value is
* permitted, and indicates that the cause is nonexistent or
* unknown.)
* @since 1.4
* @since 1.0.0
*/
public WeakSecretException(String message, Throwable cause) {
super(message, cause);
}
/**
* Constructs a new runtime exception with the specified cause and a
* detail message of {@code (cause==null ? null : cause.toString())}
* Constructs a new {@code WeakSecretException} with the specified cause
* and a detail message of {@code (cause==null ? null : cause.toString())}
* (which typically contains the class and detail message of
* {@code cause}). This constructor is useful for runtime exceptions
* that are little more than wrappers for other throwables.
* {@code cause}). This constructor is useful for runtime exceptions that
* are little more than wrappers for other throwable.
*
* @param cause the cause (which is saved for later retrieval by the
* {@link #getCause()} method). (A {@code null} value is
* permitted, and indicates that the cause is nonexistent or
* unknown.)
* @since 1.4
* @since 1.0.0
*/
public WeakSecretException(Throwable cause) {
super(cause);
}
/**
* Constructs a new runtime exception with the specified detail
* Constructs a new {@code WeakSecretException} with the specified detail
* message, cause, suppression enabled or disabled, and writable
* stack trace enabled or disabled.
*
* @param message the detail message.
* @param cause the cause. (A {@code null} value is permitted,
* and indicates that the cause is nonexistent or unknown.)
* @param enableSuppression whether or not suppression is enabled
* or disabled
* @param writableStackTrace whether or not the stack trace should
* be writable
* @since 1.7
* and indicates that the cause is nonexistent or
* unknown.)
* @param enableSuppression whether suppression is enabled or disabled
* @param writableStackTrace whether the stack trace should be writable
* @since 1.0.0
*/
public WeakSecretException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
@@ -16,26 +16,23 @@
*/
/**
* <p>
* The {@code cn.org.codecrafters.simplejwt.exceptions} package contains
* custom exception classes related to the Simple JWT library. These
* exceptions are thrown when there are issues or errors during the generation
* , validation, or processing of JSON Web Tokens (JWTs) in Java applications.
*
*
* custom exception classes related to the
* {@code cn.org.codecrafters:simple-jwt-facade} library. These exceptions are
* thrown when there are issues or errors during the generation , validation,
* or processing of JSON Web Tokens (JWTs) in Java applications.
* <p>
* Custom exception classes in this package are designed to enhance the
* robustness and reliability of the JWT handling process by providing clear
* and meaningful error messages to the developers. They help developers
* identify and troubleshoot issues related to JWT generation, validation, or
* extraction and ensure smooth operation and error handling in their
* applications.
*
*
* extraction and ensure smooth operation and error handling in
* their applications.
* <p>
* Developers using the Simple JWT library should be aware of the possible
* exceptions that can be thrown and handle them appropriately to ensure secure
* and reliable JWT handling in their Java applications.
* Developers using the {@code cn.org.codecrafters:simple-jwt-facade} library
* should be aware of the possible exceptions that can be thrown and handle
* them appropriately to ensure secure and reliable JWT handling in their
* Java applications.
*
* @since 1.0.0
*/
@@ -16,28 +16,23 @@
*/
/**
* <p>
* The {@code cn.org.codecrafters.simplejwt} package is the core package of the
* Simple JWT project, which provides a lightweight and easy-to-use library for
* working with JSON Web Tokens (JWTs) in Java applications. JWT is a
* widely-used standard for representing claims between two parties, typically
* used to secure web and mobile applications. This library aims to simplify
* the JWT handling process and provide convenient abstractions for JWT
* generation, validation, and extraction.
*
*
* <b>Simple JWT</b> project, which provides a lightweight and easy-to-use
* library for working with JSON Web Tokens (JWTs) in Java applications. JWT is
* a widely-used standard for representing claims between two parties,
* typically used to secure web and mobile applications. This library aims to
* simplify the JWT handling process and provide convenient abstractions for
* JWT generation, validation, and extraction.
* <p>
* The Simple JWT library is designed to be flexible and customizable, allowing
* developers to use different algorithms, token resolvers, and token payload
* classes based on their specific application requirements. It aims to
* The <b>Simple JWT</b> library is designed to be flexible and customisable,
* allowing developers to use different algorithms, token resolvers, and token
* payload classes based on their specific application requirements. It aims to
* simplify the JWT handling process while maintaining security and best
* practices for working with JWTs.
*
*
* <p>
* Developers should refer to the official documentation and examples for the
* Simple JWT project to understand how to use the library effectively and
* securely in their Java applications.
* <b>Simple JWT</b> project to understand how to use the library effectively
* and securely in their Java applications.
*
*
* @since 1.0.0
+1 -1
View File
@@ -23,7 +23,7 @@
<parent>
<groupId>cn.org.codecrafters</groupId>
<artifactId>jdevkit</artifactId>
<version>1.0.1</version>
<version>1.1.0</version>
</parent>
<artifactId>simple-jwt-jjwt</artifactId>
@@ -43,9 +43,61 @@ import java.util.Map;
import java.util.UUID;
/**
* JjwtTokenResolver
* The {@link JjwtTokenResolver} class is an implementation of the {@link
* cn.org.codecrafters.simplejwt.TokenResolver} interface. It uses the {@code
* io.jsonwebtoken:jjwt} library to handle JSON Web Token (JWT) resolution.
* This resolver provides functionality to create, extract, verify, and renew
* JWT tokens using various algorithms and custom payload data.
* <p>
* <b>Dependencies:</b>
* This implementation relies on the {@code io.jsonwebtoken:jjwt} library. Please
* ensure you have added this library as a dependency to your project before
* using this resolver.
* <p>
* <b>Usage:</b>
* To use the {@code JjwtTokenResolver}, first, create an instance of this
* class:
* <pre>{@code
* TokenResolver<Jws<Claims>> tokenResolver =
* new JjwtTokenResolver(TokenAlgorithm.HS256,
* "Token Subject",
* "Token Issuer",
* "Token Secret");
* }</pre>
* <p>
* Then, you can utilize the various methods provided by this resolver to
* handle JWT tokens:
* <pre>{@code
* // Creating a new JWT token
* String token =
* tokenResolver.createToken(Duration.ofHours(1),
* "your_subject",
* "your_audience",
* customPayloads);
*
* // Extracting payload data from a JWT token
* DecodedJWT decodedJWT = tokenResolver.resolve(token);
* T payloadData = decodedJWT.extract(token, T.class);
*
* // Renewing an existing JWT token
* String renewedToken =
* tokenResolver.renew(token, Duration.ofMinutes(30), customPayloads);
* }</pre>
* <p>
* <b>Note:</b>
* It is essential to configure the appropriate algorithms, secret, and issuer
* according to your specific use case when using this resolver.
* Additionally, ensure that the {@code io.jsonwebtoken:jjwt} library is
* correctly configured in your project's dependencies.
*
* @author Zihlu Wang
* @version 1.1.0
* @see Claims
* @see Jws
* @see Jwts
* @see SignatureAlgorithm
* @see Keys
* @since 1.0.0
*/
@Slf4j
public class JjwtTokenResolver implements TokenResolver<Jws<Claims>> {
@@ -67,11 +119,11 @@ public class JjwtTokenResolver implements TokenResolver<Jws<Claims>> {
if (secret.length() <= 32) {
log.error("""
The provided secret which owns {} characters is too weak. Please replace it with a stronger one.
""", secret.length());
The provided secret which owns {} characters is too weak. Please replace it with a stronger one.""",
secret.length());
throw new WeakSecretException("""
The provided secret which owns %s characters is too weak. Please replace it with a stronger one.
""".formatted(secret.length()));
The provided secret which owns %s characters is too weak. Please replace it with a stronger one."""
.formatted(secret.length()));
}
this.jtiCreator = jtiCreator;
@@ -86,12 +138,12 @@ public class JjwtTokenResolver implements TokenResolver<Jws<Claims>> {
}
if (secret.length() <= 32) {
log.error("""
The provided secret which owns {} characters is too weak. Please replace it with a stronger one.
""", secret.length());
throw new WeakSecretException("""
The provided secret which owns %s characters is too weak. Please replace it with a stronger one.
""".formatted(secret.length()));
log.error(
"The provided secret which owns {} characters is too weak. Please replace it with a stronger one.",
secret.length());
throw new WeakSecretException(
"The provided secret which owns %s characters is too weak. Please replace it with a stronger one."
.formatted(secret.length()));
}
this.jtiCreator = UUID::randomUUID;
@@ -106,12 +158,12 @@ public class JjwtTokenResolver implements TokenResolver<Jws<Claims>> {
}
if (secret.length() <= 32) {
log.error("""
The provided secret which owns {} characters is too weak. Please replace it with a stronger one.
""", secret.length());
throw new WeakSecretException("""
The provided secret which owns %s characters is too weak. Please replace it with a stronger one.
""".formatted(secret.length()));
log.error(
"The provided secret which owns {} characters is too weak. Please replace it with a stronger one.",
secret.length());
throw new WeakSecretException(
"The provided secret which owns %s characters is too weak. Please replace it with a stronger one."
.formatted(secret.length()));
}
this.jtiCreator = UUID::randomUUID;
@@ -204,7 +256,7 @@ public class JjwtTokenResolver implements TokenResolver<Jws<Claims>> {
}
/**
* Resolves the given token into a ResolvedTokenType object.
* Resolves the given token into a {@link Jws<Claims>} object.
*
* @param token the token to be resolved
* @return a ResolvedTokenType object
@@ -235,7 +287,7 @@ public class JjwtTokenResolver implements TokenResolver<Jws<Claims>> {
try {
return MapUtil.mapToObject(claims, targetType);
} catch (InvocationTargetException e) {
log.info("An error occurs while invoking the constructor of type {}.", targetType.getCanonicalName());
log.error("An error occurs while invoking the constructor of type {}.", targetType.getCanonicalName());
} catch (NoSuchMethodException e) {
log.error("The constructor of the required type {} is not found.", targetType.getCanonicalName());
} catch (InstantiationException e) {
@@ -17,22 +17,49 @@
package cn.org.codecrafters.simplejwt.jjwt.config;
import cn.org.codecrafters.simplejwt.TokenResolver;
import cn.org.codecrafters.simplejwt.config.TokenResolverConfig;
import cn.org.codecrafters.simplejwt.constants.TokenAlgorithm;
import cn.org.codecrafters.simplejwt.exceptions.UnsupportedAlgorithmException;
import cn.org.codecrafters.simplejwt.jjwt.JjwtTokenResolver;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.HashMap;
import java.util.Map;
/**
* JjwtTokenResolverConfig
* The {@code JjwtTokenResolverConfig} class provides the configuration for the
* {@link JjwtTokenResolver}.
* <p>
* This configuration class is used to establish the mapping between the
* standard {@link TokenAlgorithm} defined within the
* {@code JjwtTokenResolverConfig} and the specific algorithms used by the
* {@code io.jsonwebtoken:jjwt} library, which is the underlying library used
* by {@code JjwtTokenResolver} to handle JSON Web Tokens (JWTs).
* <p>
* <b>Algorithm Mapping:</b>
* The {@code JjwtTokenResolverConfig} allows specifying the relationship
* between the standard {@link TokenAlgorithm} instances supported by {@link
* JjwtTokenResolver} and the corresponding algorithms used by the
* {@code io.jsonwebtoken:jjwt} library. The mapping is achieved using a Map,
* where the keys are the standard {@link TokenAlgorithm} instances, and the
* values represent the algorithm functions used by
* {@code io.jsonwebtoken:jjwt} library for each corresponding key.
* <p>
* <b>Note:</b>
* The provided algorithm mapping should be consistent with the actual
* algorithms supported and used by the {@code io.jsonwebtoken:jjwt} library.
* It is crucial to ensure that the mapping is accurate to enable proper token
* validation and processing within the {@link JjwtTokenResolver}.
*
* @author Zihlu Wang
* @version 1.1.0
* @since 1.0.0
*/
public final class JjwtTokenResolverConfig implements TokenResolverConfig<SignatureAlgorithm> {
private JjwtTokenResolverConfig() {}
private JjwtTokenResolverConfig() {
}
private static final Map<TokenAlgorithm, SignatureAlgorithm> SUPPORTED_ALGORITHMS = new HashMap<>() {{
put(TokenAlgorithm.HS256, SignatureAlgorithm.HS256);
@@ -52,24 +79,25 @@ public final class JjwtTokenResolverConfig implements TokenResolverConfig<Signat
/**
* Gets the algorithm function corresponding to the specified
* TokenAlgorithm.
* {@link TokenAlgorithm}.
* <p>
* This method returns the algorithm function associated with the given
* TokenAlgorithm. The provided TokenAlgorithm represents the specific
* algorithm for which the corresponding algorithm function is required.
* The returned AlgorithmFunction represents the function implementation
* that can be used by the TokenResolver to handle the specific algorithm.
* {@link TokenAlgorithm}. The provided {@link TokenAlgorithm} represents
* the specific algorithm for which the corresponding algorithm function is
* required. The returned algorithm function represents the function
* implementation that can be used by the {@link TokenResolver} to handle
* the specific algorithm.
*
* @param algorithm the TokenAlgorithm for which the algorithm function is
* required
* @return the algorithm function associated with the given TokenAlgorithm
* @param algorithm the {@link TokenAlgorithm} for which the algorithm
* function is required
* @return the algorithm function associated with the given {@link
* TokenAlgorithm}
*/
@Override
public SignatureAlgorithm getAlgorithm(TokenAlgorithm algorithm) {
if (!SUPPORTED_ALGORITHMS.containsKey(algorithm)) {
throw new UnsupportedAlgorithmException("""
The request algorithm is not supported by our system yet. Please change to supported ones.
""");
The request algorithm is not supported by our system yet. Please change to supported ones.""");
}
return SUPPORTED_ALGORITHMS.get(algorithm);
}
@@ -16,17 +16,14 @@
*/
/**
* <p>
* The package {@code cn.org.codecrafters.simplejwt.jjwt.config} contains
* configuration classes related to the {@link
* cn.org.codecrafters.simplejwt.jjwt.JjwtTokenResolver}
* implementation.
*
* <p>
* The classes in this package provide configuration options and settings for
* the {@link cn.org.codecrafters.simplejwt.jjwt.JjwtTokenResolver},
* which is used for resolving JSON Web Tokens (JWT) using the Auth0 library.
*
* <p>
* The {@link
* cn.org.codecrafters.simplejwt.jjwt.config.JjwtTokenResolverConfig}
@@ -37,7 +34,6 @@
* JWT algorithms. It enables developers to specify and customize the
* algorithm functions according to the chosen JWT algorithm and the library
* being used.
*
* <p>
* The configuration options in this package help developers integrate and
* configure the {@link
@@ -45,13 +41,12 @@
* into their Spring Boot applications. Developers can fine-tune the token
* resolution process and customize algorithm handling to align with their
* specific requirements and desired level of security.
*
* <p>
* It is recommended to explore the classes in this package to understand how
* to configure and use the {@link
* cn.org.codecrafters.simplejwt.jjwt.JjwtTokenResolver} effectively
* in the Spring Boot environment to handle JWT authentication and
* authorization securely and efficiently.
* authorisation securely and efficiently.
*
* @since 1.0.0
*/
@@ -19,11 +19,10 @@
* This package contains classes related to the integration of the {@code
* io.jsonwebtoken:jjwt-api} library in the Simple JWT project. {@code
* io.jsonwebtoken:jjwt-api} is a powerful and widely-used Identity as a Service
* (IDaaS) platform that provides secure authentication and authorization
* (IDaaS) platform that provides secure authentication and authorisation
* solutions for web and mobile applications. The classes in this package
* provide the necessary functionality to handle JSON Web Tokens (JWTs) using
* the {@code io.jsonwebtoken:jjwt-api} library.
*
* <p>
* The main class in this package is the {@link
* cn.org.codecrafters.simplejwt.jjwt.JjwtTokenResolver}, which
@@ -33,22 +32,21 @@
* JWTs using the {@code io.jsonwebtoken:jjwt-api} library. Developers can use
* this class as the main token resolver in the Simple JWT project when
* integrating {@code io.jsonwebtoken:jjwt-api} as the JWT management library.
*
* <p>
* The {@code JjwtTokenResolver} relies on the {@code io.jsonwebtoken:jjwt-api}
* The {@link cn.org.codecrafters.simplejwt.jjwt.JjwtTokenResolver} relies on
* the {@code io.jsonwebtoken:jjwt-api}
* library to handle the underlying JWT operations, including token creation,
* validation, and extraction. It utilizes the {@code io.jsonwebtoken:jjwt-api}
* {@code Algorithm} class to define and use different algorithms for JWT
* signing and verification.
*
* {@link io.jsonwebtoken.SignatureAlgorithm} class to define and use different
* algorithms for JWT signing and verification.
* <p>
* To use the {@code JjwtTokenResolver}, developers must provide the necessary
* configurations and dependencies, such as the {@code GuidCreator} for
* generating unique JWT IDs (JTI), the supported algorithm function, the
* issuer name, and the secret key used for token signing and validation. The
* {@code JjwtTokenResolverConfig} class provides a convenient way to configure
* these dependencies.
*
* To use the {@link cn.org.codecrafters.simplejwt.jjwt.JjwtTokenResolver},
* developers must provide the necessary configurations and dependencies, such
* as the {@link cn.org.codecrafters.guid.GuidCreator} for generating unique
* JWT IDs (JTI), the supported algorithm function, the issuer name, and the
* secret key used for token signing and validation. The
* {@link cn.org.codecrafters.simplejwt.jjwt.config.JjwtTokenResolverConfig}
* class provides a convenient way to configure these dependencies.
* <p>
* Developers using the {@code io.jsonwebtoken:jjwt-api} integration should be
* familiar with the concepts and usage of the {@code io.jsonwebtoken:jjwt-api}
+1 -1
View File
@@ -23,7 +23,7 @@
<parent>
<groupId>cn.org.codecrafters</groupId>
<artifactId>jdevkit</artifactId>
<version>1.0.1</version>
<version>1.1.0</version>
</parent>
<artifactId>simple-jwt-spring-boot-starter</artifactId>
@@ -34,26 +34,23 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.DependsOn;
/**
* {@code AuthzeroTokenResolverAutoConfiguration} is responsible for
* automatically configuring the Simple JWT library with
* {@code com.auth0:java-jwt} when used in a Spring Boot application. It
* provides default settings and configurations to ensure that the library
* works smoothly without requiring manual configuration.
* <p>
* SimpleJwtAutoConfiguration is responsible for automatically configuring the
* Simple JWT library with {@code com.auth0:java-jwt} when used in a Spring
* Boot application. It provides default settings and configurations to ensure
* that the library works smoothly without requiring manual configuration.
*
* <p>
* This auto-configuration class sets up the necessary beans and components
* This autoconfiguration class sets up the necessary beans and components
* required for JWT generation and validation. It automatically creates and
* configures the {@link TokenResolver} bean based on the available options and
* properties.
*
* configures the {@link AuthzeroTokenResolver} bean based on the available
* options and properties.
* <p>
* Developers using the Simple JWT library with Spring Boot do not need to
* explicitly configure the library, as the auto-configuration takes care of
* explicitly configure the library, as the autoconfiguration takes care of
* setting up the necessary components and configurations automatically.
* However, developers still have the flexibility to customize the behavior of
* However, developers still have the flexibility to customise the behavior of
* the library by providing their own configurations and properties.
*
*
* @author Zihlu Wang
* @version 1.0.0
* @since 1.0.0
@@ -29,9 +29,11 @@ import org.springframework.context.annotation.Conditional;
import java.util.UUID;
/**
* GuidAutoConfiguration
* Autoconfiguration for injecting a {@link GuidCreator} for generating jwt id.
*
* @author Zihlu Wang
* @version 1.1.0
* @since 1.0.0
*/
@Slf4j
@AutoConfiguration
@@ -34,28 +34,25 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Bean;
/**
* <p>
* JjwtTokenResolverAutoConfiguration is responsible for automatically
* {@code JjwtTokenResolverAutoConfiguration} is responsible for automatically
* configuring the Simple JWT library with {@code io.jsonwebtoken:jjwt-api}
* when used in a Spring Boot application. It provides default settings and
* configurations to ensure that the library works smoothly without requiring
* manual configuration.
*
* <p>
* This auto-configuration class sets up the necessary beans and components
* This autoconfiguration class sets up the necessary beans and components
* required for JWT generation and validation. It automatically creates and
* configures the {@link TokenResolver} bean based on the available options and
* properties.
*
* configures the {@link JjwtTokenResolver} bean based on the available options
* and properties.
* <p>
* Developers using the Simple JWT library with Spring Boot do not need to
* explicitly configure the library, as the auto-configuration takes care of
* explicitly configure the library, as the autoconfiguration takes care of
* setting up the necessary components and configurations automatically.
* However, developers still have the flexibility to customize the behavior of
* the library by providing their own configurations and properties.
*
* @author Zihlu Wang
* @version 1.0.0
* @version 1.1.0
* @since 1.0.0
*/
@Slf4j
@@ -9,11 +9,11 @@ import org.springframework.core.type.AnnotatedTypeMetadata;
import java.util.Objects;
/**
* GuidCreatorCondition
* <p>
* Created on 28 Aug 2023
* The conditions to create bean {@code jtiCreator}.
*
* @author Zihlu Wang
* @version 1.1.0
* @since 1.0.0
*/
@Slf4j
public class GuidCreatorCondition implements Condition {
@@ -24,28 +24,24 @@ import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* <p>
* {@code SimpleJwtProperties} is a configuration properties class used to
* store the properties related to Simple JWT library configuration. These
* store the properties related to Simple JWT library configurations. These
* properties can be configured in the application's properties file (e.g.,
* application.properties) with the prefix "code-crafters.simple-jwt".
*
*
* <p>
* SimpleJwtProperties provides configuration options for the JWT algorithm,
* issuer, and secret. The properties are used by the {@link
* AuthzeroTokenResolverAutoConfiguration}
* class to set up the necessary configurations for JWT generation and
* validation.
*
*
* {@code SimpleJwtProperties} provides configuration options for the JWT
* algorithm, issuer, and secret. The properties are used by the {@link
* AuthzeroTokenResolverAutoConfiguration} and {@link
* cn.org.codecrafters.simplejwt.jjwt.JjwtTokenResolver} to set up the
* necessary configurations for JWT generation and validation.
* <p>
* Developers can customize the JWT algorithm, issuer, and secret by setting
* Developers can customise the JWT algorithm, issuer, and secret by setting
* the corresponding properties in the application's properties file. The
* SimpleJwtAutoConfiguration class reads these properties and uses them to
* create the TokenResolver bean with the desired configuration.
*
* {@code SimpleJwtAutoConfiguration} class reads these properties and uses
* them to create the TokenResolver bean with the desired configuration.
*
* @author Zihlu Wang
* @version 1.1.0
* @since 1.0.0
*/
@Data
@@ -16,15 +16,12 @@
*/
/**
* <p>
* The "cn.org.codecrafters.simplejwt.autoconfiguration.properties" package
* contains configuration properties classes used for Simple JWT library
* auto-configuration. These classes define the properties that can be
* autoconfiguration. These classes define the properties that can be
* configured in the application's properties file (e.g.,
* application.properties) to customize the behavior and settings of the Simple
* JWT library.
*
*
* <p>
* Developers can customize the JWT algorithm, issuer, and secret by setting
* the corresponding properties in the application's properties file with the
+2 -2
View File
@@ -2,12 +2,12 @@
## Introduction
The module `webcal` is a Java library that facilitates the generation and resolution of iCalendar content for web-based calendar applications. It provides a flexible and easy-to-use API for creating web calendars with customizable settings and events.
The module `webcal` is a Java library that facilitates the generation and resolution of iCalendar content for web-based calendar applications. It provides a flexible and easy-to-use API for creating web calendars with customisable settings and events.
### Key features
- Create and manage web calendars with events, including event details such as summary, description, location, and more.
- Define event classifications and categories for better organization and filtering of calendar data.
- Define event classifications and categories for better organisation and filtering of calendar data.
- Set event start and end times, durations, and time zones to handle various scheduling scenarios.
- Configure event priorities and completion percentages for visual representation in the calendar.
- Generate iCalendar format output suitable for web calendar applications.
+1 -1
View File
@@ -23,7 +23,7 @@
<parent>
<groupId>cn.org.codecrafters</groupId>
<artifactId>jdevkit</artifactId>
<version>1.0.1</version>
<version>1.1.0</version>
</parent>
<artifactId>webcal</artifactId>
@@ -21,13 +21,12 @@ import java.util.ArrayList;
import java.util.List;
/**
* The WebCalendar class represents a web calendar in iCalendar format.
*
* {@code WebCalendar} class represents a web calendar in iCalendar format.
* <p>
* It allows users to create and customize calendar components and events and
* generate an iCalendar string containing all the calendar information.
*
* <p>Usage Example:
* It allows users to create and customise calendar components and events and
* generate an <b>iCalendar</b> string containing all the calendar information.
* <p>
* Usage Example:
* <pre>
* WebCalendar calendar = new WebCalendar()
* .setName("My Web Calendar")
@@ -39,20 +38,19 @@ import java.util.List;
* .addEvent(event2);
* String iCalendarString = calendar.resolve();
* </pre>
*
* <p>
* The WebCalendar class is designed to generate an iCalendar string conforming
* to the iCalendar specification, which can be used to share calendar data
* with other calendar applications or services.
* The {@code WebCalendar} class is designed to generate an iCalendar string
* conforming to the iCalendar specification, which can be used to share
* calendar data with other calendar applications or services.
*
* @author Zihlu Wang
* @version 1.0.0
* @version 1.1.0
* @since 1.0.0
*/
public final class WebCalendar {
/**
* The VCALENDAR tag for iCalendar format
* The {@code VCALENDAR} tag for iCalendar format
*/
private final static String TAG = "VCALENDAR";
@@ -63,7 +61,6 @@ public final class WebCalendar {
/**
* The company who produces this calendar.
*
* <p>
* This property will be used in {@code PRODID}.
*/
@@ -71,7 +68,6 @@ public final class WebCalendar {
/**
* The product name.
*
* <p>
* This property will be used in {@code PRODID}
*/
@@ -28,20 +28,19 @@ import java.util.Optional;
import java.util.UUID;
/**
* The WebCalendarEvent class represents an event in the web calendar. It
* extends the abstract class WebCalendarNode and provides additional methods
* to set properties specific to events.
*
* The {@code WebCalendarEvent} class represents an event in the web calendar.
* It extends the abstract class WebCalendarNode and provides additional
* methods to set properties specific to events.
* <p>
* Users can use the methods in this class to add categories, set the
* classification, add comments, descriptions, locations, set percent complete
* , set priority, set summary, set start time, set end time, set duration, set
* URL, set UID, and set timezone for the event. After setting the properties,
* users can call the {@link #resolve()} method to generate the corresponding
* iCalendar content for the event.
* classification, add comments, descriptions, locations, set percent
* complete, set priority, set summary, set start time, set end time, set
* duration, set URL, set UID, and set timezone for the event. After setting
* the properties, users can call the {@link #resolve()} method to generate the
* corresponding iCalendar content for the event.
*
* @author Zihlu Wang
* @version 1.0.0
* @version 1.1.0
* @since 1.0.0
*/
public final class WebCalendarEvent extends WebCalendarNode {
@@ -275,7 +274,7 @@ public final class WebCalendarEvent extends WebCalendarNode {
.map((item) -> "DTEND" + Optional.ofNullable(timezone).map(tz -> ";TZID=" + tz).orElse("") + ":" +
end.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME) + "\n").orElse("") +
Optional.ofNullable(classification)
.map((item) -> "CLASS:" + item.getClassification() + "\n").orElse("") +
.map((item) -> "CLASS:" + item.name() + "\n").orElse("") +
Optional.ofNullable(comment).map((item) -> "COMMENT:" + item + "\n").orElse("") +
Optional.ofNullable(description).map((item) -> "DESCRIPTION:" + item + "\n").orElse("") +
Optional.ofNullable(location).map((item) -> "LOCATION:" + item + "\n").orElse("") +
@@ -25,17 +25,16 @@ import java.util.ArrayList;
import java.util.List;
/**
* The abstract sealed class WebCalendarNode represents a node in the web
* calendar, such as an event, a to-do item, or an alarm. It provides common
* properties and methods for all calendar components and events.
*
* The abstract sealed class {@code WebCalendarNode} represents a node in the
* web calendar, such as an event, a to-do item, or an alarm. It provides
* common properties and methods for all calendar components and events.
* <p>
* Subclasses of WebCalendarNode should implement the {@link #resolve()} method
* to generate the corresponding iCalendar content for the specific calendar
* component or event.
* Subclasses of {@code WebCalendarNode} should implement the {@link
* #resolve()} method to generate the corresponding iCalendar content for the
* specific calendar component or event.
*
* @author Zihlu Wang
* @version 1.0.0
* @version 1.1.0
* @since 1.0.0
*/
public abstract sealed class WebCalendarNode
@@ -20,9 +20,8 @@ package cn.org.codecrafters.webcal.config;
import lombok.Getter;
/**
* The Classification enum represents the classification levels of calendar
* content based on RFC 5545.
*
* The {@code Classification} enum represents the classification levels of
* calendar content based on <b>RFC-5545</b>.
* <p>
* Calendar events or components can be classified as one of the following
* levels:
@@ -42,55 +41,34 @@ import lombok.Getter;
* </ul>
*
* @author Zihlu Wang
* @version 1.0.0
* @version 1.1.0
* @since 1.0.0
*/
@Getter
public enum Classification {
/**
* Public classification level.
*
* <p>
* Indicates that the calendar content is public and can be freely
* distributed.
*/
PUBLIC("PUBLIC"),
PUBLIC,
/**
* Private classification level.
*
* <p>
* Indicates that the calendar content is private and should not be shared
* with others.
*/
PRIVATE("PRIVATE"),
PRIVATE,
/**
* Confidential classification level.
*
* <p>
* Indicates that the calendar content is confidential and should be kept
* strictly private.
*/
CONFIDENTIAL("CONFIDENTIAL"),
CONFIDENTIAL,
;
/**
* -- GETTER --
* Get the string representation of the classification level.
*
* @return the string representation of the classification level
*/
private final String classification;
/**
* Constructor for Classification enum.
*
* @param classification the classification level as a string representation
*/
Classification(String classification) {
this.classification = classification;
}
}
@@ -16,11 +16,10 @@
*/
/**
* The package cn.org.codecrafters.webcal.config contains classes related to
* the configuration and settings of the web calendar module. It provides
* various configurations and constants used in the generation and resolution
* of iCalendar content.
*
* The package {@code cn.org.codecrafters.webcal.config} contains classes
* related to the configuration and settings of the web calendar module. It
* provides various configurations and constants used in the generation and
* resolution of iCalendar content.
* <p>The classes in this package include:</p>
* <ul>
* <li>
@@ -19,13 +19,12 @@
* The package {@code cn.org.codecrafters.webcal} contains classes and modules
* related to web calendar generation and resolution. It provides functionality
* to create and manage iCalendar content for web-based calendar applications.
*
* <p>
* The main classes and modules in this package include:
* <ul>
* <li>
* {@link cn.org.codecrafters.webcal.WebCalendar}: A class for
* generating web calendars with customizable settings and events.
* generating web calendars with customisable settings and events.
* </li>
* <li>
* {@link cn.org.codecrafters.webcal.WebCalendarEvent}: A class