diff --git a/jetty-core/jetty-siwe/src/main/java/org/eclipse/jetty/security/siwe/EthereumAuthenticator.java b/jetty-core/jetty-siwe/src/main/java/org/eclipse/jetty/security/siwe/EthereumAuthenticator.java
index 6c70f00b240..e13cbebf1e0 100644
--- a/jetty-core/jetty-siwe/src/main/java/org/eclipse/jetty/security/siwe/EthereumAuthenticator.java
+++ b/jetty-core/jetty-siwe/src/main/java/org/eclipse/jetty/security/siwe/EthereumAuthenticator.java
@@ -44,7 +44,6 @@ import org.eclipse.jetty.security.authentication.LoginAuthenticator;
import org.eclipse.jetty.security.authentication.SessionAuthentication;
import org.eclipse.jetty.security.siwe.internal.AnyUserLoginService;
import org.eclipse.jetty.security.siwe.internal.EthereumUtil;
-import org.eclipse.jetty.security.siwe.internal.SignInWithEthereumParser;
import org.eclipse.jetty.security.siwe.internal.SignInWithEthereumToken;
import org.eclipse.jetty.server.FormFields;
import org.eclipse.jetty.server.Request;
@@ -573,7 +572,7 @@ public class EthereumAuthenticator extends LoginAuthenticator implements Dumpabl
SignedMessage signedMessage = parseMessage(request, response, callback);
if (signedMessage == null)
return AuthenticationState.SEND_FAILURE;
- SignInWithEthereumToken siwe = SignInWithEthereumParser.parse(signedMessage.message());
+ SignInWithEthereumToken siwe = SignInWithEthereumToken.from(signedMessage.message());
if (siwe == null || !validateSignInWithEthereumToken(siwe, signedMessage, request, response, callback))
return AuthenticationState.SEND_FAILURE;
diff --git a/jetty-core/jetty-siwe/src/main/java/org/eclipse/jetty/security/siwe/internal/SignInWithEthereumParser.java b/jetty-core/jetty-siwe/src/main/java/org/eclipse/jetty/security/siwe/internal/SignInWithEthereumParser.java
deleted file mode 100644
index 5db01554590..00000000000
--- a/jetty-core/jetty-siwe/src/main/java/org/eclipse/jetty/security/siwe/internal/SignInWithEthereumParser.java
+++ /dev/null
@@ -1,73 +0,0 @@
-//
-// ========================================================================
-// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
-//
-// This program and the accompanying materials are made available under the
-// terms of the Eclipse Public License v. 2.0 which is available at
-// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
-// which is available at https://www.apache.org/licenses/LICENSE-2.0.
-//
-// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
-// ========================================================================
-//
-
-package org.eclipse.jetty.security.siwe.internal;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Parses a SIWE Message, based off the ABNF Message Format from EIP-4361.
- */
-public class SignInWithEthereumParser
-{
- private static final String SCHEME_PATTERN = "[a-zA-Z][a-zA-Z0-9+\\-.]*";
- private static final String DOMAIN_PATTERN = "(?:[a-zA-Z0-9\\-._~%]+@)?[a-zA-Z0-9\\-._~%]+(?:\\:[0-9]+)?";
- private static final String ADDRESS_PATTERN = "0x[0-9a-fA-F]{40}";
- private static final String STATEMENT_PATTERN = "[^\\n]*";
- private static final String URI_PATTERN = "[^\\n]+";
- private static final String VERSION_PATTERN = "[0-9]+";
- private static final String CHAIN_ID_PATTERN = "[0-9]+";
- private static final String NONCE_PATTERN = "[a-zA-Z0-9]{8}";
- private static final String DATE_TIME_PATTERN = "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?(?:Z|[+-]\\d{2}:\\d{2})?";
- private static final String REQUEST_ID_PATTERN = "[^\\n]*";
- private static final String RESOURCE_PATTERN = "- " + URI_PATTERN;
- private static final String RESOURCES_PATTERN = "(?:\n" + RESOURCE_PATTERN + ")*";
- private static final Pattern SIGN_IN_WITH_ETHEREUM_PATTERN = Pattern.compile(
- "^(?:(?" + SCHEME_PATTERN + ")://)?(?" + DOMAIN_PATTERN + ") wants you to sign in with your Ethereum account:\n" +
- "(?" + ADDRESS_PATTERN + ")\n\n" +
- "(?" + STATEMENT_PATTERN + ")?\n\n" +
- "URI: (?" + URI_PATTERN + ")\n" +
- "Version: (?" + VERSION_PATTERN + ")\n" +
- "Chain ID: (?" + CHAIN_ID_PATTERN + ")\n" +
- "Nonce: (?" + NONCE_PATTERN + ")\n" +
- "Issued At: (?" + DATE_TIME_PATTERN + ")" +
- "(?:\nExpiration Time: (?" + DATE_TIME_PATTERN + "))?" +
- "(?:\nNot Before: (?" + DATE_TIME_PATTERN + "))?" +
- "(?:\nRequest ID: (?" + REQUEST_ID_PATTERN + "))?" +
- "(?:\nResources:(?" + RESOURCES_PATTERN + "))?$",
- Pattern.DOTALL
- );
-
- private SignInWithEthereumParser()
- {
- }
-
- /**
- * Parse a {@link SignInWithEthereumToken} from a {@link String}.
- * @param message the SIWE message to parse.
- * @return the {@link SignInWithEthereumToken} or null if it was not a valid SIWE message.
- */
- public static SignInWithEthereumToken parse(String message)
- {
- Matcher matcher = SIGN_IN_WITH_ETHEREUM_PATTERN.matcher(message);
- if (!matcher.matches())
- return null;
-
- return new SignInWithEthereumToken(matcher.group("scheme"), matcher.group("domain"),
- matcher.group("address"), matcher.group("statement"), matcher.group("uri"),
- matcher.group("version"), matcher.group("chainId"), matcher.group("nonce"),
- matcher.group("issuedAt"), matcher.group("expirationTime"), matcher.group("notBefore"),
- matcher.group("requestId"), matcher.group("resources"));
- }
-}
diff --git a/jetty-core/jetty-siwe/src/main/java/org/eclipse/jetty/security/siwe/internal/SignInWithEthereumToken.java b/jetty-core/jetty-siwe/src/main/java/org/eclipse/jetty/security/siwe/internal/SignInWithEthereumToken.java
index ea8ecdfe6e5..a4e2a2780e1 100644
--- a/jetty-core/jetty-siwe/src/main/java/org/eclipse/jetty/security/siwe/internal/SignInWithEthereumToken.java
+++ b/jetty-core/jetty-siwe/src/main/java/org/eclipse/jetty/security/siwe/internal/SignInWithEthereumToken.java
@@ -16,6 +16,8 @@ package org.eclipse.jetty.security.siwe.internal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.function.Predicate;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import org.eclipse.jetty.security.ServerAuthException;
import org.eclipse.jetty.security.siwe.EthereumAuthenticator;
@@ -52,6 +54,52 @@ public record SignInWithEthereumToken(String scheme,
String requestId,
String resources)
{
+ private static final String SCHEME_PATTERN = "[a-zA-Z][a-zA-Z0-9+\\-.]*";
+ private static final String DOMAIN_PATTERN = "(?:[a-zA-Z0-9\\-._~%]+@)?[a-zA-Z0-9\\-._~%]+(?:\\:[0-9]+)?";
+ private static final String ADDRESS_PATTERN = "0x[0-9a-fA-F]{40}";
+ private static final String STATEMENT_PATTERN = "[^\\n]*";
+ private static final String URI_PATTERN = "[^\\n]+";
+ private static final String VERSION_PATTERN = "[0-9]+";
+ private static final String CHAIN_ID_PATTERN = "[0-9]+";
+ private static final String NONCE_PATTERN = "[a-zA-Z0-9]{8}";
+ private static final String DATE_TIME_PATTERN = "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?(?:Z|[+-]\\d{2}:\\d{2})?";
+ private static final String REQUEST_ID_PATTERN = "[^\\n]*";
+ private static final String RESOURCE_PATTERN = "- " + URI_PATTERN;
+ private static final String RESOURCES_PATTERN = "(?:\n" + RESOURCE_PATTERN + ")*";
+ private static final Pattern SIGN_IN_WITH_ETHEREUM_PATTERN = Pattern.compile(
+ "^(?:(?" + SCHEME_PATTERN + ")://)?(?" + DOMAIN_PATTERN + ") wants you to sign in with your Ethereum account:\n" +
+ "(?" + ADDRESS_PATTERN + ")\n\n" +
+ "(?" + STATEMENT_PATTERN + ")?\n\n" +
+ "URI: (?" + URI_PATTERN + ")\n" +
+ "Version: (?" + VERSION_PATTERN + ")\n" +
+ "Chain ID: (?" + CHAIN_ID_PATTERN + ")\n" +
+ "Nonce: (?" + NONCE_PATTERN + ")\n" +
+ "Issued At: (?" + DATE_TIME_PATTERN + ")" +
+ "(?:\nExpiration Time: (?" + DATE_TIME_PATTERN + "))?" +
+ "(?:\nNot Before: (?" + DATE_TIME_PATTERN + "))?" +
+ "(?:\nRequest ID: (?" + REQUEST_ID_PATTERN + "))?" +
+ "(?:\nResources:(?" + RESOURCES_PATTERN + "))?$",
+ Pattern.DOTALL
+ );
+
+ /**
+ * Parses a SIWE Message into a {@link SignInWithEthereumToken},
+ * based off the ABNF Message Format from EIP-4361.
+ * @param message the SIWE message to parse.
+ * @return the {@link SignInWithEthereumToken} or null if it was not a valid SIWE message.
+ */
+ public static SignInWithEthereumToken from(String message)
+ {
+ Matcher matcher = SIGN_IN_WITH_ETHEREUM_PATTERN.matcher(message);
+ if (!matcher.matches())
+ return null;
+
+ return new SignInWithEthereumToken(matcher.group("scheme"), matcher.group("domain"),
+ matcher.group("address"), matcher.group("statement"), matcher.group("uri"),
+ matcher.group("version"), matcher.group("chainId"), matcher.group("nonce"),
+ matcher.group("issuedAt"), matcher.group("expirationTime"), matcher.group("notBefore"),
+ matcher.group("requestId"), matcher.group("resources"));
+ }
/**
* @param signedMessage the {@link EthereumAuthenticator.SignedMessage}.
diff --git a/jetty-core/jetty-siwe/src/test/java/org/eclipse/jetty/security/siwe/SignInWithEthereumParserTest.java b/jetty-core/jetty-siwe/src/test/java/org/eclipse/jetty/security/siwe/SignInWithEthereumParserTest.java
index 63fb1152d1b..1b24651f642 100644
--- a/jetty-core/jetty-siwe/src/test/java/org/eclipse/jetty/security/siwe/SignInWithEthereumParserTest.java
+++ b/jetty-core/jetty-siwe/src/test/java/org/eclipse/jetty/security/siwe/SignInWithEthereumParserTest.java
@@ -20,7 +20,6 @@ import java.util.List;
import java.util.stream.Stream;
import org.eclipse.jetty.security.siwe.internal.EthereumUtil;
-import org.eclipse.jetty.security.siwe.internal.SignInWithEthereumParser;
import org.eclipse.jetty.security.siwe.internal.SignInWithEthereumToken;
import org.eclipse.jetty.security.siwe.util.SignInWithEthereumGenerator;
import org.junit.jupiter.api.Test;
@@ -97,7 +96,7 @@ public class SignInWithEthereumParserTest
@MethodSource("specExamples")
public void testSpecExamples(String message, String scheme, String domain)
{
- SignInWithEthereumToken siwe = SignInWithEthereumParser.parse(message);
+ SignInWithEthereumToken siwe = SignInWithEthereumToken.from(message);
assertNotNull(siwe);
assertThat(siwe.address(), equalTo("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"));
assertThat(siwe.issuedAt(), equalTo("2021-09-30T16:25:24Z"));
@@ -139,7 +138,7 @@ public class SignInWithEthereumParserTest
String message = SignInWithEthereumGenerator.generateMessage(scheme, domain, address, statement, uri, version, chainId, nonce, issuedAt,
expirationTime, notBefore, requestId, resources);
- SignInWithEthereumToken siwe = SignInWithEthereumParser.parse(message);
+ SignInWithEthereumToken siwe = SignInWithEthereumToken.from(message);
assertNotNull(siwe);
assertThat(siwe.scheme(), equalTo(scheme));
assertThat(siwe.domain(), equalTo(domain));
diff --git a/jetty-core/jetty-siwe/src/test/java/org/eclipse/jetty/security/siwe/SignInWithEthereumTokenTest.java b/jetty-core/jetty-siwe/src/test/java/org/eclipse/jetty/security/siwe/SignInWithEthereumTokenTest.java
index e7b7511466d..a04a6d5b3c6 100644
--- a/jetty-core/jetty-siwe/src/test/java/org/eclipse/jetty/security/siwe/SignInWithEthereumTokenTest.java
+++ b/jetty-core/jetty-siwe/src/test/java/org/eclipse/jetty/security/siwe/SignInWithEthereumTokenTest.java
@@ -17,7 +17,6 @@ import java.time.LocalDateTime;
import java.util.function.Predicate;
import org.eclipse.jetty.security.siwe.internal.EthereumUtil;
-import org.eclipse.jetty.security.siwe.internal.SignInWithEthereumParser;
import org.eclipse.jetty.security.siwe.internal.SignInWithEthereumToken;
import org.eclipse.jetty.security.siwe.util.EthereumCredentials;
import org.eclipse.jetty.security.siwe.util.SignInWithEthereumGenerator;
@@ -51,7 +50,7 @@ public class SignInWithEthereumTokenTest
);
EthereumAuthenticator.SignedMessage signedMessage = credentials.signMessage(message);
- SignInWithEthereumToken siwe = SignInWithEthereumParser.parse(message);
+ SignInWithEthereumToken siwe = SignInWithEthereumToken.from(message);
assertNotNull(siwe);
Throwable error = assertThrows(Throwable.class, () ->
@@ -80,7 +79,7 @@ public class SignInWithEthereumTokenTest
);
EthereumAuthenticator.SignedMessage signedMessage = credentials.signMessage(message);
- SignInWithEthereumToken siwe = SignInWithEthereumParser.parse(message);
+ SignInWithEthereumToken siwe = SignInWithEthereumToken.from(message);
assertNotNull(siwe);
Throwable error = assertThrows(Throwable.class, () ->
@@ -110,7 +109,7 @@ public class SignInWithEthereumTokenTest
);
EthereumAuthenticator.SignedMessage signedMessage = credentials.signMessage(message);
- SignInWithEthereumToken siwe = SignInWithEthereumParser.parse(message);
+ SignInWithEthereumToken siwe = SignInWithEthereumToken.from(message);
assertNotNull(siwe);
Throwable error = assertThrows(Throwable.class, () ->
@@ -137,7 +136,7 @@ public class SignInWithEthereumTokenTest
);
EthereumAuthenticator.SignedMessage signedMessage = credentials.signMessage(message);
- SignInWithEthereumToken siwe = SignInWithEthereumParser.parse(message);
+ SignInWithEthereumToken siwe = SignInWithEthereumToken.from(message);
assertNotNull(siwe);
IncludeExcludeSet domains = new IncludeExcludeSet<>();
@@ -167,7 +166,7 @@ public class SignInWithEthereumTokenTest
);
EthereumAuthenticator.SignedMessage signedMessage = credentials.signMessage(message);
- SignInWithEthereumToken siwe = SignInWithEthereumParser.parse(message);
+ SignInWithEthereumToken siwe = SignInWithEthereumToken.from(message);
assertNotNull(siwe);
IncludeExcludeSet chainIds = new IncludeExcludeSet<>();
@@ -197,7 +196,7 @@ public class SignInWithEthereumTokenTest
);
EthereumAuthenticator.SignedMessage signedMessage = credentials.signMessage(message);
- SignInWithEthereumToken siwe = SignInWithEthereumParser.parse(message);
+ SignInWithEthereumToken siwe = SignInWithEthereumToken.from(message);
assertNotNull(siwe);
Predicate nonceValidation = nonce -> false;
@@ -225,7 +224,7 @@ public class SignInWithEthereumTokenTest
);
EthereumAuthenticator.SignedMessage signedMessage = credentials.signMessage(message);
- SignInWithEthereumToken siwe = SignInWithEthereumParser.parse(message);
+ SignInWithEthereumToken siwe = SignInWithEthereumToken.from(message);
assertNotNull(siwe);
Predicate nonceValidation = nonce -> true;