From 31cfbaa4b2d58513b6154b47bb151e73abbde662 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Wed, 16 Dec 2020 20:09:01 +0100 Subject: [PATCH] Fix various checkstyle issues --- .../org/pgpainless/sop/PGPainlessCLI.java | 48 +++++---- .../main/java/org/pgpainless/sop/Print.java | 27 +++++ .../org/pgpainless/sop/commands/Armor.java | 66 ++++++++++++ .../org/pgpainless/sop/commands/Dearmor.java | 39 +++++++ .../pgpainless/sop/commands/ExtractCert.java | 24 ++++- .../pgpainless/sop/commands/GenerateKey.java | 25 ++++- .../org/pgpainless/sop/commands/Sign.java | 33 ++++-- .../org/pgpainless/sop/commands/Verify.java | 102 ++++++++++++------ .../org/pgpainless/sop/commands/Version.java | 19 +++- .../pgpainless/sop/commands/package-info.java | 19 ++++ .../java/org/pgpainless/sop/package-info.java | 22 ++++ 11 files changed, 350 insertions(+), 74 deletions(-) create mode 100644 pgpainless-sop/src/main/java/org/pgpainless/sop/commands/Armor.java create mode 100644 pgpainless-sop/src/main/java/org/pgpainless/sop/commands/Dearmor.java create mode 100644 pgpainless-sop/src/main/java/org/pgpainless/sop/commands/package-info.java create mode 100644 pgpainless-sop/src/main/java/org/pgpainless/sop/package-info.java diff --git a/pgpainless-sop/src/main/java/org/pgpainless/sop/PGPainlessCLI.java b/pgpainless-sop/src/main/java/org/pgpainless/sop/PGPainlessCLI.java index dcab8773..7dae6552 100644 --- a/pgpainless-sop/src/main/java/org/pgpainless/sop/PGPainlessCLI.java +++ b/pgpainless-sop/src/main/java/org/pgpainless/sop/PGPainlessCLI.java @@ -1,6 +1,27 @@ +/* + * 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 org.pgpainless.sop; -import org.pgpainless.sop.commands.*; +import org.pgpainless.sop.commands.Armor; +import org.pgpainless.sop.commands.Dearmor; +import org.pgpainless.sop.commands.ExtractCert; +import org.pgpainless.sop.commands.GenerateKey; +import org.pgpainless.sop.commands.Sign; +import org.pgpainless.sop.commands.Verify; +import org.pgpainless.sop.commands.Version; import picocli.CommandLine; @CommandLine.Command( @@ -9,36 +30,17 @@ import picocli.CommandLine; GenerateKey.class, ExtractCert.class, Sign.class, - Verify.class + Verify.class, + Armor.class, + Dearmor.class } ) public class PGPainlessCLI implements Runnable { public static void main(String[] args) { - interpret(args); - // generateKey(); - } - - public static void interpret(String... args) { CommandLine.run(new PGPainlessCLI(), args); } - private static void version() { - CommandLine.run(new PGPainlessCLI(), "version"); - } - - private static void generateKey() { - interpret("generate-key", "--armor", "Alice Example "); - } - - private static void extractCert() { - CommandLine.run(new PGPainlessCLI(), "extract-cert"); - } - - private static void sign() { - interpret("sign", "--armor", "--as=text", "alice.sec"); - } - @Override public void run() { diff --git a/pgpainless-sop/src/main/java/org/pgpainless/sop/Print.java b/pgpainless-sop/src/main/java/org/pgpainless/sop/Print.java index 2dee1679..0fcb5220 100644 --- a/pgpainless-sop/src/main/java/org/pgpainless/sop/Print.java +++ b/pgpainless-sop/src/main/java/org/pgpainless/sop/Print.java @@ -1,3 +1,18 @@ +/* + * 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 org.pgpainless.sop; import java.io.IOException; @@ -13,4 +28,16 @@ public class Print { return new String(bytes, "UTF-8"); } } + + public static void print_ln(String msg) { + // CHECKSTYLE:OFF + System.out.println(msg); + // CHECKSTYLE:ON + } + + public static void err_ln(String msg) { + // CHECKSTYLE:OFF + System.err.println(msg); + // CHECKSTYLE:ON + } } diff --git a/pgpainless-sop/src/main/java/org/pgpainless/sop/commands/Armor.java b/pgpainless-sop/src/main/java/org/pgpainless/sop/commands/Armor.java new file mode 100644 index 00000000..7f028401 --- /dev/null +++ b/pgpainless-sop/src/main/java/org/pgpainless/sop/commands/Armor.java @@ -0,0 +1,66 @@ +/* + * 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 org.pgpainless.sop.commands; + +import org.bouncycastle.bcpg.ArmoredOutputStream; +import org.bouncycastle.util.io.Streams; +import picocli.CommandLine; + +import java.io.IOException; +import java.io.PushbackInputStream; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; + +import static org.pgpainless.sop.Print.err_ln; + +@CommandLine.Command(name = "armor", description = "Add ASCII Armor") +public class Armor implements Runnable { + + private static final byte[] BEGIN_ARMOR = "-----BEGIN PGP".getBytes(StandardCharsets.UTF_8); + + private enum Label { + auto, + sig, + key, + cert, + message + } + + @CommandLine.Option(names = {"--label"}, description = "Label to be used in the header and tail of the armoring.", paramLabel = "{auto|sig|key|cert|message}") + Label label; + + @CommandLine.Option(names = {"--allow-nested"}, description = "Allow additional armoring of already armored input") + boolean allowNested = false; + + @Override + public void run() { + + try (PushbackInputStream pbIn = new PushbackInputStream(System.in); ArmoredOutputStream armoredOutputStream = new ArmoredOutputStream(System.out)) { + byte[] start = new byte[14]; + int read = pbIn.read(start); + pbIn.unread(read); + if (Arrays.equals(BEGIN_ARMOR, start) && !allowNested) { + Streams.pipeAll(pbIn, System.out); + } else { + Streams.pipeAll(pbIn, armoredOutputStream); + } + } catch (IOException e) { + err_ln("Input data cannot be ASCII armored."); + err_ln(e.getMessage()); + System.exit(1); + } + } +} diff --git a/pgpainless-sop/src/main/java/org/pgpainless/sop/commands/Dearmor.java b/pgpainless-sop/src/main/java/org/pgpainless/sop/commands/Dearmor.java new file mode 100644 index 00000000..9db81bc0 --- /dev/null +++ b/pgpainless-sop/src/main/java/org/pgpainless/sop/commands/Dearmor.java @@ -0,0 +1,39 @@ +/* + * 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 org.pgpainless.sop.commands; + +import org.bouncycastle.bcpg.ArmoredInputStream; +import org.bouncycastle.util.io.Streams; +import picocli.CommandLine; + +import java.io.IOException; + +import static org.pgpainless.sop.Print.err_ln; + +@CommandLine.Command(name = "dearmor", description = "Remove ASCII Armor") +public class Dearmor implements Runnable { + + @Override + public void run() { + try (ArmoredInputStream in = new ArmoredInputStream(System.in, true)) { + Streams.pipeAll(in, System.out); + } catch (IOException e) { + err_ln("Data cannot be dearmored."); + err_ln(e.getMessage()); + System.exit(1); + } + } +} diff --git a/pgpainless-sop/src/main/java/org/pgpainless/sop/commands/ExtractCert.java b/pgpainless-sop/src/main/java/org/pgpainless/sop/commands/ExtractCert.java index e4b72484..60687ef8 100644 --- a/pgpainless-sop/src/main/java/org/pgpainless/sop/commands/ExtractCert.java +++ b/pgpainless-sop/src/main/java/org/pgpainless/sop/commands/ExtractCert.java @@ -1,3 +1,18 @@ +/* + * 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 org.pgpainless.sop.commands; import java.io.IOException; @@ -10,6 +25,9 @@ import org.pgpainless.sop.Print; import org.pgpainless.util.BCUtil; import picocli.CommandLine; +import static org.pgpainless.sop.Print.err_ln; +import static org.pgpainless.sop.Print.print_ln; + @CommandLine.Command(name = "extract-cert") public class ExtractCert implements Runnable { @@ -25,10 +43,10 @@ public class ExtractCert implements Runnable { PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(System.in); PGPPublicKeyRing publicKeys = BCUtil.publicKeyRingFromSecretKeyRing(secretKeys); - System.out.println(Print.toString(publicKeys.getEncoded(), !noArmor)); + print_ln(Print.toString(publicKeys.getEncoded(), !noArmor)); } catch (IOException | PGPException e) { - System.err.println("Error extracting certificate from keys;"); - System.err.println(e.getMessage()); + err_ln("Error extracting certificate from keys;"); + err_ln(e.getMessage()); System.exit(1); } } diff --git a/pgpainless-sop/src/main/java/org/pgpainless/sop/commands/GenerateKey.java b/pgpainless-sop/src/main/java/org/pgpainless/sop/commands/GenerateKey.java index 745411d7..5398991b 100644 --- a/pgpainless-sop/src/main/java/org/pgpainless/sop/commands/GenerateKey.java +++ b/pgpainless-sop/src/main/java/org/pgpainless/sop/commands/GenerateKey.java @@ -1,3 +1,18 @@ +/* + * 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 org.pgpainless.sop.commands; import java.io.IOException; @@ -8,9 +23,11 @@ import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.pgpainless.PGPainless; import org.pgpainless.sop.Print; -import org.pgpainless.util.ArmorUtils; import picocli.CommandLine; +import static org.pgpainless.sop.Print.err_ln; +import static org.pgpainless.sop.Print.print_ln; + @CommandLine.Command(name = "generate-key") public class GenerateKey implements Runnable { @@ -28,11 +45,11 @@ public class GenerateKey implements Runnable { try { PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().simpleEcKeyRing(userId); - System.out.println(Print.toString(secretKeys.getEncoded(), !noArmor)); + print_ln(Print.toString(secretKeys.getEncoded(), !noArmor)); } catch (InvalidAlgorithmParameterException | NoSuchAlgorithmException | PGPException | IOException e) { - System.err.println("Error creating OpenPGP key:"); - System.err.println(e.getMessage()); + err_ln("Error creating OpenPGP key:"); + err_ln(e.getMessage()); System.exit(1); } } diff --git a/pgpainless-sop/src/main/java/org/pgpainless/sop/commands/Sign.java b/pgpainless-sop/src/main/java/org/pgpainless/sop/commands/Sign.java index 5568ced7..40ca52f0 100644 --- a/pgpainless-sop/src/main/java/org/pgpainless/sop/commands/Sign.java +++ b/pgpainless-sop/src/main/java/org/pgpainless/sop/commands/Sign.java @@ -1,3 +1,18 @@ +/* + * 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 org.pgpainless.sop.commands; import java.io.ByteArrayOutputStream; @@ -16,6 +31,9 @@ import org.pgpainless.key.protection.UnprotectedKeysProtector; import org.pgpainless.sop.Print; import picocli.CommandLine; +import static org.pgpainless.sop.Print.err_ln; +import static org.pgpainless.sop.Print.print_ln; + @CommandLine.Command(name = "sign") public class Sign implements Runnable { @@ -30,7 +48,8 @@ public class Sign implements Runnable { @CommandLine.Option(names = {"--no-armor"}) boolean noArmor = false; - @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.") + @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}") Type type; @CommandLine.Parameters @@ -42,9 +61,8 @@ public class Sign implements Runnable { try { secretKeys = PGPainless.readKeyRing().secretKeyRing(new FileInputStream(secretKeyFile)); } catch (IOException | PGPException e) { - System.err.println("Error reading secret key ring."); - System.err.println(e.getMessage()); - + err_ln("Error reading secret key ring."); + err_ln(e.getMessage()); System.exit(1); return; } @@ -64,11 +82,10 @@ public class Sign implements Runnable { PGPSignature signature = encryptionStream.getResult().getSignatures().iterator().next(); - System.out.println(Print.toString(signature.getEncoded(), !noArmor)); + print_ln(Print.toString(signature.getEncoded(), !noArmor)); } catch (PGPException | IOException e) { - System.err.println("Error signing data."); - System.err.println(e.getMessage()); - + err_ln("Error signing data."); + err_ln(e.getMessage()); System.exit(1); } } diff --git a/pgpainless-sop/src/main/java/org/pgpainless/sop/commands/Verify.java b/pgpainless-sop/src/main/java/org/pgpainless/sop/commands/Verify.java index 0ec64eae..28bad051 100644 --- a/pgpainless-sop/src/main/java/org/pgpainless/sop/commands/Verify.java +++ b/pgpainless-sop/src/main/java/org/pgpainless/sop/commands/Verify.java @@ -1,3 +1,18 @@ +/* + * 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 org.pgpainless.sop.commands; import org.bouncycastle.openpgp.PGPException; @@ -12,6 +27,7 @@ import picocli.CommandLine; import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.OutputStream; import java.text.DateFormat; @@ -23,9 +39,22 @@ import java.util.HashSet; import java.util.Map; import java.util.TimeZone; +import static org.pgpainless.sop.Print.err_ln; +import static org.pgpainless.sop.Print.print_ln; + @CommandLine.Command(name = "verify", description = "Verify a detached signature.\nThe signed data is being read from standard input.") public class Verify implements Runnable { + private static final TimeZone tz = TimeZone.getTimeZone("UTC"); + private static final DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'"); + + private static final Date beginningOfTime = new Date(0); + private static final Date endOfTime = new Date(8640000000000000L); + + static { + df.setTimeZone(tz); + } + @CommandLine.Parameters(index = "0", description = "Detached signature") File signature; @@ -35,33 +64,27 @@ public class Verify implements Runnable { @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 (\"-\").") - String notBefore = "-"; + 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.") - String notAfter = "now"; - - private final TimeZone tz = TimeZone.getTimeZone("UTC"); - private final DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'"); - - private final Date beginningOfTime = new Date(0); - private final Date endOfTime = new Date(8640000000000000L); + String notAfter = "now"; @Override public void run() { - df.setTimeZone(tz); Date notBeforeDate = parseNotBefore(); Date notAfterDate = parseNotAfter(); Map publicKeys = readCertificatesFromFiles(); if (publicKeys.isEmpty()) { - System.out.println("No certificates supplied."); + err_ln("No certificates supplied."); System.exit(19); } - try(FileInputStream sigIn = new FileInputStream(signature)) { + OpenPgpMetadata metadata; + try (FileInputStream sigIn = new FileInputStream(signature)) { DecryptionStream verifier = PGPainless.decryptAndOrVerify() .onInputStream(System.in) .doNotDecrypt() @@ -74,26 +97,34 @@ public class Verify implements Runnable { Streams.pipeAll(verifier, out); verifier.close(); - OpenPgpMetadata metadata = verifier.getResult(); - - Map signaturesInTimeRange = new HashMap<>(); - for (OpenPgpV4Fingerprint fingerprint : metadata.getVerifiedSignatures().keySet()) { - PGPSignature signature = metadata.getVerifiedSignatures().get(fingerprint); - Date creationTime = signature.getCreationTime(); - if (!creationTime.before(notBeforeDate) && !creationTime.after(notAfterDate)) { - signaturesInTimeRange.put(fingerprint, signature); - } - } - - if (signaturesInTimeRange.isEmpty()) { - System.out.println("Signature validation failed."); - System.exit(3); - } - - printValidSignatures(signaturesInTimeRange, publicKeys); + metadata = verifier.getResult(); + } catch (FileNotFoundException e) { + err_ln("Signature file not found:"); + err_ln(e.getMessage()); + System.exit(1); + return; } catch (IOException | PGPException e) { - e.printStackTrace(); + err_ln("Signature validation failed."); + err_ln(e.getMessage()); + System.exit(1); + return; } + + Map signaturesInTimeRange = new HashMap<>(); + for (OpenPgpV4Fingerprint fingerprint : metadata.getVerifiedSignatures().keySet()) { + PGPSignature signature = metadata.getVerifiedSignatures().get(fingerprint); + Date creationTime = signature.getCreationTime(); + if (!creationTime.before(notBeforeDate) && !creationTime.after(notAfterDate)) { + signaturesInTimeRange.put(fingerprint, signature); + } + } + + if (signaturesInTimeRange.isEmpty()) { + err_ln("No valid signatures found."); + System.exit(3); + } + + printValidSignatures(signaturesInTimeRange, publicKeys); } private void printValidSignatures(Map validSignatures, Map publicKeys) { @@ -108,7 +139,7 @@ public class Verify implements Runnable { String utcSigDate = df.format(signature.getCreationTime()); OpenPgpV4Fingerprint primaryKeyFp = new OpenPgpV4Fingerprint(publicKeyRing); - System.out.println(utcSigDate + " " + sigKeyFp.toString() + " " + primaryKeyFp.toString() + + print_ln(utcSigDate + " " + sigKeyFp.toString() + " " + primaryKeyFp.toString() + " signed by " + file.getName()); } } @@ -117,10 +148,11 @@ public class Verify implements Runnable { private Map readCertificatesFromFiles() { Map publicKeys = new HashMap<>(); for (File cert : certificates) { - try(FileInputStream in = new FileInputStream(cert)) { + try (FileInputStream in = new FileInputStream(cert)) { publicKeys.put(cert, PGPainless.readKeyRing().publicKeyRing(in)); } catch (IOException e) { - e.printStackTrace(); + err_ln("Cannot read certificate from file " + cert.getAbsolutePath() + ":"); + err_ln(e.getMessage()); } } return publicKeys; @@ -130,7 +162,7 @@ public class Verify implements Runnable { try { return notAfter.equals("now") ? new Date() : notAfter.equals("-") ? endOfTime : df.parse(notAfter); } catch (ParseException e) { - System.out.println("Invalid date string supplied as value of --not-after."); + err_ln("Invalid date string supplied as value of --not-after."); System.exit(1); return null; } @@ -138,9 +170,9 @@ public class Verify implements Runnable { private Date parseNotBefore() { try { - return notBefore.equals("now") ? new Date() : notBefore.equals("-") ? beginningOfTime: df.parse(notBefore); + return notBefore.equals("now") ? new Date() : notBefore.equals("-") ? beginningOfTime : df.parse(notBefore); } catch (ParseException e) { - System.out.println("Invalid date string supplied as value of --not-before."); + err_ln("Invalid date string supplied as value of --not-before."); System.exit(1); return null; } diff --git a/pgpainless-sop/src/main/java/org/pgpainless/sop/commands/Version.java b/pgpainless-sop/src/main/java/org/pgpainless/sop/commands/Version.java index 772dbf88..8a5da78b 100644 --- a/pgpainless-sop/src/main/java/org/pgpainless/sop/commands/Version.java +++ b/pgpainless-sop/src/main/java/org/pgpainless/sop/commands/Version.java @@ -1,12 +1,29 @@ +/* + * 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 org.pgpainless.sop.commands; import picocli.CommandLine; +import static org.pgpainless.sop.Print.print_ln; + @CommandLine.Command(name = "version", description = "Display version information about the tool") public class Version implements Runnable { @Override public void run() { - System.out.println("PGPainless CLI version 0.0.1"); + print_ln("PGPainless CLI version 0.0.1"); } } diff --git a/pgpainless-sop/src/main/java/org/pgpainless/sop/commands/package-info.java b/pgpainless-sop/src/main/java/org/pgpainless/sop/commands/package-info.java new file mode 100644 index 00000000..633d7afb --- /dev/null +++ b/pgpainless-sop/src/main/java/org/pgpainless/sop/commands/package-info.java @@ -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 org.pgpainless.sop.commands; diff --git a/pgpainless-sop/src/main/java/org/pgpainless/sop/package-info.java b/pgpainless-sop/src/main/java/org/pgpainless/sop/package-info.java new file mode 100644 index 00000000..43afb989 --- /dev/null +++ b/pgpainless-sop/src/main/java/org/pgpainless/sop/package-info.java @@ -0,0 +1,22 @@ +/* + * 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. + */ +/** + * PGPainless SOP implementing a Stateless OpenPGP Command Line Interface. + * @see + * Stateless OpenPGP Command Line Interface + * draft-dkg-openpgp-stateless-cli-01 + */ +package org.pgpainless.sop;