Skip to content

Commit

Permalink
Merge pull request #102 from s4u/keyinfo-factory
Browse files Browse the repository at this point in the history
Refactor code for private key configuration
  • Loading branch information
slawekjaranowski authored Dec 4, 2021
2 parents ec455a1 + b16eacd commit 0acdafc
Show file tree
Hide file tree
Showing 16 changed files with 573 additions and 400 deletions.
28 changes: 1 addition & 27 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version='1.0' encoding='UTF-8'?>
<!--
~ Copyright 2020 Slawomir Jaranowski
~ Copyright 2020-2021 Slawomir Jaranowski
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -106,7 +106,6 @@

<dependencyManagement>
<dependencies>

<!-- maven core -->
<dependency>
<groupId>org.apache.maven</groupId>
Expand Down Expand Up @@ -175,11 +174,6 @@
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.junit-pioneer</groupId>
<artifactId>junit-pioneer</artifactId>
<version>1.5.0</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
Expand Down Expand Up @@ -222,7 +216,6 @@
</dependencyManagement>

<dependencies>

<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
Expand Down Expand Up @@ -279,11 +272,6 @@
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit-pioneer</groupId>
<artifactId>junit-pioneer</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
Expand All @@ -294,7 +282,6 @@
<artifactId>slf4j-mock</artifactId>
<scope>test</scope>
</dependency>

</dependencies>

<repositories>
Expand Down Expand Up @@ -358,19 +345,6 @@
<invoker.streamLogsOnFailures>true</invoker.streamLogsOnFailures>
</properties>
</profile>
<profile>
<!-- https://junit-pioneer.org/docs/environment-variables -->
<!-- https://github.com/junit-pioneer/junit-pioneer/issues/387 -->
<id>jmv-9+</id>
<activation>
<jdk>[9,)</jdk>
</activation>
<properties>
<opens.util>--add-opens=java.base/java.util=ALL-UNNAMED</opens.util>
<opens.lang>--add-opens=java.base/java.lang=ALL-UNNAMED</opens.lang>
<argLine>${opens.util} ${opens.lang}</argLine>
</properties>
</profile>

<profile>
<!-- when maven.test.skip is set we skip integration tests -->
Expand Down
2 changes: 1 addition & 1 deletion src/it/pom-packaging/invoker.properties
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@
#
invoker.goals = install --no-transfer-progress -Drevision=1.1.1 -Dsettings.security=${project.basedir}/src/it/settings-security.xml
invoker.mavenOpts = ${argLine}
invoker.debug=true

