mirror of
https://github.com/TuxCoding/FastLogin.git
synced 2025-07-30 10:47:33 +02:00
Migrate tests to use Junit5
This commit is contained in:
@ -110,7 +110,7 @@ final class EncryptionUtil {
|
|||||||
* in a login session.
|
* in a login session.
|
||||||
*
|
*
|
||||||
* @param random random generator
|
* @param random random generator
|
||||||
* @return an error with 4 bytes long
|
* @return a token with 4 bytes long
|
||||||
*/
|
*/
|
||||||
public static byte[] generateVerifyToken(RandomGenerator random) {
|
public static byte[] generateVerifyToken(RandomGenerator random) {
|
||||||
byte[] token = new byte[VERIFY_TOKEN_LENGTH];
|
byte[] token = new byte[VERIFY_TOKEN_LENGTH];
|
||||||
@ -157,11 +157,11 @@ final class EncryptionUtil {
|
|||||||
return verifier.verify(clientKey.signature());
|
return verifier.verify(clientKey.signature());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean verifyNonce(byte[] exptected, PrivateKey decryptionKey, byte[] encryptedNonce)
|
public static boolean verifyNonce(byte[] expected, PrivateKey decryptionKey, byte[] encryptedNonce)
|
||||||
throws NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException,
|
throws NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException,
|
||||||
BadPaddingException, InvalidKeyException {
|
BadPaddingException, InvalidKeyException {
|
||||||
byte[] decryptedNonce = decrypt(decryptionKey, encryptedNonce);
|
byte[] decryptedNonce = decrypt(decryptionKey, encryptedNonce);
|
||||||
return Arrays.equals(exptected, decryptedNonce);
|
return Arrays.equals(expected, decryptedNonce);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean verifySignedNonce(byte[] nonce, PublicKey clientKey, long signatureSalt, byte[] signature)
|
public static boolean verifySignedNonce(byte[] nonce, PublicKey clientKey, long signatureSalt, byte[] signature)
|
||||||
@ -199,6 +199,7 @@ final class EncryptionUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] getServerIdHash(String sessionId, PublicKey publicKey, SecretKey sharedSecret) {
|
private static byte[] getServerIdHash(String sessionId, PublicKey publicKey, SecretKey sharedSecret) {
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
Hasher hasher = Hashing.sha1().newHasher();
|
Hasher hasher = Hashing.sha1().newHasher();
|
||||||
|
|
||||||
hasher.putBytes(sessionId.getBytes(StandardCharsets.ISO_8859_1));
|
hasher.putBytes(sessionId.getBytes(StandardCharsets.ISO_8859_1));
|
||||||
|
@ -30,23 +30,21 @@ import com.github.games647.fastlogin.core.CommonUtil;
|
|||||||
import net.md_5.bungee.api.chat.TextComponent;
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
import net.md_5.bungee.chat.ComponentSerializer;
|
import net.md_5.bungee.chat.ComponentSerializer;
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
|
||||||
|
|
||||||
public class FastLoginBukkitTest extends TestCase {
|
class FastLoginBukkitTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRGB() {
|
void testRGB() {
|
||||||
var message = "&x00002a00002b&lText";
|
var message = "&x00002a00002b&lText";
|
||||||
var msg = CommonUtil.translateColorCodes(message);
|
var msg = CommonUtil.translateColorCodes(message);
|
||||||
assertThat(msg, is("§x00002a00002b§lText"));
|
assertEquals(msg, "§x00002a00002b§lText");
|
||||||
|
|
||||||
var components = TextComponent.fromLegacyText(msg);
|
var components = TextComponent.fromLegacyText(msg);
|
||||||
var expected = """
|
var expected = """
|
||||||
{"bold":true,"color":"#00a00b","text":"Text"}""";
|
{"bold":true,"color":"#00a00b","text":"Text"}""";
|
||||||
assertThat(ComponentSerializer.toString(components), is(expected));
|
assertEquals(ComponentSerializer.toString(components), expected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,88 +50,77 @@ import javax.crypto.NoSuchPaddingException;
|
|||||||
import javax.crypto.SecretKey;
|
import javax.crypto.SecretKey;
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.ValueSource;
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
import static org.hamcrest.CoreMatchers.not;
|
|
||||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertTrue;
|
class EncryptionUtilTest {
|
||||||
|
|
||||||
public class EncryptionUtilTest {
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testVerifyToken() {
|
void testVerifyToken() {
|
||||||
var random = ThreadLocalRandom.current();
|
var random = ThreadLocalRandom.current();
|
||||||
byte[] token = EncryptionUtil.generateVerifyToken(random);
|
byte[] token = EncryptionUtil.generateVerifyToken(random);
|
||||||
|
|
||||||
assertThat(token, notNullValue());
|
assertAll(
|
||||||
assertThat(token.length, is(4));
|
() -> assertNotNull(token),
|
||||||
|
() -> assertEquals(token.length, 4)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testServerKey() {
|
void testServerKey() {
|
||||||
KeyPair keyPair = EncryptionUtil.generateKeyPair();
|
KeyPair keyPair = EncryptionUtil.generateKeyPair();
|
||||||
|
|
||||||
Key privateKey = keyPair.getPrivate();
|
Key privateKey = keyPair.getPrivate();
|
||||||
assertThat(privateKey.getAlgorithm(), is("RSA"));
|
assertEquals(privateKey.getAlgorithm(), "RSA");
|
||||||
|
|
||||||
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
|
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
|
||||||
assertThat(publicKey.getAlgorithm(), is("RSA"));
|
assertEquals(publicKey.getAlgorithm(), "RSA");
|
||||||
|
|
||||||
// clients accept larger values than the standard vanilla server, but we shouldn't crash them
|
// clients accept larger values than the standard vanilla server, but we shouldn't crash them
|
||||||
assertTrue(publicKey.getModulus().bitLength() >= 1024);
|
assertAll(
|
||||||
assertTrue(publicKey.getModulus().bitLength() < 8192);
|
() -> assertTrue(publicKey.getModulus().bitLength() >= 1024),
|
||||||
|
() -> assertTrue(publicKey.getModulus().bitLength() < 8192)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExpiredClientKey() throws Exception {
|
void testExpiredClientKey() throws Exception {
|
||||||
var clientKey = ResourceLoader.loadClientKey("client_keys/valid_public_key.json");
|
var clientKey = ResourceLoader.loadClientKey("client_keys/valid_public_key.json");
|
||||||
|
|
||||||
// Client expires at the exact second mentioned, so use it for verification
|
// Client expires at the exact second mentioned, so use it for verification
|
||||||
var expiredTimestamp = clientKey.expiry();
|
var expiredTimestamp = clientKey.expiry();
|
||||||
assertThat(EncryptionUtil.verifyClientKey(clientKey, expiredTimestamp), is(false));
|
assertFalse(EncryptionUtil.verifyClientKey(clientKey, expiredTimestamp));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@ParameterizedTest
|
||||||
public void testInvalidChangedExpiration() throws Exception {
|
@ValueSource(strings = {
|
||||||
// expiration date changed should make the signature invalid
|
// expiration date changed should make the signature invalid while still being not expired
|
||||||
// expiration should still be valid
|
"client_keys/invalid_wrong_expiration.json",
|
||||||
var clientKey = ResourceLoader.loadClientKey("client_keys/invalid_wrong_expiration.json");
|
// changed public key no longer corresponding to the signature
|
||||||
|
"client_keys/invalid_wrong_key.json",
|
||||||
|
// signature modified no longer corresponding to key and expiration date
|
||||||
|
"client_keys/invalid_wrong_signature.json"
|
||||||
|
})
|
||||||
|
void testInvalidClientKey(String clientKeySource) throws Exception {
|
||||||
|
var clientKey = ResourceLoader.loadClientKey(clientKeySource);
|
||||||
Instant expireTimestamp = clientKey.expiry().minus(5, ChronoUnit.HOURS);
|
Instant expireTimestamp = clientKey.expiry().minus(5, ChronoUnit.HOURS);
|
||||||
|
|
||||||
assertThat(EncryptionUtil.verifyClientKey(clientKey, expireTimestamp), is(false));
|
assertFalse(EncryptionUtil.verifyClientKey(clientKey, expireTimestamp));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInvalidChangedKey() throws Exception {
|
void testValidClientKey() throws Exception {
|
||||||
// changed public key no longer corresponding to the signature
|
|
||||||
var clientKey = ResourceLoader.loadClientKey("client_keys/invalid_wrong_key.json");
|
|
||||||
Instant expireTimestamp = clientKey.expiry().minus(5, ChronoUnit.HOURS);
|
|
||||||
|
|
||||||
assertThat(EncryptionUtil.verifyClientKey(clientKey, expireTimestamp), is(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testInvalidChangedSignature() throws Exception {
|
|
||||||
// signature modified no longer corresponding to key and expiration date
|
|
||||||
var clientKey = ResourceLoader.loadClientKey("client_keys/invalid_wrong_signature.json");
|
|
||||||
Instant expireTimestamp = clientKey.expiry().minus(5, ChronoUnit.HOURS);
|
|
||||||
|
|
||||||
assertThat(EncryptionUtil.verifyClientKey(clientKey, expireTimestamp), is(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testValidClientKey() throws Exception {
|
|
||||||
var clientKey = ResourceLoader.loadClientKey("client_keys/valid_public_key.json");
|
var clientKey = ResourceLoader.loadClientKey("client_keys/valid_public_key.json");
|
||||||
var verificationTimestamp = clientKey.expiry().minus(5, ChronoUnit.HOURS);
|
var verificationTimestamp = clientKey.expiry().minus(5, ChronoUnit.HOURS);
|
||||||
|
|
||||||
assertThat(EncryptionUtil.verifyClientKey(clientKey, verificationTimestamp), is(true));
|
assertTrue(EncryptionUtil.verifyClientKey(clientKey, verificationTimestamp));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDecryptSharedSecret() throws Exception {
|
void testDecryptSharedSecret() throws Exception {
|
||||||
KeyPair serverPair = EncryptionUtil.generateKeyPair();
|
KeyPair serverPair = EncryptionUtil.generateKeyPair();
|
||||||
var serverPK = serverPair.getPublic();
|
var serverPK = serverPair.getPublic();
|
||||||
|
|
||||||
@ -139,12 +128,12 @@ public class EncryptionUtilTest {
|
|||||||
byte[] encryptedSecret = encrypt(serverPK, secretKey.getEncoded());
|
byte[] encryptedSecret = encrypt(serverPK, secretKey.getEncoded());
|
||||||
|
|
||||||
SecretKey decryptSharedKey = EncryptionUtil.decryptSharedKey(serverPair.getPrivate(), encryptedSecret);
|
SecretKey decryptSharedKey = EncryptionUtil.decryptSharedKey(serverPair.getPrivate(), encryptedSecret);
|
||||||
assertThat(decryptSharedKey, is(secretKey));
|
assertEquals(decryptSharedKey, secretKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] encrypt(PublicKey receiverKey, byte... message)
|
private static byte[] encrypt(PublicKey receiverKey, byte... message)
|
||||||
throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
|
throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
|
||||||
IllegalBlockSizeException, BadPaddingException {
|
IllegalBlockSizeException, BadPaddingException {
|
||||||
var encryptCipher = Cipher.getInstance(receiverKey.getAlgorithm());
|
var encryptCipher = Cipher.getInstance(receiverKey.getAlgorithm());
|
||||||
encryptCipher.init(Cipher.ENCRYPT_MODE, receiverKey);
|
encryptCipher.init(Cipher.ENCRYPT_MODE, receiverKey);
|
||||||
return encryptCipher.doFinal(message);
|
return encryptCipher.doFinal(message);
|
||||||
@ -160,13 +149,13 @@ public class EncryptionUtilTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testServerIdHash() throws Exception {
|
void testServerIdHash() throws Exception {
|
||||||
var serverId = "";
|
var serverId = "";
|
||||||
var sharedSecret = generateSharedKey();
|
var sharedSecret = generateSharedKey();
|
||||||
var serverPK = ResourceLoader.loadClientKey("client_keys/valid_public_key.json").key();
|
var serverPK = ResourceLoader.loadClientKey("client_keys/valid_public_key.json").key();
|
||||||
|
|
||||||
String sessionHash = getServerHash(serverId, sharedSecret, serverPK);
|
String sessionHash = getServerHash(serverId, sharedSecret, serverPK);
|
||||||
assertThat(EncryptionUtil.getServerIdHashString(serverId, sharedSecret, serverPK), is(sessionHash));
|
assertEquals(EncryptionUtil.getServerIdHashString(serverId, sharedSecret, serverPK), sessionHash);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getServerHash(CharSequence serverId, SecretKey sharedSecret, PublicKey serverPK) {
|
private static String getServerHash(CharSequence serverId, SecretKey sharedSecret, PublicKey serverPK) {
|
||||||
@ -183,71 +172,61 @@ public class EncryptionUtilTest {
|
|||||||
hasher.putBytes(serverPK.getEncoded());
|
hasher.putBytes(serverPK.getEncoded());
|
||||||
// It works by treating the sha1 output bytes as one large integer in two's complement and then printing the
|
// It works by treating the sha1 output bytes as one large integer in two's complement and then printing the
|
||||||
// integer in base 16, placing a minus sign if the interpreted number is negative.
|
// integer in base 16, placing a minus sign if the interpreted number is negative.
|
||||||
// reference: https://github.com/SpigotMC/BungeeCord/blob/ff5727c5ef9c0b56ad35f9816ae6bd660b622cf0/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java#L456
|
// reference:
|
||||||
|
// https://github.com/SpigotMC/BungeeCord/blob/ff5727c5ef9c0b56ad35f9816ae6bd660b622cf0/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java#L456
|
||||||
return new BigInteger(hasher.hash().asBytes()).toString(16);
|
return new BigInteger(hasher.hash().asBytes()).toString(16);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testServerIdHashWrongSecret() throws Exception {
|
void testServerIdHashWrongSecret() throws Exception {
|
||||||
var serverId = "";
|
var serverId = "";
|
||||||
var sharedSecret = generateSharedKey();
|
var sharedSecret = generateSharedKey();
|
||||||
var serverPK = ResourceLoader.loadClientKey("client_keys/valid_public_key.json").key();
|
var serverPK = ResourceLoader.loadClientKey("client_keys/valid_public_key.json").key();
|
||||||
|
|
||||||
String sessionHash = getServerHash(serverId, sharedSecret, serverPK);
|
String sessionHash = getServerHash(serverId, sharedSecret, serverPK);
|
||||||
assertThat(EncryptionUtil.getServerIdHashString("", generateSharedKey(), serverPK), not(sessionHash));
|
assertNotEquals(EncryptionUtil.getServerIdHashString("", generateSharedKey(), serverPK), sessionHash);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testServerIdHashWrongServerKey() {
|
void testServerIdHashWrongServerKey() {
|
||||||
var serverId = "";
|
var serverId = "";
|
||||||
var sharedSecret = generateSharedKey();
|
var sharedSecret = generateSharedKey();
|
||||||
var serverPK = EncryptionUtil.generateKeyPair().getPublic();
|
var serverPK = EncryptionUtil.generateKeyPair().getPublic();
|
||||||
|
|
||||||
String sessionHash = getServerHash(serverId, sharedSecret, serverPK);
|
String sessionHash = getServerHash(serverId, sharedSecret, serverPK);
|
||||||
var wrongPK = EncryptionUtil.generateKeyPair().getPublic();
|
var wrongPK = EncryptionUtil.generateKeyPair().getPublic();
|
||||||
assertThat(EncryptionUtil.getServerIdHashString("", sharedSecret, wrongPK), not(sessionHash));
|
assertNotEquals(EncryptionUtil.getServerIdHashString("", sharedSecret, wrongPK), sessionHash);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testValidSignedNonce() throws Exception {
|
void testValidSignedNonce() throws Exception {
|
||||||
ClientPublicKey clientKey = ResourceLoader.loadClientKey("client_keys/valid_public_key.json");
|
ClientPublicKey clientKey = ResourceLoader.loadClientKey("client_keys/valid_public_key.json");
|
||||||
SignatureTestData testData = SignatureTestData.fromResource("signature/valid_signature.json");
|
SignatureTestData testData = SignatureTestData.fromResource("signature/valid_signature.json");
|
||||||
assertThat(verifySignedNonce(testData, clientKey), is(true));
|
assertTrue(verifySignedNonce(testData, clientKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@ParameterizedTest
|
||||||
public void testIncorrectNonce() throws Exception {
|
@ValueSource(strings = {
|
||||||
|
"signature/incorrect_nonce.json",
|
||||||
|
"signature/incorrect_salt.json",
|
||||||
|
"signature/incorrect_signature.json",
|
||||||
|
})
|
||||||
|
void testIncorrectNonce(String signatureSource) throws Exception {
|
||||||
ClientPublicKey clientKey = ResourceLoader.loadClientKey("client_keys/valid_public_key.json");
|
ClientPublicKey clientKey = ResourceLoader.loadClientKey("client_keys/valid_public_key.json");
|
||||||
SignatureTestData testData = SignatureTestData.fromResource("signature/incorrect_nonce.json");
|
SignatureTestData testData = SignatureTestData.fromResource(signatureSource);
|
||||||
assertThat(verifySignedNonce(testData, clientKey), is(false));
|
assertFalse(verifySignedNonce(testData, clientKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIncorrectSalt() throws Exception {
|
void testWrongPublicKeySigned() throws Exception {
|
||||||
// client generated
|
|
||||||
ClientPublicKey clientKey = ResourceLoader.loadClientKey("client_keys/valid_public_key.json");
|
|
||||||
SignatureTestData testData = SignatureTestData.fromResource("signature/incorrect_salt.json");
|
|
||||||
assertThat(verifySignedNonce(testData, clientKey), is(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testIncorrectSignature() throws Exception {
|
|
||||||
// client generated
|
|
||||||
ClientPublicKey clientKey = ResourceLoader.loadClientKey("client_keys/valid_public_key.json");
|
|
||||||
SignatureTestData testData = SignatureTestData.fromResource("signature/incorrect_signature.json");
|
|
||||||
assertThat(verifySignedNonce(testData, clientKey), is(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testWrongPublicKeySigned() throws Exception {
|
|
||||||
// load a different public key
|
// load a different public key
|
||||||
ClientPublicKey clientKey = ResourceLoader.loadClientKey("client_keys/invalid_wrong_key.json");
|
ClientPublicKey clientKey = ResourceLoader.loadClientKey("client_keys/invalid_wrong_key.json");
|
||||||
SignatureTestData testData = SignatureTestData.fromResource("signature/valid_signature.json");
|
SignatureTestData testData = SignatureTestData.fromResource("signature/valid_signature.json");
|
||||||
assertThat(verifySignedNonce(testData, clientKey), is(false));
|
assertFalse(verifySignedNonce(testData, clientKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean verifySignedNonce(SignatureTestData testData, ClientPublicKey clientKey)
|
private static boolean verifySignedNonce(SignatureTestData testData, ClientPublicKey clientKey)
|
||||||
throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
|
throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
|
||||||
PublicKey clientPublicKey = clientKey.key();
|
PublicKey clientPublicKey = clientKey.key();
|
||||||
|
|
||||||
byte[] nonce = testData.getNonce();
|
byte[] nonce = testData.getNonce();
|
||||||
@ -257,41 +236,44 @@ public class EncryptionUtilTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNonce() throws Exception {
|
void testNonce() throws Exception {
|
||||||
byte[] expected = {1, 2, 3, 4};
|
byte[] expected = {1, 2, 3, 4};
|
||||||
var serverKey = EncryptionUtil.generateKeyPair();
|
var serverKey = EncryptionUtil.generateKeyPair();
|
||||||
var encryptedNonce = encrypt(serverKey.getPublic(), expected);
|
var encryptedNonce = encrypt(serverKey.getPublic(), expected);
|
||||||
|
|
||||||
assertThat(EncryptionUtil.verifyNonce(expected, serverKey.getPrivate(), encryptedNonce), is(true));
|
assertTrue(EncryptionUtil.verifyNonce(expected, serverKey.getPrivate(), encryptedNonce));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNonceIncorrect() throws Exception {
|
void testNonceIncorrect() throws Exception {
|
||||||
byte[] expected = {1, 2, 3, 4};
|
byte[] expected = {1, 2, 3, 4};
|
||||||
var serverKey = EncryptionUtil.generateKeyPair();
|
var serverKey = EncryptionUtil.generateKeyPair();
|
||||||
|
|
||||||
// flipped first character
|
// flipped first character
|
||||||
var encryptedNonce = encrypt(serverKey.getPublic(), new byte[]{0, 2, 3 , 4});
|
var encryptedNonce = encrypt(serverKey.getPublic(), new byte[]{0, 2, 3, 4});
|
||||||
|
assertFalse(EncryptionUtil.verifyNonce(expected, serverKey.getPrivate(), encryptedNonce));
|
||||||
assertThat(EncryptionUtil.verifyNonce(expected, serverKey.getPrivate(), encryptedNonce), is(false));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = GeneralSecurityException.class)
|
@Test
|
||||||
public void testNonceFailedDecryption() throws Exception {
|
void testNonceFailedDecryption() throws Exception {
|
||||||
byte[] expected = {1, 2, 3, 4};
|
byte[] expected = {1, 2, 3, 4};
|
||||||
var serverKey = EncryptionUtil.generateKeyPair();
|
var serverKey = EncryptionUtil.generateKeyPair();
|
||||||
// generate a new keypair that iss different
|
// generate a new keypair that is different
|
||||||
var encryptedNonce = encrypt(EncryptionUtil.generateKeyPair().getPublic(), expected);
|
var encryptedNonce = encrypt(EncryptionUtil.generateKeyPair().getPublic(), expected);
|
||||||
|
|
||||||
EncryptionUtil.verifyNonce(expected, serverKey.getPrivate(), encryptedNonce);
|
assertThrows(GeneralSecurityException.class,
|
||||||
|
() -> EncryptionUtil.verifyNonce(expected, serverKey.getPrivate(), encryptedNonce)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = GeneralSecurityException.class)
|
@Test
|
||||||
public void testNonceIncorrectEmpty() throws Exception {
|
void testNonceIncorrectEmpty() {
|
||||||
byte[] expected = {1, 2, 3, 4};
|
byte[] expected = {1, 2, 3, 4};
|
||||||
var serverKey = EncryptionUtil.generateKeyPair();
|
var serverKey = EncryptionUtil.generateKeyPair();
|
||||||
byte[] encryptedNonce = {};
|
byte[] encryptedNonce = {};
|
||||||
|
|
||||||
assertThat(EncryptionUtil.verifyNonce(expected, serverKey.getPrivate(), encryptedNonce), is(false));
|
assertThrows(GeneralSecurityException.class,
|
||||||
|
() -> EncryptionUtil.verifyNonce(expected, serverKey.getPrivate(), encryptedNonce)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,132 +25,80 @@
|
|||||||
*/
|
*/
|
||||||
package com.github.games647.fastlogin.core;
|
package com.github.games647.fastlogin.core;
|
||||||
|
|
||||||
|
import com.github.games647.fastlogin.core.antibot.RateLimiter;
|
||||||
import com.github.games647.fastlogin.core.antibot.TickingRateLimiter;
|
import com.github.games647.fastlogin.core.antibot.TickingRateLimiter;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.ValueSource;
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
public class TickingRateLimiterTest {
|
class TickingRateLimiterTest {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Always expired
|
* Always expired
|
||||||
*/
|
*/
|
||||||
@Test
|
@ParameterizedTest
|
||||||
public void allowExpire() {
|
@ValueSource(longs = {5_000_000L, -5_000_000L})
|
||||||
|
void allowExpire(long initial) {
|
||||||
int size = 3;
|
int size = 3;
|
||||||
|
|
||||||
FakeTicker ticker = new FakeTicker(5_000_000L);
|
FakeTicker ticker = new FakeTicker(initial);
|
||||||
|
|
||||||
// run twice the size to fill it first and then test it
|
// run twice the size to fill it first and then test it
|
||||||
TickingRateLimiter rateLimiter = new TickingRateLimiter(ticker, size, 0);
|
RateLimiter rateLimiter = new TickingRateLimiter(ticker, size, 0);
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
assertThat("Filling up", rateLimiter.tryAcquire(), is(true));
|
assertTrue(rateLimiter.tryAcquire(), "Filling up");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
ticker.add(Duration.ofSeconds(1));
|
ticker.add(Duration.ofSeconds(1));
|
||||||
assertThat("Should be expired", rateLimiter.tryAcquire(), is(true));
|
assertTrue(rateLimiter.tryAcquire(), "Should be expired");
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void allowExpireNegative() {
|
|
||||||
int size = 3;
|
|
||||||
|
|
||||||
FakeTicker ticker = new FakeTicker(-5_000_000L);
|
|
||||||
|
|
||||||
// run twice the size to fill it first and then test it
|
|
||||||
TickingRateLimiter rateLimiter = new TickingRateLimiter(ticker, size, 0);
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
assertThat("Filling up", rateLimiter.tryAcquire(), is(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
ticker.add(Duration.ofSeconds(1));
|
|
||||||
assertThat("Should be expired", rateLimiter.tryAcquire(), is(true));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Too many requests
|
* Too many requests
|
||||||
*/
|
*/
|
||||||
@Test
|
@ParameterizedTest
|
||||||
public void shouldBlock() {
|
@ValueSource(longs = {5_000_000L, -5_000_000L})
|
||||||
|
void shouldBlock(long initial) {
|
||||||
int size = 3;
|
int size = 3;
|
||||||
|
|
||||||
FakeTicker ticker = new FakeTicker(5_000_000L);
|
FakeTicker ticker = new FakeTicker(initial);
|
||||||
|
|
||||||
// fill the size
|
// fill the size
|
||||||
TickingRateLimiter rateLimiter = new TickingRateLimiter(ticker, size, TimeUnit.SECONDS.toMillis(30));
|
RateLimiter rateLimiter = new TickingRateLimiter(ticker, size, TimeUnit.SECONDS.toMillis(30));
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
assertThat("Filling up", rateLimiter.tryAcquire(), is(true));
|
assertTrue(rateLimiter.tryAcquire(), "Filling up");
|
||||||
}
|
}
|
||||||
|
|
||||||
assertThat("Should be full and no entry should be expired", rateLimiter.tryAcquire(), is(false));
|
assertFalse(rateLimiter.tryAcquire(), "Should be full and no entry should be expired");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Too many requests
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void shouldBlockNegative() {
|
|
||||||
int size = 3;
|
|
||||||
|
|
||||||
FakeTicker ticker = new FakeTicker(-5_000_000L);
|
|
||||||
|
|
||||||
// fill the size
|
|
||||||
TickingRateLimiter rateLimiter = new TickingRateLimiter(ticker, size, TimeUnit.SECONDS.toMillis(30));
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
assertThat("Filling up", rateLimiter.tryAcquire(), is(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
assertThat("Should be full and no entry should be expired", rateLimiter.tryAcquire(), is(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Blocked attempts shouldn't replace existing ones.
|
* Blocked attempts shouldn't replace existing ones.
|
||||||
*/
|
*/
|
||||||
@Test
|
@ParameterizedTest
|
||||||
public void blockedNotAdded() {
|
@ValueSource(longs = {5_000_000L, -5_000_000L})
|
||||||
FakeTicker ticker = new FakeTicker(5_000_000L);
|
void blockedNotAdded(long initial) {
|
||||||
|
FakeTicker ticker = new FakeTicker(initial);
|
||||||
|
|
||||||
// fill the size - 100ms should be reasonable high
|
// fill the size - 100ms should be reasonable high
|
||||||
TickingRateLimiter rateLimiter = new TickingRateLimiter(ticker, 1, 100);
|
RateLimiter rateLimiter = new TickingRateLimiter(ticker, 1, 100);
|
||||||
assertThat("Filling up", rateLimiter.tryAcquire(), is(true));
|
assertTrue(rateLimiter.tryAcquire(), "Filling up");
|
||||||
|
|
||||||
ticker.add(Duration.ofMillis(50));
|
ticker.add(Duration.ofMillis(50));
|
||||||
|
|
||||||
// still is full - should fail
|
// still is full - should fail
|
||||||
assertThat("Expired too early", rateLimiter.tryAcquire(), is(false));
|
assertFalse(rateLimiter.tryAcquire(), "Expired too early");
|
||||||
|
|
||||||
// wait the remaining time and add a threshold, because
|
// wait the remaining time and add a threshold, because
|
||||||
ticker.add(Duration.ofMillis(50));
|
ticker.add(Duration.ofMillis(50));
|
||||||
assertThat("Request not released", rateLimiter.tryAcquire(), is(true));
|
assertTrue(rateLimiter.tryAcquire(), "Request not released");
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Blocked attempts shouldn't replace existing ones.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void blockedNotAddedNegative() {
|
|
||||||
FakeTicker ticker = new FakeTicker(-5_000_000L);
|
|
||||||
|
|
||||||
// fill the size - 100ms should be reasonable high
|
|
||||||
TickingRateLimiter rateLimiter = new TickingRateLimiter(ticker, 1, 100);
|
|
||||||
assertThat("Filling up", rateLimiter.tryAcquire(), is(true));
|
|
||||||
|
|
||||||
ticker.add(Duration.ofMillis(50));
|
|
||||||
|
|
||||||
// still is full - should fail
|
|
||||||
assertThat("Expired too early", rateLimiter.tryAcquire(), is(false));
|
|
||||||
|
|
||||||
// wait the remaining time and add a threshold, because
|
|
||||||
ticker.add(Duration.ofMillis(50));
|
|
||||||
assertThat("Request not released", rateLimiter.tryAcquire(), is(true));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
14
pom.xml
14
pom.xml
@ -152,6 +152,14 @@
|
|||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<version>2.22.2</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-failsafe-plugin</artifactId>
|
||||||
|
<version>2.22.2</version>
|
||||||
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
|
|
||||||
<resources>
|
<resources>
|
||||||
@ -176,9 +184,9 @@
|
|||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit-jupiter</artifactId>
|
||||||
<version>4.13.2</version>
|
<version>5.8.2</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
Reference in New Issue
Block a user