From 21f8ba8ccfe3b05cc7e66fc38c9a8d7d530de669 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Tue, 29 Nov 2022 14:21:44 +0100 Subject: [PATCH 1/8] Add support for different regex parsers --- hsregex/build.gradle | 28 ++++ .../algorithm/HSRegexInterpreterFactory.java | 33 +++++ .../pgpainless/algorithm/package-info.java | 10 ++ pgpainless-core/build.gradle | 3 + .../java/org/pgpainless/algorithm/Regex.java | 28 ++++ .../algorithm/RegexInterpreterFactory.java | 46 +++++++ .../org/pgpainless/algorithm/RegexTest.java | 120 ++++++++++++++++++ settings.gradle | 3 +- 8 files changed, 270 insertions(+), 1 deletion(-) create mode 100644 hsregex/build.gradle create mode 100644 hsregex/src/main/java/org/pgpainless/algorithm/HSRegexInterpreterFactory.java create mode 100644 hsregex/src/main/java/org/pgpainless/algorithm/package-info.java create mode 100644 pgpainless-core/src/main/java/org/pgpainless/algorithm/Regex.java create mode 100644 pgpainless-core/src/main/java/org/pgpainless/algorithm/RegexInterpreterFactory.java create mode 100644 pgpainless-core/src/test/java/org/pgpainless/algorithm/RegexTest.java diff --git a/hsregex/build.gradle b/hsregex/build.gradle new file mode 100644 index 00000000..d8953b40 --- /dev/null +++ b/hsregex/build.gradle @@ -0,0 +1,28 @@ +// SPDX-FileCopyrightText: 2021 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +plugins { + id 'java-library' +} + +group 'org.pgpainless' + +repositories { + mavenCentral() + mavenLocal() +} + +dependencies { + testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion" + testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitVersion" + + implementation(project(":pgpainless-core")) + + // Henry Spencers Regular Expression (RegEx packets) + implementation 'com.basistech.tclre:tcl-regex:0.14.5' +} + +test { + useJUnitPlatform() +} diff --git a/hsregex/src/main/java/org/pgpainless/algorithm/HSRegexInterpreterFactory.java b/hsregex/src/main/java/org/pgpainless/algorithm/HSRegexInterpreterFactory.java new file mode 100644 index 00000000..8d8a3068 --- /dev/null +++ b/hsregex/src/main/java/org/pgpainless/algorithm/HSRegexInterpreterFactory.java @@ -0,0 +1,33 @@ +// SPDX-FileCopyrightText: 2022 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package org.pgpainless.algorithm; + +import com.basistech.tclre.HsrePattern; +import com.basistech.tclre.PatternFlags; +import com.basistech.tclre.RePattern; +import com.basistech.tclre.RegexException; + +public class HSRegexInterpreterFactory extends RegexInterpreterFactory { + + public Regex instantiate(String regex) { + return new Regex() { + + private final RePattern pattern; + + { + try { + pattern = HsrePattern.compile(regex, PatternFlags.ADVANCED); + } catch (RegexException e) { + throw new IllegalArgumentException(e); + } + } + + @Override + public boolean matches(String string) { + return pattern.matcher(string).find(); + } + }; + } +} diff --git a/hsregex/src/main/java/org/pgpainless/algorithm/package-info.java b/hsregex/src/main/java/org/pgpainless/algorithm/package-info.java new file mode 100644 index 00000000..5dc78706 --- /dev/null +++ b/hsregex/src/main/java/org/pgpainless/algorithm/package-info.java @@ -0,0 +1,10 @@ +// SPDX-FileCopyrightText: 2022 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +/** + * Regex interpreter implementation based on Henry Spencers Regular Expression library. + * + * @see RFC4880 - §8. Regular Expressions + */ +package org.pgpainless.algorithm; diff --git a/pgpainless-core/build.gradle b/pgpainless-core/build.gradle index 84b4273f..c6886f36 100644 --- a/pgpainless-core/build.gradle +++ b/pgpainless-core/build.gradle @@ -30,4 +30,7 @@ dependencies { // @Nullable, @Nonnull annotations implementation "com.google.code.findbugs:jsr305:3.0.2" + + // HSRE regex for tests + testImplementation project(":hsregex") } diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/Regex.java b/pgpainless-core/src/main/java/org/pgpainless/algorithm/Regex.java new file mode 100644 index 00000000..5e23874b --- /dev/null +++ b/pgpainless-core/src/main/java/org/pgpainless/algorithm/Regex.java @@ -0,0 +1,28 @@ +// SPDX-FileCopyrightText: 2022 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package org.pgpainless.algorithm; + +import org.pgpainless.key.util.UserId; + +public interface Regex { + + /** + * Return true, if the regex matches the given user-id. + * + * @param userId userId + * @return true if matches, false otherwise + */ + default boolean matches(UserId userId) { + return matches(userId.toString()); + } + + /** + * Return true, if the regex matches the given string. + * + * @param string string + * @return true if matches, false otherwise + */ + boolean matches(String string); +} diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/RegexInterpreterFactory.java b/pgpainless-core/src/main/java/org/pgpainless/algorithm/RegexInterpreterFactory.java new file mode 100644 index 00000000..266a245c --- /dev/null +++ b/pgpainless-core/src/main/java/org/pgpainless/algorithm/RegexInterpreterFactory.java @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: 2022 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package org.pgpainless.algorithm; + +import javax.annotation.Nonnull; +import java.util.regex.Pattern; + +public abstract class RegexInterpreterFactory { + + private static RegexInterpreterFactory INSTANCE; + + public static RegexInterpreterFactory getInstance() { + if (INSTANCE == null) { + INSTANCE = new JavaRegexInterpreterFactory(); + } + return INSTANCE; + } + + public static void setInstance(@Nonnull RegexInterpreterFactory instance) { + INSTANCE = instance; + } + + public static Regex create(String regex) { + return getInstance().instantiate(regex); + } + + public abstract Regex instantiate(String regex) throws IllegalArgumentException; + + public static class JavaRegexInterpreterFactory extends RegexInterpreterFactory { + + @Override + public Regex instantiate(String regex) { + return new Regex() { + + private final Pattern pattern = Pattern.compile(regex); + + @Override + public boolean matches(String string) { + return pattern.matcher(string).find(); + } + }; + } + } +} diff --git a/pgpainless-core/src/test/java/org/pgpainless/algorithm/RegexTest.java b/pgpainless-core/src/test/java/org/pgpainless/algorithm/RegexTest.java new file mode 100644 index 00000000..0eafec9d --- /dev/null +++ b/pgpainless-core/src/test/java/org/pgpainless/algorithm/RegexTest.java @@ -0,0 +1,120 @@ +// SPDX-FileCopyrightText: 2022 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package org.pgpainless.algorithm; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.stream.Stream; + +import org.junit.jupiter.api.Named; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.pgpainless.key.util.UserId; + +public class RegexTest { + private static Stream provideRegexInterpreterFactories() { + return Stream.of( + Arguments.of(Named.of("Default JavaRegexInterpreterFactory", + new RegexInterpreterFactory.JavaRegexInterpreterFactory())), + Arguments.of(Named.of("HSRegexInterpreterFactory", + new HSRegexInterpreterFactory())) + ); + } + + @ParameterizedTest + @MethodSource("provideRegexInterpreterFactories") + public void simpleTest(RegexInterpreterFactory factory) { + Regex regex = factory.instantiate("Alice|Bob"); + assertTrue(regex.matches("Alice")); + assertTrue(regex.matches("Bob")); + assertFalse(regex.matches("Charlie")); + } + + @ParameterizedTest + @MethodSource("provideRegexInterpreterFactories") + public void testEmailRegexMatchesDomain(RegexInterpreterFactory factory) { + Regex regex = factory.instantiate("<[^>]+[@.]pgpainless\\.org>$"); + assertTrue(regex.matches("Alice ")); + assertTrue(regex.matches("Bob ")); + assertFalse(regex.matches("Alice "), "wrong domain"); + assertFalse(regex.matches("Bob "), "wrong domain"); + } + + @ParameterizedTest + @MethodSource("provideRegexInterpreterFactories") + public void testEmailRegexMatchesOnlyWrappedAddresses(RegexInterpreterFactory factory) { + Regex regex = factory.instantiate("<[^>]+[@.]pgpainless\\.org>$"); + assertTrue(regex.matches("")); + assertFalse(regex.matches("alice@pgpainless.org"), "only match mails in <>"); + } + + @ParameterizedTest + @MethodSource("provideRegexInterpreterFactories") + public void testCaseSensitivity(RegexInterpreterFactory factory) { + Regex regex = factory.instantiate("<[^>]+[@.]pgpainless\\.org>$"); + assertFalse(regex.matches("Alice ")); + } + + @ParameterizedTest + @MethodSource("provideRegexInterpreterFactories") + public void testWildCard(RegexInterpreterFactory factory) { + Regex regex = factory.instantiate(".*"); + assertTrue(regex.matches("")); + assertTrue(regex.matches("Alice")); + assertTrue(regex.matches("")); + } + + @ParameterizedTest + @MethodSource("provideRegexInterpreterFactories") + public void testExclusion(RegexInterpreterFactory factory) { + // Test [^>] matches all but '>' + Regex regex = factory.instantiate("<[^>]+[@.]pgpainless\\.org>$"); + assertFalse(regex.matches("appendix@pgpainless.org>")); + assertFalse(regex.matches("<>alice@pgpainless.org>")); + } + + @ParameterizedTest + @MethodSource("provideRegexInterpreterFactories") + public void testOnlyMatchAtTheEnd(RegexInterpreterFactory factory) { + Regex regex = factory.instantiate("<[^>]+[@.]pgpainless\\.org>$"); + assertFalse(regex.matches("Alice ")); + } + + @ParameterizedTest + @MethodSource("provideRegexInterpreterFactories") + public void testRanges(RegexInterpreterFactory factory) { + Regex regex = factory.instantiate("<[^>]+[0-9][@.]pgpainless\\.org>$"); + + for (int i = 0; i < 10; i++) { + String mail = ""; + assertTrue(regex.matches(mail)); + } + + assertFalse(regex.matches("")); + } + + @ParameterizedTest + @MethodSource("provideRegexInterpreterFactories") + public void testExactMailMatch(RegexInterpreterFactory factory) { + Regex exactMail = factory.instantiate("$"); + assertTrue(exactMail.matches("")); + assertTrue(exactMail.matches("Exact Match ")); + assertFalse(exactMail.matches("")); + } + + @ParameterizedTest + @MethodSource("provideRegexInterpreterFactories") + public void testSetInstance(RegexInterpreterFactory factory) { + RegexInterpreterFactory before = RegexInterpreterFactory.getInstance(); + RegexInterpreterFactory.setInstance(factory); + + Regex regex = RegexInterpreterFactory.create("<[^>]+[@.]pgpainless\\.org>$"); + assertTrue(regex.matches(UserId.nameAndEmail("Alice", "alice@pgpainless.org"))); + + RegexInterpreterFactory.setInstance(before); + } +} diff --git a/settings.gradle b/settings.gradle index aea19392..9fe2061a 100644 --- a/settings.gradle +++ b/settings.gradle @@ -6,5 +6,6 @@ rootProject.name = 'PGPainless' include 'pgpainless-core', 'pgpainless-sop', - 'pgpainless-cli' + 'pgpainless-cli', + 'hsregex' From 766af27b0241865ec9d0f7b36b7c0ac586171206 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Wed, 30 Nov 2022 15:42:08 +0100 Subject: [PATCH 2/8] Add dummy tests for hsregex module to fix jacoco --- .../HSRegexInterpreterFactoryTest.java | 24 +++++++++++++++++++ .../pgpainless/algorithm/package-info.java | 10 ++++++++ 2 files changed, 34 insertions(+) create mode 100644 hsregex/src/test/java/org/pgpainless/algorithm/HSRegexInterpreterFactoryTest.java create mode 100644 hsregex/src/test/java/org/pgpainless/algorithm/package-info.java diff --git a/hsregex/src/test/java/org/pgpainless/algorithm/HSRegexInterpreterFactoryTest.java b/hsregex/src/test/java/org/pgpainless/algorithm/HSRegexInterpreterFactoryTest.java new file mode 100644 index 00000000..e203a8dc --- /dev/null +++ b/hsregex/src/test/java/org/pgpainless/algorithm/HSRegexInterpreterFactoryTest.java @@ -0,0 +1,24 @@ +// SPDX-FileCopyrightText: 2022 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package org.pgpainless.algorithm; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class HSRegexInterpreterFactoryTest { + + @Test + public void dummyRegexTest() { + HSRegexInterpreterFactory factory = new HSRegexInterpreterFactory(); + RegexInterpreterFactory.setInstance(factory); + Regex regex = RegexInterpreterFactory.create("Alice|Bob"); + + assertTrue(regex.matches("Alice")); + assertTrue(regex.matches("Bob")); + assertFalse(regex.matches("Charlie")); + } +} diff --git a/hsregex/src/test/java/org/pgpainless/algorithm/package-info.java b/hsregex/src/test/java/org/pgpainless/algorithm/package-info.java new file mode 100644 index 00000000..5dc78706 --- /dev/null +++ b/hsregex/src/test/java/org/pgpainless/algorithm/package-info.java @@ -0,0 +1,10 @@ +// SPDX-FileCopyrightText: 2022 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +/** + * Regex interpreter implementation based on Henry Spencers Regular Expression library. + * + * @see RFC4880 - §8. Regular Expressions + */ +package org.pgpainless.algorithm; From 8169db4bbdc87c999f716869e38dc609a684f8cf Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Wed, 30 Nov 2022 15:58:38 +0100 Subject: [PATCH 3/8] Add test for invalid regex --- .../src/test/java/org/pgpainless/algorithm/RegexTest.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pgpainless-core/src/test/java/org/pgpainless/algorithm/RegexTest.java b/pgpainless-core/src/test/java/org/pgpainless/algorithm/RegexTest.java index 0eafec9d..f1692569 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/algorithm/RegexTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/algorithm/RegexTest.java @@ -5,6 +5,7 @@ package org.pgpainless.algorithm; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.stream.Stream; @@ -117,4 +118,10 @@ public class RegexTest { RegexInterpreterFactory.setInstance(before); } + + @ParameterizedTest + @MethodSource("provideRegexInterpreterFactories") + public void testInvalidRegex(RegexInterpreterFactory factory) { + assertThrows(IllegalArgumentException.class, () -> factory.instantiate("[ab")); + } } From 77c669d2894875e4a1c95c6985875a37cca918d0 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Wed, 30 Nov 2022 17:01:21 +0100 Subject: [PATCH 4/8] Add README for hsregex module --- hsregex/README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 hsregex/README.md diff --git a/hsregex/README.md b/hsregex/README.md new file mode 100644 index 00000000..ad5fcddc --- /dev/null +++ b/hsregex/README.md @@ -0,0 +1,18 @@ + + +# Evaluate Regular Expressions in OpenPGP Signatures using TCL-Regex + +RFC4880 specifies contains a section about RegularExpression subpackets on signatures. +Within this section, the syntax of the RegularExpression subpackets is defined to be the same as Henry Spencer's "almost public domain" regular expression package. + +Since Java's `java.util.regex` syntax is too powerful, this module exists to implement regex evaluation using [tcl-regex](https://github.com/basis-technology-corp/tcl-regex-java) +which appears to be a Java port of Henry Spencers regex package. + +To make use of this implementation, simply call +```java +RegexInterpreterFactory.setInstance(new HSRegexInterpreterFactory()); +``` From fffb4b17a402f0a5222b76af9633a4ea3eef0877 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 1 Dec 2022 15:19:57 +0100 Subject: [PATCH 5/8] Add RegexInterpreterFactory.createDefaultMailDomainRegex() --- .../algorithm/RegexInterpreterFactory.java | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/RegexInterpreterFactory.java b/pgpainless-core/src/main/java/org/pgpainless/algorithm/RegexInterpreterFactory.java index 266a245c..426b6c49 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/algorithm/RegexInterpreterFactory.java +++ b/pgpainless-core/src/main/java/org/pgpainless/algorithm/RegexInterpreterFactory.java @@ -4,8 +4,8 @@ package org.pgpainless.algorithm; -import javax.annotation.Nonnull; import java.util.regex.Pattern; +import javax.annotation.Nonnull; public abstract class RegexInterpreterFactory { @@ -26,6 +26,32 @@ public abstract class RegexInterpreterFactory { return getInstance().instantiate(regex); } + /** + * Regex that matches any mail address on the given mail server. + * For example, calling this method with parameter
pgpainless.org
will return a regex + * that matches any of the following user ids: + *
+     *     Alice 
+     *     
+     *     Issuer (code signing) 
+     * 
+ * It will however not match the following mail addresses: + *
+     *     Alice 
+     *     alice@pgpainless.org
+     *     alice@pgpainless.org 
+     *     Bob 
+     * 
+ * Note: This method will not validate the given domain string, so that is your responsibility! + * + * @param mailDomain domain + * @return regex matching the domain + */ + public static Regex createDefaultMailDomainRegex(String mailDomain) { + String escaped = mailDomain.replace(".", "\\."); + return create("<[^>]+[@.]" + escaped + ">$"); + } + public abstract Regex instantiate(String regex) throws IllegalArgumentException; public static class JavaRegexInterpreterFactory extends RegexInterpreterFactory { From 15142b57751ee058d9a9db5bfcc3a15408c2290c Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 1 Dec 2022 15:20:36 +0100 Subject: [PATCH 6/8] Add Regex.wildcard() factory method --- .../src/main/java/org/pgpainless/algorithm/Regex.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/Regex.java b/pgpainless-core/src/main/java/org/pgpainless/algorithm/Regex.java index 5e23874b..f28bca75 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/algorithm/Regex.java +++ b/pgpainless-core/src/main/java/org/pgpainless/algorithm/Regex.java @@ -25,4 +25,13 @@ public interface Regex { * @return true if matches, false otherwise */ boolean matches(String string); + + static Regex wildcard() { + return new Regex() { + @Override + public boolean matches(String string) { + return true; + } + }; + } } From f62a6a30ffc7779fc396995bc138744adcbd469e Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 1 Dec 2022 15:21:00 +0100 Subject: [PATCH 7/8] Implement RegexSet to validate a single user-id against multiple wildcards --- .../org/pgpainless/algorithm/RegexSet.java | 40 +++++++++++++++ .../pgpainless/algorithm/RegexSetTest.java | 51 +++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 pgpainless-core/src/main/java/org/pgpainless/algorithm/RegexSet.java create mode 100644 pgpainless-core/src/test/java/org/pgpainless/algorithm/RegexSetTest.java diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/RegexSet.java b/pgpainless-core/src/main/java/org/pgpainless/algorithm/RegexSet.java new file mode 100644 index 00000000..e4639e03 --- /dev/null +++ b/pgpainless-core/src/main/java/org/pgpainless/algorithm/RegexSet.java @@ -0,0 +1,40 @@ +// SPDX-FileCopyrightText: 2022 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package org.pgpainless.algorithm; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +public final class RegexSet { + + private final Set regexSet = new HashSet<>(); + + private RegexSet(Collection regexes) { + this.regexSet.addAll(regexes); + } + + public static RegexSet matchAnything() { + return new RegexSet(Collections.singleton(Regex.wildcard())); + } + + public static RegexSet matchNothing() { + return new RegexSet(Collections.emptySet()); + } + + public static RegexSet matchSome(Collection regexes) { + return new RegexSet(regexes); + } + + public boolean matches(String userId) { + for (Regex regex : regexSet) { + if (regex.matches(userId)) { + return true; + } + } + return false; + } +} diff --git a/pgpainless-core/src/test/java/org/pgpainless/algorithm/RegexSetTest.java b/pgpainless-core/src/test/java/org/pgpainless/algorithm/RegexSetTest.java new file mode 100644 index 00000000..ff8b12fe --- /dev/null +++ b/pgpainless-core/src/test/java/org/pgpainless/algorithm/RegexSetTest.java @@ -0,0 +1,51 @@ +// SPDX-FileCopyrightText: 2022 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package org.pgpainless.algorithm; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Arrays; + +import org.junit.jupiter.api.Test; + +public class RegexSetTest { + + @Test + public void matchNothingTest() { + RegexSet set = RegexSet.matchNothing(); + assertFalse(set.matches("")); + assertFalse(set.matches("Alice")); + assertFalse(set.matches("Alice ")); + assertFalse(set.matches("")); + } + + @Test + public void matchAnything() { + RegexSet set = RegexSet.matchAnything(); + assertTrue(set.matches("Alice")); + assertTrue(set.matches("")); + assertTrue(set.matches("Alice ")); + assertTrue(set.matches("Alice ")); + assertTrue(set.matches("")); + } + + @Test + public void matchSome() { + Regex pgpainless_org = RegexInterpreterFactory.createDefaultMailDomainRegex("pgpainless.org"); + Regex example_org = RegexInterpreterFactory.createDefaultMailDomainRegex("example.org"); + + RegexSet set = RegexSet.matchSome(Arrays.asList(pgpainless_org, example_org)); + assertTrue(set.matches("Alice ")); + assertTrue(set.matches("")); + assertTrue(set.matches("Bob ")); + assertTrue(set.matches("")); + assertFalse(set.matches("Bob ")); + assertFalse(set.matches("Alice ")); + assertFalse(set.matches("alice@pgpainless.org")); + assertFalse(set.matches("Alice")); + assertFalse(set.matches("")); + } +} From 6a4ea5fbdb190ea7a64b880b1d33aca846925a05 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Tue, 29 Nov 2022 14:38:39 +0100 Subject: [PATCH 8/8] Update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bb449799..3c5969d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,9 @@ SPDX-License-Identifier: CC0-1.0 - Make countermeasures against KOpenPGP attacks configurable - Countermeasures are now disabled by default since they are costly and have a specific threat model - Can be enabled by calling `Policy.setEnableKeyParameterValidation(true)` +- Add support for parsing RegularExpressions + - Add module `hsregex` which uses `tcl-regex-java` implementing Henry Spencers Regular Expression library + ## 1.4.0-rc2 - Bump `bcpg-jdk15to18` to `1.72.3`