mirror of
https://github.com/pgpainless/pgpainless.git
synced 2025-09-15 13:19:38 +02:00
Initial implementation of WKD address generation
This commit is contained in:
parent
db58280db6
commit
142296cef7
4 changed files with 147 additions and 1 deletions
|
@ -6,5 +6,6 @@ rootProject.name = 'PGPainless'
|
|||
|
||||
include 'pgpainless-core',
|
||||
'pgpainless-sop',
|
||||
'pgpainless-cli'
|
||||
'pgpainless-cli',
|
||||
'wkd-java'
|
||||
|
||||
|
|
28
wkd-java/build.gradle
Normal file
28
wkd-java/build.gradle
Normal file
|
@ -0,0 +1,28 @@
|
|||
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
plugins {
|
||||
id 'java-library'
|
||||
}
|
||||
|
||||
group 'org.pgpainless'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion"
|
||||
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitVersion"
|
||||
|
||||
// Logging
|
||||
testImplementation "ch.qos.logback:logback-classic:$logbackVersion"
|
||||
|
||||
// Z-Base32
|
||||
implementation 'com.sandinh:zbase32-commons-codec:1.0.0'
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
75
wkd-java/src/main/java/pgp/wkd/UserIdToWKDAddress.java
Normal file
75
wkd-java/src/main/java/pgp/wkd/UserIdToWKDAddress.java
Normal file
|
@ -0,0 +1,75 @@
|
|||
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package pgp.wkd;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.codec.binary.ZBase32;
|
||||
|
||||
public class UserIdToWKDAddress {
|
||||
|
||||
// RegEx for Email Addresses
|
||||
// https://www.baeldung.com/java-email-validation-regex#regular-expression-by-rfc-5322-for-email-validation
|
||||
// Modified by adding capture groups '()' for local and domain part
|
||||
private static final Pattern PATTERN_EMAIL = Pattern.compile("^([a-zA-Z0-9_!#$%&'*+/=?`{|}~^.-]+)@([a-zA-Z0-9.-]+)$");
|
||||
private static final Pattern PATTERN_USER_ID = Pattern.compile("^.*\\<([a-zA-Z0-9_!#$%&'*+/=?`{|}~^.-]+@[a-zA-Z0-9.-]+)\\>.*");
|
||||
|
||||
/**
|
||||
* Extract the email address from a user-id.
|
||||
* The user-id is expected to correspond to a RFC2822 name-addr.
|
||||
* The email address is expected to be framed by angle brackets.
|
||||
*
|
||||
* @see <a href="https://datatracker.ietf.org/doc/html/rfc2822#section-3.4">RFC2822 - Internet Message Format §3.4: Address Specification</a>
|
||||
* @param userId user-id name-addr
|
||||
* @return WKD URI
|
||||
*
|
||||
* @throws IllegalArgumentException in case the user-id does not match the expected format
|
||||
*/
|
||||
public URI userIdToUri(String userId) {
|
||||
String lowerCase = userId.toLowerCase();
|
||||
Matcher matcher = PATTERN_USER_ID.matcher(lowerCase);
|
||||
if (!matcher.matches()) {
|
||||
throw new IllegalArgumentException("User-ID does not follow excepted pattern \"Firstname Lastname <email.address> [Optional Comment]\"");
|
||||
}
|
||||
String email = matcher.group(1);
|
||||
return mailToUri(email);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate an email address (localpart@domainpart) to a WKD URI.
|
||||
*
|
||||
* @param email email address
|
||||
* @return WKD URI
|
||||
* @throws IllegalArgumentException in case of a malformed email address
|
||||
*/
|
||||
public URI mailToUri(String email) {
|
||||
String lowerCase = email.toLowerCase();
|
||||
Matcher matcher = PATTERN_EMAIL.matcher(lowerCase);
|
||||
if (!matcher.matches()) {
|
||||
throw new IllegalArgumentException("Invalid email address.");
|
||||
}
|
||||
|
||||
String localPart = matcher.group(1);
|
||||
String domainPart = matcher.group(2);
|
||||
|
||||
MessageDigest sha1;
|
||||
try {
|
||||
sha1 = MessageDigest.getInstance("SHA1");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new AssertionError("SHA-1 is available on all JVMs.", e);
|
||||
}
|
||||
sha1.update(localPart.getBytes(StandardCharsets.UTF_8));
|
||||
byte[] digest = sha1.digest();
|
||||
|
||||
String base32KeyHandle = new ZBase32().encodeAsString(digest);
|
||||
|
||||
return URI.create("https://" + domainPart + "/.well-known/openpgpkey/hu/" + base32KeyHandle);
|
||||
}
|
||||
}
|
42
wkd-java/src/test/java/pgp/wkd/WKDResolverTest.java
Normal file
42
wkd-java/src/test/java/pgp/wkd/WKDResolverTest.java
Normal file
|
@ -0,0 +1,42 @@
|
|||
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package pgp.wkd;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class WKDResolverTest {
|
||||
|
||||
@Test
|
||||
public void testUserIdToUri() {
|
||||
String userId = "Joe Doe <joe.doe@example.org> [Work Address]";
|
||||
URI expectedURI = URI.create("https://example.org/.well-known/openpgpkey/hu/iy9q119eutrkn8s1mk4r39qejnbu3n5q");
|
||||
|
||||
URI actual = new UserIdToWKDAddress().userIdToUri(userId);
|
||||
assertEquals(expectedURI, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMailToUri() {
|
||||
String mailAddress = "Joe.Doe@Example.ORG";
|
||||
URI expectedURI = URI.create("https://example.org/.well-known/openpgpkey/hu/iy9q119eutrkn8s1mk4r39qejnbu3n5q");
|
||||
|
||||
URI actual = new UserIdToWKDAddress().mailToUri(mailAddress);
|
||||
assertEquals(expectedURI, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidEmailToUri() {
|
||||
UserIdToWKDAddress uid2wkd = new UserIdToWKDAddress();
|
||||
assertThrows(IllegalArgumentException.class, () -> uid2wkd.mailToUri("john.doe"));
|
||||
assertThrows(IllegalArgumentException.class, () -> uid2wkd.mailToUri("@example.org"));
|
||||
assertThrows(IllegalArgumentException.class, () -> uid2wkd.mailToUri("john doe@example.org"));
|
||||
assertThrows(IllegalArgumentException.class, () -> uid2wkd.mailToUri("john.doe@example org"));
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue