mirror of
https://github.com/pgpainless/pgpainless.git
synced 2025-09-10 02:39:39 +02:00
Base PGPainlessCLI on new sop-java module
* Rename pgpainless-sop -> pgpainless-cli * Introduce sop-java (implementation-independent SOP API) * Introduce sop-java-picocli (CLI frontend for sop-java) * Introduce pgpainless-sop (implementation of sop-java using PGPainless) * Rework pgpainless-cli (plugs pgpainless-sop into sop-java-picocli)
This commit is contained in:
parent
2ba782c451
commit
8cf5347b52
112 changed files with 6146 additions and 1303 deletions
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright 2021 Paul Schaub.
|
||||
*
|
||||
* 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 sop.cli.picocli;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import sop.util.UTCUtil;
|
||||
|
||||
public class DateParser {
|
||||
|
||||
public static final Date BEGINNING_OF_TIME = new Date(0);
|
||||
public static final Date END_OF_TIME = new Date(8640000000000000L);
|
||||
|
||||
public static Date parseNotAfter(String notAfter) {
|
||||
Date date = notAfter.equals("now") ? new Date() : notAfter.equals("-") ? END_OF_TIME : UTCUtil.parseUTCDate(notAfter);
|
||||
if (date == null) {
|
||||
Print.errln("Invalid date string supplied as value of --not-after.");
|
||||
System.exit(1);
|
||||
}
|
||||
return date;
|
||||
}
|
||||
|
||||
public static Date parseNotBefore(String notBefore) {
|
||||
Date date = notBefore.equals("now") ? new Date() : notBefore.equals("-") ? BEGINNING_OF_TIME : UTCUtil.parseUTCDate(notBefore);
|
||||
if (date == null) {
|
||||
Print.errln("Invalid date string supplied as value of --not-before.");
|
||||
System.exit(1);
|
||||
}
|
||||
return date;
|
||||
}
|
||||
}
|
37
sop-java-picocli/src/main/java/sop/cli/picocli/Print.java
Normal file
37
sop-java-picocli/src/main/java/sop/cli/picocli/Print.java
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright 2021 Paul Schaub.
|
||||
*
|
||||
* 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 sop.cli.picocli;
|
||||
|
||||
public class Print {
|
||||
|
||||
public static void errln(String string) {
|
||||
// CHECKSTYLE:OFF
|
||||
System.err.println(string);
|
||||
// CHECKSTYLE:ON
|
||||
}
|
||||
|
||||
public static void trace(Throwable e) {
|
||||
// CHECKSTYLE:OFF
|
||||
e.printStackTrace();
|
||||
// CHECKSTYLE:ON
|
||||
}
|
||||
|
||||
public static void outln(String string) {
|
||||
// CHECKSTYLE:OFF
|
||||
System.out.println(string);
|
||||
// CHECKSTYLE:ON
|
||||
}
|
||||
}
|
71
sop-java-picocli/src/main/java/sop/cli/picocli/SopCLI.java
Normal file
71
sop-java-picocli/src/main/java/sop/cli/picocli/SopCLI.java
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright 2021 Paul Schaub.
|
||||
*
|
||||
* 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 sop.cli.picocli;
|
||||
|
||||
import picocli.CommandLine;
|
||||
import sop.SOP;
|
||||
import sop.cli.picocli.commands.ArmorCmd;
|
||||
import sop.cli.picocli.commands.DearmorCmd;
|
||||
import sop.cli.picocli.commands.DecryptCmd;
|
||||
import sop.cli.picocli.commands.EncryptCmd;
|
||||
import sop.cli.picocli.commands.ExtractCertCmd;
|
||||
import sop.cli.picocli.commands.GenerateKeyCmd;
|
||||
import sop.cli.picocli.commands.SignCmd;
|
||||
import sop.cli.picocli.commands.VerifyCmd;
|
||||
import sop.cli.picocli.commands.VersionCmd;
|
||||
|
||||
@CommandLine.Command(
|
||||
exitCodeOnInvalidInput = 69,
|
||||
subcommands = {
|
||||
ArmorCmd.class,
|
||||
DearmorCmd.class,
|
||||
DecryptCmd.class,
|
||||
EncryptCmd.class,
|
||||
ExtractCertCmd.class,
|
||||
GenerateKeyCmd.class,
|
||||
SignCmd.class,
|
||||
VerifyCmd.class,
|
||||
VersionCmd.class
|
||||
}
|
||||
)
|
||||
public class SopCLI {
|
||||
|
||||
static SOP SOP_INSTANCE;
|
||||
|
||||
public static void main(String[] args) {
|
||||
int exitCode = execute(args);
|
||||
if (exitCode != 0) {
|
||||
System.exit(exitCode);
|
||||
}
|
||||
}
|
||||
|
||||
public static int execute(String[] args) {
|
||||
return new CommandLine(SopCLI.class)
|
||||
.setCaseInsensitiveEnumValuesAllowed(true)
|
||||
.execute(args);
|
||||
}
|
||||
|
||||
public static SOP getSop() {
|
||||
if (SOP_INSTANCE == null) {
|
||||
throw new IllegalStateException("No SOP backend set.");
|
||||
}
|
||||
return SOP_INSTANCE;
|
||||
}
|
||||
|
||||
public static void setSopInstance(SOP instance) {
|
||||
SOP_INSTANCE = instance;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright 2021 Paul Schaub.
|
||||
*
|
||||
* 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 sop.cli.picocli.commands;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import picocli.CommandLine;
|
||||
import sop.Ready;
|
||||
import sop.cli.picocli.Print;
|
||||
import sop.cli.picocli.SopCLI;
|
||||
import sop.enums.ArmorLabel;
|
||||
import sop.exception.SOPGPException;
|
||||
import sop.operation.Armor;
|
||||
|
||||
@CommandLine.Command(name = "armor",
|
||||
description = "Add ASCII Armor to standard input",
|
||||
exitCodeOnInvalidInput = SOPGPException.UnsupportedOption.EXIT_CODE)
|
||||
public class ArmorCmd implements Runnable {
|
||||
|
||||
@CommandLine.Option(names = {"--label"}, description = "Label to be used in the header and tail of the armoring.", paramLabel = "{auto|sig|key|cert|message}")
|
||||
ArmorLabel label;
|
||||
|
||||
@CommandLine.Option(names = {"--allow-nested"}, description = "Allow additional armoring of already armored input")
|
||||
boolean allowNested = false;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Armor armor = SopCLI.getSop().armor();
|
||||
if (allowNested) {
|
||||
try {
|
||||
armor.allowNested();
|
||||
} catch (SOPGPException.UnsupportedOption unsupportedOption) {
|
||||
Print.errln("Option --allow-nested is not supported.");
|
||||
Print.trace(unsupportedOption);
|
||||
System.exit(unsupportedOption.getExitCode());
|
||||
}
|
||||
}
|
||||
if (label != null) {
|
||||
try {
|
||||
armor.label(label);
|
||||
} catch (SOPGPException.UnsupportedOption unsupportedOption) {
|
||||
Print.errln("Armor labels not supported.");
|
||||
System.exit(unsupportedOption.getExitCode());
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
Ready ready = armor.data(System.in);
|
||||
ready.writeTo(System.out);
|
||||
} catch (SOPGPException.BadData badData) {
|
||||
Print.errln("Bad data.");
|
||||
Print.trace(badData);
|
||||
System.exit(badData.getExitCode());
|
||||
} catch (IOException e) {
|
||||
Print.errln("IO Error.");
|
||||
Print.trace(e);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2020 Paul Schaub.
|
||||
*
|
||||
* 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 sop.cli.picocli.commands;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import picocli.CommandLine;
|
||||
import sop.cli.picocli.Print;
|
||||
import sop.cli.picocli.SopCLI;
|
||||
import sop.exception.SOPGPException;
|
||||
|
||||
@CommandLine.Command(name = "dearmor",
|
||||
description = "Remove ASCII Armor from standard input",
|
||||
exitCodeOnInvalidInput = SOPGPException.UnsupportedOption.EXIT_CODE)
|
||||
public class DearmorCmd implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
SopCLI.getSop()
|
||||
.dearmor()
|
||||
.data(System.in)
|
||||
.writeTo(System.out);
|
||||
} catch (SOPGPException.BadData e) {
|
||||
Print.errln("Bad data.");
|
||||
Print.trace(e);
|
||||
System.exit(e.getExitCode());
|
||||
} catch (IOException e) {
|
||||
Print.errln("IO Error.");
|
||||
Print.trace(e);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,290 @@
|
|||
/*
|
||||
* Copyright 2020 Paul Schaub.
|
||||
*
|
||||
* 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 sop.cli.picocli.commands;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import picocli.CommandLine;
|
||||
import sop.DecryptionResult;
|
||||
import sop.ReadyWithResult;
|
||||
import sop.SessionKey;
|
||||
import sop.Verification;
|
||||
import sop.cli.picocli.DateParser;
|
||||
import sop.cli.picocli.Print;
|
||||
import sop.cli.picocli.SopCLI;
|
||||
import sop.exception.SOPGPException;
|
||||
import sop.operation.Decrypt;
|
||||
import sop.util.HexUtil;
|
||||
|
||||
@CommandLine.Command(name = "decrypt",
|
||||
description = "Decrypt a message from standard input",
|
||||
exitCodeOnInvalidInput = SOPGPException.UnsupportedOption.EXIT_CODE)
|
||||
public class DecryptCmd implements Runnable {
|
||||
|
||||
@CommandLine.Option(
|
||||
names = {"--session-key-out"},
|
||||
description = "Can be used to learn the session key on successful decryption",
|
||||
paramLabel = "SESSIONKEY")
|
||||
File sessionKeyOut;
|
||||
|
||||
@CommandLine.Option(
|
||||
names = {"--with-session-key"},
|
||||
description = "Enables decryption of the \"CIPHERTEXT\" using the session key directly against the \"SEIPD\" packet",
|
||||
paramLabel = "SESSIONKEY")
|
||||
List<String> withSessionKey = new ArrayList<>();
|
||||
|
||||
@CommandLine.Option(
|
||||
names = {"--with-password"},
|
||||
description = "Enables decryption based on any \"SKESK\" packets in the \"CIPHERTEXT\"",
|
||||
paramLabel = "PASSWORD")
|
||||
List<String> withPassword = new ArrayList<>();
|
||||
|
||||
@CommandLine.Option(names = {"--verify-out"},
|
||||
description = "Produces signature verification status to the designated file",
|
||||
paramLabel = "VERIFICATIONS")
|
||||
File verifyOut;
|
||||
|
||||
@CommandLine.Option(names = {"--verify-with"},
|
||||
description = "Certificates whose signatures would be acceptable for signatures over this message",
|
||||
paramLabel = "CERT")
|
||||
List<File> certs = new ArrayList<>();
|
||||
|
||||
@CommandLine.Option(names = {"--not-before"},
|
||||
description = "ISO-8601 formatted UTC date (eg. '2020-11-23T16:35Z)\n" +
|
||||
"Reject signatures with a creation date not in range.\n" +
|
||||
"Defaults to beginning of time (\"-\").",
|
||||
paramLabel = "DATE")
|
||||
String notBefore = "-";
|
||||
|
||||
@CommandLine.Option(names = {"--not-after"},
|
||||
description = "ISO-8601 formatted UTC date (eg. '2020-11-23T16:35Z)\n" +
|
||||
"Reject signatures with a creation date not in range.\n" +
|
||||
"Defaults to current system time (\"now\").\n" +
|
||||
"Accepts special value \"-\" for end of time.",
|
||||
paramLabel = "DATE")
|
||||
String notAfter = "now";
|
||||
|
||||
@CommandLine.Parameters(index = "0..*",
|
||||
description = "Secret keys to attempt decryption with",
|
||||
paramLabel = "KEY")
|
||||
List<File> keys = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
unlinkExistingVerifyOut(verifyOut);
|
||||
|
||||
Decrypt decrypt = SopCLI.getSop().decrypt();
|
||||
setNotAfter(notAfter, decrypt);
|
||||
setNotBefore(notBefore, decrypt);
|
||||
setWithPasswords(withPassword, decrypt);
|
||||
setWithSessionKeys(withSessionKey, decrypt);
|
||||
setVerifyWith(certs, decrypt);
|
||||
setDecryptWith(keys, decrypt);
|
||||
|
||||
if (verifyOut != null && certs.isEmpty()) {
|
||||
Print.errln("--verify-out is requested, but no --verify-with was provided.");
|
||||
System.exit(23);
|
||||
}
|
||||
|
||||
try {
|
||||
ReadyWithResult<DecryptionResult> ready = decrypt.ciphertext(System.in);
|
||||
DecryptionResult result = ready.writeTo(System.out);
|
||||
if (sessionKeyOut != null) {
|
||||
if (sessionKeyOut.exists()) {
|
||||
Print.errln("File " + sessionKeyOut.getAbsolutePath() + " already exists.");
|
||||
Print.trace(new SOPGPException.OutputExists());
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
try (FileOutputStream outputStream = new FileOutputStream(sessionKeyOut)) {
|
||||
if (!result.getSessionKey().isPresent()) {
|
||||
Print.errln("Session key not extracted. Possibly the feature is not supported.");
|
||||
System.exit(SOPGPException.UnsupportedOption.EXIT_CODE);
|
||||
} else {
|
||||
SessionKey sessionKey = result.getSessionKey().get();
|
||||
outputStream.write(sessionKey.getAlgorithm());
|
||||
outputStream.write(sessionKey.getKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (verifyOut != null) {
|
||||
if (!verifyOut.createNewFile()) {
|
||||
throw new IOException("Cannot create file " + verifyOut.getAbsolutePath());
|
||||
}
|
||||
try (FileOutputStream outputStream = new FileOutputStream(verifyOut)) {
|
||||
PrintWriter writer = new PrintWriter(outputStream);
|
||||
for (Verification verification : result.getVerifications()) {
|
||||
// CHECKSTYLE:OFF
|
||||
writer.println(verification.toString());
|
||||
// CHECKSTYLE:ON
|
||||
}
|
||||
writer.flush();
|
||||
}
|
||||
}
|
||||
} catch (SOPGPException.BadData badData) {
|
||||
Print.errln("No valid OpenPGP message found on Standard Input.");
|
||||
Print.trace(badData);
|
||||
System.exit(badData.getExitCode());
|
||||
} catch (SOPGPException.MissingArg missingArg) {
|
||||
Print.errln("Missing arguments.");
|
||||
Print.trace(missingArg);
|
||||
System.exit(missingArg.getExitCode());
|
||||
} catch (IOException e) {
|
||||
Print.errln("IO Error.");
|
||||
Print.trace(e);
|
||||
System.exit(1);
|
||||
} catch (SOPGPException.NoSignature noSignature) {
|
||||
Print.errln("No verifiable signature found.");
|
||||
Print.trace(noSignature);
|
||||
System.exit(noSignature.getExitCode());
|
||||
} catch (SOPGPException.CannotDecrypt cannotDecrypt) {
|
||||
Print.errln("Cannot decrypt.");
|
||||
Print.trace(cannotDecrypt);
|
||||
System.exit(cannotDecrypt.getExitCode());
|
||||
}
|
||||
}
|
||||
|
||||
private void setDecryptWith(List<File> keys, Decrypt decrypt) {
|
||||
for (File key : keys) {
|
||||
try (FileInputStream keyIn = new FileInputStream(key)) {
|
||||
decrypt.withKey(keyIn);
|
||||
} catch (SOPGPException.KeyIsProtected keyIsProtected) {
|
||||
Print.errln("Key in file " + key.getAbsolutePath() + " is password protected.");
|
||||
Print.trace(keyIsProtected);
|
||||
System.exit(1);
|
||||
} catch (SOPGPException.UnsupportedAsymmetricAlgo unsupportedAsymmetricAlgo) {
|
||||
Print.errln("Key uses unsupported asymmetric algorithm.");
|
||||
Print.trace(unsupportedAsymmetricAlgo);
|
||||
System.exit(unsupportedAsymmetricAlgo.getExitCode());
|
||||
} catch (SOPGPException.BadData badData) {
|
||||
Print.errln("File " + key.getAbsolutePath() + " does not contain a private key.");
|
||||
Print.trace(badData);
|
||||
System.exit(badData.getExitCode());
|
||||
} catch (FileNotFoundException e) {
|
||||
Print.errln("File " + key.getAbsolutePath() + " does not exist.");
|
||||
Print.trace(e);
|
||||
System.exit(1);
|
||||
} catch (IOException e) {
|
||||
Print.errln("IO Error.");
|
||||
Print.trace(e);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setVerifyWith(List<File> certs, Decrypt decrypt) {
|
||||
for (File cert : certs) {
|
||||
try (FileInputStream certIn = new FileInputStream(cert)) {
|
||||
decrypt.verifyWithCert(certIn);
|
||||
} catch (FileNotFoundException e) {
|
||||
Print.errln("File " + cert.getAbsolutePath() + " does not exist.");
|
||||
Print.trace(e);
|
||||
System.exit(1);
|
||||
} catch (IOException e) {
|
||||
Print.errln("IO Error.");
|
||||
Print.trace(e);
|
||||
System.exit(1);
|
||||
} catch (SOPGPException.BadData badData) {
|
||||
Print.errln("File " + cert.getAbsolutePath() + " does not contain a valid certificate.");
|
||||
Print.trace(badData);
|
||||
System.exit(badData.getExitCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void unlinkExistingVerifyOut(File verifyOut) {
|
||||
if (verifyOut == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (verifyOut.exists()) {
|
||||
if (!verifyOut.delete()) {
|
||||
Print.errln("Cannot delete existing verification file" + verifyOut.getAbsolutePath());
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setWithSessionKeys(List<String> withSessionKey, Decrypt decrypt) {
|
||||
Pattern sessionKeyPattern = Pattern.compile("^\\d+:[0-9A-F]+$");
|
||||
for (String sessionKey : withSessionKey) {
|
||||
if (!sessionKeyPattern.matcher(sessionKey).matches()) {
|
||||
Print.errln("Invalid session key format.");
|
||||
Print.errln("Session keys are expected in the format 'ALGONUM:HEXKEY'");
|
||||
System.exit(1);
|
||||
}
|
||||
String[] split = sessionKey.split(":");
|
||||
byte algorithm = (byte) Integer.parseInt(split[0]);
|
||||
byte[] key = HexUtil.hexToBytes(split[1]);
|
||||
|
||||
try {
|
||||
decrypt.withSessionKey(new SessionKey(algorithm, key));
|
||||
} catch (SOPGPException.UnsupportedOption unsupportedOption) {
|
||||
Print.errln("Unsupported option '--with-session-key'.");
|
||||
Print.trace(unsupportedOption);
|
||||
System.exit(unsupportedOption.getExitCode());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setWithPasswords(List<String> withPassword, Decrypt decrypt) {
|
||||
for (String password : withPassword) {
|
||||
try {
|
||||
decrypt.withPassword(password);
|
||||
} catch (SOPGPException.PasswordNotHumanReadable passwordNotHumanReadable) {
|
||||
Print.errln("Password not human readable.");
|
||||
Print.trace(passwordNotHumanReadable);
|
||||
System.exit(passwordNotHumanReadable.getExitCode());
|
||||
} catch (SOPGPException.UnsupportedOption unsupportedOption) {
|
||||
Print.errln("Unsupported option '--with-password'.");
|
||||
Print.trace(unsupportedOption);
|
||||
System.exit(unsupportedOption.getExitCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setNotAfter(String notAfter, Decrypt decrypt) {
|
||||
Date notAfterDate = DateParser.parseNotAfter(notAfter);
|
||||
try {
|
||||
decrypt.verifyNotAfter(notAfterDate);
|
||||
} catch (SOPGPException.UnsupportedOption unsupportedOption) {
|
||||
Print.errln("Option '--not-after' not supported.");
|
||||
Print.trace(unsupportedOption);
|
||||
System.exit(unsupportedOption.getExitCode());
|
||||
}
|
||||
}
|
||||
|
||||
private void setNotBefore(String notBefore, Decrypt decrypt) {
|
||||
Date notBeforeDate = DateParser.parseNotBefore(notBefore);
|
||||
try {
|
||||
decrypt.verifyNotBefore(notBeforeDate);
|
||||
} catch (SOPGPException.UnsupportedOption unsupportedOption) {
|
||||
Print.errln("Option '--not-before' not supported.");
|
||||
Print.trace(unsupportedOption);
|
||||
System.exit(unsupportedOption.getExitCode());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
* Copyright 2020 Paul Schaub.
|
||||
*
|
||||
* 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 sop.cli.picocli.commands;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import picocli.CommandLine;
|
||||
import sop.Ready;
|
||||
import sop.cli.picocli.Print;
|
||||
import sop.cli.picocli.SopCLI;
|
||||
import sop.enums.EncryptAs;
|
||||
import sop.exception.SOPGPException;
|
||||
import sop.operation.Encrypt;
|
||||
|
||||
@CommandLine.Command(name = "encrypt",
|
||||
description = "Encrypt a message from standard input",
|
||||
exitCodeOnInvalidInput = 37)
|
||||
public class EncryptCmd implements Runnable {
|
||||
|
||||
@CommandLine.Option(names = "--no-armor",
|
||||
description = "ASCII armor the output",
|
||||
negatable = true)
|
||||
boolean armor = true;
|
||||
|
||||
@CommandLine.Option(names = {"--as"},
|
||||
description = "Type of the input data. Defaults to 'binary'",
|
||||
paramLabel = "{binary|text|mime}")
|
||||
EncryptAs type;
|
||||
|
||||
@CommandLine.Option(names = "--with-password",
|
||||
description = "Encrypt the message with a password",
|
||||
paramLabel = "PASSWORD")
|
||||
List<String> withPassword = new ArrayList<>();
|
||||
|
||||
@CommandLine.Option(names = "--sign-with",
|
||||
description = "Sign the output with a private key",
|
||||
paramLabel = "KEY")
|
||||
List<File> signWith = new ArrayList<>();
|
||||
|
||||
@CommandLine.Parameters(description = "Certificates the message gets encrypted to",
|
||||
index = "0..*",
|
||||
paramLabel = "CERTS")
|
||||
List<File> certs = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Encrypt encrypt = SopCLI.getSop().encrypt();
|
||||
if (type != null) {
|
||||
try {
|
||||
encrypt.mode(type);
|
||||
} catch (SOPGPException.UnsupportedOption unsupportedOption) {
|
||||
Print.errln("Unsupported option '--as'.");
|
||||
Print.trace(unsupportedOption);
|
||||
System.exit(unsupportedOption.getExitCode());
|
||||
}
|
||||
}
|
||||
|
||||
if (withPassword.isEmpty() && certs.isEmpty()) {
|
||||
Print.errln("At least one password or cert file required for encryption.");
|
||||
System.exit(19);
|
||||
}
|
||||
|
||||
for (String password : withPassword) {
|
||||
try {
|
||||
encrypt.withPassword(password);
|
||||
} catch (SOPGPException.PasswordNotHumanReadable passwordNotHumanReadable) {
|
||||
Print.errln("Password is not human-readable.");
|
||||
Print.trace(passwordNotHumanReadable);
|
||||
System.exit(passwordNotHumanReadable.getExitCode());
|
||||
} catch (SOPGPException.UnsupportedOption unsupportedOption) {
|
||||
Print.errln("Unsupported option '--with-password'.");
|
||||
Print.trace(unsupportedOption);
|
||||
System.exit(unsupportedOption.getExitCode());
|
||||
}
|
||||
}
|
||||
|
||||
for (File keyFile : signWith) {
|
||||
try (FileInputStream keyIn = new FileInputStream(keyFile)) {
|
||||
encrypt.signWith(keyIn);
|
||||
} catch (FileNotFoundException e) {
|
||||
Print.errln("Key file " + keyFile.getAbsolutePath() + " not found.");
|
||||
Print.trace(e);
|
||||
System.exit(1);
|
||||
} catch (IOException e) {
|
||||
Print.errln("IO Error.");
|
||||
Print.trace(e);
|
||||
System.exit(1);
|
||||
} catch (SOPGPException.KeyIsProtected keyIsProtected) {
|
||||
Print.errln("Key from " + keyFile.getAbsolutePath() + " is password protected.");
|
||||
Print.trace(keyIsProtected);
|
||||
System.exit(1);
|
||||
} catch (SOPGPException.UnsupportedAsymmetricAlgo unsupportedAsymmetricAlgo) {
|
||||
Print.errln("Key from " + keyFile.getAbsolutePath() + " has unsupported asymmetric algorithm.");
|
||||
Print.trace(unsupportedAsymmetricAlgo);
|
||||
System.exit(unsupportedAsymmetricAlgo.getExitCode());
|
||||
} catch (SOPGPException.CertCannotSign certCannotSign) {
|
||||
Print.errln("Key from " + keyFile.getAbsolutePath() + " cannot sign.");
|
||||
Print.trace(certCannotSign);
|
||||
System.exit(1);
|
||||
} catch (SOPGPException.BadData badData) {
|
||||
Print.errln("Key file " + keyFile.getAbsolutePath() + " does not contain a valid OpenPGP private key.");
|
||||
Print.trace(badData);
|
||||
System.exit(badData.getExitCode());
|
||||
}
|
||||
}
|
||||
|
||||
for (File certFile : certs) {
|
||||
try (FileInputStream certIn = new FileInputStream(certFile)) {
|
||||
encrypt.withCert(certIn);
|
||||
} catch (FileNotFoundException e) {
|
||||
Print.errln("Certificate file " + certFile.getAbsolutePath() + " not found.");
|
||||
Print.trace(e);
|
||||
System.exit(1);
|
||||
} catch (IOException e) {
|
||||
Print.errln("IO Error.");
|
||||
Print.trace(e);
|
||||
System.exit(1);
|
||||
} catch (SOPGPException.UnsupportedAsymmetricAlgo unsupportedAsymmetricAlgo) {
|
||||
Print.errln("Certificate from " + certFile.getAbsolutePath() + " has unsupported asymmetric algorithm.");
|
||||
Print.trace(unsupportedAsymmetricAlgo);
|
||||
System.exit(unsupportedAsymmetricAlgo.getExitCode());
|
||||
} catch (SOPGPException.CertCannotEncrypt certCannotEncrypt) {
|
||||
Print.errln("Certificate from " + certFile.getAbsolutePath() + " is not capable of encryption.");
|
||||
Print.trace(certCannotEncrypt);
|
||||
System.exit(certCannotEncrypt.getExitCode());
|
||||
} catch (SOPGPException.BadData badData) {
|
||||
Print.errln("Certificate file " + certFile.getAbsolutePath() + " does not contain a valid OpenPGP certificate.");
|
||||
Print.trace(badData);
|
||||
System.exit(badData.getExitCode());
|
||||
}
|
||||
}
|
||||
|
||||
if (!armor) {
|
||||
encrypt.noArmor();
|
||||
}
|
||||
|
||||
try {
|
||||
Ready ready = encrypt.plaintext(System.in);
|
||||
ready.writeTo(System.out);
|
||||
} catch (IOException e) {
|
||||
Print.errln("IO Error.");
|
||||
Print.trace(e);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright 2020 Paul Schaub.
|
||||
*
|
||||
* 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 sop.cli.picocli.commands;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import picocli.CommandLine;
|
||||
import sop.Ready;
|
||||
import sop.cli.picocli.Print;
|
||||
import sop.cli.picocli.SopCLI;
|
||||
import sop.exception.SOPGPException;
|
||||
import sop.operation.ExtractCert;
|
||||
|
||||
@CommandLine.Command(name = "extract-cert",
|
||||
description = "Extract a public key certificate from a secret key from standard input",
|
||||
exitCodeOnInvalidInput = 37)
|
||||
public class ExtractCertCmd implements Runnable {
|
||||
|
||||
@CommandLine.Option(names = "--no-armor",
|
||||
description = "ASCII armor the output",
|
||||
negatable = true)
|
||||
boolean armor = true;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
ExtractCert extractCert = SopCLI.getSop().extractCert();
|
||||
if (!armor) {
|
||||
extractCert.noArmor();
|
||||
}
|
||||
|
||||
try {
|
||||
Ready ready = extractCert.key(System.in);
|
||||
ready.writeTo(System.out);
|
||||
} catch (IOException e) {
|
||||
Print.errln("IO Error.");
|
||||
Print.trace(e);
|
||||
System.exit(1);
|
||||
} catch (SOPGPException.BadData badData) {
|
||||
Print.errln("Standard Input does not contain valid OpenPGP private key material.");
|
||||
Print.trace(badData);
|
||||
System.exit(badData.getExitCode());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright 2020 Paul Schaub.
|
||||
*
|
||||
* 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 sop.cli.picocli.commands;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import picocli.CommandLine;
|
||||
import sop.Ready;
|
||||
import sop.cli.picocli.Print;
|
||||
import sop.cli.picocli.SopCLI;
|
||||
import sop.exception.SOPGPException;
|
||||
import sop.operation.GenerateKey;
|
||||
|
||||
@CommandLine.Command(name = "generate-key",
|
||||
description = "Generate a secret key",
|
||||
exitCodeOnInvalidInput = 37)
|
||||
public class GenerateKeyCmd implements Runnable {
|
||||
|
||||
@CommandLine.Option(names = "--no-armor",
|
||||
description = "ASCII armor the output",
|
||||
negatable = true)
|
||||
boolean armor = true;
|
||||
|
||||
@CommandLine.Parameters(description = "User-ID, eg. \"Alice <alice@example.com>\"")
|
||||
List<String> userId = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
GenerateKey generateKey = SopCLI.getSop().generateKey();
|
||||
for (String userId : userId) {
|
||||
generateKey.userId(userId);
|
||||
}
|
||||
|
||||
if (!armor) {
|
||||
generateKey.noArmor();
|
||||
}
|
||||
|
||||
try {
|
||||
Ready ready = generateKey.generate();
|
||||
ready.writeTo(System.out);
|
||||
} catch (SOPGPException.MissingArg missingArg) {
|
||||
Print.errln("Missing argument.");
|
||||
Print.trace(missingArg);
|
||||
System.exit(missingArg.getExitCode());
|
||||
} catch (SOPGPException.UnsupportedAsymmetricAlgo unsupportedAsymmetricAlgo) {
|
||||
Print.errln("Unsupported asymmetric algorithm.");
|
||||
Print.trace(unsupportedAsymmetricAlgo);
|
||||
System.exit(unsupportedAsymmetricAlgo.getExitCode());
|
||||
} catch (IOException e) {
|
||||
Print.errln("IO Error.");
|
||||
Print.trace(e);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Copyright 2020 Paul Schaub.
|
||||
*
|
||||
* 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 sop.cli.picocli.commands;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import picocli.CommandLine;
|
||||
import sop.Ready;
|
||||
import sop.cli.picocli.Print;
|
||||
import sop.cli.picocli.SopCLI;
|
||||
import sop.enums.SignAs;
|
||||
import sop.exception.SOPGPException;
|
||||
import sop.operation.Sign;
|
||||
|
||||
@CommandLine.Command(name = "sign",
|
||||
description = "Create a detached signature on the data from standard input",
|
||||
exitCodeOnInvalidInput = 37)
|
||||
public class SignCmd implements Runnable {
|
||||
|
||||
@CommandLine.Option(names = "--no-armor",
|
||||
description = "ASCII armor the output",
|
||||
negatable = true)
|
||||
boolean armor = true;
|
||||
|
||||
@CommandLine.Option(names = "--as", description = "Defaults to 'binary'. If '--as=text' and the input data is not valid UTF-8, sign fails with return code 53.",
|
||||
paramLabel = "{binary|text}")
|
||||
SignAs type;
|
||||
|
||||
@CommandLine.Parameters(description = "Secret keys used for signing",
|
||||
paramLabel = "KEY")
|
||||
List<File> secretKeyFile = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Sign sign = SopCLI.getSop().sign();
|
||||
|
||||
if (type != null) {
|
||||
try {
|
||||
sign.mode(type);
|
||||
} catch (SOPGPException.UnsupportedOption unsupportedOption) {
|
||||
Print.errln("Unsupported option '--as'");
|
||||
Print.trace(unsupportedOption);
|
||||
System.exit(unsupportedOption.getExitCode());
|
||||
}
|
||||
}
|
||||
|
||||
if (secretKeyFile.isEmpty()) {
|
||||
Print.errln("Missing required parameter 'KEY'.");
|
||||
System.exit(19);
|
||||
}
|
||||
|
||||
for (File keyFile : secretKeyFile) {
|
||||
try (FileInputStream keyIn = new FileInputStream(keyFile)) {
|
||||
sign.key(keyIn);
|
||||
} catch (FileNotFoundException e) {
|
||||
Print.errln("File " + keyFile.getAbsolutePath() + " does not exist.");
|
||||
Print.trace(e);
|
||||
System.exit(1);
|
||||
} catch (IOException e) {
|
||||
Print.errln("Cannot access file " + keyFile.getAbsolutePath());
|
||||
Print.trace(e);
|
||||
System.exit(1);
|
||||
} catch (SOPGPException.KeyIsProtected e) {
|
||||
Print.errln("Key " + keyFile.getName() + " is password protected.");
|
||||
Print.trace(e);
|
||||
System.exit(1);
|
||||
} catch (SOPGPException.BadData badData) {
|
||||
Print.errln("Bad data in key file " + keyFile.getAbsolutePath() + ":");
|
||||
Print.trace(badData);
|
||||
System.exit(badData.getExitCode());
|
||||
}
|
||||
}
|
||||
|
||||
if (!armor) {
|
||||
sign.noArmor();
|
||||
}
|
||||
|
||||
try {
|
||||
Ready ready = sign.data(System.in);
|
||||
ready.writeTo(System.out);
|
||||
} catch (IOException e) {
|
||||
Print.errln("IO Error.");
|
||||
Print.trace(e);
|
||||
System.exit(1);
|
||||
} catch (SOPGPException.ExpectedText expectedText) {
|
||||
Print.errln("Expected text input, but got binary data.");
|
||||
Print.trace(expectedText);
|
||||
System.exit(expectedText.getExitCode());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* Copyright 2020 Paul Schaub.
|
||||
*
|
||||
* 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 sop.cli.picocli.commands;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import picocli.CommandLine;
|
||||
import sop.Verification;
|
||||
import sop.cli.picocli.DateParser;
|
||||
import sop.cli.picocli.Print;
|
||||
import sop.cli.picocli.SopCLI;
|
||||
import sop.exception.SOPGPException;
|
||||
import sop.operation.Verify;
|
||||
|
||||
@CommandLine.Command(name = "verify",
|
||||
description = "Verify a detached signature over the data from standard input",
|
||||
exitCodeOnInvalidInput = 37)
|
||||
public class VerifyCmd implements Runnable {
|
||||
|
||||
@CommandLine.Parameters(index = "0",
|
||||
description = "Detached signature",
|
||||
paramLabel = "SIGNATURE")
|
||||
File signature;
|
||||
|
||||
@CommandLine.Parameters(index = "1..*",
|
||||
arity = "1..*",
|
||||
description = "Public key certificates",
|
||||
paramLabel = "CERT")
|
||||
List<File> certificates = new ArrayList<>();
|
||||
|
||||
@CommandLine.Option(names = {"--not-before"},
|
||||
description = "ISO-8601 formatted UTC date (eg. '2020-11-23T16:35Z)\n" +
|
||||
"Reject signatures with a creation date not in range.\n" +
|
||||
"Defaults to beginning of time (\"-\").",
|
||||
paramLabel = "DATE")
|
||||
String notBefore = "-";
|
||||
|
||||
@CommandLine.Option(names = {"--not-after"},
|
||||
description = "ISO-8601 formatted UTC date (eg. '2020-11-23T16:35Z)\n" +
|
||||
"Reject signatures with a creation date not in range.\n" +
|
||||
"Defaults to current system time (\"now\").\n" +
|
||||
"Accepts special value \"-\" for end of time.",
|
||||
paramLabel = "DATE")
|
||||
String notAfter = "now";
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Verify verify = SopCLI.getSop().verify();
|
||||
if (notAfter != null) {
|
||||
try {
|
||||
verify.notAfter(DateParser.parseNotAfter(notAfter));
|
||||
} catch (SOPGPException.UnsupportedOption unsupportedOption) {
|
||||
Print.errln("Unsupported option '--not-after'.");
|
||||
Print.trace(unsupportedOption);
|
||||
System.exit(unsupportedOption.getExitCode());
|
||||
}
|
||||
}
|
||||
if (notBefore != null) {
|
||||
try {
|
||||
verify.notBefore(DateParser.parseNotBefore(notBefore));
|
||||
} catch (SOPGPException.UnsupportedOption unsupportedOption) {
|
||||
Print.errln("Unsupported option '--not-before'.");
|
||||
Print.trace(unsupportedOption);
|
||||
System.exit(unsupportedOption.getExitCode());
|
||||
}
|
||||
}
|
||||
|
||||
for (File certFile : certificates) {
|
||||
try (FileInputStream certIn = new FileInputStream(certFile)) {
|
||||
verify.cert(certIn);
|
||||
} catch (FileNotFoundException fileNotFoundException) {
|
||||
Print.errln("Certificate file " + certFile.getAbsolutePath() + " not found.");
|
||||
|
||||
Print.trace(fileNotFoundException);
|
||||
System.exit(1);
|
||||
} catch (IOException ioException) {
|
||||
Print.errln("IO Error.");
|
||||
Print.trace(ioException);
|
||||
System.exit(1);
|
||||
} catch (SOPGPException.BadData badData) {
|
||||
Print.errln("Certificate file " + certFile.getAbsolutePath() + " appears to not contain a valid OpenPGP certificate.");
|
||||
Print.trace(badData);
|
||||
System.exit(badData.getExitCode());
|
||||
}
|
||||
}
|
||||
|
||||
if (signature != null) {
|
||||
try (FileInputStream sigIn = new FileInputStream(signature)) {
|
||||
verify.signatures(sigIn);
|
||||
} catch (FileNotFoundException e) {
|
||||
Print.errln("Signature file " + signature.getAbsolutePath() + " does not exist.");
|
||||
Print.trace(e);
|
||||
System.exit(1);
|
||||
} catch (IOException e) {
|
||||
Print.errln("IO Error.");
|
||||
Print.trace(e);
|
||||
System.exit(1);
|
||||
} catch (SOPGPException.BadData badData) {
|
||||
Print.errln("File " + signature.getAbsolutePath() + " does not contain a valid OpenPGP signature.");
|
||||
Print.trace(badData);
|
||||
System.exit(badData.getExitCode());
|
||||
}
|
||||
}
|
||||
|
||||
List<Verification> verifications = null;
|
||||
try {
|
||||
verifications = verify.data(System.in);
|
||||
} catch (SOPGPException.NoSignature e) {
|
||||
Print.errln("No verifiable signature found.");
|
||||
Print.trace(e);
|
||||
System.exit(e.getExitCode());
|
||||
} catch (IOException ioException) {
|
||||
Print.errln("IO Error.");
|
||||
Print.trace(ioException);
|
||||
System.exit(1);
|
||||
} catch (SOPGPException.BadData badData) {
|
||||
Print.errln("Standard Input appears not to contain a valid OpenPGP message.");
|
||||
Print.trace(badData);
|
||||
System.exit(badData.getExitCode());
|
||||
}
|
||||
for (Verification verification : verifications) {
|
||||
Print.outln(verification.toString());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright 2020 Paul Schaub.
|
||||
*
|
||||
* 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 sop.cli.picocli.commands;
|
||||
|
||||
import picocli.CommandLine;
|
||||
import sop.cli.picocli.Print;
|
||||
import sop.cli.picocli.SopCLI;
|
||||
import sop.operation.Version;
|
||||
|
||||
@CommandLine.Command(name = "version", description = "Display version information about the tool",
|
||||
exitCodeOnInvalidInput = 37)
|
||||
public class VersionCmd implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Version version = SopCLI.getSop().version();
|
||||
|
||||
Print.outln(version.getName() + " " + version.getVersion());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright 2020 Paul Schaub.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/**
|
||||
* Subcommands of the PGPainless SOP.
|
||||
*/
|
||||
package sop.cli.picocli.commands;
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright 2021 Paul Schaub.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/**
|
||||
* Implementation of the Stateless OpenPGP Command Line Interface using Picocli.
|
||||
*/
|
||||
package sop.cli.picocli;
|
Loading…
Add table
Add a link
Reference in a new issue