invoker.ordinal = 100
invoker.debug = true
128 changes: 128 additions & 0 deletions src/main/java/org/simplify4u/plugins/sign/KeyInfoFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/*
* Copyright 2021 Slawomir Jaranowski
*
* 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 org.simplify4u.plugins.sign;

import java.io.File;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.Optional;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;

import io.vavr.control.Try;
import lombok.Builder;
import lombok.Value;
import lombok.extern.slf4j.Slf4j;
import org.simplify4u.plugins.sign.openpgp.PGPKeyInfo;
import org.simplify4u.plugins.sign.utils.Environment;
import org.simplify4u.plugins.sign.utils.FileUtil;
import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher;

/**
* Service to build {@link PGPKeyInfo} object.
*/
@Singleton
@Named
@Slf4j
public class KeyInfoFactory {

private static final String SIGN_KEY_ID_ENV = "SIGN_KEY_ID";
private static final String SIGN_KEY_ENV = "SIGN_KEY";
private static final String SIGN_KEY_PASS_ENV = "SIGN_KEY_PASS";

@Inject
private Environment environment;

@Inject
private SecDispatcher secDispatcher;

/**
* Value class for data needed to build key info.
*/
@Value
@Builder
public static class KeyInfoRequest {
String id;
String pass;
File file;
}

/**
* Build {@link PGPKeyInfo}.
*
* @param keyInfoRequest input data for key
*
* @return a {@link PGPKeyInfo} with resolved data.
*/
public PGPKeyInfo buildKeyInfo(KeyInfoRequest keyInfoRequest) {

return PGPKeyInfo.builder()
.id(resolveKeyId(keyInfoRequest))
.pass(resolveKeyPass(keyInfoRequest))
.key(resolveKey(keyInfoRequest))
.build();
}

private Long resolveKeyId(KeyInfoRequest keyInfoRequest) {
return Optional.ofNullable(environment.getEnv(SIGN_KEY_ID_ENV).orElseGet(keyInfoRequest::getId))
.map(KeyInfoFactory::parseKeyId)
.orElse(null);
}

private String resolveKeyPass(KeyInfoRequest keyInfoRequest) {
return Optional.ofNullable(environment.getEnv(SIGN_KEY_PASS_ENV).orElseGet(keyInfoRequest::getPass))
.map(this::decryptPass)
.orElse(null);
}

private byte[] resolveKey(KeyInfoRequest keyInfoRequest) {
return environment.getEnv(SIGN_KEY_ENV)
.map(String::trim)
.map(KeyInfoFactory::keyFromString)
.orElseGet(() -> keyFromFile(keyInfoRequest.getFile()));
}

private String decryptPass(String pass) {
return Try.of(() -> secDispatcher.decrypt(pass))
.getOrElseThrow(e -> new SignMojoException("Invalid encrypted password: " + e.getMessage()));
}

private static long parseKeyId(String key) {
return Try.of(() -> new BigInteger(key, 16))
.map(BigInteger::longValue)
.getOrElseThrow(e -> new SignMojoException("Invalid keyId: " + e.getMessage()));
}

private static byte[] keyFromString(String key) {
return key.getBytes(StandardCharsets.US_ASCII);
}

private static byte[] keyFromFile(File keyFile) {

File file = FileUtil.calculateWithUserHome(keyFile);

if (file.exists()) {
LOGGER.debug("Read key from file: {}", file);
return Try.of(() -> Files.readAllBytes(file.toPath())).get();
} else {
LOGGER.debug("Key file: {} not exist", keyFile);
}

return new byte[]{};
}
}
32 changes: 11 additions & 21 deletions src/main/java/org/simplify4u/plugins/sign/SignMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import java.util.Set;
import javax.inject.Inject;

import io.vavr.control.Try;
import lombok.AccessLevel;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -34,8 +33,6 @@
import org.apache.maven.project.MavenProjectHelper;
import org.apache.maven.project.artifact.ProjectArtifact;
import org.simplify4u.plugins.sign.openpgp.PGPKeyInfo;
import org.simplify4u.plugins.sign.openpgp.PGPSignerKeyNotFoundException;
import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher;

/**
* Creates Open PGP / GPG signatures for all of the project's artifacts.
Expand All @@ -54,10 +51,10 @@ public class SignMojo extends AbstractMojo {
private MavenProjectHelper projectHelper;

@Inject
private ArtifactSignerFactory artifactSignerFactory;
private KeyInfoFactory keyInfoFactory;

@Inject
private SecDispatcher secDispatcher;
private ArtifactSignerFactory artifactSignerFactory;

/**
* <p><code>keyId</code> used for signing. If not provided first key from <code>keyFile</code> will be taken.</p>
Expand Down Expand Up @@ -134,21 +131,19 @@ public void execute() {
return;
}

PGPKeyInfo keyInfo;
try {
keyInfo = PGPKeyInfo.builder()
.passDecryptor(this::decryptPass)
.keyId(keyId)
.keyPass(keyPass)
.keyFile(keyFile)
.build();
} catch (PGPSignerKeyNotFoundException e) {
PGPKeyInfo keyInfo = keyInfoFactory.buildKeyInfo(
KeyInfoFactory.KeyInfoRequest.builder()
.id(keyId)
.pass(keyPass)
.file(keyFile)
.build());

if (!keyInfo.isKeyAvailable()) {
if (skipNoKey) {
LOGGER.info("Sign - key not found - skip execution");
return;
} else {
throw e;
}
throw new SignMojoException("Required key for signing not found");
}

ArtifactSigner artifactSigner = artifactSignerFactory.getSigner(keyInfo);
Expand All @@ -167,11 +162,6 @@ public void execute() {
.forEach(this::attachSignResult);
}

private String decryptPass(String pass) {
return Try.of(() -> secDispatcher.decrypt(pass))
.getOrElseThrow(e -> new SignMojoException("Invalid encrypted password", e));
}

/**
* Attache sign result to project.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,4 @@ public class SignMojoException extends RuntimeException {
SignMojoException(String message) {
super(message);
}

SignMojoException(String message, Throwable cause) {
super(message, cause);
}
}
Loading

0 comments on commit 0acdafc

Please sign in to comment.