mirror of
https://codeberg.org/PGPainless/sop-java.git
synced 2025-09-10 02:39:45 +02:00
Compare commits
5 commits
Author | SHA1 | Date | |
---|---|---|---|
e46e50556f | |||
e158d9365d | |||
19818f6e9d | |||
ffb8d297d3 | |||
51bca5eb4f |
164 changed files with 910 additions and 3915 deletions
29
.github/ISSUE_TEMPLATE/bug_report.md
vendored
29
.github/ISSUE_TEMPLATE/bug_report.md
vendored
|
@ -1,29 +0,0 @@
|
||||||
---
|
|
||||||
name: Bug report
|
|
||||||
about: Create a report to help us improve
|
|
||||||
title: ''
|
|
||||||
labels: ''
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Describe the bug**
|
|
||||||
<!-- A clear and concise description of what the bug is. -->
|
|
||||||
|
|
||||||
**Version**
|
|
||||||
<!-- What versions of the following libraries are you using? -->
|
|
||||||
- `sop-java`:
|
|
||||||
- `pgpainless-core`:
|
|
||||||
- `bouncycastle`:
|
|
||||||
|
|
||||||
**To Reproduce**
|
|
||||||
<!-- Steps to reproduce the behavior: -->
|
|
||||||
```
|
|
||||||
Example Code Block
|
|
||||||
```
|
|
||||||
|
|
||||||
**Expected behavior**
|
|
||||||
<!-- A clear and concise description of what you expected to happen. -->
|
|
||||||
|
|
||||||
**Additional context**
|
|
||||||
<!-- Add any other context about the problem here. -->
|
|
24
.reuse/dep5
Normal file
24
.reuse/dep5
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||||
|
Upstream-Name: SOP-Java
|
||||||
|
Upstream-Contact: Paul Schaub <info@pgpainless.org>
|
||||||
|
Source: https://pgpainless.org
|
||||||
|
|
||||||
|
# Sample paragraph, commented out:
|
||||||
|
#
|
||||||
|
# Files: src/*
|
||||||
|
# Copyright: $YEAR $NAME <$CONTACT>
|
||||||
|
# License: ...
|
||||||
|
|
||||||
|
# Gradle build tool
|
||||||
|
Files: gradle*
|
||||||
|
Copyright: 2015 the original author or authors.
|
||||||
|
License: Apache-2.0
|
||||||
|
|
||||||
|
# Woodpecker build files
|
||||||
|
Files: .woodpecker/*
|
||||||
|
Copyright: 2022 the original author or authors.
|
||||||
|
License: Apache-2.0
|
||||||
|
|
||||||
|
Files: external-sop/src/main/resources/sop/testsuite/external/*
|
||||||
|
Copyright: 2023 the original author or authors
|
||||||
|
License: Apache-2.0
|
|
@ -1,7 +1,5 @@
|
||||||
steps:
|
steps:
|
||||||
run:
|
run:
|
||||||
when:
|
|
||||||
event: push
|
|
||||||
image: gradle:7.6-jdk11-jammy
|
image: gradle:7.6-jdk11-jammy
|
||||||
commands:
|
commands:
|
||||||
# Install Sequoia-SOP
|
# Install Sequoia-SOP
|
||||||
|
@ -16,6 +14,4 @@ steps:
|
||||||
- gradle check javadocAll
|
- gradle check javadocAll
|
||||||
# Code has coverage
|
# Code has coverage
|
||||||
- gradle jacocoRootReport coveralls
|
- gradle jacocoRootReport coveralls
|
||||||
environment:
|
secrets: [coveralls_repo_token]
|
||||||
COVERALLS_REPO_TOKEN:
|
|
||||||
from_secret: coveralls_repo_token
|
|
|
@ -2,8 +2,6 @@
|
||||||
# See https://reuse.software/
|
# See https://reuse.software/
|
||||||
steps:
|
steps:
|
||||||
reuse:
|
reuse:
|
||||||
when:
|
|
||||||
event: push
|
|
||||||
image: fsfe/reuse:latest
|
image: fsfe/reuse:latest
|
||||||
commands:
|
commands:
|
||||||
- reuse lint
|
- reuse lint
|
60
CHANGELOG.md
60
CHANGELOG.md
|
@ -6,66 +6,6 @@ SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## 14.0.0
|
|
||||||
- Update implementation to [SOP Specification revision 14](https://www.ietf.org/archive/id/draft-dkg-openpgp-stateless-cli-14.html),
|
|
||||||
including changes from revisions `11`, `12`, `13`, `14`.
|
|
||||||
- Implement newly introduced operations
|
|
||||||
- `update-key` 'fixes' everything wrong with a key
|
|
||||||
- `merge-certs` merges a certificate with other copies
|
|
||||||
- `certify-userid` create signatures over user-ids on certificates
|
|
||||||
- `validate-userid` validate signatures over user-ids
|
|
||||||
- Add new exceptions
|
|
||||||
- `UnspecificFailure` maps generic application errors
|
|
||||||
- `KeyCannotCertify` signals that a key cannot be used for third-party certifications
|
|
||||||
- `NoHardwareKeyFound` signals that a key backed by a hardware device cannot be found
|
|
||||||
- `HardwareKeyFailure` signals a hardware device failure
|
|
||||||
- `PrimaryKeyBad` signals an unusable or bad primary key
|
|
||||||
- `CertUserIdNoMatch` signals that a user-id cannot be found/validated on a certificate
|
|
||||||
- `Verification`: Add support for JSON description extensions
|
|
||||||
- Remove `animalsniffer` from build dependencies
|
|
||||||
- Bump `logback` to `1.5.13`
|
|
||||||
|
|
||||||
## 10.1.1
|
|
||||||
- Prepare jar files for use in native images, e.g. using GraalVM by generating and including
|
|
||||||
configuration files for reflection, resources and dynamic proxies.
|
|
||||||
- gradle: Make use of jvmToolchain functionality
|
|
||||||
- gradle: Improve reproducibility
|
|
||||||
- gradle: Bump animalsniffer to `2.0.0`
|
|
||||||
|
|
||||||
## 10.1.0
|
|
||||||
- `sop-java`:
|
|
||||||
- Remove `label()` option from `armor()` subcommand
|
|
||||||
- Move test-fixtures artifact built with the `testFixtures` plugin into
|
|
||||||
its own module `sop-java-testfixtures`, which can be consumed by maven builds.
|
|
||||||
- `sop-java-picocli`:
|
|
||||||
- Properly map `MissingParameterException` to `MissingArg` exit code
|
|
||||||
- As a workaround for native builds using graalvm:
|
|
||||||
- Do not re-set message bundles dynamically (fails in native builds)
|
|
||||||
- Prevent an unmatched argument error
|
|
||||||
|
|
||||||
## 10.0.3
|
|
||||||
- CLI `change-key-password`: Fix indirect parameter passing for new and old passwords (thanks to @dkg for the report)
|
|
||||||
- Backport: `revoke-key`: Allow for multiple password options
|
|
||||||
|
|
||||||
## 10.0.2
|
|
||||||
- Downgrade `logback-core` to `1.2.13`
|
|
||||||
|
|
||||||
## 10.0.1
|
|
||||||
- Remove `label()` option from `Armor` operation
|
|
||||||
- Fix exit code for 'Missing required option/parameter' error
|
|
||||||
- Fix `revoke-key`: Allow for multiple invocations of `--with-key-password` option
|
|
||||||
- Fix `EncryptExternal` use of `--sign-with` parameter
|
|
||||||
- Fix `NullPointerException` in `DecryptExternal` when reading lines
|
|
||||||
- Fix `DecryptExternal` use of `verifications-out`
|
|
||||||
- Test suite: Ignore tests if `UnsupportedOption` is thrown
|
|
||||||
- Bump `logback-core` to `1.4.14`
|
|
||||||
|
|
||||||
## 10.0.0
|
|
||||||
- Update implementation to [SOP Specification revision 10](https://www.ietf.org/archive/id/draft-dkg-openpgp-stateless-cli-10.html).
|
|
||||||
- Throw `BadData` when passing KEYS where CERTS are expected
|
|
||||||
- Introduce `sopv` interface subset with revision `1.0`
|
|
||||||
- Add `sop version --sopv`
|
|
||||||
|
|
||||||
## 8.0.2
|
## 8.0.2
|
||||||
- CLI `change-key-password`: Fix indirect parameter passing for new and old passwords (thanks to @dkg for the report)
|
- CLI `change-key-password`: Fix indirect parameter passing for new and old passwords (thanks to @dkg for the report)
|
||||||
- Backport: `revoke-key`: Allow for multiple password options
|
- Backport: `revoke-key`: Allow for multiple password options
|
||||||
|
|
16
README.md
16
README.md
|
@ -7,7 +7,7 @@ SPDX-License-Identifier: Apache-2.0
|
||||||
# SOP for Java
|
# SOP for Java
|
||||||
|
|
||||||
[](https://ci.codeberg.org/PGPainless/sop-java)
|
[](https://ci.codeberg.org/PGPainless/sop-java)
|
||||||
[](https://datatracker.ietf.org/doc/draft-dkg-openpgp-stateless-cli/14/)
|
[](https://datatracker.ietf.org/doc/draft-dkg-openpgp-stateless-cli/08/)
|
||||||
[](https://coveralls.io/github/pgpainless/sop-java?branch=main)
|
[](https://coveralls.io/github/pgpainless/sop-java?branch=main)
|
||||||
[](https://api.reuse.software/info/github.com/pgpainless/sop-java)
|
[](https://api.reuse.software/info/github.com/pgpainless/sop-java)
|
||||||
|
|
||||||
|
@ -25,10 +25,6 @@ The repository contains the following modules:
|
||||||
* [sop-java](/sop-java) defines a set of Java interfaces describing the Stateless OpenPGP Protocol.
|
* [sop-java](/sop-java) defines a set of Java interfaces describing the Stateless OpenPGP Protocol.
|
||||||
* [sop-java-picocli](/sop-java-picocli) contains a wrapper application that transforms the `sop-java` API into a command line application
|
* [sop-java-picocli](/sop-java-picocli) contains a wrapper application that transforms the `sop-java` API into a command line application
|
||||||
compatible with the SOP-CLI specification.
|
compatible with the SOP-CLI specification.
|
||||||
* [external-sop](/external-sop) contains an API implementation that can be used to forward API calls to a SOP executable,
|
|
||||||
allowing to delegate the implementation logic to an arbitrary SOP CLI implementation.
|
|
||||||
* [sop-java-testfixtures](/sop-java-testfixtures) contains a test suite that can be shared by downstream implementations
|
|
||||||
of `sop-java`.
|
|
||||||
|
|
||||||
## Known Implementations
|
## Known Implementations
|
||||||
(Please expand!)
|
(Please expand!)
|
||||||
|
@ -37,11 +33,9 @@ allowing to delegate the implementation logic to an arbitrary SOP CLI implementa
|
||||||
|-------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------|
|
|-------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------|
|
||||||
| [pgpainless-sop](https://github.com/pgpainless/pgpainless/tree/main/pgpainless-sop) | Implementation of `sop-java` using PGPainless |
|
| [pgpainless-sop](https://github.com/pgpainless/pgpainless/tree/main/pgpainless-sop) | Implementation of `sop-java` using PGPainless |
|
||||||
| [external-sop](https://github.com/pgpainless/sop-java/tree/main/external-sop) | Implementation of `sop-java` that allows binding to external SOP binaries such as `sqop` |
|
| [external-sop](https://github.com/pgpainless/sop-java/tree/main/external-sop) | Implementation of `sop-java` that allows binding to external SOP binaries such as `sqop` |
|
||||||
| [bcsop](https://codeberg.org/PGPainless/bc-sop) | Implementation of `sop-java` using vanilla Bouncy Castle |
|
|
||||||
|
|
||||||
### Implementations in other languages
|
### Implementations in other languages
|
||||||
| Project | Language |
|
| Project | Language |
|
||||||
|---------------------------------------------------|----------|
|
|-------------------------------------------------|----------|
|
||||||
| [sop-rs](https://sequoia-pgp.gitlab.io/sop-rs/) | Rust |
|
| [sop-rs](https://sequoia-pgp.gitlab.io/sop-rs/) | Rust |
|
||||||
| [SOP for python](https://pypi.org/project/sop/) | Python |
|
| [SOP for python](https://pypi.org/project/sop/) | Python |
|
||||||
| [rpgpie-sop](https://crates.io/crates/rpgpie-sop) | Rust |
|
|
||||||
|
|
32
REUSE.toml
32
REUSE.toml
|
@ -1,32 +0,0 @@
|
||||||
# SPDX-FileCopyrightText: 2025 Paul Schaub <info@pgpainless.org>
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: CC0-1.0
|
|
||||||
|
|
||||||
version = 1
|
|
||||||
SPDX-PackageName = "SOP-Java"
|
|
||||||
SPDX-PackageSupplier = "Paul Schaub <info@pgpainless.org>"
|
|
||||||
SPDX-PackageDownloadLocation = "https://pgpainless.org"
|
|
||||||
|
|
||||||
[[annotations]]
|
|
||||||
path = "gradle**"
|
|
||||||
precedence = "aggregate"
|
|
||||||
SPDX-FileCopyrightText = "2015 the original author or authors."
|
|
||||||
SPDX-License-Identifier = "Apache-2.0"
|
|
||||||
|
|
||||||
[[annotations]]
|
|
||||||
path = ".woodpecker/**"
|
|
||||||
precedence = "aggregate"
|
|
||||||
SPDX-FileCopyrightText = "2022 the original author or authors."
|
|
||||||
SPDX-License-Identifier = "Apache-2.0"
|
|
||||||
|
|
||||||
[[annotations]]
|
|
||||||
path = "external-sop/src/main/resources/sop/testsuite/external/**"
|
|
||||||
precedence = "aggregate"
|
|
||||||
SPDX-FileCopyrightText = "2023 the original author or authors"
|
|
||||||
SPDX-License-Identifier = "Apache-2.0"
|
|
||||||
|
|
||||||
[[annotations]]
|
|
||||||
path = ".github/ISSUE_TEMPLATE/**"
|
|
||||||
precedence = "aggregate"
|
|
||||||
SPDX-FileCopyrightText = "2024 the original author or authors"
|
|
||||||
SPDX-License-Identifier = "Apache-2.0"
|
|
41
build.gradle
41
build.gradle
|
@ -18,7 +18,8 @@ buildscript {
|
||||||
}
|
}
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id 'org.jetbrains.kotlin.jvm' version "1.9.21"
|
id 'ru.vyarus.animalsniffer' version '1.5.3'
|
||||||
|
id 'org.jetbrains.kotlin.jvm' version "1.8.10"
|
||||||
id 'com.diffplug.spotless' version '6.22.0' apply false
|
id 'com.diffplug.spotless' version '6.22.0' apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,9 +32,20 @@ allprojects {
|
||||||
apply plugin: 'jacoco'
|
apply plugin: 'jacoco'
|
||||||
apply plugin: 'checkstyle'
|
apply plugin: 'checkstyle'
|
||||||
apply plugin: 'kotlin'
|
apply plugin: 'kotlin'
|
||||||
apply plugin: 'kotlin-kapt'
|
|
||||||
apply plugin: 'com.diffplug.spotless'
|
apply plugin: 'com.diffplug.spotless'
|
||||||
|
|
||||||
|
// For non-cli modules enable android api compatibility check
|
||||||
|
if (it.name.equals('sop-java')) {
|
||||||
|
// animalsniffer
|
||||||
|
apply plugin: 'ru.vyarus.animalsniffer'
|
||||||
|
dependencies {
|
||||||
|
signature "net.sf.androidscents.signature:android-api-level-${minAndroidSdk}:2.3.3_r2@signature"
|
||||||
|
}
|
||||||
|
animalsniffer {
|
||||||
|
sourceSets = [sourceSets.main]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Only generate jar for submodules
|
// Only generate jar for submodules
|
||||||
// https://stackoverflow.com/a/25445035
|
// https://stackoverflow.com/a/25445035
|
||||||
jar {
|
jar {
|
||||||
|
@ -55,6 +67,8 @@ allprojects {
|
||||||
description = "Stateless OpenPGP Protocol API for Java"
|
description = "Stateless OpenPGP Protocol API for Java"
|
||||||
version = shortVersion
|
version = shortVersion
|
||||||
|
|
||||||
|
sourceCompatibility = javaSourceCompatibility
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
@ -63,13 +77,6 @@ allprojects {
|
||||||
tasks.withType(AbstractArchiveTask) {
|
tasks.withType(AbstractArchiveTask) {
|
||||||
preserveFileTimestamps = false
|
preserveFileTimestamps = false
|
||||||
reproducibleFileOrder = true
|
reproducibleFileOrder = true
|
||||||
|
|
||||||
dirMode = 0755
|
|
||||||
fileMode = 0644
|
|
||||||
}
|
|
||||||
|
|
||||||
kotlin {
|
|
||||||
jvmToolchain(javaSourceCompatibility)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compatibility of default implementations in kotlin interfaces with Java implementations.
|
// Compatibility of default implementations in kotlin interfaces with Java implementations.
|
||||||
|
@ -104,7 +111,7 @@ allprojects {
|
||||||
}
|
}
|
||||||
|
|
||||||
jacoco {
|
jacoco {
|
||||||
toolVersion = "0.8.8"
|
toolVersion = "0.8.7"
|
||||||
}
|
}
|
||||||
|
|
||||||
jacocoTestReport {
|
jacocoTestReport {
|
||||||
|
@ -112,7 +119,7 @@ allprojects {
|
||||||
sourceDirectories.setFrom(project.files(sourceSets.main.allSource.srcDirs))
|
sourceDirectories.setFrom(project.files(sourceSets.main.allSource.srcDirs))
|
||||||
classDirectories.setFrom(project.files(sourceSets.main.output))
|
classDirectories.setFrom(project.files(sourceSets.main.output))
|
||||||
reports {
|
reports {
|
||||||
xml.required = true
|
xml.enabled true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,15 +137,15 @@ subprojects {
|
||||||
apply plugin: 'signing'
|
apply plugin: 'signing'
|
||||||
|
|
||||||
task sourcesJar(type: Jar, dependsOn: classes) {
|
task sourcesJar(type: Jar, dependsOn: classes) {
|
||||||
archiveClassifier = 'sources'
|
classifier = 'sources'
|
||||||
from sourceSets.main.allSource
|
from sourceSets.main.allSource
|
||||||
}
|
}
|
||||||
task javadocJar(type: Jar, dependsOn: javadoc) {
|
task javadocJar(type: Jar, dependsOn: javadoc) {
|
||||||
archiveClassifier = 'javadoc'
|
classifier = 'javadoc'
|
||||||
from javadoc.destinationDir
|
from javadoc.destinationDir
|
||||||
}
|
}
|
||||||
task testsJar(type: Jar, dependsOn: testClasses) {
|
task testsJar(type: Jar, dependsOn: testClasses) {
|
||||||
archiveClassifier = 'tests'
|
classifier = 'tests'
|
||||||
from sourceSets.test.output
|
from sourceSets.test.output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,7 +242,7 @@ task jacocoRootReport(type: JacocoReport) {
|
||||||
classDirectories.setFrom(files(subprojects.sourceSets.main.output))
|
classDirectories.setFrom(files(subprojects.sourceSets.main.output))
|
||||||
executionData.setFrom(files(subprojects.jacocoTestReport.executionData))
|
executionData.setFrom(files(subprojects.jacocoTestReport.executionData))
|
||||||
reports {
|
reports {
|
||||||
xml.required = true
|
xml.enabled true
|
||||||
xml.destination file("${buildDir}/reports/jacoco/test/jacocoTestReport.xml")
|
xml.destination file("${buildDir}/reports/jacoco/test/jacocoTestReport.xml")
|
||||||
}
|
}
|
||||||
// We could remove the following setOnlyIf line, but then
|
// We could remove the following setOnlyIf line, but then
|
||||||
|
@ -246,6 +253,10 @@ task jacocoRootReport(type: JacocoReport) {
|
||||||
}
|
}
|
||||||
|
|
||||||
task javadocAll(type: Javadoc) {
|
task javadocAll(type: Javadoc) {
|
||||||
|
def currentJavaVersion = JavaVersion.current()
|
||||||
|
if (currentJavaVersion.compareTo(JavaVersion.VERSION_1_9) >= 0) {
|
||||||
|
options.addStringOption("-release", "8");
|
||||||
|
}
|
||||||
source subprojects.collect {project ->
|
source subprojects.collect {project ->
|
||||||
project.sourceSets.main.allJava }
|
project.sourceSets.main.allJava }
|
||||||
destinationDir = new File(buildDir, 'javadoc')
|
destinationDir = new File(buildDir, 'javadoc')
|
||||||
|
|
|
@ -15,9 +15,7 @@ repositories {
|
||||||
dependencies {
|
dependencies {
|
||||||
testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion"
|
testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion"
|
||||||
testImplementation "org.junit.jupiter:junit-jupiter-params:$junitVersion"
|
testImplementation "org.junit.jupiter:junit-jupiter-params:$junitVersion"
|
||||||
|
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitVersion"
|
||||||
testImplementation "org.junit.platform:junit-platform-suite-api:1.13.2"
|
|
||||||
testRuntimeOnly 'org.junit.platform:junit-platform-suite:1.13.2'
|
|
||||||
|
|
||||||
api project(":sop-java")
|
api project(":sop-java")
|
||||||
api "org.slf4j:slf4j-api:$slf4jVersion"
|
api "org.slf4j:slf4j-api:$slf4jVersion"
|
||||||
|
@ -29,7 +27,7 @@ dependencies {
|
||||||
// The ExternalTestSubjectFactory reads json config file to find configured SOP binaries...
|
// The ExternalTestSubjectFactory reads json config file to find configured SOP binaries...
|
||||||
testImplementation "com.google.code.gson:gson:$gsonVersion"
|
testImplementation "com.google.code.gson:gson:$gsonVersion"
|
||||||
// ...and extends TestSubjectFactory
|
// ...and extends TestSubjectFactory
|
||||||
testImplementation(project(":sop-java-testfixtures"))
|
testImplementation(testFixtures(project(":sop-java")))
|
||||||
}
|
}
|
||||||
|
|
||||||
test {
|
test {
|
||||||
|
|
|
@ -16,7 +16,7 @@ import sop.external.operation.*
|
||||||
import sop.operation.*
|
import sop.operation.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of the [SOP] API using an external SOP binary.
|
* Implementation of the {@link SOP} API using an external SOP binary.
|
||||||
*
|
*
|
||||||
* Instantiate an [ExternalSOP] object for the given binary and the given [TempDirProvider] using
|
* Instantiate an [ExternalSOP] object for the given binary and the given [TempDirProvider] using
|
||||||
* empty environment variables.
|
* empty environment variables.
|
||||||
|
@ -69,14 +69,6 @@ class ExternalSOP(
|
||||||
override fun changeKeyPassword(): ChangeKeyPassword =
|
override fun changeKeyPassword(): ChangeKeyPassword =
|
||||||
ChangeKeyPasswordExternal(binaryName, properties)
|
ChangeKeyPasswordExternal(binaryName, properties)
|
||||||
|
|
||||||
override fun updateKey(): UpdateKey = UpdateKeyExternal(binaryName, properties)
|
|
||||||
|
|
||||||
override fun mergeCerts(): MergeCerts = MergeCertsExternal(binaryName, properties)
|
|
||||||
|
|
||||||
override fun certifyUserId(): CertifyUserId = CertifyUserIdExternal(binaryName, properties)
|
|
||||||
|
|
||||||
override fun validateUserId(): ValidateUserId = ValidateUserIdExternal(binaryName, properties)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This interface can be used to provide a directory in which external SOP binaries can
|
* This interface can be used to provide a directory in which external SOP binaries can
|
||||||
* temporarily store additional results of OpenPGP operations such that the binding classes can
|
* temporarily store additional results of OpenPGP operations such that the binding classes can
|
||||||
|
@ -120,9 +112,6 @@ class ExternalSOP(
|
||||||
val errorMessage = readString(errIn)
|
val errorMessage = readString(errIn)
|
||||||
|
|
||||||
when (exitCode) {
|
when (exitCode) {
|
||||||
UnspecificFailure.EXIT_CODE ->
|
|
||||||
throw UnspecificFailure(
|
|
||||||
"External SOP backend reported an unspecific error ($exitCode):\n$errorMessage")
|
|
||||||
NoSignature.EXIT_CODE ->
|
NoSignature.EXIT_CODE ->
|
||||||
throw NoSignature(
|
throw NoSignature(
|
||||||
"External SOP backend reported error NoSignature ($exitCode):\n$errorMessage")
|
"External SOP backend reported error NoSignature ($exitCode):\n$errorMessage")
|
||||||
|
@ -180,21 +169,6 @@ class ExternalSOP(
|
||||||
UnsupportedProfile.EXIT_CODE ->
|
UnsupportedProfile.EXIT_CODE ->
|
||||||
throw UnsupportedProfile(
|
throw UnsupportedProfile(
|
||||||
"External SOP backend reported error UnsupportedProfile ($exitCode):\n$errorMessage")
|
"External SOP backend reported error UnsupportedProfile ($exitCode):\n$errorMessage")
|
||||||
NoHardwareKeyFound.EXIT_CODE ->
|
|
||||||
throw NoHardwareKeyFound(
|
|
||||||
"External SOP backend reported error NoHardwareKeyFound ($exitCode):\n$errorMessage")
|
|
||||||
HardwareKeyFailure.EXIT_CODE ->
|
|
||||||
throw HardwareKeyFailure(
|
|
||||||
"External SOP backend reported error HardwareKeyFailure ($exitCode):\n$errorMessage")
|
|
||||||
PrimaryKeyBad.EXIT_CODE ->
|
|
||||||
throw PrimaryKeyBad(
|
|
||||||
"External SOP backend reported error PrimaryKeyBad ($exitCode):\n$errorMessage")
|
|
||||||
CertUserIdNoMatch.EXIT_CODE ->
|
|
||||||
throw CertUserIdNoMatch(
|
|
||||||
"External SOP backend reported error CertUserIdNoMatch ($exitCode):\n$errorMessage")
|
|
||||||
KeyCannotCertify.EXIT_CODE ->
|
|
||||||
throw KeyCannotCertify(
|
|
||||||
"External SOP backend reported error KeyCannotCertify ($exitCode):\n$errorMessage")
|
|
||||||
|
|
||||||
// Did you forget to add a case for a new exception type?
|
// Did you forget to add a case for a new exception type?
|
||||||
else ->
|
else ->
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: 2024 Paul Schaub <vanitasvitae@fsfe.org>
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package sop.external
|
|
||||||
|
|
||||||
import java.nio.file.Files
|
|
||||||
import java.util.*
|
|
||||||
import sop.SOPV
|
|
||||||
import sop.external.ExternalSOP.TempDirProvider
|
|
||||||
import sop.external.operation.DetachedVerifyExternal
|
|
||||||
import sop.external.operation.InlineVerifyExternal
|
|
||||||
import sop.external.operation.ValidateUserIdExternal
|
|
||||||
import sop.external.operation.VersionExternal
|
|
||||||
import sop.operation.DetachedVerify
|
|
||||||
import sop.operation.InlineVerify
|
|
||||||
import sop.operation.ValidateUserId
|
|
||||||
import sop.operation.Version
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation of the [SOPV] API subset using an external sopv/sop binary.
|
|
||||||
*
|
|
||||||
* Instantiate an [ExternalSOPV] object for the given binary and the given [TempDirProvider] using
|
|
||||||
* empty environment variables.
|
|
||||||
*
|
|
||||||
* @param binaryName name / path of the sopv binary
|
|
||||||
* @param tempDirProvider custom tempDirProvider
|
|
||||||
*/
|
|
||||||
class ExternalSOPV(
|
|
||||||
private val binaryName: String,
|
|
||||||
private val properties: Properties = Properties(),
|
|
||||||
private val tempDirProvider: TempDirProvider = defaultTempDirProvider()
|
|
||||||
) : SOPV {
|
|
||||||
|
|
||||||
override fun version(): Version = VersionExternal(binaryName, properties)
|
|
||||||
|
|
||||||
override fun detachedVerify(): DetachedVerify = DetachedVerifyExternal(binaryName, properties)
|
|
||||||
|
|
||||||
override fun inlineVerify(): InlineVerify =
|
|
||||||
InlineVerifyExternal(binaryName, properties, tempDirProvider)
|
|
||||||
|
|
||||||
override fun validateUserId(): ValidateUserId = ValidateUserIdExternal(binaryName, properties)
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default implementation of the [TempDirProvider] which stores temporary files in the
|
|
||||||
* systems temp dir ([Files.createTempDirectory]).
|
|
||||||
*
|
|
||||||
* @return default implementation
|
|
||||||
*/
|
|
||||||
@JvmStatic
|
|
||||||
fun defaultTempDirProvider(): TempDirProvider {
|
|
||||||
return TempDirProvider { Files.createTempDirectory("ext-sopv").toFile() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,6 +7,7 @@ package sop.external.operation
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.util.Properties
|
import java.util.Properties
|
||||||
import sop.Ready
|
import sop.Ready
|
||||||
|
import sop.enums.ArmorLabel
|
||||||
import sop.exception.SOPGPException
|
import sop.exception.SOPGPException
|
||||||
import sop.external.ExternalSOP
|
import sop.external.ExternalSOP
|
||||||
import sop.operation.Armor
|
import sop.operation.Armor
|
||||||
|
@ -17,6 +18,8 @@ class ArmorExternal(binary: String, environment: Properties) : Armor {
|
||||||
private val commandList: MutableList<String> = mutableListOf(binary, "armor")
|
private val commandList: MutableList<String> = mutableListOf(binary, "armor")
|
||||||
private val envList: List<String> = ExternalSOP.propertiesToEnv(environment)
|
private val envList: List<String> = ExternalSOP.propertiesToEnv(environment)
|
||||||
|
|
||||||
|
override fun label(label: ArmorLabel): Armor = apply { commandList.add("--label=$label") }
|
||||||
|
|
||||||
@Throws(SOPGPException.BadData::class)
|
@Throws(SOPGPException.BadData::class)
|
||||||
override fun data(data: InputStream): Ready =
|
override fun data(data: InputStream): Ready =
|
||||||
ExternalSOP.executeTransformingOperation(Runtime.getRuntime(), commandList, envList, data)
|
ExternalSOP.executeTransformingOperation(Runtime.getRuntime(), commandList, envList, data)
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: 2024 Paul Schaub <vanitasvitae@fsfe.org>
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package sop.external.operation
|
|
||||||
|
|
||||||
import java.io.InputStream
|
|
||||||
import java.util.*
|
|
||||||
import sop.Ready
|
|
||||||
import sop.external.ExternalSOP
|
|
||||||
import sop.operation.CertifyUserId
|
|
||||||
|
|
||||||
class CertifyUserIdExternal(binary: String, environment: Properties) : CertifyUserId {
|
|
||||||
|
|
||||||
private val commandList = mutableListOf(binary, "certify-userid")
|
|
||||||
private val envList = ExternalSOP.propertiesToEnv(environment).toMutableList()
|
|
||||||
|
|
||||||
private var argCount = 0
|
|
||||||
|
|
||||||
private val keys: MutableList<String> = mutableListOf()
|
|
||||||
|
|
||||||
override fun noArmor(): CertifyUserId = apply { commandList.add("--no-armor") }
|
|
||||||
|
|
||||||
override fun userId(userId: String): CertifyUserId = apply {
|
|
||||||
commandList.add("--userid")
|
|
||||||
commandList.add(userId)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun withKeyPassword(password: ByteArray): CertifyUserId = apply {
|
|
||||||
commandList.add("--with-key-password=@ENV:KEY_PASSWORD_$argCount")
|
|
||||||
envList.add("KEY_PASSWORD_$argCount=${String(password)}")
|
|
||||||
argCount += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun noRequireSelfSig(): CertifyUserId = apply {
|
|
||||||
commandList.add("--no-require-self-sig")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun keys(keys: InputStream): CertifyUserId = apply {
|
|
||||||
this.keys.add("@ENV:KEY_$argCount")
|
|
||||||
envList.add("KEY_$argCount=${ExternalSOP.readString(keys)}")
|
|
||||||
argCount += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun certs(certs: InputStream): Ready =
|
|
||||||
ExternalSOP.executeTransformingOperation(
|
|
||||||
Runtime.getRuntime(), commandList.plus("--").plus(keys), envList, certs)
|
|
||||||
}
|
|
|
@ -78,7 +78,7 @@ class DecryptExternal(
|
||||||
val verifyOut = File(tempDir, "verifications-out")
|
val verifyOut = File(tempDir, "verifications-out")
|
||||||
verifyOut.delete()
|
verifyOut.delete()
|
||||||
if (requireVerification) {
|
if (requireVerification) {
|
||||||
commandList.add("--verifications-out=${verifyOut.absolutePath}")
|
commandList.add("--verify-out=${verifyOut.absolutePath}")
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -108,8 +108,8 @@ class DecryptExternal(
|
||||||
finish(process)
|
finish(process)
|
||||||
|
|
||||||
val sessionKeyOutIn = FileInputStream(sessionKeyOut)
|
val sessionKeyOutIn = FileInputStream(sessionKeyOut)
|
||||||
var line: String? = readString(sessionKeyOutIn)
|
var line = readString(sessionKeyOutIn)
|
||||||
val sessionKey = line?.let { l -> SessionKey.fromString(l.trim { it <= ' ' }) }
|
val sessionKey = SessionKey.fromString(line.trim { it <= ' ' })
|
||||||
sessionKeyOutIn.close()
|
sessionKeyOutIn.close()
|
||||||
sessionKeyOut.delete()
|
sessionKeyOut.delete()
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ class DecryptExternal(
|
||||||
val verifyOutIn = FileInputStream(verifyOut)
|
val verifyOutIn = FileInputStream(verifyOut)
|
||||||
val reader = BufferedReader(InputStreamReader(verifyOutIn))
|
val reader = BufferedReader(InputStreamReader(verifyOutIn))
|
||||||
while (reader.readLine().also { line = it } != null) {
|
while (reader.readLine().also { line = it } != null) {
|
||||||
line?.let { verifications.add(Verification.fromString(it.trim())) }
|
verifications.add(Verification.fromString(line.trim()))
|
||||||
}
|
}
|
||||||
reader.close()
|
reader.close()
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,8 +36,8 @@ class EncryptExternal(
|
||||||
override fun mode(mode: EncryptAs): Encrypt = apply { commandList.add("--as=$mode") }
|
override fun mode(mode: EncryptAs): Encrypt = apply { commandList.add("--as=$mode") }
|
||||||
|
|
||||||
override fun signWith(key: InputStream): Encrypt = apply {
|
override fun signWith(key: InputStream): Encrypt = apply {
|
||||||
commandList.add("--sign-with=@ENV:SIGN_WITH_$argCounter")
|
commandList.add("--sign-with@ENV:SIGN_WITH_$argCounter")
|
||||||
envList.add("SIGN_WITH_$argCounter=${readString(key)}")
|
envList.add("SIGN_WITH_$argCounter=${ExternalSOP.readString(key)}")
|
||||||
argCounter += 1
|
argCounter += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: 2024 Paul Schaub <vanitasvitae@fsfe.org>
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package sop.external.operation
|
|
||||||
|
|
||||||
import java.io.InputStream
|
|
||||||
import java.util.*
|
|
||||||
import sop.Ready
|
|
||||||
import sop.external.ExternalSOP
|
|
||||||
import sop.operation.MergeCerts
|
|
||||||
|
|
||||||
class MergeCertsExternal(binary: String, environment: Properties) : MergeCerts {
|
|
||||||
|
|
||||||
private val commandList = mutableListOf(binary, "merge-certs")
|
|
||||||
private val envList = ExternalSOP.propertiesToEnv(environment).toMutableList()
|
|
||||||
|
|
||||||
private var argCount = 0
|
|
||||||
|
|
||||||
override fun noArmor(): MergeCerts = apply { commandList.add("--no-armor") }
|
|
||||||
|
|
||||||
override fun updates(updateCerts: InputStream): MergeCerts = apply {
|
|
||||||
commandList.add("@ENV:CERT_$argCount")
|
|
||||||
envList.add("CERT_$argCount=${ExternalSOP.readString(updateCerts)}")
|
|
||||||
argCount += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun baseCertificates(certs: InputStream): Ready =
|
|
||||||
ExternalSOP.executeTransformingOperation(Runtime.getRuntime(), commandList, envList, certs)
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: 2024 Paul Schaub <vanitasvitae@fsfe.org>
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package sop.external.operation
|
|
||||||
|
|
||||||
import java.io.InputStream
|
|
||||||
import java.util.*
|
|
||||||
import sop.Ready
|
|
||||||
import sop.external.ExternalSOP
|
|
||||||
import sop.operation.UpdateKey
|
|
||||||
|
|
||||||
class UpdateKeyExternal(binary: String, environment: Properties) : UpdateKey {
|
|
||||||
|
|
||||||
private val commandList = mutableListOf(binary, "update-key")
|
|
||||||
private val envList = ExternalSOP.propertiesToEnv(environment).toMutableList()
|
|
||||||
|
|
||||||
private var argCount = 0
|
|
||||||
|
|
||||||
override fun noArmor(): UpdateKey = apply { commandList.add("--no-armor") }
|
|
||||||
|
|
||||||
override fun signingOnly(): UpdateKey = apply { commandList.add("--signing-only") }
|
|
||||||
|
|
||||||
override fun noAddedCapabilities(): UpdateKey = apply {
|
|
||||||
commandList.add("--no-added-capabilities")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun withKeyPassword(password: ByteArray): UpdateKey = apply {
|
|
||||||
commandList.add("--with-key-password=@ENV:KEY_PASSWORD_$argCount")
|
|
||||||
envList.add("KEY_PASSWORD_$argCount=${String(password)}")
|
|
||||||
argCount += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun mergeCerts(certs: InputStream): UpdateKey = apply {
|
|
||||||
commandList.add("--merge-certs")
|
|
||||||
commandList.add("@ENV:CERT_$argCount")
|
|
||||||
envList.add("CERT_$argCount=${ExternalSOP.readString(certs)}")
|
|
||||||
argCount += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun key(key: InputStream): Ready =
|
|
||||||
ExternalSOP.executeTransformingOperation(Runtime.getRuntime(), commandList, envList, key)
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: 2024 Paul Schaub <vanitasvitae@fsfe.org>
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package sop.external.operation
|
|
||||||
|
|
||||||
import java.io.InputStream
|
|
||||||
import java.util.*
|
|
||||||
import sop.external.ExternalSOP
|
|
||||||
import sop.operation.ValidateUserId
|
|
||||||
import sop.util.UTCUtil
|
|
||||||
|
|
||||||
class ValidateUserIdExternal(binary: String, environment: Properties) : ValidateUserId {
|
|
||||||
|
|
||||||
private val commandList = mutableListOf(binary, "validate-userid")
|
|
||||||
private val envList = ExternalSOP.propertiesToEnv(environment).toMutableList()
|
|
||||||
|
|
||||||
private var argCount = 0
|
|
||||||
|
|
||||||
private var userId: String? = null
|
|
||||||
private val authorities: MutableList<String> = mutableListOf()
|
|
||||||
|
|
||||||
override fun addrSpecOnly(): ValidateUserId = apply { commandList.add("--addr-spec-only") }
|
|
||||||
|
|
||||||
override fun userId(userId: String): ValidateUserId = apply { this.userId = userId }
|
|
||||||
|
|
||||||
override fun authorities(certs: InputStream): ValidateUserId = apply {
|
|
||||||
this.authorities.add("@ENV:CERT_$argCount")
|
|
||||||
envList.add("CERT_$argCount=${ExternalSOP.readString(certs)}")
|
|
||||||
argCount += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun subjects(certs: InputStream): Boolean {
|
|
||||||
ExternalSOP.executeTransformingOperation(
|
|
||||||
Runtime.getRuntime(), commandList.plus(userId!!).plus(authorities), envList, certs)
|
|
||||||
.bytes
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun validateAt(date: Date): ValidateUserId = apply {
|
|
||||||
commandList.add("--validate-at=${UTCUtil.formatUTCDate(date)}")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -68,10 +68,6 @@ class VersionExternal(binary: String, environment: Properties) : Version {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getSopVVersion(): String {
|
|
||||||
return executeForLines(commandList.plus("--sopv"))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getSopSpecVersion(): String {
|
override fun getSopSpecVersion(): String {
|
||||||
return executeForLines(commandList.plus("--sop-spec"))
|
return executeForLines(commandList.plus("--sop-spec"))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: 2025 Paul Schaub <vanitasvitae@fsfe.org>
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package sop.testsuite.external;
|
|
||||||
|
|
||||||
import org.junit.platform.suite.api.IncludeClassNamePatterns;
|
|
||||||
import org.junit.platform.suite.api.SelectPackages;
|
|
||||||
import org.junit.platform.suite.api.Suite;
|
|
||||||
import org.junit.platform.suite.api.SuiteDisplayName;
|
|
||||||
|
|
||||||
@Suite
|
|
||||||
@SuiteDisplayName("External SOP Tests")
|
|
||||||
@SelectPackages("sop.testsuite.operation")
|
|
||||||
@IncludeClassNamePatterns(".*Test")
|
|
||||||
public class ExternalTestSuite {
|
|
||||||
|
|
||||||
}
|
|
13
external-sop/src/test/java/sop/testsuite/external/operation/ExternalArmorDearmorTest.java
vendored
Normal file
13
external-sop/src/test/java/sop/testsuite/external/operation/ExternalArmorDearmorTest.java
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package sop.testsuite.external.operation;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.condition.EnabledIf;
|
||||||
|
import sop.testsuite.operation.ArmorDearmorTest;
|
||||||
|
|
||||||
|
@EnabledIf("sop.testsuite.operation.AbstractSOPTest#hasBackends")
|
||||||
|
public class ExternalArmorDearmorTest extends ArmorDearmorTest {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package sop.testsuite.external.operation;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.condition.EnabledIf;
|
||||||
|
import sop.testsuite.operation.DecryptWithSessionKeyTest;
|
||||||
|
|
||||||
|
@EnabledIf("sop.testsuite.operation.AbstractSOPTest#hasBackends")
|
||||||
|
public class ExternalDecryptWithSessionKeyTest extends DecryptWithSessionKeyTest {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package sop.testsuite.external.operation;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.condition.EnabledIf;
|
||||||
|
import sop.testsuite.operation.DetachedSignDetachedVerifyTest;
|
||||||
|
|
||||||
|
@EnabledIf("sop.testsuite.operation.AbstractSOPTest#hasBackends")
|
||||||
|
public class ExternalDetachedSignDetachedVerifyTest extends DetachedSignDetachedVerifyTest {
|
||||||
|
}
|
13
external-sop/src/test/java/sop/testsuite/external/operation/ExternalEncryptDecryptTest.java
vendored
Normal file
13
external-sop/src/test/java/sop/testsuite/external/operation/ExternalEncryptDecryptTest.java
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package sop.testsuite.external.operation;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.condition.EnabledIf;
|
||||||
|
import sop.testsuite.operation.EncryptDecryptTest;
|
||||||
|
|
||||||
|
@EnabledIf("sop.testsuite.operation.AbstractSOPTest#hasBackends")
|
||||||
|
public class ExternalEncryptDecryptTest extends EncryptDecryptTest {
|
||||||
|
|
||||||
|
}
|
13
external-sop/src/test/java/sop/testsuite/external/operation/ExternalExtractCertTest.java
vendored
Normal file
13
external-sop/src/test/java/sop/testsuite/external/operation/ExternalExtractCertTest.java
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package sop.testsuite.external.operation;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.condition.EnabledIf;
|
||||||
|
import sop.testsuite.operation.ExtractCertTest;
|
||||||
|
|
||||||
|
@EnabledIf("sop.testsuite.operation.AbstractSOPTest#hasBackends")
|
||||||
|
public class ExternalExtractCertTest extends ExtractCertTest {
|
||||||
|
|
||||||
|
}
|
13
external-sop/src/test/java/sop/testsuite/external/operation/ExternalGenerateKeyTest.java
vendored
Normal file
13
external-sop/src/test/java/sop/testsuite/external/operation/ExternalGenerateKeyTest.java
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package sop.testsuite.external.operation;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.condition.EnabledIf;
|
||||||
|
import sop.testsuite.operation.GenerateKeyTest;
|
||||||
|
|
||||||
|
@EnabledIf("sop.testsuite.operation.AbstractSOPTest#hasBackends")
|
||||||
|
public class ExternalGenerateKeyTest extends GenerateKeyTest {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package sop.testsuite.external.operation;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.condition.EnabledIf;
|
||||||
|
import sop.testsuite.operation.InlineSignInlineDetachDetachedVerifyTest;
|
||||||
|
|
||||||
|
@EnabledIf("sop.testsuite.operation.AbstractSOPTest#hasBackends")
|
||||||
|
public class ExternalInlineSignInlineDetachDetachedVerifyTest
|
||||||
|
extends InlineSignInlineDetachDetachedVerifyTest {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package sop.testsuite.external.operation;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.condition.EnabledIf;
|
||||||
|
import sop.testsuite.operation.InlineSignInlineVerifyTest;
|
||||||
|
|
||||||
|
@EnabledIf("sop.testsuite.operation.AbstractSOPTest#hasBackends")
|
||||||
|
public class ExternalInlineSignInlineVerifyTest extends InlineSignInlineVerifyTest {
|
||||||
|
|
||||||
|
}
|
13
external-sop/src/test/java/sop/testsuite/external/operation/ExternalListProfilesTest.java
vendored
Normal file
13
external-sop/src/test/java/sop/testsuite/external/operation/ExternalListProfilesTest.java
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package sop.testsuite.external.operation;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.condition.EnabledIf;
|
||||||
|
import sop.testsuite.operation.ListProfilesTest;
|
||||||
|
|
||||||
|
@EnabledIf("sop.testsuite.operation.AbstractSOPTest#hasBackends")
|
||||||
|
public class ExternalListProfilesTest extends ListProfilesTest {
|
||||||
|
|
||||||
|
}
|
13
external-sop/src/test/java/sop/testsuite/external/operation/ExternalRevokeKeyTest.java
vendored
Normal file
13
external-sop/src/test/java/sop/testsuite/external/operation/ExternalRevokeKeyTest.java
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package sop.testsuite.external.operation;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.condition.EnabledIf;
|
||||||
|
import sop.testsuite.operation.RevokeKeyTest;
|
||||||
|
|
||||||
|
@EnabledIf("sop.testsuite.operation.AbstractSOPTest#hasBackends")
|
||||||
|
public class ExternalRevokeKeyTest extends RevokeKeyTest {
|
||||||
|
|
||||||
|
}
|
13
external-sop/src/test/java/sop/testsuite/external/operation/ExternalVersionTest.java
vendored
Normal file
13
external-sop/src/test/java/sop/testsuite/external/operation/ExternalVersionTest.java
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package sop.testsuite.external.operation;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.condition.EnabledIf;
|
||||||
|
import sop.testsuite.operation.VersionTest;
|
||||||
|
|
||||||
|
@EnabledIf("sop.testsuite.operation.AbstractSOPTest#hasBackends")
|
||||||
|
public class ExternalVersionTest extends VersionTest {
|
||||||
|
|
||||||
|
}
|
|
@ -6,7 +6,5 @@ rootProject.name = 'SOP-Java'
|
||||||
|
|
||||||
include 'sop-java',
|
include 'sop-java',
|
||||||
'sop-java-picocli',
|
'sop-java-picocli',
|
||||||
'sop-java-testfixtures',
|
'external-sop'
|
||||||
'external-sop',
|
|
||||||
'sop-java-json-gson'
|
|
||||||
|
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
<!--
|
|
||||||
SPDX-FileCopyrightText: 2025 Paul Schaub <vanitasvitae@fsfe.org>
|
|
||||||
|
|
||||||
SPDX-License-Identifier: Apache-2.0
|
|
||||||
-->
|
|
||||||
|
|
||||||
# SOP-Java-JSON-GSON
|
|
||||||
|
|
||||||
## JSON Parsing VERIFICATION extension JSON using Gson
|
|
||||||
|
|
||||||
Since revision 11, the SOP specification defines VERIFICATIONS extension JSON.
|
|
||||||
|
|
||||||
This module implements the `JSONParser` and `JSONSerializer` interfaces using Googles Gson library.
|
|
|
@ -1,28 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: 2025 Paul Schaub <vanitasvitae@fsfe.org>
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
plugins {
|
|
||||||
id 'java-library'
|
|
||||||
}
|
|
||||||
|
|
||||||
group 'org.pgpainless'
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation "org.junit.jupiter:junit-jupiter-api:$junitVersion"
|
|
||||||
implementation "org.junit.jupiter:junit-jupiter-params:$junitVersion"
|
|
||||||
runtimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitVersion"
|
|
||||||
|
|
||||||
implementation project(":sop-java")
|
|
||||||
api "org.slf4j:slf4j-api:$slf4jVersion"
|
|
||||||
testImplementation "ch.qos.logback:logback-classic:$logbackVersion"
|
|
||||||
|
|
||||||
// @Nonnull, @Nullable...
|
|
||||||
implementation "com.google.code.findbugs:jsr305:$jsrVersion"
|
|
||||||
|
|
||||||
api "com.google.code.gson:gson:$gsonVersion"
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: 2025 Paul Schaub <vanitasvitae@fsfe.org>
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package sop
|
|
||||||
|
|
||||||
import com.google.gson.Gson
|
|
||||||
import com.google.gson.JsonSyntaxException
|
|
||||||
import com.google.gson.reflect.TypeToken
|
|
||||||
import java.text.ParseException
|
|
||||||
|
|
||||||
class GsonParser(
|
|
||||||
private val gson: Gson = Gson()
|
|
||||||
) : Verification.JSONParser {
|
|
||||||
|
|
||||||
override fun parse(string: String): Verification.JSON {
|
|
||||||
try {
|
|
||||||
return gson.fromJson(string, object : TypeToken<Verification.JSON>(){}.type)
|
|
||||||
} catch (e: JsonSyntaxException) {
|
|
||||||
throw ParseException(e.message, 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: 2025 Paul Schaub <vanitasvitae@fsfe.org>
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package sop
|
|
||||||
|
|
||||||
import com.google.gson.Gson
|
|
||||||
|
|
||||||
class GsonSerializer(
|
|
||||||
private val gson: Gson = Gson()
|
|
||||||
) : Verification.JSONSerializer {
|
|
||||||
|
|
||||||
override fun serialize(json: Verification.JSON): String {
|
|
||||||
return gson.toJson(json)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,96 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: 2025 Paul Schaub <vanitasvitae@fsfe.org>
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package sop
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Assertions.assertEquals
|
|
||||||
import org.junit.jupiter.api.Test
|
|
||||||
import org.junit.jupiter.api.assertThrows
|
|
||||||
import java.text.ParseException
|
|
||||||
|
|
||||||
class GsonSerializerAndParserTest {
|
|
||||||
|
|
||||||
private val serializer: GsonSerializer = GsonSerializer()
|
|
||||||
private val parser: GsonParser = GsonParser()
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun simpleSingleTest() {
|
|
||||||
val before = Verification.JSON("/tmp/alice.pgp")
|
|
||||||
|
|
||||||
val json = serializer.serialize(before)
|
|
||||||
assertEquals("{\"signers\":[\"/tmp/alice.pgp\"]}", json)
|
|
||||||
|
|
||||||
val after = parser.parse(json)
|
|
||||||
|
|
||||||
assertEquals(before, after)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun simpleListTest() {
|
|
||||||
val before = Verification.JSON(listOf("/tmp/alice.pgp", "/tmp/bob.asc"))
|
|
||||||
|
|
||||||
val json = serializer.serialize(before)
|
|
||||||
assertEquals("{\"signers\":[\"/tmp/alice.pgp\",\"/tmp/bob.asc\"]}", json)
|
|
||||||
|
|
||||||
val after = parser.parse(json)
|
|
||||||
|
|
||||||
assertEquals(before, after)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun withCommentTest() {
|
|
||||||
val before = Verification.JSON(
|
|
||||||
listOf("/tmp/alice.pgp"),
|
|
||||||
"This is a comment.",
|
|
||||||
null)
|
|
||||||
|
|
||||||
val json = serializer.serialize(before)
|
|
||||||
assertEquals("{\"signers\":[\"/tmp/alice.pgp\"],\"comment\":\"This is a comment.\"}", json)
|
|
||||||
|
|
||||||
val after = parser.parse(json)
|
|
||||||
|
|
||||||
assertEquals(before, after)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun withExtStringTest() {
|
|
||||||
val before = Verification.JSON(
|
|
||||||
listOf("/tmp/alice.pgp"),
|
|
||||||
"This is a comment.",
|
|
||||||
"This is an ext object string.")
|
|
||||||
|
|
||||||
val json = serializer.serialize(before)
|
|
||||||
assertEquals("{\"signers\":[\"/tmp/alice.pgp\"],\"comment\":\"This is a comment.\",\"ext\":\"This is an ext object string.\"}", json)
|
|
||||||
|
|
||||||
val after = parser.parse(json)
|
|
||||||
|
|
||||||
assertEquals(before, after)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun withExtListTest() {
|
|
||||||
val before = Verification.JSON(
|
|
||||||
listOf("/tmp/alice.pgp"),
|
|
||||||
"This is a comment.",
|
|
||||||
listOf(1.0,2.0,3.0))
|
|
||||||
|
|
||||||
val json = serializer.serialize(before)
|
|
||||||
assertEquals("{\"signers\":[\"/tmp/alice.pgp\"],\"comment\":\"This is a comment.\",\"ext\":[1.0,2.0,3.0]}", json)
|
|
||||||
|
|
||||||
val after = parser.parse(json)
|
|
||||||
|
|
||||||
assertEquals(before, after)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun parseInvalidJSON() {
|
|
||||||
assertThrows<ParseException> { parser.parse("Invalid") }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun parseMalformedJSON() {
|
|
||||||
// Missing '}'
|
|
||||||
assertThrows<ParseException> { parser.parse("{\"signers\":[\"Alice\"]") }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -12,16 +12,19 @@ dependencies {
|
||||||
testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion"
|
testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion"
|
||||||
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitVersion"
|
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitVersion"
|
||||||
|
|
||||||
|
// Testing Exit Codes in JUnit
|
||||||
|
// https://todd.ginsberg.com/post/testing-system-exit/
|
||||||
|
testImplementation "com.ginsberg:junit5-system-exit:$junitSysExitVersion"
|
||||||
|
|
||||||
// Mocking Components
|
// Mocking Components
|
||||||
testImplementation "org.mockito:mockito-core:$mockitoVersion"
|
testImplementation "org.mockito:mockito-core:$mockitoVersion"
|
||||||
|
|
||||||
// SOP
|
// SOP
|
||||||
implementation(project(":sop-java"))
|
implementation(project(":sop-java"))
|
||||||
testImplementation(project(":sop-java-testfixtures"))
|
|
||||||
|
|
||||||
// CLI
|
// CLI
|
||||||
implementation "info.picocli:picocli:$picocliVersion"
|
implementation "info.picocli:picocli:$picocliVersion"
|
||||||
kapt "info.picocli:picocli-codegen:$picocliVersion"
|
annotationProcessor "info.picocli:picocli-codegen:$picocliVersion"
|
||||||
|
|
||||||
// @Nonnull, @Nullable...
|
// @Nonnull, @Nullable...
|
||||||
implementation "com.google.code.findbugs:jsr305:$jsrVersion"
|
implementation "com.google.code.findbugs:jsr305:$jsrVersion"
|
||||||
|
@ -33,10 +36,6 @@ application {
|
||||||
mainClass = mainClassName
|
mainClass = mainClassName
|
||||||
}
|
}
|
||||||
|
|
||||||
compileJava {
|
|
||||||
options.compilerArgs += ["-Aproject=${project.group}/${project.name}"]
|
|
||||||
}
|
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
dependsOn(":sop-java:jar")
|
dependsOn(":sop-java:jar")
|
||||||
duplicatesStrategy(DuplicatesStrategy.EXCLUDE)
|
duplicatesStrategy(DuplicatesStrategy.EXCLUDE)
|
||||||
|
|
|
@ -21,8 +21,6 @@ class SOPExceptionExitCodeMapper : IExitCodeExceptionMapper {
|
||||||
// Unmatched subcommand
|
// Unmatched subcommand
|
||||||
SOPGPException.UnsupportedSubcommand.EXIT_CODE
|
SOPGPException.UnsupportedSubcommand.EXIT_CODE
|
||||||
}
|
}
|
||||||
} else if (exception is MissingParameterException) {
|
|
||||||
SOPGPException.MissingArg.EXIT_CODE
|
|
||||||
} else if (exception is ParameterException) {
|
} else if (exception is ParameterException) {
|
||||||
// Invalid option (e.g. `--as invalid`)
|
// Invalid option (e.g. `--as invalid`)
|
||||||
SOPGPException.UnsupportedOption.EXIT_CODE
|
SOPGPException.UnsupportedOption.EXIT_CODE
|
||||||
|
|
|
@ -27,10 +27,6 @@ import sop.exception.SOPGPException
|
||||||
ChangeKeyPasswordCmd::class,
|
ChangeKeyPasswordCmd::class,
|
||||||
RevokeKeyCmd::class,
|
RevokeKeyCmd::class,
|
||||||
ExtractCertCmd::class,
|
ExtractCertCmd::class,
|
||||||
UpdateKeyCmd::class,
|
|
||||||
MergeCertsCmd::class,
|
|
||||||
CertifyUserIdCmd::class,
|
|
||||||
ValidateUserIdCmd::class,
|
|
||||||
// Messaging subcommands
|
// Messaging subcommands
|
||||||
SignCmd::class,
|
SignCmd::class,
|
||||||
VerifyCmd::class,
|
VerifyCmd::class,
|
||||||
|
@ -64,7 +60,7 @@ class SopCLI {
|
||||||
@JvmField var EXECUTABLE_NAME = "sop"
|
@JvmField var EXECUTABLE_NAME = "sop"
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
@Option(names = ["--stacktrace", "--debug"], scope = ScopeType.INHERIT)
|
@Option(names = ["--stacktrace"], scope = CommandLine.ScopeType.INHERIT)
|
||||||
var stacktrace = false
|
var stacktrace = false
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
|
@ -78,21 +74,17 @@ class SopCLI {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun execute(vararg args: String): Int {
|
fun execute(vararg args: String): Int {
|
||||||
// Set locale
|
// Set locale
|
||||||
CommandLine(InitLocale()).setUnmatchedArgumentsAllowed(true).parseArgs(*args)
|
CommandLine(InitLocale()).parseArgs(*args)
|
||||||
|
|
||||||
// Re-set bundle with updated locale
|
// Re-set bundle with updated locale
|
||||||
cliMsg = ResourceBundle.getBundle("msg_sop")
|
cliMsg = ResourceBundle.getBundle("msg_sop")
|
||||||
|
|
||||||
return CommandLine(SopCLI::class.java)
|
return CommandLine(SopCLI::class.java)
|
||||||
.apply {
|
.apply {
|
||||||
|
// explicitly set help command resource bundle
|
||||||
|
subcommands["help"]?.setResourceBundle(ResourceBundle.getBundle("msg_help"))
|
||||||
// Hide generate-completion command
|
// Hide generate-completion command
|
||||||
subcommands["generate-completion"]?.commandSpec?.usageMessage()?.hidden(true)
|
subcommands["generate-completion"]?.commandSpec?.usageMessage()?.hidden(true)
|
||||||
// render Input/Output sections in help command
|
|
||||||
subcommands.values
|
|
||||||
.filter {
|
|
||||||
(it.getCommand() as Any) is AbstractSopCmd
|
|
||||||
} // Only for AbstractSopCmd objects
|
|
||||||
.forEach { (it.getCommand() as AbstractSopCmd).installIORenderer(it) }
|
|
||||||
// overwrite executable name
|
// overwrite executable name
|
||||||
commandName = EXECUTABLE_NAME
|
commandName = EXECUTABLE_NAME
|
||||||
// setup exception handling
|
// setup exception handling
|
||||||
|
|
|
@ -1,99 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: 2024 Paul Schaub <vanitasvitae@fsfe.org>
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package sop.cli.picocli
|
|
||||||
|
|
||||||
import java.util.*
|
|
||||||
import kotlin.system.exitProcess
|
|
||||||
import picocli.AutoComplete
|
|
||||||
import picocli.CommandLine
|
|
||||||
import sop.SOPV
|
|
||||||
import sop.cli.picocli.commands.*
|
|
||||||
import sop.exception.SOPGPException
|
|
||||||
|
|
||||||
@CommandLine.Command(
|
|
||||||
name = "sopv",
|
|
||||||
resourceBundle = "msg_sop",
|
|
||||||
exitCodeOnInvalidInput = SOPGPException.UnsupportedSubcommand.EXIT_CODE,
|
|
||||||
subcommands =
|
|
||||||
[
|
|
||||||
// Meta subcommands
|
|
||||||
VersionCmd::class,
|
|
||||||
// signature verification subcommands
|
|
||||||
VerifyCmd::class,
|
|
||||||
InlineVerifyCmd::class,
|
|
||||||
// misc
|
|
||||||
CommandLine.HelpCommand::class,
|
|
||||||
AutoComplete.GenerateCompletion::class])
|
|
||||||
class SopVCLI {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
@JvmStatic private var sopvInstance: SOPV? = null
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun getSopV(): SOPV =
|
|
||||||
checkNotNull(sopvInstance) { cliMsg.getString("sop.error.runtime.no_backend_set") }
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun setSopVInstance(sopv: SOPV?) {
|
|
||||||
sopvInstance = sopv
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmField var cliMsg: ResourceBundle = ResourceBundle.getBundle("msg_sop")
|
|
||||||
|
|
||||||
@JvmField var EXECUTABLE_NAME = "sopv"
|
|
||||||
|
|
||||||
@JvmField
|
|
||||||
@CommandLine.Option(
|
|
||||||
names = ["--stacktrace", "--debug"], scope = CommandLine.ScopeType.INHERIT)
|
|
||||||
var stacktrace = false
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun main(vararg args: String) {
|
|
||||||
val exitCode = execute(*args)
|
|
||||||
if (exitCode != 0) {
|
|
||||||
exitProcess(exitCode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun execute(vararg args: String): Int {
|
|
||||||
// Set locale
|
|
||||||
CommandLine(InitLocale()).parseArgs(*args)
|
|
||||||
|
|
||||||
// Re-set bundle with updated locale
|
|
||||||
cliMsg = ResourceBundle.getBundle("msg_sop")
|
|
||||||
|
|
||||||
return CommandLine(SopVCLI::class.java)
|
|
||||||
.apply {
|
|
||||||
// explicitly set help command resource bundle
|
|
||||||
subcommands["help"]?.setResourceBundle(ResourceBundle.getBundle("msg_help"))
|
|
||||||
// Hide generate-completion command
|
|
||||||
subcommands["generate-completion"]?.commandSpec?.usageMessage()?.hidden(true)
|
|
||||||
// overwrite executable name
|
|
||||||
commandName = EXECUTABLE_NAME
|
|
||||||
// setup exception handling
|
|
||||||
executionExceptionHandler = SOPExecutionExceptionHandler()
|
|
||||||
exitCodeExceptionMapper = SOPExceptionExitCodeMapper()
|
|
||||||
isCaseInsensitiveEnumValuesAllowed = true
|
|
||||||
}
|
|
||||||
.execute(*args)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Control the locale.
|
|
||||||
*
|
|
||||||
* @see <a href="https://picocli.info/#_controlling_the_locale">Picocli Readme</a>
|
|
||||||
*/
|
|
||||||
@CommandLine.Command
|
|
||||||
class InitLocale {
|
|
||||||
@CommandLine.Option(names = ["-l", "--locale"], descriptionKey = "sop.locale")
|
|
||||||
fun setLocale(locale: String) = Locale.setDefault(Locale(locale))
|
|
||||||
|
|
||||||
@CommandLine.Unmatched
|
|
||||||
var remainder: MutableList<String> =
|
|
||||||
mutableListOf() // ignore any other parameters and options in the first parsing phase
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,11 +7,6 @@ package sop.cli.picocli.commands
|
||||||
import java.io.*
|
import java.io.*
|
||||||
import java.text.ParseException
|
import java.text.ParseException
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import picocli.CommandLine
|
|
||||||
import picocli.CommandLine.Help
|
|
||||||
import picocli.CommandLine.Help.Column
|
|
||||||
import picocli.CommandLine.Help.TextTable
|
|
||||||
import picocli.CommandLine.IHelpSectionRenderer
|
|
||||||
import sop.cli.picocli.commands.AbstractSopCmd.EnvironmentVariableResolver
|
import sop.cli.picocli.commands.AbstractSopCmd.EnvironmentVariableResolver
|
||||||
import sop.exception.SOPGPException.*
|
import sop.exception.SOPGPException.*
|
||||||
import sop.util.UTCUtil.Companion.parseUTCDate
|
import sop.util.UTCUtil.Companion.parseUTCDate
|
||||||
|
@ -220,106 +215,11 @@ abstract class AbstractSopCmd(locale: Locale = Locale.getDefault()) : Runnable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* See
|
|
||||||
* [Example](https://github.com/remkop/picocli/blob/main/picocli-examples/src/main/java/picocli/examples/customhelp/EnvironmentVariablesSection.java)
|
|
||||||
*/
|
|
||||||
class InputOutputHelpSectionRenderer(private val argument: Pair<String?, String?>) :
|
|
||||||
IHelpSectionRenderer {
|
|
||||||
|
|
||||||
override fun render(help: Help): String {
|
|
||||||
return argument.let {
|
|
||||||
val calcLen =
|
|
||||||
help.calcLongOptionColumnWidth(
|
|
||||||
help.commandSpec().options(),
|
|
||||||
help.commandSpec().positionalParameters(),
|
|
||||||
help.colorScheme())
|
|
||||||
val keyLength =
|
|
||||||
help
|
|
||||||
.commandSpec()
|
|
||||||
.usageMessage()
|
|
||||||
.longOptionsMaxWidth()
|
|
||||||
.coerceAtMost(calcLen - 1)
|
|
||||||
val table =
|
|
||||||
TextTable.forColumns(
|
|
||||||
help.colorScheme(),
|
|
||||||
Column(keyLength + 7, 6, Column.Overflow.SPAN),
|
|
||||||
Column(width(help) - (keyLength + 7), 0, Column.Overflow.WRAP))
|
|
||||||
table.setAdjustLineBreaksForWideCJKCharacters(adjustCJK(help))
|
|
||||||
table.addRowValues("@|yellow ${argument.first}|@", argument.second ?: "")
|
|
||||||
table.toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun adjustCJK(help: Help) =
|
|
||||||
help.commandSpec().usageMessage().adjustLineBreaksForWideCJKCharacters()
|
|
||||||
|
|
||||||
private fun width(help: Help) = help.commandSpec().usageMessage().width()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun installIORenderer(cmd: CommandLine) {
|
|
||||||
val inputName = getResString(cmd, "standardInput")
|
|
||||||
if (inputName != null) {
|
|
||||||
cmd.helpSectionMap[SECTION_KEY_STANDARD_INPUT_HEADING] = IHelpSectionRenderer {
|
|
||||||
getResString(cmd, "standardInputHeading")
|
|
||||||
}
|
|
||||||
cmd.helpSectionMap[SECTION_KEY_STANDARD_INPUT_DETAILS] =
|
|
||||||
InputOutputHelpSectionRenderer(
|
|
||||||
inputName to getResString(cmd, "standardInputDescription"))
|
|
||||||
cmd.helpSectionKeys =
|
|
||||||
insertKey(
|
|
||||||
cmd.helpSectionKeys,
|
|
||||||
SECTION_KEY_STANDARD_INPUT_HEADING,
|
|
||||||
SECTION_KEY_STANDARD_INPUT_DETAILS)
|
|
||||||
}
|
|
||||||
|
|
||||||
val outputName = getResString(cmd, "standardOutput")
|
|
||||||
if (outputName != null) {
|
|
||||||
cmd.helpSectionMap[SECTION_KEY_STANDARD_OUTPUT_HEADING] = IHelpSectionRenderer {
|
|
||||||
getResString(cmd, "standardOutputHeading")
|
|
||||||
}
|
|
||||||
cmd.helpSectionMap[SECTION_KEY_STANDARD_OUTPUT_DETAILS] =
|
|
||||||
InputOutputHelpSectionRenderer(
|
|
||||||
outputName to getResString(cmd, "standardOutputDescription"))
|
|
||||||
cmd.helpSectionKeys =
|
|
||||||
insertKey(
|
|
||||||
cmd.helpSectionKeys,
|
|
||||||
SECTION_KEY_STANDARD_OUTPUT_HEADING,
|
|
||||||
SECTION_KEY_STANDARD_OUTPUT_DETAILS)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun insertKey(keys: List<String>, header: String, details: String): List<String> {
|
|
||||||
val index =
|
|
||||||
keys.indexOf(CommandLine.Model.UsageMessageSpec.SECTION_KEY_EXIT_CODE_LIST_HEADING)
|
|
||||||
val result = keys.toMutableList()
|
|
||||||
result.add(index, header)
|
|
||||||
result.add(index + 1, details)
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getResString(cmd: CommandLine, key: String): String? =
|
|
||||||
try {
|
|
||||||
cmd.resourceBundle.getString(key)
|
|
||||||
} catch (m: MissingResourceException) {
|
|
||||||
try {
|
|
||||||
cmd.parent.resourceBundle.getString(key)
|
|
||||||
} catch (m: MissingResourceException) {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?.let { String.format(it) }
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val PRFX_ENV = "@ENV:"
|
const val PRFX_ENV = "@ENV:"
|
||||||
|
|
||||||
const val PRFX_FD = "@FD:"
|
const val PRFX_FD = "@FD:"
|
||||||
|
|
||||||
const val SECTION_KEY_STANDARD_INPUT_HEADING = "standardInputHeading"
|
|
||||||
const val SECTION_KEY_STANDARD_INPUT_DETAILS = "standardInput"
|
|
||||||
const val SECTION_KEY_STANDARD_OUTPUT_HEADING = "standardOutputHeading"
|
|
||||||
const val SECTION_KEY_STANDARD_OUTPUT_DETAILS = "standardOutput"
|
|
||||||
|
|
||||||
@JvmField val DAWN_OF_TIME = Date(0)
|
@JvmField val DAWN_OF_TIME = Date(0)
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
|
|
|
@ -1,84 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: 2024 Paul Schaub <vanitasvitae@fsfe.org>
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package sop.cli.picocli.commands
|
|
||||||
|
|
||||||
import java.io.IOException
|
|
||||||
import picocli.CommandLine.Command
|
|
||||||
import picocli.CommandLine.Option
|
|
||||||
import picocli.CommandLine.Parameters
|
|
||||||
import sop.cli.picocli.SopCLI
|
|
||||||
import sop.exception.SOPGPException.BadData
|
|
||||||
import sop.exception.SOPGPException.UnsupportedOption
|
|
||||||
|
|
||||||
@Command(
|
|
||||||
name = "certify-userid",
|
|
||||||
resourceBundle = "msg_certify-userid",
|
|
||||||
exitCodeOnInvalidInput = UnsupportedOption.EXIT_CODE,
|
|
||||||
showEndOfOptionsDelimiterInUsageHelp = true)
|
|
||||||
class CertifyUserIdCmd : AbstractSopCmd() {
|
|
||||||
|
|
||||||
@Option(names = ["--no-armor"], negatable = true) var armor = true
|
|
||||||
|
|
||||||
@Option(names = ["--userid"], required = true, arity = "1..*", paramLabel = "USERID")
|
|
||||||
var userIds: List<String> = listOf()
|
|
||||||
|
|
||||||
@Option(names = ["--with-key-password"], paramLabel = "PASSWORD")
|
|
||||||
var withKeyPassword: List<String> = listOf()
|
|
||||||
|
|
||||||
@Option(names = ["--no-require-self-sig"]) var noRequireSelfSig = false
|
|
||||||
|
|
||||||
@Parameters(paramLabel = "KEYS", arity = "1..*") var keys: List<String> = listOf()
|
|
||||||
|
|
||||||
override fun run() {
|
|
||||||
val certifyUserId =
|
|
||||||
throwIfUnsupportedSubcommand(SopCLI.getSop().certifyUserId(), "certify-userid")
|
|
||||||
|
|
||||||
if (!armor) {
|
|
||||||
certifyUserId.noArmor()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (noRequireSelfSig) {
|
|
||||||
certifyUserId.noRequireSelfSig()
|
|
||||||
}
|
|
||||||
|
|
||||||
for (userId in userIds) {
|
|
||||||
certifyUserId.userId(userId)
|
|
||||||
}
|
|
||||||
|
|
||||||
for (passwordFileName in withKeyPassword) {
|
|
||||||
try {
|
|
||||||
val password = stringFromInputStream(getInput(passwordFileName))
|
|
||||||
certifyUserId.withKeyPassword(password)
|
|
||||||
} catch (unsupportedOption: UnsupportedOption) {
|
|
||||||
val errorMsg =
|
|
||||||
getMsg("sop.error.feature_support.option_not_supported", "--with-key-password")
|
|
||||||
throw UnsupportedOption(errorMsg, unsupportedOption)
|
|
||||||
} catch (e: IOException) {
|
|
||||||
throw RuntimeException(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (keyInput in keys) {
|
|
||||||
try {
|
|
||||||
getInput(keyInput).use { certifyUserId.keys(it) }
|
|
||||||
} catch (e: IOException) {
|
|
||||||
throw RuntimeException(e)
|
|
||||||
} catch (badData: BadData) {
|
|
||||||
val errorMsg = getMsg("sop.error.input.not_a_private_key", keyInput)
|
|
||||||
throw BadData(errorMsg, badData)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
val ready = certifyUserId.certs(System.`in`)
|
|
||||||
ready.writeTo(System.out)
|
|
||||||
} catch (e: IOException) {
|
|
||||||
throw RuntimeException(e)
|
|
||||||
} catch (badData: BadData) {
|
|
||||||
val errorMsg = getMsg("sop.error.input.not_a_private_key", "STDIN")
|
|
||||||
throw BadData(errorMsg, badData)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -29,7 +29,7 @@ class DecryptCmd : AbstractSopCmd() {
|
||||||
@Option(names = [OPT_WITH_PASSWORD], paramLabel = "PASSWORD")
|
@Option(names = [OPT_WITH_PASSWORD], paramLabel = "PASSWORD")
|
||||||
var withPassword: List<String> = listOf()
|
var withPassword: List<String> = listOf()
|
||||||
|
|
||||||
@Option(names = [OPT_VERIFICATIONS_OUT, "--verify-out"], paramLabel = "VERIFICATIONS")
|
@Option(names = [OPT_VERIFICATIONS_OUT], paramLabel = "VERIFICATIONS")
|
||||||
var verifyOut: String? = null
|
var verifyOut: String? = null
|
||||||
|
|
||||||
@Option(names = [OPT_VERIFY_WITH], paramLabel = "CERT") var certs: List<String> = listOf()
|
@Option(names = [OPT_VERIFY_WITH], paramLabel = "CERT") var certs: List<String> = listOf()
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: 2024 Paul Schaub <vanitasvitae@fsfe.org>
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package sop.cli.picocli.commands
|
|
||||||
|
|
||||||
import java.io.IOException
|
|
||||||
import picocli.CommandLine
|
|
||||||
import picocli.CommandLine.Command
|
|
||||||
import sop.cli.picocli.SopCLI
|
|
||||||
import sop.exception.SOPGPException
|
|
||||||
|
|
||||||
@Command(
|
|
||||||
name = "merge-certs",
|
|
||||||
resourceBundle = "msg_merge-certs",
|
|
||||||
exitCodeOnInvalidInput = SOPGPException.UnsupportedOption.EXIT_CODE)
|
|
||||||
class MergeCertsCmd : AbstractSopCmd() {
|
|
||||||
|
|
||||||
@CommandLine.Option(names = ["--no-armor"], negatable = true) var armor = true
|
|
||||||
|
|
||||||
@CommandLine.Parameters(paramLabel = "CERTS") var updates: List<String> = listOf()
|
|
||||||
|
|
||||||
override fun run() {
|
|
||||||
val mergeCerts = throwIfUnsupportedSubcommand(SopCLI.getSop().mergeCerts(), "merge-certs")
|
|
||||||
|
|
||||||
if (!armor) {
|
|
||||||
mergeCerts.noArmor()
|
|
||||||
}
|
|
||||||
|
|
||||||
for (certFileName in updates) {
|
|
||||||
try {
|
|
||||||
getInput(certFileName).use { mergeCerts.updates(it) }
|
|
||||||
} catch (e: IOException) {
|
|
||||||
throw RuntimeException(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
val ready = mergeCerts.baseCertificates(System.`in`)
|
|
||||||
ready.writeTo(System.out)
|
|
||||||
} catch (e: IOException) {
|
|
||||||
throw RuntimeException(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,79 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: 2024 Paul Schaub <vanitasvitae@fsfe.org>
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package sop.cli.picocli.commands
|
|
||||||
|
|
||||||
import java.io.IOException
|
|
||||||
import picocli.CommandLine.Command
|
|
||||||
import picocli.CommandLine.Option
|
|
||||||
import sop.cli.picocli.SopCLI
|
|
||||||
import sop.exception.SOPGPException.*
|
|
||||||
|
|
||||||
@Command(
|
|
||||||
name = "update-key",
|
|
||||||
resourceBundle = "msg_update-key",
|
|
||||||
exitCodeOnInvalidInput = UnsupportedOption.EXIT_CODE)
|
|
||||||
class UpdateKeyCmd : AbstractSopCmd() {
|
|
||||||
|
|
||||||
@Option(names = ["--no-armor"], negatable = true) var armor = true
|
|
||||||
|
|
||||||
@Option(names = ["--signing-only"]) var signingOnly = false
|
|
||||||
|
|
||||||
@Option(names = ["--no-added-capabilities"]) var noAddedCapabilities = false
|
|
||||||
|
|
||||||
@Option(names = ["--with-key-password"], paramLabel = "PASSWORD")
|
|
||||||
var withKeyPassword: List<String> = listOf()
|
|
||||||
|
|
||||||
@Option(names = ["--merge-certs"], paramLabel = "CERTS") var mergeCerts: List<String> = listOf()
|
|
||||||
|
|
||||||
override fun run() {
|
|
||||||
val updateKey = throwIfUnsupportedSubcommand(SopCLI.getSop().updateKey(), "update-key")
|
|
||||||
|
|
||||||
if (!armor) {
|
|
||||||
updateKey.noArmor()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (signingOnly) {
|
|
||||||
updateKey.signingOnly()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (noAddedCapabilities) {
|
|
||||||
updateKey.noAddedCapabilities()
|
|
||||||
}
|
|
||||||
|
|
||||||
for (passwordFileName in withKeyPassword) {
|
|
||||||
try {
|
|
||||||
val password = stringFromInputStream(getInput(passwordFileName))
|
|
||||||
updateKey.withKeyPassword(password)
|
|
||||||
} catch (unsupportedOption: UnsupportedOption) {
|
|
||||||
val errorMsg =
|
|
||||||
getMsg("sop.error.feature_support.option_not_supported", "--with-key-password")
|
|
||||||
throw UnsupportedOption(errorMsg, unsupportedOption)
|
|
||||||
} catch (e: IOException) {
|
|
||||||
throw RuntimeException(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (certInput in mergeCerts) {
|
|
||||||
try {
|
|
||||||
getInput(certInput).use { updateKey.mergeCerts(it) }
|
|
||||||
} catch (e: IOException) {
|
|
||||||
throw RuntimeException(e)
|
|
||||||
} catch (badData: BadData) {
|
|
||||||
val errorMsg = getMsg("sop.error.input.not_a_certificate", certInput)
|
|
||||||
throw BadData(errorMsg, badData)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
val ready = updateKey.key(System.`in`)
|
|
||||||
ready.writeTo(System.out)
|
|
||||||
} catch (e: IOException) {
|
|
||||||
throw RuntimeException(e)
|
|
||||||
} catch (badData: BadData) {
|
|
||||||
val errorMsg = getMsg("sop.error.input.not_a_private_key", "STDIN")
|
|
||||||
throw BadData(errorMsg, badData)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,82 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: 2024 Paul Schaub <vanitasvitae@fsfe.org>
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package sop.cli.picocli.commands
|
|
||||||
|
|
||||||
import java.io.IOException
|
|
||||||
import java.util.*
|
|
||||||
import picocli.CommandLine.Command
|
|
||||||
import picocli.CommandLine.Option
|
|
||||||
import picocli.CommandLine.Parameters
|
|
||||||
import sop.cli.picocli.SopCLI
|
|
||||||
import sop.exception.SOPGPException
|
|
||||||
import sop.util.HexUtil.Companion.bytesToHex
|
|
||||||
|
|
||||||
@Command(
|
|
||||||
name = "validate-userid",
|
|
||||||
resourceBundle = "msg_validate-userid",
|
|
||||||
exitCodeOnInvalidInput = SOPGPException.MissingArg.EXIT_CODE,
|
|
||||||
showEndOfOptionsDelimiterInUsageHelp = true)
|
|
||||||
class ValidateUserIdCmd : AbstractSopCmd() {
|
|
||||||
|
|
||||||
@Option(names = ["--addr-spec-only"]) var addrSpecOnly: Boolean = false
|
|
||||||
|
|
||||||
@Option(names = ["--validate-at"]) var validateAt: Date? = null
|
|
||||||
|
|
||||||
@Parameters(index = "0", arity = "1", paramLabel = "USERID") lateinit var userId: String
|
|
||||||
|
|
||||||
@Parameters(index = "1..*", arity = "1..*", paramLabel = "CERTS")
|
|
||||||
var authorities: List<String> = listOf()
|
|
||||||
|
|
||||||
override fun run() {
|
|
||||||
val validateUserId =
|
|
||||||
throwIfUnsupportedSubcommand(SopCLI.getSop().validateUserId(), "validate-userid")
|
|
||||||
|
|
||||||
if (addrSpecOnly) {
|
|
||||||
validateUserId.addrSpecOnly()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (validateAt != null) {
|
|
||||||
validateUserId.validateAt(validateAt!!)
|
|
||||||
}
|
|
||||||
|
|
||||||
validateUserId.userId(userId)
|
|
||||||
|
|
||||||
for (authority in authorities) {
|
|
||||||
try {
|
|
||||||
getInput(authority).use { validateUserId.authorities(it) }
|
|
||||||
} catch (e: IOException) {
|
|
||||||
throw RuntimeException(e)
|
|
||||||
} catch (b: SOPGPException.BadData) {
|
|
||||||
val errorMsg = getMsg("sop.error.input.not_a_certificate", authority)
|
|
||||||
throw SOPGPException.BadData(errorMsg, b)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
val valid = validateUserId.subjects(System.`in`)
|
|
||||||
|
|
||||||
if (!valid) {
|
|
||||||
val errorMsg = getMsg("sop.error.runtime.any_cert_user_id_no_match", userId)
|
|
||||||
throw SOPGPException.CertUserIdNoMatch(errorMsg)
|
|
||||||
}
|
|
||||||
} catch (e: SOPGPException.CertUserIdNoMatch) {
|
|
||||||
val errorMsg =
|
|
||||||
if (e.fingerprint != null) {
|
|
||||||
getMsg(
|
|
||||||
"sop.error.runtime.cert_user_id_no_match",
|
|
||||||
bytesToHex(e.fingerprint!!),
|
|
||||||
userId)
|
|
||||||
} else {
|
|
||||||
getMsg("sop.error.runtime.any_cert_user_id_no_match", userId)
|
|
||||||
}
|
|
||||||
throw SOPGPException.CertUserIdNoMatch(errorMsg, e)
|
|
||||||
} catch (e: SOPGPException.BadData) {
|
|
||||||
val errorMsg = getMsg("sop.error.input.not_a_certificate", "STDIN")
|
|
||||||
throw SOPGPException.BadData(errorMsg, e)
|
|
||||||
} catch (e: IOException) {
|
|
||||||
throw RuntimeException(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -22,7 +22,6 @@ class VersionCmd : AbstractSopCmd() {
|
||||||
@Option(names = ["--extended"]) var extended: Boolean = false
|
@Option(names = ["--extended"]) var extended: Boolean = false
|
||||||
@Option(names = ["--backend"]) var backend: Boolean = false
|
@Option(names = ["--backend"]) var backend: Boolean = false
|
||||||
@Option(names = ["--sop-spec"]) var sopSpec: Boolean = false
|
@Option(names = ["--sop-spec"]) var sopSpec: Boolean = false
|
||||||
@Option(names = ["--sopv"]) var sopv: Boolean = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun run() {
|
override fun run() {
|
||||||
|
@ -48,10 +47,5 @@ class VersionCmd : AbstractSopCmd() {
|
||||||
println(version.getSopSpecVersion())
|
println(version.getSopSpecVersion())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exclusive!!.sopv) {
|
|
||||||
println(version.getSopVVersion())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,14 +2,11 @@
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
usage.header=Add ASCII Armor to standard input
|
usage.header=Add ASCII Armor to standard input
|
||||||
|
label=Label to be used in the header and tail of the armoring
|
||||||
standardInput=BINARY
|
|
||||||
standardInputDescription=OpenPGP material (SIGNATURES, KEYS, CERTS, CIPHERTEXT, INLINESIGNED)
|
|
||||||
standardOutput=ARMORED
|
|
||||||
standardOutputDescription=Same material, but with ASCII-armoring added, if not already present
|
|
||||||
|
|
||||||
stacktrace=Print stacktrace
|
stacktrace=Print stacktrace
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
# Generic TODO: Remove when bumping picocli to 4.7.0
|
||||||
usage.synopsisHeading=Usage:\u0020
|
usage.synopsisHeading=Usage:\u0020
|
||||||
usage.optionListHeading=%nOptions:%n
|
usage.commandListHeading = %nCommands:%n
|
||||||
|
usage.optionListHeading = %nOptions:%n
|
||||||
usage.footerHeading=Powered by picocli%n
|
usage.footerHeading=Powered by picocli%n
|
||||||
|
|
|
@ -2,12 +2,11 @@
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
usage.header=Schütze Standard-Eingabe mit ASCII Armor
|
usage.header=Schütze Standard-Eingabe mit ASCII Armor
|
||||||
|
label=Label für Kopf- und Fußzeile der ASCII Armor
|
||||||
standardInputDescription=OpenPGP Material (SIGNATURES, KEYS, CERTS, CIPHERTEXT, INLINESIGNED)
|
|
||||||
standardOutputDescription=Dasselbe Material, aber mit ASCII Armor kodiert, falls noch nicht geschehen
|
|
||||||
|
|
||||||
stacktrace=Stacktrace ausgeben
|
stacktrace=Stacktrace ausgeben
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
# Generic TODO: Remove when bumping picocli to 4.7.0
|
||||||
usage.synopsisHeading=Aufruf:\u0020
|
usage.synopsisHeading=Aufruf:\u0020
|
||||||
usage.optionListHeading=%nOptionen:%n
|
usage.commandListHeading=%nBefehle:%n
|
||||||
|
usage.optionListHeading = %nOptionen:%n
|
||||||
usage.footerHeading=Powered by Picocli%n
|
usage.footerHeading=Powered by Picocli%n
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
# SPDX-FileCopyrightText: 2024 Paul Schaub <vanitasvitae@fsfe.org>
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
usage.header=Certify OpenPGP Certificate User IDs
|
|
||||||
no-armor=ASCII armor the output
|
|
||||||
userid=Identities that shall be certified
|
|
||||||
with-key-password.0=Passphrase to unlock the secret key(s).
|
|
||||||
with-key-password.1=Is an INDIRECT data type (e.g. file, environment variable, file descriptor...).
|
|
||||||
no-require-self-sig=Certify the UserID regardless of whether self-certifications are present
|
|
||||||
KEYS[0..*]=Private keys
|
|
||||||
|
|
||||||
standardInput=CERTS
|
|
||||||
standardInputDescription=Certificates that shall be certified
|
|
||||||
standardOutput=CERTS
|
|
||||||
standardOutputDescription=Certified certificates
|
|
||||||
|
|
||||||
picocli.endofoptions.description=End of options. Remainder are positional parameters. Fixes 'Missing required parameter' error
|
|
||||||
|
|
||||||
stacktrace=Print stacktrace
|
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
|
||||||
usage.parameterListHeading=%nParameters:%n
|
|
||||||
usage.synopsisHeading=Usage:\u0020
|
|
||||||
usage.commandListHeading=%nCommands:%n
|
|
||||||
usage.optionListHeading=%nOptions:%n
|
|
||||||
usage.footerHeading=Powered by picocli%n
|
|
|
@ -1,22 +0,0 @@
|
||||||
# SPDX-FileCopyrightText: 2024 Paul Schaub <vanitasvitae@fsfe.org>
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
usage.header=Zertifiziere OpenPGP Zertifikat Identitäten
|
|
||||||
no-armor=Schütze Ausgabe mit ASCII Armor
|
|
||||||
userid=Identität, die zertifiziert werden soll
|
|
||||||
with-key-password.0=Passwort zum Entsperren der privaten Schlüssel
|
|
||||||
with-key-password.1=Ist INDIREKTER Datentyp (z.B.. Datei, Umgebungsvariable, Dateideskriptor...).
|
|
||||||
no-require-self-sig=Zertifiziere die Identität, unabhängig davon, ob eine Selbstzertifizierung vorhanden ist
|
|
||||||
KEYS[0..*]=Private Schlüssel
|
|
||||||
|
|
||||||
standardInputDescription=Zertifikate, auf denen Identitäten zertifiziert werden sollen
|
|
||||||
standardOutputDescription=Zertifizierte Zertifikate
|
|
||||||
|
|
||||||
picocli.endofoptions.description=Ende der Optionen. Der Rest sind Positionsparameter. Behebt 'Missing required parameter' Fehler
|
|
||||||
|
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
|
||||||
usage.parameterListHeading=%nParameter:%n
|
|
||||||
usage.synopsisHeading=Aufruf:\u0020
|
|
||||||
usage.commandListHeading=%nBefehle:%n
|
|
||||||
usage.optionListHeading=%nOptionen:%n
|
|
||||||
usage.footerHeading=Powered by Picocli%n
|
|
|
@ -12,15 +12,10 @@ old-key-password.0=Old passwords to unlock the keys with.
|
||||||
old-key-password.1=Multiple passwords can be passed in, which are tested sequentially to unlock locked subkeys.
|
old-key-password.1=Multiple passwords can be passed in, which are tested sequentially to unlock locked subkeys.
|
||||||
old-key-password.2=Is an INDIRECT data type (e.g. file, environment variable, file descriptor...).
|
old-key-password.2=Is an INDIRECT data type (e.g. file, environment variable, file descriptor...).
|
||||||
|
|
||||||
standardInput=KEYS
|
|
||||||
standardInputDescription=OpenPGP keys whose passphrases shall be changed
|
|
||||||
standardOutput=KEYS
|
|
||||||
standardOutputDescription=OpenPGP keys with changed passphrases
|
|
||||||
|
|
||||||
stacktrace=Print stacktrace
|
stacktrace=Print stacktrace
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
# Generic TODO: Remove when bumping picocli to 4.7.0
|
||||||
usage.descriptionHeading=%nDescription:%n
|
usage.descriptionHeading=%nDescription:%n
|
||||||
usage.synopsisHeading=Usage:\u0020
|
usage.synopsisHeading=Usage:\u0020
|
||||||
usage.commandListHeading=%nCommands:%n
|
usage.commandListHeading = %nCommands:%n
|
||||||
usage.optionListHeading=%nOptions:%n
|
usage.optionListHeading = %nOptions:%n
|
||||||
usage.footerHeading=Powered by picocli%n
|
usage.footerHeading=Powered by picocli%n
|
||||||
|
|
|
@ -12,13 +12,10 @@ old-key-password.0=Alte Passw
|
||||||
old-key-password.1=Mehrere Passwortkandidaten können übergeben werden, welche der Reihe nach durchprobiert werden, um Unterschlüssel zu entsperren.
|
old-key-password.1=Mehrere Passwortkandidaten können übergeben werden, welche der Reihe nach durchprobiert werden, um Unterschlüssel zu entsperren.
|
||||||
old-key-password.2=Ist ein INDIREKTER Datentyp (z.B.. Datei, Umgebungsvariable, Dateideskriptor...).
|
old-key-password.2=Ist ein INDIREKTER Datentyp (z.B.. Datei, Umgebungsvariable, Dateideskriptor...).
|
||||||
|
|
||||||
standardInputDescription=OpenPGP Schlüssel deren Passwörter geändert werden sollen
|
|
||||||
standardOutputDescription=OpenPGP Schlüssel mit geänderten Passwörtern
|
|
||||||
|
|
||||||
stacktrace=Stacktrace ausgeben
|
stacktrace=Stacktrace ausgeben
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
# Generic TODO: Remove when bumping picocli to 4.7.0
|
||||||
usage.descriptionHeading=%nBeschreibung:%n
|
usage.descriptionHeading=%nBeschreibung:%n
|
||||||
usage.synopsisHeading=Aufruf:\u0020
|
usage.synopsisHeading=Aufruf:\u0020
|
||||||
usage.commandListHeading=%nBefehle:%n
|
usage.commandListHeading=%nBefehle:%n
|
||||||
usage.optionListHeading=%nOptionen:%n
|
usage.optionListHeading = %nOptionen:%n
|
||||||
usage.footerHeading=Powered by Picocli%n
|
usage.footerHeading=Powered by Picocli%n
|
||||||
|
|
|
@ -3,14 +3,9 @@
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
usage.header=Remove ASCII Armor from standard input
|
usage.header=Remove ASCII Armor from standard input
|
||||||
|
|
||||||
standardInput=ARMORED
|
|
||||||
standardInputDescription=Armored OpenPGP material (SIGNATURES, KEYS, CERTS, CIPHERTEXT, INLINESIGNED)
|
|
||||||
standardOutput=BINARY
|
|
||||||
standardOutputDescription=Same material, but with ASCII-armoring removed
|
|
||||||
|
|
||||||
stacktrace=Print stacktrace
|
stacktrace=Print stacktrace
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
# Generic TODO: Remove when bumping picocli to 4.7.0
|
||||||
usage.synopsisHeading=Usage:\u0020
|
usage.synopsisHeading=Usage:\u0020
|
||||||
usage.commandListHeading=%nCommands:%n
|
usage.commandListHeading = %nCommands:%n
|
||||||
usage.optionListHeading=%nOptions:%n
|
usage.optionListHeading = %nOptions:%n
|
||||||
usage.footerHeading=Powered by picocli%n
|
usage.footerHeading=Powered by picocli%n
|
||||||
|
|
|
@ -3,12 +3,9 @@
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
usage.header=Entferne ASCII Armor von Standard-Eingabe
|
usage.header=Entferne ASCII Armor von Standard-Eingabe
|
||||||
|
|
||||||
standardInputDescription=OpenPGP Material mit ASCII Armor (SIGNATURES, KEYS, CERTS, CIPHERTEXT, INLINESIGNED)
|
|
||||||
standardOutputDescription=Dasselbe Material, aber mit entfernter ASCII Armor
|
|
||||||
|
|
||||||
stacktrace=Stacktrace ausgeben
|
stacktrace=Stacktrace ausgeben
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
# Generic TODO: Remove when bumping picocli to 4.7.0
|
||||||
usage.synopsisHeading=Aufruf:\u0020
|
usage.synopsisHeading=Aufruf:\u0020
|
||||||
usage.commandListHeading=%nBefehle:%n
|
usage.commandListHeading=%nBefehle:%n
|
||||||
usage.optionListHeading=%nOptionen:%n
|
usage.optionListHeading = %nOptionen:%n
|
||||||
usage.footerHeading=Powered by Picocli%n
|
usage.footerHeading=Powered by Picocli%n
|
||||||
|
|
|
@ -22,15 +22,10 @@ with-key-password.0=Passphrase to unlock the secret key(s).
|
||||||
with-key-password.1=Is an INDIRECT data type (e.g. file, environment variable, file descriptor...).
|
with-key-password.1=Is an INDIRECT data type (e.g. file, environment variable, file descriptor...).
|
||||||
KEY[0..*]=Secret keys to attempt decryption with
|
KEY[0..*]=Secret keys to attempt decryption with
|
||||||
|
|
||||||
standardInput=CIPHERTEXT
|
|
||||||
standardInputDescription=Encrypted OpenPGP message
|
|
||||||
standardOutput=DATA
|
|
||||||
standardOutputDescription=Decrypted OpenPGP message
|
|
||||||
|
|
||||||
stacktrace=Print stacktrace
|
stacktrace=Print stacktrace
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
# Generic TODO: Remove when bumping picocli to 4.7.0
|
||||||
usage.parameterListHeading=%nParameters:%n
|
usage.parameterListHeading=%nParameters:%n
|
||||||
usage.synopsisHeading=Usage:\u0020
|
usage.synopsisHeading=Usage:\u0020
|
||||||
usage.commandListHeading=%nCommands:%n
|
usage.commandListHeading = %nCommands:%n
|
||||||
usage.optionListHeading=%nOptions:%n
|
usage.optionListHeading = %nOptions:%n
|
||||||
usage.footerHeading=Powered by picocli%n
|
usage.footerHeading=Powered by picocli%n
|
||||||
|
|
|
@ -22,13 +22,10 @@ with-key-password.0=Passwort zum Entsperren der privaten Schl
|
||||||
with-key-password.1=Ist INDIREKTER Datentyp (z.B.. Datei, Umgebungsvariable, Dateideskriptor...).
|
with-key-password.1=Ist INDIREKTER Datentyp (z.B.. Datei, Umgebungsvariable, Dateideskriptor...).
|
||||||
KEY[0..*]=Private Schlüssel zum Entschlüsseln der Nachricht
|
KEY[0..*]=Private Schlüssel zum Entschlüsseln der Nachricht
|
||||||
|
|
||||||
standardInputDescription=Verschlüsselte OpenPGP Nachricht
|
|
||||||
standardOutputDescription=Entschlüsselte OpenPGP Nachricht
|
|
||||||
|
|
||||||
stacktrace=Stacktrace ausgeben
|
stacktrace=Stacktrace ausgeben
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
# Generic TODO: Remove when bumping picocli to 4.7.0
|
||||||
usage.parameterListHeading=%nParameter:%n
|
usage.parameterListHeading=%nParameter:%n
|
||||||
usage.synopsisHeading=Aufruf:\u0020
|
usage.synopsisHeading=Aufruf:\u0020
|
||||||
usage.commandListHeading=%nBefehle:%n
|
usage.commandListHeading=%nBefehle:%n
|
||||||
usage.optionListHeading=%nOptionen:%n
|
usage.optionListHeading = %nOptionen:%n
|
||||||
usage.footerHeading=Powered by Picocli%n
|
usage.footerHeading=Powered by Picocli%n
|
||||||
|
|
|
@ -11,15 +11,10 @@ with-key-password.1=Is an INDIRECT data type (e.g. file, environment variable, f
|
||||||
micalg-out=Emits the digest algorithm used to the specified file in a way that can be used to populate the micalg parameter for the PGP/MIME Content-Type (RFC3156).
|
micalg-out=Emits the digest algorithm used to the specified file in a way that can be used to populate the micalg parameter for the PGP/MIME Content-Type (RFC3156).
|
||||||
KEYS[0..*]=Secret keys used for signing
|
KEYS[0..*]=Secret keys used for signing
|
||||||
|
|
||||||
standardInput=DATA
|
|
||||||
standardInputDescription=Data that shall be signed
|
|
||||||
standardOutput=SIGNATURES
|
|
||||||
standardOutputDescription=Detached OpenPGP signature(s)
|
|
||||||
|
|
||||||
stacktrace=Print stacktrace
|
stacktrace=Print stacktrace
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
# Generic TODO: Remove when bumping picocli to 4.7.0
|
||||||
usage.parameterListHeading=%nParameters:%n
|
usage.parameterListHeading=%nParameters:%n
|
||||||
usage.synopsisHeading=Usage:\u0020
|
usage.synopsisHeading=Usage:\u0020
|
||||||
usage.commandListHeading=%nCommands:%n
|
usage.commandListHeading = %nCommands:%n
|
||||||
usage.optionListHeading=%nOptions:%n
|
usage.optionListHeading = %nOptions:%n
|
||||||
usage.footerHeading=Powered by picocli%n
|
usage.footerHeading=Powered by picocli%n
|
||||||
|
|
|
@ -11,13 +11,10 @@ with-key-password.1=Ist ein INDIREKTER Datentyp (z.B.. Datei, Umgebungsvariable,
|
||||||
micalg-out=Gibt den verwendeten Digest-Algorithmus an die angegebene Ausgabe in einer Form aus, die zum Auffüllen des micalg-Parameters für den PGP/MIME Content-Type (RFC3156) verwendet werden kann.
|
micalg-out=Gibt den verwendeten Digest-Algorithmus an die angegebene Ausgabe in einer Form aus, die zum Auffüllen des micalg-Parameters für den PGP/MIME Content-Type (RFC3156) verwendet werden kann.
|
||||||
KEYS[0..*]=Private Signaturschlüssel
|
KEYS[0..*]=Private Signaturschlüssel
|
||||||
|
|
||||||
standardInputDescription=Daten die signiert werden sollen
|
|
||||||
standardOutputDescription=Abgetrennte OpenPGP Signatur(en)
|
|
||||||
|
|
||||||
stacktrace=Stacktrace ausgeben
|
stacktrace=Stacktrace ausgeben
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
# Generic TODO: Remove when bumping picocli to 4.7.0
|
||||||
usage.parameterListHeading=%nParameter:%n
|
usage.parameterListHeading=%nParameter:%n
|
||||||
usage.synopsisHeading=Aufruf:\u0020
|
usage.synopsisHeading=Aufruf:\u0020
|
||||||
usage.commandListHeading=%nBefehle:%n
|
usage.commandListHeading=%nBefehle:%n
|
||||||
usage.optionListHeading=%nOptionen:%n
|
usage.optionListHeading = %nOptionen:%n
|
||||||
usage.footerHeading=Powered by Picocli%n
|
usage.footerHeading=Powered by Picocli%n
|
||||||
|
|
|
@ -13,16 +13,11 @@ not-after.3=Accepts special value "-" for end of time.
|
||||||
SIGNATURE[0]=Detached signature
|
SIGNATURE[0]=Detached signature
|
||||||
CERT[1..*]=Public key certificates for signature verification
|
CERT[1..*]=Public key certificates for signature verification
|
||||||
|
|
||||||
standardInput=DATA
|
|
||||||
standardInputDescription=Data over which the detached signatures were calculated
|
|
||||||
standardOutput=VERIFICATIONS
|
|
||||||
standardOutputDescription=Information about successfully verified signatures
|
|
||||||
|
|
||||||
stacktrace=Print stacktrace
|
stacktrace=Print stacktrace
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
# Generic TODO: Remove when bumping picocli to 4.7.0
|
||||||
usage.descriptionHeading=%nDescription:%n
|
usage.descriptionHeading=%nDescription:%n
|
||||||
usage.parameterListHeading=%nParameters:%n
|
usage.parameterListHeading=%nParameters:%n
|
||||||
usage.synopsisHeading=Usage:\u0020
|
usage.synopsisHeading=Usage:\u0020
|
||||||
usage.commandListHeading=%nCommands:%n
|
usage.commandListHeading = %nCommands:%n
|
||||||
usage.optionListHeading=%nOptions:%n
|
usage.optionListHeading = %nOptions:%n
|
||||||
usage.footerHeading=Powered by picocli%n
|
usage.footerHeading=Powered by picocli%n
|
||||||
|
|
|
@ -13,14 +13,11 @@ not-after.3=Akzeptiert speziellen Wert '-' f
|
||||||
SIGNATURE[0]=Abgetrennte Signatur
|
SIGNATURE[0]=Abgetrennte Signatur
|
||||||
CERT[1..*]=Zertifikate (öffentliche Schlüssel) zur Signaturprüfung
|
CERT[1..*]=Zertifikate (öffentliche Schlüssel) zur Signaturprüfung
|
||||||
|
|
||||||
standardInputDescription=Daten, über die die abgetrennten Signaturen erstellt wurden
|
|
||||||
standardOutputDescription=Informationen über erfolgreich verifizierte Signaturen
|
|
||||||
|
|
||||||
stacktrace=Stacktrace ausgeben
|
stacktrace=Stacktrace ausgeben
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
# Generic TODO: Remove when bumping picocli to 4.7.0
|
||||||
usage.descriptionHeading=%nBeschreibung:%n
|
usage.descriptionHeading=%nBeschreibung:%n
|
||||||
usage.parameterListHeading=%nParameter:%n
|
usage.parameterListHeading=%nParameter:%n
|
||||||
usage.synopsisHeading=Aufruf:\u0020
|
usage.synopsisHeading=Aufruf:\u0020
|
||||||
usage.commandListHeading=%nBefehle:%n
|
usage.commandListHeading=%nBefehle:%n
|
||||||
usage.optionListHeading=%nOptionen:%n
|
usage.optionListHeading = %nOptionen:%n
|
||||||
usage.footerHeading=Powered by Picocli%n
|
usage.footerHeading=Powered by Picocli%n
|
||||||
|
|
|
@ -12,15 +12,10 @@ with-key-password.0=Passphrase to unlock the secret key(s).
|
||||||
with-key-password.1=Is an INDIRECT data type (e.g. file, environment variable, file descriptor...).
|
with-key-password.1=Is an INDIRECT data type (e.g. file, environment variable, file descriptor...).
|
||||||
CERTS[0..*]=Certificates the message gets encrypted to
|
CERTS[0..*]=Certificates the message gets encrypted to
|
||||||
|
|
||||||
standardInput=DATA
|
|
||||||
standardInputDescription=Data that shall be encrypted
|
|
||||||
standardOutput=CIPHERTEXT
|
|
||||||
standardOutputDescription=Encrypted OpenPGP message
|
|
||||||
|
|
||||||
stacktrace=Print stacktrace
|
stacktrace=Print stacktrace
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
# Generic TODO: Remove when bumping picocli to 4.7.0
|
||||||
usage.parameterListHeading=%nParameters:%n
|
usage.parameterListHeading=%nParameters:%n
|
||||||
usage.synopsisHeading=Usage:\u0020
|
usage.synopsisHeading=Usage:\u0020
|
||||||
usage.commandListHeading=%nCommands:%n
|
usage.commandListHeading = %nCommands:%n
|
||||||
usage.optionListHeading=%nOptions:%n
|
usage.optionListHeading = %nOptions:%n
|
||||||
usage.footerHeading=Powered by picocli%n
|
usage.footerHeading=Powered by picocli%n
|
||||||
|
|
|
@ -12,13 +12,10 @@ with-key-password.0=Passwort zum Entsperren der privaten Schl
|
||||||
with-key-password.1=Ist INDIREKTER Datentyp (z.B.. Datei, Umgebungsvariable, Dateideskriptor...).
|
with-key-password.1=Ist INDIREKTER Datentyp (z.B.. Datei, Umgebungsvariable, Dateideskriptor...).
|
||||||
CERTS[0..*]=Zertifikate für die die Nachricht verschlüsselt werden soll
|
CERTS[0..*]=Zertifikate für die die Nachricht verschlüsselt werden soll
|
||||||
|
|
||||||
standardInputDescription=Daten, die verschlüsselt werden sollen
|
|
||||||
standardOutputDescription=Verschlüsselte OpenPGP Nachricht
|
|
||||||
|
|
||||||
stacktrace=Stacktrace ausgeben
|
stacktrace=Stacktrace ausgeben
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
# Generic TODO: Remove when bumping picocli to 4.7.0
|
||||||
usage.parameterListHeading=%nParameter:%n
|
usage.parameterListHeading=%nParameter:%n
|
||||||
usage.synopsisHeading=Aufruf:\u0020
|
usage.synopsisHeading=Aufruf:\u0020
|
||||||
usage.commandListHeading=%nBefehle:%n
|
usage.commandListHeading=%nBefehle:%n
|
||||||
usage.optionListHeading=%nOptionen:%n
|
usage.optionListHeading = %nOptionen:%n
|
||||||
usage.footerHeading=Powered by Picocli%n
|
usage.footerHeading=Powered by Picocli%n
|
||||||
|
|
|
@ -5,15 +5,10 @@ usage.header=Extract a public key certificate from a secret key
|
||||||
usage.description=Read a secret key from STDIN and emit the public key certificate to STDOUT.
|
usage.description=Read a secret key from STDIN and emit the public key certificate to STDOUT.
|
||||||
no-armor=ASCII armor the output
|
no-armor=ASCII armor the output
|
||||||
|
|
||||||
standardInput=KEYS
|
|
||||||
standardInputDescription=Private key(s), from which certificate(s) shall be extracted
|
|
||||||
standardOutput=CERTS
|
|
||||||
standardOutputDescription=Extracted certificate(s)
|
|
||||||
|
|
||||||
stacktrace=Print stacktrace
|
stacktrace=Print stacktrace
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
# Generic TODO: Remove when bumping picocli to 4.7.0
|
||||||
usage.descriptionHeading=%nDescription:%n
|
usage.descriptionHeading=%nDescription:%n
|
||||||
usage.synopsisHeading=Usage:\u0020
|
usage.synopsisHeading=Usage:\u0020
|
||||||
usage.commandListHeading=%nCommands:%n
|
usage.commandListHeading = %nCommands:%n
|
||||||
usage.optionListHeading=%nOptions:%n
|
usage.optionListHeading = %nOptions:%n
|
||||||
usage.footerHeading=Powered by picocli%n
|
usage.footerHeading=Powered by picocli%n
|
||||||
|
|
|
@ -5,13 +5,10 @@ usage.header=Extrahiere Zertifikat (
|
||||||
usage.description=Lese einen Schlüssel von Standard-Eingabe und gebe das Zertifikat auf Standard-Ausgabe aus.
|
usage.description=Lese einen Schlüssel von Standard-Eingabe und gebe das Zertifikat auf Standard-Ausgabe aus.
|
||||||
no-armor=Schütze Ausgabe mit ASCII Armor
|
no-armor=Schütze Ausgabe mit ASCII Armor
|
||||||
|
|
||||||
standardInputDescription=Private Schlüssel, deren Zertifikate extrahiert werden sollen
|
|
||||||
standardOutputDescription=Extrahierte Zertifikate
|
|
||||||
|
|
||||||
stacktrace=Stacktrace ausgeben
|
stacktrace=Stacktrace ausgeben
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
# Generic TODO: Remove when bumping picocli to 4.7.0
|
||||||
usage.descriptionHeading=%nBeschreibung:%n
|
usage.descriptionHeading=%nBeschreibung:%n
|
||||||
usage.synopsisHeading=Aufruf:\u0020
|
usage.synopsisHeading=Aufruf:\u0020
|
||||||
usage.commandListHeading=%nBefehle:%n
|
usage.commandListHeading=%nBefehle:%n
|
||||||
usage.optionListHeading=%nOptionen:%n
|
usage.optionListHeading = %nOptionen:%n
|
||||||
usage.footerHeading=Powered by Picocli%n
|
usage.footerHeading=Powered by Picocli%n
|
||||||
|
|
|
@ -9,13 +9,10 @@ signing-only=Generate a key that can only be used for signing
|
||||||
with-key-password.0=Password to protect the private key with
|
with-key-password.0=Password to protect the private key with
|
||||||
with-key-password.1=Is an INDIRECT data type (e.g. file, environment variable, file descriptor...).
|
with-key-password.1=Is an INDIRECT data type (e.g. file, environment variable, file descriptor...).
|
||||||
|
|
||||||
standardOutput=KEYS
|
|
||||||
standardOutputDescription=Generated OpenPGP key
|
|
||||||
|
|
||||||
stacktrace=Print stacktrace
|
stacktrace=Print stacktrace
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
# Generic TODO: Remove when bumping picocli to 4.7.0
|
||||||
usage.parameterListHeading=%nParameters:%n
|
usage.parameterListHeading=%nParameters:%n
|
||||||
usage.synopsisHeading=Usage:\u0020
|
usage.synopsisHeading=Usage:\u0020
|
||||||
usage.commandListHeading=%nCommands:%n
|
usage.commandListHeading = %nCommands:%n
|
||||||
usage.optionListHeading=%nOptions:%n
|
usage.optionListHeading = %nOptions:%n
|
||||||
usage.footerHeading=Powered by picocli%n
|
usage.footerHeading=Powered by picocli%n
|
||||||
|
|
|
@ -9,12 +9,10 @@ signing-only=Generiere einen Schl
|
||||||
with-key-password.0=Passwort zum Schutz des privaten Schlüssels
|
with-key-password.0=Passwort zum Schutz des privaten Schlüssels
|
||||||
with-key-password.1=Ist ein INDIREKTER Datentyp (z.B.. Datei, Umgebungsvariable, Dateideskriptor...).
|
with-key-password.1=Ist ein INDIREKTER Datentyp (z.B.. Datei, Umgebungsvariable, Dateideskriptor...).
|
||||||
|
|
||||||
standardOutputDescription=Erzeugter OpenPGP Schlüssel
|
|
||||||
|
|
||||||
stacktrace=Stacktrace ausgeben
|
stacktrace=Stacktrace ausgeben
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
# Generic TODO: Remove when bumping picocli to 4.7.0
|
||||||
usage.parameterListHeading=%nParameter:%n
|
usage.parameterListHeading=%nParameter:%n
|
||||||
usage.synopsisHeading=Aufruf:\u0020
|
usage.synopsisHeading=Aufruf:\u0020
|
||||||
usage.commandListHeading=%nBefehle:%n
|
usage.commandListHeading=%nBefehle:%n
|
||||||
usage.optionListHeading=%nOptionen:%n
|
usage.optionListHeading = %nOptionen:%n
|
||||||
usage.footerHeading=Powered by Picocli%n
|
usage.footerHeading=Powered by Picocli%n
|
||||||
|
|
|
@ -6,6 +6,6 @@ usage.header=Display usage information for the specified subcommand
|
||||||
stacktrace=Print stacktrace
|
stacktrace=Print stacktrace
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
# Generic TODO: Remove when bumping picocli to 4.7.0
|
||||||
usage.synopsisHeading=Usage:\u0020
|
usage.synopsisHeading=Usage:\u0020
|
||||||
usage.commandListHeading=%nCommands:%n
|
usage.commandListHeading = %nCommands:%n
|
||||||
usage.optionListHeading=%nOptions:%n
|
usage.optionListHeading = %nOptions:%n
|
||||||
usage.footerHeading=Powered by picocli%n
|
usage.footerHeading=Powered by picocli%n
|
||||||
|
|
|
@ -7,5 +7,5 @@ stacktrace=Stacktrace ausgeben
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
# Generic TODO: Remove when bumping picocli to 4.7.0
|
||||||
usage.synopsisHeading=Aufruf:\u0020
|
usage.synopsisHeading=Aufruf:\u0020
|
||||||
usage.commandListHeading=%nBefehle:%n
|
usage.commandListHeading=%nBefehle:%n
|
||||||
usage.optionListHeading=%nOptionen:%n
|
usage.optionListHeading = %nOptionen:%n
|
||||||
usage.footerHeading=Powered by Picocli%n
|
usage.footerHeading=Powered by Picocli%n
|
||||||
|
|
|
@ -5,14 +5,9 @@ usage.header=Split signatures from a clearsigned message
|
||||||
no-armor=ASCII armor the output
|
no-armor=ASCII armor the output
|
||||||
signatures-out=Destination to which a detached signatures block will be written
|
signatures-out=Destination to which a detached signatures block will be written
|
||||||
|
|
||||||
standardInput=INLINESIGNED
|
|
||||||
standardInputDescription=Inline-signed OpenPGP message
|
|
||||||
standardOutput=DATA
|
|
||||||
standardOutputDescription=The message without any signatures
|
|
||||||
|
|
||||||
stacktrace=Print stacktrace
|
stacktrace=Print stacktrace
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
# Generic TODO: Remove when bumping picocli to 4.7.0
|
||||||
usage.synopsisHeading=Usage:\u0020
|
usage.synopsisHeading=Usage:\u0020
|
||||||
usage.commandListHeading=%nCommands:%n
|
usage.commandListHeading = %nCommands:%n
|
||||||
usage.optionListHeading=%nOptions:%n
|
usage.optionListHeading = %nOptions:%n
|
||||||
usage.footerHeading=Powered by picocli%n
|
usage.footerHeading=Powered by picocli%n
|
||||||
|
|
|
@ -5,12 +5,9 @@ usage.header=Trenne Signaturen von Klartext-signierter Nachricht
|
||||||
no-armor=Schütze Ausgabe mit ASCII Armor
|
no-armor=Schütze Ausgabe mit ASCII Armor
|
||||||
signatures-out=Schreibe abgetrennte Signaturen in Ausgabe
|
signatures-out=Schreibe abgetrennte Signaturen in Ausgabe
|
||||||
|
|
||||||
standardInputDescription=Klartext-signierte OpenPGP Nachricht
|
|
||||||
standardOutputDescription=Nachricht ohne Signaturen
|
|
||||||
|
|
||||||
stacktrace=Stacktrace ausgeben
|
stacktrace=Stacktrace ausgeben
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
# Generic TODO: Remove when bumping picocli to 4.7.0
|
||||||
usage.synopsisHeading=Aufruf:\u0020
|
usage.synopsisHeading=Aufruf:\u0020
|
||||||
usage.commandListHeading=%nBefehle:%n
|
usage.commandListHeading=%nBefehle:%n
|
||||||
usage.optionListHeading=%nOptionen:%n
|
usage.optionListHeading = %nOptionen:%n
|
||||||
usage.footerHeading=Powered by Picocli%n
|
usage.footerHeading=Powered by Picocli%n
|
||||||
|
|
|
@ -13,15 +13,10 @@ with-key-password.1=Is an INDIRECT data type (e.g. file, environment variable, f
|
||||||
micalg=Emits the digest algorithm used to the specified file in a way that can be used to populate the micalg parameter for the PGP/MIME Content-Type (RFC3156).
|
micalg=Emits the digest algorithm used to the specified file in a way that can be used to populate the micalg parameter for the PGP/MIME Content-Type (RFC3156).
|
||||||
KEYS[0..*]=Secret keys used for signing
|
KEYS[0..*]=Secret keys used for signing
|
||||||
|
|
||||||
standardInput=DATA
|
|
||||||
standardInputDescription=Data that shall be signed
|
|
||||||
standardOutput=INLINESIGNED
|
|
||||||
standardOutputDescription=Inline-signed OpenPGP message
|
|
||||||
|
|
||||||
stacktrace=Print stacktrace
|
stacktrace=Print stacktrace
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
# Generic TODO: Remove when bumping picocli to 4.7.0
|
||||||
usage.parameterListHeading=%nParameters:%n
|
usage.parameterListHeading=%nParameters:%n
|
||||||
usage.synopsisHeading=Usage:\u0020
|
usage.synopsisHeading=Usage:\u0020
|
||||||
usage.commandListHeading=%nCommands:%n
|
usage.commandListHeading = %nCommands:%n
|
||||||
usage.optionListHeading=%nOptions:%n
|
usage.optionListHeading = %nOptions:%n
|
||||||
usage.footerHeading=Powered by picocli%n
|
usage.footerHeading=Powered by picocli%n
|
||||||
|
|
|
@ -13,13 +13,10 @@ with-key-password.1=Ist ein INDIREKTER Datentyp (z.B.. Datei, Umgebungsvariable,
|
||||||
micalg=Gibt den verwendeten Digest-Algorithmus an die angegebene Ausgabe in einer Form aus, die zum Auffüllen des micalg-Parameters für den PGP/MIME Content-Type (RFC3156) verwendet werden kann.
|
micalg=Gibt den verwendeten Digest-Algorithmus an die angegebene Ausgabe in einer Form aus, die zum Auffüllen des micalg-Parameters für den PGP/MIME Content-Type (RFC3156) verwendet werden kann.
|
||||||
KEYS[0..*]=Private Signaturschlüssel
|
KEYS[0..*]=Private Signaturschlüssel
|
||||||
|
|
||||||
standardInputDescription=Daten, die signiert werden sollen
|
|
||||||
standardOutputDescription=Inline-signierte OpenPGP Nachricht
|
|
||||||
|
|
||||||
stacktrace=Stacktrace ausgeben
|
stacktrace=Stacktrace ausgeben
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
# Generic TODO: Remove when bumping picocli to 4.7.0
|
||||||
usage.parameterListHeading=%nParameter:%n
|
usage.parameterListHeading=%nParameter:%n
|
||||||
usage.synopsisHeading=Aufruf:\u0020
|
usage.synopsisHeading=Aufruf:\u0020
|
||||||
usage.commandListHeading=%nBefehle:%n
|
usage.commandListHeading=%nBefehle:%n
|
||||||
usage.optionListHeading=%nOptionen:%n
|
usage.optionListHeading = %nOptionen:%n
|
||||||
usage.footerHeading=Powered by Picocli%n
|
usage.footerHeading=Powered by Picocli%n
|
||||||
|
|
|
@ -12,15 +12,10 @@ not-after.3=Accepts special value "-" for end of time.
|
||||||
verifications-out=File to write details over successful verifications to
|
verifications-out=File to write details over successful verifications to
|
||||||
CERT[0..*]=Public key certificates for signature verification
|
CERT[0..*]=Public key certificates for signature verification
|
||||||
|
|
||||||
standardInput=INLINESIGNED
|
|
||||||
standardInputDescription=Inline-signed OpenPGP message
|
|
||||||
standardOutput=DATA
|
|
||||||
standardOutputDescription=The message without any signatures
|
|
||||||
|
|
||||||
stacktrace=Print stacktrace
|
stacktrace=Print stacktrace
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
# Generic TODO: Remove when bumping picocli to 4.7.0
|
||||||
usage.parameterListHeading=%nParameters:%n
|
usage.parameterListHeading=%nParameters:%n
|
||||||
usage.synopsisHeading=Usage:\u0020
|
usage.synopsisHeading=Usage:\u0020
|
||||||
usage.commandListHeading=%nCommands:%n
|
usage.commandListHeading = %nCommands:%n
|
||||||
usage.optionListHeading=%nOptions:%n
|
usage.optionListHeading = %nOptions:%n
|
||||||
usage.footerHeading=Powered by picocli%n
|
usage.footerHeading=Powered by picocli%n
|
||||||
|
|
|
@ -12,13 +12,10 @@ not-after.3=Akzeptiert speziellen Wert '-' f
|
||||||
verifications-out=Schreibe Status der Signaturprüfung in angegebene Ausgabe
|
verifications-out=Schreibe Status der Signaturprüfung in angegebene Ausgabe
|
||||||
CERT[0..*]=Zertifikate (öffentlich Schlüssel) zur Signaturprüfung
|
CERT[0..*]=Zertifikate (öffentlich Schlüssel) zur Signaturprüfung
|
||||||
|
|
||||||
standardInputDescription=Inline-signierte OpenPGP Nachricht
|
|
||||||
standardOutputDescription=Nachricht ohne Signaturen
|
|
||||||
|
|
||||||
stacktrace=Stacktrace ausgeben
|
stacktrace=Stacktrace ausgeben
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
# Generic TODO: Remove when bumping picocli to 4.7.0
|
||||||
usage.parameterListHeading=%nParameter:%n
|
usage.parameterListHeading=%nParameter:%n
|
||||||
usage.synopsisHeading=Aufruf:\u0020
|
usage.synopsisHeading=Aufruf:\u0020
|
||||||
usage.commandListHeading=%nBefehle:%n
|
usage.commandListHeading=%nBefehle:%n
|
||||||
usage.optionListHeading=%nOptionen:%n
|
usage.optionListHeading = %nOptionen:%n
|
||||||
usage.footerHeading=Powered by Picocli%n
|
usage.footerHeading=Powered by Picocli%n
|
||||||
|
|
|
@ -4,13 +4,10 @@
|
||||||
usage.header=Emit a list of profiles supported by the identified subcommand
|
usage.header=Emit a list of profiles supported by the identified subcommand
|
||||||
subcommand=Subcommand for which to list profiles
|
subcommand=Subcommand for which to list profiles
|
||||||
|
|
||||||
standardOutput=PROFILELIST
|
|
||||||
standardOutputDescription=List of profiles supported by the identified subcommand
|
|
||||||
|
|
||||||
stacktrace=Print stacktrace
|
stacktrace=Print stacktrace
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
# Generic TODO: Remove when bumping picocli to 4.7.0
|
||||||
usage.parameterListHeading=%nParameters:%n
|
usage.parameterListHeading=%nParameters:%n
|
||||||
usage.synopsisHeading=Usage:\u0020
|
usage.synopsisHeading=Usage:\u0020
|
||||||
usage.commandListHeading=%nCommands:%n
|
usage.commandListHeading = %nCommands:%n
|
||||||
usage.optionListHeading=%nOptions:%n
|
usage.optionListHeading = %nOptions:%n
|
||||||
usage.footerHeading=Powered by picocli%n
|
usage.footerHeading=Powered by picocli%n
|
||||||
|
|
|
@ -4,12 +4,10 @@
|
||||||
usage.header=Gebe eine Liste von Profilen aus, welche vom angegebenen Unterbefehl unterstützt werden
|
usage.header=Gebe eine Liste von Profilen aus, welche vom angegebenen Unterbefehl unterstützt werden
|
||||||
subcommand=Unterbefehl, für welchen Profile gelistet werden sollen
|
subcommand=Unterbefehl, für welchen Profile gelistet werden sollen
|
||||||
|
|
||||||
standardOutputDescription=Liste von Profilen, die der identifizierte Unterbefehl unterstützt
|
|
||||||
|
|
||||||
stacktrace=Stacktrace ausgeben
|
stacktrace=Stacktrace ausgeben
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
# Generic TODO: Remove when bumping picocli to 4.7.0
|
||||||
usage.parameterListHeading=%nParameter:%n
|
usage.parameterListHeading=%nParameter:%n
|
||||||
usage.synopsisHeading=Aufruf:\u0020
|
usage.synopsisHeading=Aufruf:\u0020
|
||||||
usage.commandListHeading=%nBefehle:%n
|
usage.commandListHeading=%nBefehle:%n
|
||||||
usage.optionListHeading=%nOptionen:%n
|
usage.optionListHeading = %nOptionen:%n
|
||||||
usage.footerHeading=Powered by Picocli%n
|
usage.footerHeading=Powered by Picocli%n
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
# SPDX-FileCopyrightText: 2024 Paul Schaub <vanitasvitae@fsfe.org>
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
usage.headerHeading=Merge OpenPGP certificates%n
|
|
||||||
usage.header=Merge OpenPGP certificates from standard input with related elements from CERTS and emit the result to standard output
|
|
||||||
usage.description=Only certificates that were part of standard input will be emitted to standard output
|
|
||||||
no-armor=ASCII armor the output
|
|
||||||
CERTS[0..*]=OpenPGP certificates from which updates shall be merged into the base certificates from standard input
|
|
||||||
|
|
||||||
standardInput=CERTS
|
|
||||||
standardInputDescription=Base certificates into which additional elements from the command line shall be merged
|
|
||||||
standardOutput=CERTS
|
|
||||||
standardOutputDescription=Merged certificates
|
|
||||||
|
|
||||||
stacktrace=Print stacktrace
|
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
|
||||||
usage.parameterListHeading=%nParameters:%n
|
|
||||||
usage.synopsisHeading=Usage:\u0020
|
|
||||||
usage.descriptionHeading=%nNote:%n
|
|
||||||
usage.commandListHeading=%nCommands:%n
|
|
||||||
usage.optionListHeading=%nOptions:%n
|
|
||||||
usage.footerHeading=Powered by picocli%n
|
|
|
@ -1,19 +0,0 @@
|
||||||
# SPDX-FileCopyrightText: 2024 Paul Schaub <vanitasvitae@fsfe.org>
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
usage.headerHeading=OpenPGP Zertifikate zusammenführen%n
|
|
||||||
usage.header=Führe OpenPGP Zertifikate aus der Standardeingabe mit ensprechenden Elementen aus CERTS zusammen und gebe das Ergebnis auf der Standardausgabe aus
|
|
||||||
usage.description=Es werden nur Zertifikate auf die Standardausgabe geschrieben, welche Teil der Standardeingabe waren
|
|
||||||
no-armor=Schütze Ausgabe mit ASCII Armor
|
|
||||||
CERTS[0..*]=OpenPGP Zertifikate aus denen neue Elemente in die Basiszertifikate aus der Standardeingabe übernommen werden sollen
|
|
||||||
|
|
||||||
standardInputDescription=Basis-Zertifikate, in welche zusätzliche Elemente von der Kommandozeile zusammengeführt werden sollen
|
|
||||||
standardOutputDescription=Zusammengeführte Zertifikate
|
|
||||||
|
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
|
||||||
usage.parameterListHeading=%nParameter:%n
|
|
||||||
usage.synopsisHeading=Aufruf:\u0020
|
|
||||||
usage.descriptionHeading=%nHinweis:%n
|
|
||||||
usage.commandListHeading=%nBefehle:%n
|
|
||||||
usage.optionListHeading=%nOptionen:%n
|
|
||||||
usage.footerHeading=Powered by Picocli%n
|
|
|
@ -7,15 +7,10 @@ no-armor=ASCII armor the output
|
||||||
with-key-password.0=Passphrase to unlock the secret key(s).
|
with-key-password.0=Passphrase to unlock the secret key(s).
|
||||||
with-key-password.1=Is an INDIRECT data type (e.g. file, environment variable, file descriptor...).
|
with-key-password.1=Is an INDIRECT data type (e.g. file, environment variable, file descriptor...).
|
||||||
|
|
||||||
standardInput=KEYS
|
|
||||||
standardInputDescription=OpenPGP key that shall be revoked
|
|
||||||
standardOutput=CERTS
|
|
||||||
standardOutputDescription=Revocation certificate
|
|
||||||
|
|
||||||
stacktrace=Print stacktrace
|
stacktrace=Print stacktrace
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
# Generic TODO: Remove when bumping picocli to 4.7.0
|
||||||
usage.descriptionHeading=D%nescription:%n
|
usage.descriptionHeading=%nDescription:%n
|
||||||
usage.synopsisHeading=Usage:\u0020
|
usage.synopsisHeading=Usage:\u0020
|
||||||
usage.commandListHeading=%nCommands:%n
|
usage.commandListHeading = %nCommands:%n
|
||||||
usage.optionListHeading=%nOptions:%n
|
usage.optionListHeading = %nOptions:%n
|
||||||
usage.footerHeading=Powered by picocli%n
|
usage.footerHeading=Powered by picocli%n
|
||||||
|
|
|
@ -7,13 +7,10 @@ no-armor=Sch
|
||||||
with-key-password.0=Passwort zum Entsperren der privaten Schlüssel
|
with-key-password.0=Passwort zum Entsperren der privaten Schlüssel
|
||||||
with-key-password.1=Ist INDIREKTER Datentyp (z.B.. Datei, Umgebungsvariable, Dateideskriptor...).
|
with-key-password.1=Ist INDIREKTER Datentyp (z.B.. Datei, Umgebungsvariable, Dateideskriptor...).
|
||||||
|
|
||||||
standardInputDescription=OpenPGP Schlüssel, der widerrufen werden soll
|
|
||||||
standardOutputDescription=Widerrufszertifikat
|
|
||||||
|
|
||||||
stacktrace=Stacktrace ausgeben
|
stacktrace=Stacktrace ausgeben
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
# Generic TODO: Remove when bumping picocli to 4.7.0
|
||||||
usage.descriptionHeading=%nBeschreibung:%n
|
usage.descriptionHeading=%nBeschreibung:%n
|
||||||
usage.synopsisHeading=Aufruf:\u0020
|
usage.synopsisHeading=Aufruf:\u0020
|
||||||
usage.commandListHeading=%nBefehle:%n
|
usage.commandListHeading=%nBefehle:%n
|
||||||
usage.optionListHeading=%nOptionen:%n
|
usage.optionListHeading = %nOptionen:%n
|
||||||
usage.footerHeading=Powered by Picocli%n
|
usage.footerHeading=Powered by Picocli%n
|
||||||
|
|
|
@ -2,21 +2,15 @@
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
sop.name=sop
|
sop.name=sop
|
||||||
sopv.name=sopv
|
|
||||||
usage.header=Stateless OpenPGP Protocol
|
usage.header=Stateless OpenPGP Protocol
|
||||||
sopv.usage.header=Stateless OpenPGP Protocol - Signature Verification Interface Subset
|
|
||||||
locale=Locale for description texts
|
locale=Locale for description texts
|
||||||
|
|
||||||
# Generic
|
# Generic
|
||||||
usage.synopsisHeading=Usage:\u0020
|
usage.synopsisHeading=Usage:\u0020
|
||||||
usage.commandListHeading=%nCommands:%n
|
usage.commandListHeading = %nCommands:%n
|
||||||
usage.optionListHeading=%nOptions:%n
|
usage.optionListHeading = %nOptions:%n
|
||||||
usage.parameterListHeading=%nParameters:%n
|
|
||||||
usage.footerHeading=Powered by picocli%n
|
usage.footerHeading=Powered by picocli%n
|
||||||
|
|
||||||
standardInputHeading=%nInput:%n
|
|
||||||
standardOutputHeading=%nOutput:%n
|
|
||||||
|
|
||||||
# Exit Codes
|
# Exit Codes
|
||||||
usage.exitCodeListHeading=%nExit Codes:%n
|
usage.exitCodeListHeading=%nExit Codes:%n
|
||||||
usage.exitCodeList.0=\u00200:Successful program execution
|
usage.exitCodeList.0=\u00200:Successful program execution
|
||||||
|
@ -40,10 +34,6 @@ usage.exitCodeList.17=73:Ambiguous input (a filename matching the designator alr
|
||||||
usage.exitCodeList.18=79:Key is not signing capable
|
usage.exitCodeList.18=79:Key is not signing capable
|
||||||
usage.exitCodeList.19=83:Options were supplied that are incompatible with each other
|
usage.exitCodeList.19=83:Options were supplied that are incompatible with each other
|
||||||
usage.exitCodeList.20=89:The requested profile is unsupported, or the indicated subcommand does not accept profiles
|
usage.exitCodeList.20=89:The requested profile is unsupported, or the indicated subcommand does not accept profiles
|
||||||
usage.exitCodeList.21=97:The implementation supports some form of hardware-backed secret keys, but could not identify the hardware device
|
|
||||||
usage.exitCodeList.22=101:The implementation tried to use a hardware-backed secret key, but the cryptographic hardware refused the operation for some reason other than a bad PIN or password
|
|
||||||
usage.exitCodeList.23=103:The primary key of a KEYS object is too weak or revoked
|
|
||||||
usage.exitCodeList.24=107:The CERTS object has no matching User ID
|
|
||||||
|
|
||||||
## SHARED RESOURCES
|
## SHARED RESOURCES
|
||||||
stacktrace=Print stacktrace
|
stacktrace=Print stacktrace
|
||||||
|
@ -80,8 +70,6 @@ sop.error.runtime.cert_cannot_encrypt=Certificate from input '%s' cannot encrypt
|
||||||
sop.error.runtime.no_session_key_extracted=Session key not extracted. Feature potentially not supported.
|
sop.error.runtime.no_session_key_extracted=Session key not extracted. Feature potentially not supported.
|
||||||
sop.error.runtime.no_verifiable_signature_found=No verifiable signature found.
|
sop.error.runtime.no_verifiable_signature_found=No verifiable signature found.
|
||||||
sop.error.runtime.cannot_decrypt_message=Message could not be decrypted.
|
sop.error.runtime.cannot_decrypt_message=Message could not be decrypted.
|
||||||
sop.error.runtime.cert_user_id_no_match=Certificate '%s' does not contain a valid binding for user id '%s'.
|
|
||||||
sop.error.runtime.any_cert_user_id_no_match=Any certificate does not contain a valid binding for user id '%s'.
|
|
||||||
## Usage errors
|
## Usage errors
|
||||||
sop.error.usage.password_or_cert_required=At least one password file or cert file required for encryption.
|
sop.error.usage.password_or_cert_required=At least one password file or cert file required for encryption.
|
||||||
sop.error.usage.argument_required=Argument '%s' is required.
|
sop.error.usage.argument_required=Argument '%s' is required.
|
||||||
|
|
|
@ -2,21 +2,15 @@
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
sop.name=sop
|
sop.name=sop
|
||||||
sopv.name=sopv
|
|
||||||
usage.header=Stateless OpenPGP Protocol
|
usage.header=Stateless OpenPGP Protocol
|
||||||
sopv.usage.header=Stateless OpenPGP Protocol - Signature Verification Interface Subset
|
|
||||||
locale=Gebietsschema für Beschreibungstexte
|
locale=Gebietsschema für Beschreibungstexte
|
||||||
|
|
||||||
# Generic
|
# Generic
|
||||||
usage.synopsisHeading=Aufruf:\u0020
|
usage.synopsisHeading=Aufruf:\u0020
|
||||||
usage.commandListHeading=%nBefehle:%n
|
usage.commandListHeading=%nBefehle:%n
|
||||||
usage.optionListHeading=%nOptionen:%n
|
usage.optionListHeading = %nOptionen:%n
|
||||||
usage.parameterListHeading=%nParameter:%n
|
|
||||||
usage.footerHeading=Powered by Picocli%n
|
usage.footerHeading=Powered by Picocli%n
|
||||||
|
|
||||||
standardInputHeading=%nEingabe:%n
|
|
||||||
standardOutputHeading=%nAusgabe:%n
|
|
||||||
|
|
||||||
# Exit Codes
|
# Exit Codes
|
||||||
usage.exitCodeListHeading=%nExit Codes:%n
|
usage.exitCodeListHeading=%nExit Codes:%n
|
||||||
usage.exitCodeList.0=\u00200:Erfolgreiche Programmausführung
|
usage.exitCodeList.0=\u00200:Erfolgreiche Programmausführung
|
||||||
|
@ -40,10 +34,6 @@ usage.exitCodeList.17=73:Mehrdeutige Eingabe (ein Dateiname, der dem Bezeichner
|
||||||
usage.exitCodeList.18=79:Schlüssel ist nicht fähig zu signieren
|
usage.exitCodeList.18=79:Schlüssel ist nicht fähig zu signieren
|
||||||
usage.exitCodeList.19=83:Miteinander inkompatible Optionen spezifiziert
|
usage.exitCodeList.19=83:Miteinander inkompatible Optionen spezifiziert
|
||||||
usage.exitCodeList.20=89:Das angeforderte Profil wird nicht unterstützt, oder der angegebene Unterbefehl akzeptiert keine Profile
|
usage.exitCodeList.20=89:Das angeforderte Profil wird nicht unterstützt, oder der angegebene Unterbefehl akzeptiert keine Profile
|
||||||
usage.exitCodeList.21=97:Die Anwendung unterstützt hardwaregestützte private Schlüssel, aber kann das Gerät nicht identifizieren
|
|
||||||
usage.exitCodeList.22=101:Die Anwendung versuchte, einen hardwaregestützten Schlüssel zu verwenden, aber das Gerät lehnte den Vorgang aus einem anderen Grund als einer falschen PIN oder einem falschen Passwort ab
|
|
||||||
usage.exitCodeList.23=103:Der primäre private Schlüssel ist zu schwach oder widerrufen
|
|
||||||
usage.exitCodeList.24=107:Das Zertifikat hat keine übereinstimmende User ID
|
|
||||||
|
|
||||||
## SHARED RESOURCES
|
## SHARED RESOURCES
|
||||||
stacktrace=Stacktrace ausgeben
|
stacktrace=Stacktrace ausgeben
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
# SPDX-FileCopyrightText: 2024 Paul Schaub <vanitasvitae@fsfe.org>
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
usage.header=Keep a secret key up-to-date
|
|
||||||
no-armor=ASCII armor the output
|
|
||||||
signing-only=TODO: Document
|
|
||||||
no-added-capabilities=Do not add feature support for new mechanisms, which the key did not previously support
|
|
||||||
with-key-password.0=Passphrase to unlock the secret key(s).
|
|
||||||
with-key-password.1=Is an INDIRECT data type (e.g. file, environment variable, file descriptor...).
|
|
||||||
merge-certs.0=Merge additional elements found in the corresponding CERTS objects into the updated secret keys
|
|
||||||
merge-certs.1=This can be used, for example, to absorb a third-party certification into the Transferable Secret Key
|
|
||||||
|
|
||||||
standardInput=KEYS
|
|
||||||
standardInputDescription=OpenPGP key that shall be kept up-to-date
|
|
||||||
standardOutput=KEYS
|
|
||||||
standardOutputDescription=Updated OpenPGP key
|
|
||||||
|
|
||||||
stacktrace=Print stacktrace
|
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
|
||||||
usage.parameterListHeading=%nParameters:%n
|
|
||||||
usage.synopsisHeading=Usage:\u0020
|
|
||||||
usage.commandListHeading=%nCommands:%n
|
|
||||||
usage.optionListHeading=%nOptions:%n
|
|
||||||
usage.footerHeading=Powered by picocli%n
|
|
|
@ -1,21 +0,0 @@
|
||||||
# SPDX-FileCopyrightText: 2024 Paul Schaub <vanitasvitae@fsfe.org>
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
usage.header=Halte einen Schlüssel auf dem neusten Stand
|
|
||||||
no-armor=Schütze Ausgabe mit ASCII Armor
|
|
||||||
signing-only=TODO: Dokumentieren
|
|
||||||
no-added-capabilities=Füge keine neuen Funktionen hinzu, die der Schlüssel nicht bereits zuvor unterstützt hat
|
|
||||||
with-key-password.0=Passwort zum Entsperren der privaten Schlüssel
|
|
||||||
with-key-password.1=Ist INDIREKTER Datentyp (z.B.. Datei, Umgebungsvariable, Dateideskriptor...).
|
|
||||||
merge-certs.0=Führe zusätzliche Elemente aus entsprechenden CERTS Objekten mit dem privaten Schlüssel zusammen
|
|
||||||
merge-certs.1=Dies kann zum Beispiel dazu genutzt werden, Zertifizierungen dritter in den privaten Schlüssel zu übernehmen
|
|
||||||
|
|
||||||
standardInputDescription=OpenPGP Schlüssel, der auf den neusten Stand gebracht werden soll
|
|
||||||
standardOutputDescription=Erneuerter OpenPGP Schlüssel
|
|
||||||
|
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
|
||||||
usage.parameterListHeading=%nParameter:%n
|
|
||||||
usage.synopsisHeading=Aufruf:\u0020
|
|
||||||
usage.commandListHeading=%nBefehle:%n
|
|
||||||
usage.optionListHeading=%nOptionen:%n
|
|
||||||
usage.footerHeading=Powered by Picocli%n
|
|
|
@ -1,20 +0,0 @@
|
||||||
# SPDX-FileCopyrightText: 2024 Paul Schaub <vanitasvitae@fsfe.org>
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
usage.header=Validate a UserID in an OpenPGP certificate
|
|
||||||
addr-spec-only=Treat the USERID as an email address, match only against the email address part of each correctly bound UserID
|
|
||||||
USERID[0]=UserID
|
|
||||||
CERTS[1..*]=Authority OpenPGP certificates
|
|
||||||
|
|
||||||
standardInput=CERTS
|
|
||||||
standardInputDescription=OpenPGP certificates in which UserID bindings shall be validated
|
|
||||||
|
|
||||||
picocli.endofoptions.description=End of options. Remainder are positional parameters. Fixes 'Missing required parameter' error
|
|
||||||
|
|
||||||
stacktrace=Print stacktrace
|
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
|
||||||
usage.parameterListHeading=%nParameters:%n
|
|
||||||
usage.synopsisHeading=Usage:\u0020
|
|
||||||
usage.commandListHeading=%nCommands:%n
|
|
||||||
usage.optionListHeading=%nOptions:%n
|
|
||||||
usage.footerHeading=Powered by picocli%n
|
|
|
@ -1,20 +0,0 @@
|
||||||
# SPDX-FileCopyrightText: 2024 Paul Schaub <vanitasvitae@fsfe.org>
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
usage.header=Validiere eine UserID auf OpenPGP Zertifikaten
|
|
||||||
addr-spec-only=Behandle die USERID als E-Mail-Adresse, vergleiche sie nur mit dem E-Mail-Adressen-Teil jeder korrekten UserID
|
|
||||||
USERID[0]=UserID
|
|
||||||
CERTS[1..*]=Autoritäre OpenPGP Zertifikate
|
|
||||||
|
|
||||||
standardInput=CERTS
|
|
||||||
standardInputDescription=OpenPGP Zertifikate auf denen UserIDs validiert werden sollen
|
|
||||||
|
|
||||||
picocli.endofoptions.description=Ende der Optionen. Der Rest sind Positionsparameter. Behebt 'Missing required parameter' Fehler
|
|
||||||
|
|
||||||
stacktrace=Print stacktrace
|
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
|
||||||
usage.parameterListHeading=%nParameter:%n
|
|
||||||
usage.synopsisHeading=Aufruf:\u0020
|
|
||||||
usage.commandListHeading=%nBefehle:%n
|
|
||||||
usage.optionListHeading=%nOptionen:%n
|
|
||||||
usage.footerHeading=Powered by Picocli%n
|
|
|
@ -5,13 +5,10 @@ usage.header=Display version information about the tool
|
||||||
extended=Print an extended version string
|
extended=Print an extended version string
|
||||||
backend=Print information about the cryptographic backend
|
backend=Print information about the cryptographic backend
|
||||||
sop-spec=Print the latest revision of the SOP specification targeted by the implementation
|
sop-spec=Print the latest revision of the SOP specification targeted by the implementation
|
||||||
sopv=Print the SOPV API version
|
|
||||||
|
|
||||||
standardOutput=version information
|
|
||||||
|
|
||||||
stacktrace=Print stacktrace
|
stacktrace=Print stacktrace
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
# Generic TODO: Remove when bumping picocli to 4.7.0
|
||||||
usage.synopsisHeading=Usage:\u0020
|
usage.synopsisHeading=Usage:\u0020
|
||||||
usage.commandListHeading=%nCommands:%n
|
usage.commandListHeading = %nCommands:%n
|
||||||
usage.optionListHeading=%nOptions:%n
|
usage.optionListHeading = %nOptions:%n
|
||||||
usage.footerHeading=Powered by picocli%n
|
usage.footerHeading=Powered by picocli%n
|
||||||
|
|
|
@ -5,13 +5,10 @@ usage.header=Zeige Versionsinformationen
|
||||||
extended=Gebe erweiterte Versionsinformationen aus
|
extended=Gebe erweiterte Versionsinformationen aus
|
||||||
backend=Gebe Informationen über das kryptografische Backend aus
|
backend=Gebe Informationen über das kryptografische Backend aus
|
||||||
sop-spec=Gebe die neuste Revision der SOP Spezifikation aus, welche von dieser Implementierung umgesetzt wird
|
sop-spec=Gebe die neuste Revision der SOP Spezifikation aus, welche von dieser Implementierung umgesetzt wird
|
||||||
sopv=Gebe die SOPV API Version aus
|
|
||||||
|
|
||||||
standardOutput=Versionsinformationen
|
|
||||||
|
|
||||||
stacktrace=Stacktrace ausgeben
|
stacktrace=Stacktrace ausgeben
|
||||||
# Generic TODO: Remove when bumping picocli to 4.7.0
|
# Generic TODO: Remove when bumping picocli to 4.7.0
|
||||||
usage.synopsisHeading=Aufruf:\u0020
|
usage.synopsisHeading=Aufruf:\u0020
|
||||||
usage.commandListHeading=%nBefehle:%n
|
usage.commandListHeading=%nBefehle:%n
|
||||||
usage.optionListHeading=%nOptionen:%n
|
usage.optionListHeading = %nOptionen:%n
|
||||||
usage.footerHeading=Powered by Picocli%n
|
usage.footerHeading=Powered by Picocli%n
|
||||||
|
|
|
@ -6,18 +6,16 @@ package sop.cli.picocli;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertGenericError;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertUnsupportedSubcommand;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.ginsberg.junit.exit.ExpectSystemExitWithStatus;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import sop.SOP;
|
import sop.SOP;
|
||||||
import sop.exception.SOPGPException;
|
import sop.exception.SOPGPException;
|
||||||
import sop.operation.Armor;
|
import sop.operation.Armor;
|
||||||
import sop.operation.CertifyUserId;
|
|
||||||
import sop.operation.ChangeKeyPassword;
|
import sop.operation.ChangeKeyPassword;
|
||||||
import sop.operation.Dearmor;
|
import sop.operation.Dearmor;
|
||||||
import sop.operation.Decrypt;
|
import sop.operation.Decrypt;
|
||||||
|
@ -30,52 +28,31 @@ import sop.operation.InlineVerify;
|
||||||
import sop.operation.DetachedSign;
|
import sop.operation.DetachedSign;
|
||||||
import sop.operation.DetachedVerify;
|
import sop.operation.DetachedVerify;
|
||||||
import sop.operation.ListProfiles;
|
import sop.operation.ListProfiles;
|
||||||
import sop.operation.MergeCerts;
|
|
||||||
import sop.operation.RevokeKey;
|
import sop.operation.RevokeKey;
|
||||||
import sop.operation.UpdateKey;
|
|
||||||
import sop.operation.ValidateUserId;
|
|
||||||
import sop.operation.Version;
|
import sop.operation.Version;
|
||||||
|
|
||||||
public class SOPTest {
|
public class SOPTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.UnsupportedSubcommand.EXIT_CODE)
|
||||||
public void assertExitOnInvalidSubcommand() {
|
public void assertExitOnInvalidSubcommand() {
|
||||||
SOP sop = mock(SOP.class);
|
SOP sop = mock(SOP.class);
|
||||||
SopCLI.setSopInstance(sop);
|
SopCLI.setSopInstance(sop);
|
||||||
|
|
||||||
assertUnsupportedSubcommand(() -> SopCLI.execute("invalid"));
|
SopCLI.main(new String[] {"invalid"});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(1)
|
||||||
public void assertThrowsIfNoSOPBackendSet() {
|
public void assertThrowsIfNoSOPBackendSet() {
|
||||||
SopCLI.setSopInstance(null);
|
SopCLI.setSopInstance(null);
|
||||||
// At this point, no SOP backend is set, so an InvalidStateException triggers error code 1
|
// At this point, no SOP backend is set, so an InvalidStateException triggers exit(1)
|
||||||
assertGenericError(() -> SopCLI.execute("armor"));
|
SopCLI.main(new String[] {"armor"});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void UnsupportedSubcommandsTest() {
|
public void UnsupportedSubcommandsTest() {
|
||||||
SOP nullCommandSOP = new SOP() {
|
SOP nullCommandSOP = new SOP() {
|
||||||
@Override
|
|
||||||
public ValidateUserId validateUserId() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CertifyUserId certifyUserId() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MergeCerts mergeCerts() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UpdateKey updateKey() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Version version() {
|
public Version version() {
|
||||||
return null;
|
return null;
|
||||||
|
@ -164,11 +141,6 @@ public class SOPTest {
|
||||||
commands.add(new String[] {"sign"});
|
commands.add(new String[] {"sign"});
|
||||||
commands.add(new String[] {"verify", "signature.asc", "cert.asc"});
|
commands.add(new String[] {"verify", "signature.asc", "cert.asc"});
|
||||||
commands.add(new String[] {"version"});
|
commands.add(new String[] {"version"});
|
||||||
commands.add(new String[] {"list-profiles", "generate-key"});
|
|
||||||
commands.add(new String[] {"certify-userid", "--userid", "Alice <alice@pgpainless.org>", "--", "alice.pgp"});
|
|
||||||
commands.add(new String[] {"validate-userid", "Alice <alice@pgpainless.org>", "bob.pgp", "--", "alice.pgp"});
|
|
||||||
commands.add(new String[] {"update-key"});
|
|
||||||
commands.add(new String[] {"merge-certs"});
|
|
||||||
|
|
||||||
for (String[] command : commands) {
|
for (String[] command : commands) {
|
||||||
int exit = SopCLI.execute(command);
|
int exit = SopCLI.execute(command);
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
package sop.cli.picocli.commands;
|
package sop.cli.picocli.commands;
|
||||||
|
|
||||||
|
import com.ginsberg.junit.exit.ExpectSystemExitWithStatus;
|
||||||
|
import com.ginsberg.junit.exit.FailOnSystemExit;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import sop.Ready;
|
import sop.Ready;
|
||||||
|
@ -22,8 +24,6 @@ import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertBadData;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertSuccess;
|
|
||||||
|
|
||||||
public class ArmorCmdTest {
|
public class ArmorCmdTest {
|
||||||
|
|
||||||
|
@ -42,22 +42,24 @@ public class ArmorCmdTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void assertDataIsAlwaysCalled() throws SOPGPException.BadData, IOException {
|
public void assertDataIsAlwaysCalled() throws SOPGPException.BadData, IOException {
|
||||||
assertSuccess(() -> SopCLI.execute("armor"));
|
SopCLI.main(new String[] {"armor"});
|
||||||
verify(armor, times(1)).data((InputStream) any());
|
verify(armor, times(1)).data((InputStream) any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.BadData.EXIT_CODE)
|
||||||
public void ifBadDataExit41() throws SOPGPException.BadData, IOException {
|
public void ifBadDataExit41() throws SOPGPException.BadData, IOException {
|
||||||
when(armor.data((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException()));
|
when(armor.data((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException()));
|
||||||
|
|
||||||
assertBadData(() -> SopCLI.execute("armor"));
|
SopCLI.main(new String[] {"armor"});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@FailOnSystemExit
|
||||||
public void ifNoErrorsNoExit() {
|
public void ifNoErrorsNoExit() {
|
||||||
when(sop.armor()).thenReturn(armor);
|
when(sop.armor()).thenReturn(armor);
|
||||||
|
|
||||||
assertSuccess(() -> SopCLI.execute("armor"));
|
SopCLI.main(new String[] {"armor"});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Ready nopReady() {
|
private static Ready nopReady() {
|
||||||
|
|
|
@ -9,13 +9,12 @@ import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertBadData;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertSuccess;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
import com.ginsberg.junit.exit.ExpectSystemExitWithStatus;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import sop.Ready;
|
import sop.Ready;
|
||||||
|
@ -49,13 +48,14 @@ public class DearmorCmdTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void assertDataIsCalled() throws IOException, SOPGPException.BadData {
|
public void assertDataIsCalled() throws IOException, SOPGPException.BadData {
|
||||||
assertSuccess(() -> SopCLI.execute("dearmor"));
|
SopCLI.main(new String[] {"dearmor"});
|
||||||
verify(dearmor, times(1)).data((InputStream) any());
|
verify(dearmor, times(1)).data((InputStream) any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.BadData.EXIT_CODE)
|
||||||
public void assertBadDataCausesExit41() throws IOException, SOPGPException.BadData {
|
public void assertBadDataCausesExit41() throws IOException, SOPGPException.BadData {
|
||||||
when(dearmor.data((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException("invalid armor")));
|
when(dearmor.data((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException("invalid armor")));
|
||||||
assertBadData(() -> SopCLI.execute("dearmor"));
|
SopCLI.main(new String[] {"dearmor"});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
package sop.cli.picocli.commands;
|
package sop.cli.picocli.commands;
|
||||||
|
|
||||||
|
import com.ginsberg.junit.exit.ExpectSystemExitWithStatus;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.mockito.ArgumentMatcher;
|
import org.mockito.ArgumentMatcher;
|
||||||
|
@ -41,18 +42,6 @@ import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertBadData;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertCannotDecrypt;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertGenericError;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertIncompleteVerification;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertKeyIsProtected;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertMissingArg;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertMissingInput;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertOutputExists;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertPasswordNotHumanReadable;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertSuccess;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertUnsupportedAsymmetricAlgo;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertUnsupportedOption;
|
|
||||||
|
|
||||||
public class DecryptCmdTest {
|
public class DecryptCmdTest {
|
||||||
|
|
||||||
|
@ -85,47 +74,47 @@ public class DecryptCmdTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.MissingArg.EXIT_CODE)
|
||||||
public void missingArgumentsExceptionCausesExit19() throws SOPGPException.MissingArg, SOPGPException.BadData, SOPGPException.CannotDecrypt, IOException {
|
public void missingArgumentsExceptionCausesExit19() throws SOPGPException.MissingArg, SOPGPException.BadData, SOPGPException.CannotDecrypt, IOException {
|
||||||
when(decrypt.ciphertext((InputStream) any())).thenThrow(new SOPGPException.MissingArg("Missing arguments."));
|
when(decrypt.ciphertext((InputStream) any())).thenThrow(new SOPGPException.MissingArg("Missing arguments."));
|
||||||
assertMissingArg(() -> SopCLI.execute("decrypt"));
|
SopCLI.main(new String[] {"decrypt"});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.BadData.EXIT_CODE)
|
||||||
public void badDataExceptionCausesExit41() throws SOPGPException.MissingArg, SOPGPException.BadData, SOPGPException.CannotDecrypt, IOException {
|
public void badDataExceptionCausesExit41() throws SOPGPException.MissingArg, SOPGPException.BadData, SOPGPException.CannotDecrypt, IOException {
|
||||||
when(decrypt.ciphertext((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException()));
|
when(decrypt.ciphertext((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException()));
|
||||||
assertBadData(() -> SopCLI.execute("decrypt"));
|
SopCLI.main(new String[] {"decrypt"});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.PasswordNotHumanReadable.EXIT_CODE)
|
||||||
public void assertNotHumanReadablePasswordCausesExit31() throws SOPGPException.PasswordNotHumanReadable,
|
public void assertNotHumanReadablePasswordCausesExit31() throws SOPGPException.PasswordNotHumanReadable,
|
||||||
SOPGPException.UnsupportedOption, IOException {
|
SOPGPException.UnsupportedOption, IOException {
|
||||||
File passwordFile = TestFileUtil.writeTempStringFile("pretendThisIsNotReadable");
|
File passwordFile = TestFileUtil.writeTempStringFile("pretendThisIsNotReadable");
|
||||||
when(decrypt.withPassword(any())).thenThrow(new SOPGPException.PasswordNotHumanReadable());
|
when(decrypt.withPassword(any())).thenThrow(new SOPGPException.PasswordNotHumanReadable());
|
||||||
assertPasswordNotHumanReadable(() ->
|
SopCLI.main(new String[] {"decrypt", "--with-password", passwordFile.getAbsolutePath()});
|
||||||
SopCLI.execute("decrypt", "--with-password", passwordFile.getAbsolutePath())
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void assertWithPasswordPassesPasswordDown() throws SOPGPException.PasswordNotHumanReadable, SOPGPException.UnsupportedOption, IOException {
|
public void assertWithPasswordPassesPasswordDown() throws SOPGPException.PasswordNotHumanReadable, SOPGPException.UnsupportedOption, IOException {
|
||||||
File passwordFile = TestFileUtil.writeTempStringFile("orange");
|
File passwordFile = TestFileUtil.writeTempStringFile("orange");
|
||||||
assertSuccess(() -> SopCLI.execute("decrypt", "--with-password", passwordFile.getAbsolutePath()));
|
SopCLI.main(new String[] {"decrypt", "--with-password", passwordFile.getAbsolutePath()});
|
||||||
verify(decrypt, times(1)).withPassword("orange");
|
verify(decrypt, times(1)).withPassword("orange");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.UnsupportedOption.EXIT_CODE)
|
||||||
public void assertUnsupportedWithPasswordCausesExit37() throws SOPGPException.PasswordNotHumanReadable, SOPGPException.UnsupportedOption, IOException {
|
public void assertUnsupportedWithPasswordCausesExit37() throws SOPGPException.PasswordNotHumanReadable, SOPGPException.UnsupportedOption, IOException {
|
||||||
File passwordFile = TestFileUtil.writeTempStringFile("swordfish");
|
File passwordFile = TestFileUtil.writeTempStringFile("swordfish");
|
||||||
when(decrypt.withPassword(any())).thenThrow(new SOPGPException.UnsupportedOption("Decrypting with password not supported."));
|
when(decrypt.withPassword(any())).thenThrow(new SOPGPException.UnsupportedOption("Decrypting with password not supported."));
|
||||||
assertUnsupportedOption(() ->
|
SopCLI.main(new String[] {"decrypt", "--with-password", passwordFile.getAbsolutePath()});
|
||||||
SopCLI.execute("decrypt", "--with-password", passwordFile.getAbsolutePath())
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void assertDefaultTimeRangesAreUsedIfNotOverwritten() throws SOPGPException.UnsupportedOption {
|
public void assertDefaultTimeRangesAreUsedIfNotOverwritten() throws SOPGPException.UnsupportedOption {
|
||||||
Date now = new Date();
|
Date now = new Date();
|
||||||
assertSuccess(() -> SopCLI.execute("decrypt"));
|
SopCLI.main(new String[] {"decrypt"});
|
||||||
verify(decrypt, times(1)).verifyNotBefore(AbstractSopCmd.BEGINNING_OF_TIME);
|
verify(decrypt, times(1)).verifyNotBefore(AbstractSopCmd.BEGINNING_OF_TIME);
|
||||||
verify(decrypt, times(1)).verifyNotAfter(
|
verify(decrypt, times(1)).verifyNotAfter(
|
||||||
ArgumentMatchers.argThat(argument -> {
|
ArgumentMatchers.argThat(argument -> {
|
||||||
|
@ -136,8 +125,7 @@ public class DecryptCmdTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void assertVerifyNotAfterAndBeforeDashResultsInMaxTimeRange() throws SOPGPException.UnsupportedOption {
|
public void assertVerifyNotAfterAndBeforeDashResultsInMaxTimeRange() throws SOPGPException.UnsupportedOption {
|
||||||
assertSuccess(() ->
|
SopCLI.main(new String[] {"decrypt", "--verify-not-before", "-", "--verify-not-after", "-"});
|
||||||
SopCLI.execute("decrypt", "--verify-not-before", "-", "--verify-not-after", "-"));
|
|
||||||
verify(decrypt, times(1)).verifyNotBefore(AbstractSopCmd.BEGINNING_OF_TIME);
|
verify(decrypt, times(1)).verifyNotBefore(AbstractSopCmd.BEGINNING_OF_TIME);
|
||||||
verify(decrypt, times(1)).verifyNotAfter(AbstractSopCmd.END_OF_TIME);
|
verify(decrypt, times(1)).verifyNotAfter(AbstractSopCmd.END_OF_TIME);
|
||||||
}
|
}
|
||||||
|
@ -150,57 +138,54 @@ public class DecryptCmdTest {
|
||||||
return Math.abs(now.getTime() - argument.getTime()) <= 1000;
|
return Math.abs(now.getTime() - argument.getTime()) <= 1000;
|
||||||
};
|
};
|
||||||
|
|
||||||
assertSuccess(() ->
|
SopCLI.main(new String[] {"decrypt", "--verify-not-before", "now", "--verify-not-after", "now"});
|
||||||
SopCLI.execute("decrypt", "--verify-not-before", "now", "--verify-not-after", "now"));
|
|
||||||
verify(decrypt, times(1)).verifyNotAfter(ArgumentMatchers.argThat(isMaxOneSecOff));
|
verify(decrypt, times(1)).verifyNotAfter(ArgumentMatchers.argThat(isMaxOneSecOff));
|
||||||
verify(decrypt, times(1)).verifyNotBefore(ArgumentMatchers.argThat(isMaxOneSecOff));
|
verify(decrypt, times(1)).verifyNotBefore(ArgumentMatchers.argThat(isMaxOneSecOff));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(1)
|
||||||
public void assertMalformedDateInNotBeforeCausesExit1() {
|
public void assertMalformedDateInNotBeforeCausesExit1() {
|
||||||
// ParserException causes exit(1)
|
// ParserException causes exit(1)
|
||||||
assertGenericError(() ->
|
SopCLI.main(new String[] {"decrypt", "--verify-not-before", "invalid"});
|
||||||
SopCLI.execute("decrypt", "--verify-not-before", "invalid"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(1)
|
||||||
public void assertMalformedDateInNotAfterCausesExit1() {
|
public void assertMalformedDateInNotAfterCausesExit1() {
|
||||||
// ParserException causes exit(1)
|
// ParserException causes exit(1)
|
||||||
assertGenericError(() ->
|
SopCLI.main(new String[] {"decrypt", "--verify-not-after", "invalid"});
|
||||||
SopCLI.execute("decrypt", "--verify-not-after", "invalid"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.UnsupportedOption.EXIT_CODE)
|
||||||
public void assertUnsupportedNotAfterCausesExit37() throws SOPGPException.UnsupportedOption {
|
public void assertUnsupportedNotAfterCausesExit37() throws SOPGPException.UnsupportedOption {
|
||||||
when(decrypt.verifyNotAfter(any())).thenThrow(
|
when(decrypt.verifyNotAfter(any())).thenThrow(new SOPGPException.UnsupportedOption("Setting upper signature date boundary not supported."));
|
||||||
new SOPGPException.UnsupportedOption("Setting upper signature date boundary not supported."));
|
SopCLI.main(new String[] {"decrypt", "--verify-not-after", "now"});
|
||||||
assertUnsupportedOption(() ->
|
|
||||||
SopCLI.execute("decrypt", "--verify-not-after", "now"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.UnsupportedOption.EXIT_CODE)
|
||||||
public void assertUnsupportedNotBeforeCausesExit37() throws SOPGPException.UnsupportedOption {
|
public void assertUnsupportedNotBeforeCausesExit37() throws SOPGPException.UnsupportedOption {
|
||||||
when(decrypt.verifyNotBefore(any())).thenThrow(
|
when(decrypt.verifyNotBefore(any())).thenThrow(new SOPGPException.UnsupportedOption("Setting lower signature date boundary not supported."));
|
||||||
new SOPGPException.UnsupportedOption("Setting lower signature date boundary not supported."));
|
SopCLI.main(new String[] {"decrypt", "--verify-not-before", "now"});
|
||||||
assertUnsupportedOption(() ->
|
|
||||||
SopCLI.execute("decrypt", "--verify-not-before", "now"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.OutputExists.EXIT_CODE)
|
||||||
public void assertExistingSessionKeyOutFileCausesExit59() throws IOException {
|
public void assertExistingSessionKeyOutFileCausesExit59() throws IOException {
|
||||||
File tempFile = File.createTempFile("existing-session-key-", ".tmp");
|
File tempFile = File.createTempFile("existing-session-key-", ".tmp");
|
||||||
tempFile.deleteOnExit();
|
tempFile.deleteOnExit();
|
||||||
assertOutputExists(() ->
|
SopCLI.main(new String[] {"decrypt", "--session-key-out", tempFile.getAbsolutePath()});
|
||||||
SopCLI.execute("decrypt", "--session-key-out", tempFile.getAbsolutePath()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.UnsupportedOption.EXIT_CODE)
|
||||||
public void assertWhenSessionKeyCannotBeExtractedExit37() throws IOException {
|
public void assertWhenSessionKeyCannotBeExtractedExit37() throws IOException {
|
||||||
Path tempDir = Files.createTempDirectory("session-key-out-dir");
|
Path tempDir = Files.createTempDirectory("session-key-out-dir");
|
||||||
File tempFile = new File(tempDir.toFile(), "session-key");
|
File tempFile = new File(tempDir.toFile(), "session-key");
|
||||||
tempFile.deleteOnExit();
|
tempFile.deleteOnExit();
|
||||||
assertUnsupportedOption(() ->
|
SopCLI.main(new String[] {"decrypt", "--session-key-out", tempFile.getAbsolutePath()});
|
||||||
SopCLI.execute("decrypt", "--session-key-out", tempFile.getAbsolutePath()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -225,10 +210,8 @@ public class DecryptCmdTest {
|
||||||
File verificationsFile = new File(tempDir.toFile(), "verifications");
|
File verificationsFile = new File(tempDir.toFile(), "verifications");
|
||||||
File keyFile = new File(tempDir.toFile(), "key.asc");
|
File keyFile = new File(tempDir.toFile(), "key.asc");
|
||||||
keyFile.createNewFile();
|
keyFile.createNewFile();
|
||||||
assertSuccess(() ->
|
SopCLI.main(new String[] {"decrypt", "--session-key-out", sessionKeyFile.getAbsolutePath(),
|
||||||
SopCLI.execute("decrypt", "--session-key-out", sessionKeyFile.getAbsolutePath(),
|
"--verifications-out", verificationsFile.getAbsolutePath(), "--verify-with", keyFile.getAbsolutePath()});
|
||||||
"--verifications-out", verificationsFile.getAbsolutePath(), "--verify-with",
|
|
||||||
keyFile.getAbsolutePath()));
|
|
||||||
|
|
||||||
ByteArrayOutputStream bytesInFile = new ByteArrayOutputStream();
|
ByteArrayOutputStream bytesInFile = new ByteArrayOutputStream();
|
||||||
try (FileInputStream fileIn = new FileInputStream(sessionKeyFile)) {
|
try (FileInputStream fileIn = new FileInputStream(sessionKeyFile)) {
|
||||||
|
@ -258,10 +241,10 @@ public class DecryptCmdTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.CannotDecrypt.EXIT_CODE)
|
||||||
public void assertUnableToDecryptExceptionResultsInExit29() throws SOPGPException.CannotDecrypt, SOPGPException.MissingArg, SOPGPException.BadData, IOException {
|
public void assertUnableToDecryptExceptionResultsInExit29() throws SOPGPException.CannotDecrypt, SOPGPException.MissingArg, SOPGPException.BadData, IOException {
|
||||||
when(decrypt.ciphertext((InputStream) any())).thenThrow(new SOPGPException.CannotDecrypt());
|
when(decrypt.ciphertext((InputStream) any())).thenThrow(new SOPGPException.CannotDecrypt());
|
||||||
assertCannotDecrypt(() ->
|
SopCLI.main(new String[] {"decrypt"});
|
||||||
SopCLI.execute("decrypt"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -275,32 +258,30 @@ public class DecryptCmdTest {
|
||||||
return new DecryptionResult(null, Collections.emptyList());
|
return new DecryptionResult(null, Collections.emptyList());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
assertSuccess(() ->
|
SopCLI.main(new String[] {"decrypt", "--verify-with", tempFile.getAbsolutePath(), "--verifications-out", verifyOut.getAbsolutePath()});
|
||||||
SopCLI.execute("decrypt", "--verify-with", tempFile.getAbsolutePath(), "--verifications-out",
|
|
||||||
verifyOut.getAbsolutePath()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.BadData.EXIT_CODE)
|
||||||
public void badDataInVerifyWithCausesExit41() throws IOException, SOPGPException.BadData {
|
public void badDataInVerifyWithCausesExit41() throws IOException, SOPGPException.BadData {
|
||||||
when(decrypt.verifyWithCert((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException()));
|
when(decrypt.verifyWithCert((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException()));
|
||||||
File tempFile = File.createTempFile("verify-with-", ".tmp");
|
File tempFile = File.createTempFile("verify-with-", ".tmp");
|
||||||
assertBadData(() ->
|
SopCLI.main(new String[] {"decrypt", "--verify-with", tempFile.getAbsolutePath()});
|
||||||
SopCLI.execute("decrypt", "--verify-with", tempFile.getAbsolutePath()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.MissingInput.EXIT_CODE)
|
||||||
public void unexistentCertFileCausesExit61() {
|
public void unexistentCertFileCausesExit61() {
|
||||||
assertMissingInput(() ->
|
SopCLI.main(new String[] {"decrypt", "--verify-with", "invalid"});
|
||||||
SopCLI.execute("decrypt", "--verify-with", "invalid"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.OutputExists.EXIT_CODE)
|
||||||
public void existingVerifyOutCausesExit59() throws IOException {
|
public void existingVerifyOutCausesExit59() throws IOException {
|
||||||
File certFile = File.createTempFile("existing-verify-out-cert", ".asc");
|
File certFile = File.createTempFile("existing-verify-out-cert", ".asc");
|
||||||
File existingVerifyOut = File.createTempFile("existing-verify-out", ".tmp");
|
File existingVerifyOut = File.createTempFile("existing-verify-out", ".tmp");
|
||||||
|
|
||||||
assertOutputExists(() -> SopCLI.execute("decrypt", "--verifications-out",
|
SopCLI.main(new String[] {"decrypt", "--verifications-out", existingVerifyOut.getAbsolutePath(), "--verify-with", certFile.getAbsolutePath()});
|
||||||
existingVerifyOut.getAbsolutePath(), "--verify-with", certFile.getAbsolutePath()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -324,9 +305,7 @@ public class DecryptCmdTest {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
assertSuccess(() ->
|
SopCLI.main(new String[] {"decrypt", "--verifications-out", verifyOut.getAbsolutePath(), "--verify-with", certFile.getAbsolutePath()});
|
||||||
SopCLI.execute("decrypt", "--verifications-out", verifyOut.getAbsolutePath(),
|
|
||||||
"--verify-with", certFile.getAbsolutePath()));
|
|
||||||
try (BufferedReader reader = new BufferedReader(new FileReader(verifyOut))) {
|
try (BufferedReader reader = new BufferedReader(new FileReader(verifyOut))) {
|
||||||
String line = reader.readLine();
|
String line = reader.readLine();
|
||||||
assertEquals("2021-07-11T20:58:23Z 1B66A707819A920925BC6777C3E0AFC0B2DFF862 C8CD564EBF8D7BBA90611D8D071773658BF6BF86", line);
|
assertEquals("2021-07-11T20:58:23Z 1B66A707819A920925BC6777C3E0AFC0B2DFF862 C8CD564EBF8D7BBA90611D8D071773658BF6BF86", line);
|
||||||
|
@ -341,64 +320,66 @@ public class DecryptCmdTest {
|
||||||
File sessionKeyFile1 = TestFileUtil.writeTempStringFile(key1.toString());
|
File sessionKeyFile1 = TestFileUtil.writeTempStringFile(key1.toString());
|
||||||
File sessionKeyFile2 = TestFileUtil.writeTempStringFile(key2.toString());
|
File sessionKeyFile2 = TestFileUtil.writeTempStringFile(key2.toString());
|
||||||
|
|
||||||
assertSuccess(() ->
|
SopCLI.main(new String[] {"decrypt",
|
||||||
SopCLI.execute("decrypt",
|
"--with-session-key", sessionKeyFile1.getAbsolutePath(),
|
||||||
"--with-session-key", sessionKeyFile1.getAbsolutePath(),
|
"--with-session-key", sessionKeyFile2.getAbsolutePath()});
|
||||||
"--with-session-key", sessionKeyFile2.getAbsolutePath()));
|
|
||||||
verify(decrypt).withSessionKey(key1);
|
verify(decrypt).withSessionKey(key1);
|
||||||
verify(decrypt).withSessionKey(key2);
|
verify(decrypt).withSessionKey(key2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(1)
|
||||||
public void assertMalformedSessionKeysResultInExit1() throws IOException {
|
public void assertMalformedSessionKeysResultInExit1() throws IOException {
|
||||||
File sessionKeyFile = TestFileUtil.writeTempStringFile("C7CBDAF42537776F12509B5168793C26B93294E5ABDFA73224FB0177123E9137");
|
File sessionKeyFile = TestFileUtil.writeTempStringFile("C7CBDAF42537776F12509B5168793C26B93294E5ABDFA73224FB0177123E9137");
|
||||||
assertGenericError(() ->
|
SopCLI.main(new String[] {"decrypt",
|
||||||
SopCLI.execute("decrypt",
|
"--with-session-key", sessionKeyFile.getAbsolutePath()});
|
||||||
"--with-session-key", sessionKeyFile.getAbsolutePath()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.BadData.EXIT_CODE)
|
||||||
public void assertBadDataInKeysResultsInExit41() throws SOPGPException.KeyIsProtected, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.BadData, IOException {
|
public void assertBadDataInKeysResultsInExit41() throws SOPGPException.KeyIsProtected, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.BadData, IOException {
|
||||||
when(decrypt.withKey((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException()));
|
when(decrypt.withKey((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException()));
|
||||||
File tempKeyFile = File.createTempFile("key-", ".tmp");
|
File tempKeyFile = File.createTempFile("key-", ".tmp");
|
||||||
assertBadData(() -> SopCLI.execute("decrypt", tempKeyFile.getAbsolutePath()));
|
SopCLI.main(new String[] {"decrypt", tempKeyFile.getAbsolutePath()});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.MissingInput.EXIT_CODE)
|
||||||
public void assertKeyFileNotFoundCausesExit61() {
|
public void assertKeyFileNotFoundCausesExit61() {
|
||||||
assertMissingInput(() -> SopCLI.execute("decrypt", "nonexistent-key"));
|
SopCLI.main(new String[] {"decrypt", "nonexistent-key"});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.KeyIsProtected.EXIT_CODE)
|
||||||
public void assertProtectedKeyCausesExit67() throws IOException, SOPGPException.KeyIsProtected, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.BadData {
|
public void assertProtectedKeyCausesExit67() throws IOException, SOPGPException.KeyIsProtected, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.BadData {
|
||||||
when(decrypt.withKey((InputStream) any())).thenThrow(new SOPGPException.KeyIsProtected());
|
when(decrypt.withKey((InputStream) any())).thenThrow(new SOPGPException.KeyIsProtected());
|
||||||
File tempKeyFile = File.createTempFile("key-", ".tmp");
|
File tempKeyFile = File.createTempFile("key-", ".tmp");
|
||||||
assertKeyIsProtected(() -> SopCLI.execute("decrypt", tempKeyFile.getAbsolutePath()));
|
SopCLI.main(new String[] {"decrypt", tempKeyFile.getAbsolutePath()});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.UnsupportedAsymmetricAlgo.EXIT_CODE)
|
||||||
public void assertUnsupportedAlgorithmExceptionCausesExit13() throws SOPGPException.KeyIsProtected, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.BadData, IOException {
|
public void assertUnsupportedAlgorithmExceptionCausesExit13() throws SOPGPException.KeyIsProtected, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.BadData, IOException {
|
||||||
when(decrypt.withKey((InputStream) any())).thenThrow(new SOPGPException.UnsupportedAsymmetricAlgo("Unsupported asymmetric algorithm.", new IOException()));
|
when(decrypt.withKey((InputStream) any())).thenThrow(new SOPGPException.UnsupportedAsymmetricAlgo("Unsupported asymmetric algorithm.", new IOException()));
|
||||||
File tempKeyFile = File.createTempFile("key-", ".tmp");
|
File tempKeyFile = File.createTempFile("key-", ".tmp");
|
||||||
assertUnsupportedAsymmetricAlgo(() ->
|
SopCLI.main(new String[] {"decrypt", tempKeyFile.getAbsolutePath()});
|
||||||
SopCLI.execute("decrypt", tempKeyFile.getAbsolutePath()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.MissingInput.EXIT_CODE)
|
||||||
public void assertMissingPassphraseFileCausesExit61() {
|
public void assertMissingPassphraseFileCausesExit61() {
|
||||||
assertMissingInput(() ->
|
SopCLI.main(new String[] {"decrypt", "--with-password", "missing"});
|
||||||
SopCLI.execute("decrypt", "--with-password", "missing"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.MissingInput.EXIT_CODE)
|
||||||
public void assertMissingSessionKeyFileCausesExit61() {
|
public void assertMissingSessionKeyFileCausesExit61() {
|
||||||
assertMissingInput(() ->
|
SopCLI.main(new String[] {"decrypt", "--with-session-key", "missing"});
|
||||||
SopCLI.execute("decrypt", "--with-session-key", "missing"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.IncompleteVerification.EXIT_CODE)
|
||||||
public void verifyOutWithoutVerifyWithCausesExit23() {
|
public void verifyOutWithoutVerifyWithCausesExit23() {
|
||||||
assertIncompleteVerification(() ->
|
SopCLI.main(new String[] {"decrypt", "--verifications-out", "out.file"});
|
||||||
SopCLI.execute("decrypt", "--verifications-out", "out.file"));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
package sop.cli.picocli.commands;
|
package sop.cli.picocli.commands;
|
||||||
|
|
||||||
|
import com.ginsberg.junit.exit.ExpectSystemExitWithStatus;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
@ -27,17 +28,6 @@ import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertBadData;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertCertCannotEncrypt;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertGenericError;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertKeyCannotSign;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertKeyIsProtected;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertMissingArg;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertMissingInput;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertPasswordNotHumanReadable;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertSuccess;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertUnsupportedAsymmetricAlgo;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertUnsupportedOption;
|
|
||||||
|
|
||||||
public class EncryptCmdTest {
|
public class EncryptCmdTest {
|
||||||
|
|
||||||
|
@ -60,50 +50,48 @@ public class EncryptCmdTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void missingBothPasswordAndCertFileCausesMissingArg() {
|
@ExpectSystemExitWithStatus(SOPGPException.MissingArg.EXIT_CODE)
|
||||||
assertMissingArg(() ->
|
public void missingBothPasswordAndCertFileCauseExit19() {
|
||||||
SopCLI.execute("encrypt", "--no-armor"));
|
SopCLI.main(new String[] {"encrypt", "--no-armor"});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void as_unsupportedEncryptAsCausesUnsupportedOption() throws SOPGPException.UnsupportedOption {
|
@ExpectSystemExitWithStatus(SOPGPException.UnsupportedOption.EXIT_CODE)
|
||||||
|
public void as_unsupportedEncryptAsCausesExit37() throws SOPGPException.UnsupportedOption {
|
||||||
when(encrypt.mode(any())).thenThrow(new SOPGPException.UnsupportedOption("Setting encryption mode not supported."));
|
when(encrypt.mode(any())).thenThrow(new SOPGPException.UnsupportedOption("Setting encryption mode not supported."));
|
||||||
|
|
||||||
assertUnsupportedOption(() ->
|
SopCLI.main(new String[] {"encrypt", "--as", "Binary"});
|
||||||
SopCLI.execute("encrypt", "--as", "Binary"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void as_invalidModeOptionCausesUnsupportedOption() {
|
@ExpectSystemExitWithStatus(SOPGPException.UnsupportedOption.EXIT_CODE)
|
||||||
assertUnsupportedOption(() ->
|
public void as_invalidModeOptionCausesExit37() {
|
||||||
SopCLI.execute("encrypt", "--as", "invalid"));
|
SopCLI.main(new String[] {"encrypt", "--as", "invalid"});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void as_modeIsPassedDown() throws SOPGPException.UnsupportedOption, IOException {
|
public void as_modeIsPassedDown() throws SOPGPException.UnsupportedOption, IOException {
|
||||||
File passwordFile = TestFileUtil.writeTempStringFile("0rbit");
|
File passwordFile = TestFileUtil.writeTempStringFile("0rbit");
|
||||||
for (EncryptAs mode : EncryptAs.values()) {
|
for (EncryptAs mode : EncryptAs.values()) {
|
||||||
assertSuccess(() ->
|
SopCLI.main(new String[] {"encrypt", "--as", mode.name(), "--with-password", passwordFile.getAbsolutePath()});
|
||||||
SopCLI.execute("encrypt", "--as", mode.name(),
|
|
||||||
"--with-password", passwordFile.getAbsolutePath()));
|
|
||||||
verify(encrypt, times(1)).mode(mode);
|
verify(encrypt, times(1)).mode(mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void withPassword_notHumanReadablePasswordCausesPWNotHumanReadable() throws SOPGPException.PasswordNotHumanReadable, SOPGPException.UnsupportedOption, IOException {
|
@ExpectSystemExitWithStatus(SOPGPException.PasswordNotHumanReadable.EXIT_CODE)
|
||||||
|
public void withPassword_notHumanReadablePasswordCausesExit31() throws SOPGPException.PasswordNotHumanReadable, SOPGPException.UnsupportedOption, IOException {
|
||||||
when(encrypt.withPassword("pretendThisIsNotReadable")).thenThrow(new SOPGPException.PasswordNotHumanReadable());
|
when(encrypt.withPassword("pretendThisIsNotReadable")).thenThrow(new SOPGPException.PasswordNotHumanReadable());
|
||||||
File passwordFile = TestFileUtil.writeTempStringFile("pretendThisIsNotReadable");
|
File passwordFile = TestFileUtil.writeTempStringFile("pretendThisIsNotReadable");
|
||||||
assertPasswordNotHumanReadable(() ->
|
SopCLI.main(new String[] {"encrypt", "--with-password", passwordFile.getAbsolutePath()});
|
||||||
SopCLI.execute("encrypt", "--with-password", passwordFile.getAbsolutePath()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void withPassword_unsupportedWithPasswordCausesUnsupportedOption() throws SOPGPException.PasswordNotHumanReadable, SOPGPException.UnsupportedOption, IOException {
|
@ExpectSystemExitWithStatus(SOPGPException.UnsupportedOption.EXIT_CODE)
|
||||||
|
public void withPassword_unsupportedWithPasswordCausesExit37() throws SOPGPException.PasswordNotHumanReadable, SOPGPException.UnsupportedOption, IOException {
|
||||||
when(encrypt.withPassword(any())).thenThrow(new SOPGPException.UnsupportedOption("Encrypting with password not supported."));
|
when(encrypt.withPassword(any())).thenThrow(new SOPGPException.UnsupportedOption("Encrypting with password not supported."));
|
||||||
File passwordFile = TestFileUtil.writeTempStringFile("orange");
|
File passwordFile = TestFileUtil.writeTempStringFile("orange");
|
||||||
assertUnsupportedOption(() ->
|
SopCLI.main(new String[] {"encrypt", "--with-password", passwordFile.getAbsolutePath()});
|
||||||
SopCLI.execute("encrypt", "--with-password", passwordFile.getAbsolutePath()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -111,107 +99,99 @@ public class EncryptCmdTest {
|
||||||
File keyFile1 = File.createTempFile("sign-with-1-", ".asc");
|
File keyFile1 = File.createTempFile("sign-with-1-", ".asc");
|
||||||
File keyFile2 = File.createTempFile("sign-with-2-", ".asc");
|
File keyFile2 = File.createTempFile("sign-with-2-", ".asc");
|
||||||
File passwordFile = TestFileUtil.writeTempStringFile("password");
|
File passwordFile = TestFileUtil.writeTempStringFile("password");
|
||||||
assertSuccess(() ->
|
SopCLI.main(new String[] {"encrypt", "--with-password", passwordFile.getAbsolutePath(), "--sign-with", keyFile1.getAbsolutePath(), "--sign-with", keyFile2.getAbsolutePath()});
|
||||||
SopCLI.execute("encrypt", "--with-password", passwordFile.getAbsolutePath(),
|
|
||||||
"--sign-with", keyFile1.getAbsolutePath(),
|
|
||||||
"--sign-with", keyFile2.getAbsolutePath()));
|
|
||||||
verify(encrypt, times(2)).signWith((InputStream) any());
|
verify(encrypt, times(2)).signWith((InputStream) any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void signWith_nonExistentKeyFileCausesMissingInput() {
|
@ExpectSystemExitWithStatus(SOPGPException.MissingInput.EXIT_CODE)
|
||||||
assertMissingInput(() ->
|
public void signWith_nonExistentKeyFileCausesExit61() {
|
||||||
SopCLI.execute("encrypt", "--with-password", "admin", "--sign-with", "nonExistent.asc"));
|
SopCLI.main(new String[] {"encrypt", "--with-password", "admin", "--sign-with", "nonExistent.asc"});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void signWith_keyIsProtectedCausesKeyIsProtected() throws SOPGPException.KeyIsProtected, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.KeyCannotSign, SOPGPException.BadData, IOException {
|
@ExpectSystemExitWithStatus(SOPGPException.KeyIsProtected.EXIT_CODE)
|
||||||
|
public void signWith_keyIsProtectedCausesExit67() throws SOPGPException.KeyIsProtected, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.KeyCannotSign, SOPGPException.BadData, IOException {
|
||||||
when(encrypt.signWith((InputStream) any())).thenThrow(new SOPGPException.KeyIsProtected());
|
when(encrypt.signWith((InputStream) any())).thenThrow(new SOPGPException.KeyIsProtected());
|
||||||
File keyFile = File.createTempFile("sign-with", ".asc");
|
File keyFile = File.createTempFile("sign-with", ".asc");
|
||||||
File passwordFile = TestFileUtil.writeTempStringFile("starship");
|
File passwordFile = TestFileUtil.writeTempStringFile("starship");
|
||||||
assertKeyIsProtected(() ->
|
SopCLI.main(new String[] {"encrypt", "--sign-with", keyFile.getAbsolutePath(), "--with-password", passwordFile.getAbsolutePath()});
|
||||||
SopCLI.execute("encrypt", "--sign-with", keyFile.getAbsolutePath(),
|
|
||||||
"--with-password", passwordFile.getAbsolutePath()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void signWith_unsupportedAsymmetricAlgoCausesUnsupportedAsymAlgo() throws SOPGPException.KeyIsProtected, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.KeyCannotSign, SOPGPException.BadData, IOException {
|
@ExpectSystemExitWithStatus(SOPGPException.UnsupportedAsymmetricAlgo.EXIT_CODE)
|
||||||
|
public void signWith_unsupportedAsymmetricAlgoCausesExit13() throws SOPGPException.KeyIsProtected, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.KeyCannotSign, SOPGPException.BadData, IOException {
|
||||||
when(encrypt.signWith((InputStream) any())).thenThrow(new SOPGPException.UnsupportedAsymmetricAlgo("Unsupported asymmetric algorithm.", new Exception()));
|
when(encrypt.signWith((InputStream) any())).thenThrow(new SOPGPException.UnsupportedAsymmetricAlgo("Unsupported asymmetric algorithm.", new Exception()));
|
||||||
File keyFile = File.createTempFile("sign-with", ".asc");
|
File keyFile = File.createTempFile("sign-with", ".asc");
|
||||||
File passwordFile = TestFileUtil.writeTempStringFile("123456");
|
File passwordFile = TestFileUtil.writeTempStringFile("123456");
|
||||||
assertUnsupportedAsymmetricAlgo(() ->
|
SopCLI.main(new String[] {"encrypt", "--with-password", passwordFile.getAbsolutePath(), "--sign-with", keyFile.getAbsolutePath()});
|
||||||
SopCLI.execute("encrypt", "--with-password", passwordFile.getAbsolutePath(),
|
|
||||||
"--sign-with", keyFile.getAbsolutePath()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void signWith_certCannotSignCausesKeyCannotSign() throws IOException, SOPGPException.KeyIsProtected, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.KeyCannotSign, SOPGPException.BadData {
|
@ExpectSystemExitWithStatus(SOPGPException.KeyCannotSign.EXIT_CODE)
|
||||||
|
public void signWith_certCannotSignCausesExit79() throws IOException, SOPGPException.KeyIsProtected, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.KeyCannotSign, SOPGPException.BadData {
|
||||||
when(encrypt.signWith((InputStream) any())).thenThrow(new SOPGPException.KeyCannotSign());
|
when(encrypt.signWith((InputStream) any())).thenThrow(new SOPGPException.KeyCannotSign());
|
||||||
File keyFile = File.createTempFile("sign-with", ".asc");
|
File keyFile = File.createTempFile("sign-with", ".asc");
|
||||||
File passwordFile = TestFileUtil.writeTempStringFile("dragon");
|
File passwordFile = TestFileUtil.writeTempStringFile("dragon");
|
||||||
assertKeyCannotSign(() ->
|
SopCLI.main(new String[] {"encrypt", "--with-password", passwordFile.getAbsolutePath(), "--sign-with", keyFile.getAbsolutePath()});
|
||||||
SopCLI.execute("encrypt", "--with-password", passwordFile.getAbsolutePath(),
|
|
||||||
"--sign-with", keyFile.getAbsolutePath()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void signWith_badDataCausesBadData() throws SOPGPException.KeyIsProtected, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.KeyCannotSign, SOPGPException.BadData, IOException {
|
@ExpectSystemExitWithStatus(SOPGPException.BadData.EXIT_CODE)
|
||||||
|
public void signWith_badDataCausesExit41() throws SOPGPException.KeyIsProtected, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.KeyCannotSign, SOPGPException.BadData, IOException {
|
||||||
when(encrypt.signWith((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException()));
|
when(encrypt.signWith((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException()));
|
||||||
File keyFile = File.createTempFile("sign-with", ".asc");
|
File keyFile = File.createTempFile("sign-with", ".asc");
|
||||||
File passwordFile = TestFileUtil.writeTempStringFile("orange");
|
File passwordFile = TestFileUtil.writeTempStringFile("orange");
|
||||||
assertBadData(() ->
|
SopCLI.main(new String[] {"encrypt", "--with-password", passwordFile.getAbsolutePath(), "--sign-with", keyFile.getAbsolutePath()});
|
||||||
SopCLI.execute("encrypt", "--with-password", passwordFile.getAbsolutePath(),
|
|
||||||
"--sign-with", keyFile.getAbsolutePath()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void cert_nonExistentCertFileCausesMissingInput() {
|
@ExpectSystemExitWithStatus(SOPGPException.MissingInput.EXIT_CODE)
|
||||||
assertMissingInput(() ->
|
public void cert_nonExistentCertFileCausesExit61() {
|
||||||
SopCLI.execute("encrypt", "invalid.asc"));
|
SopCLI.main(new String[] {"encrypt", "invalid.asc"});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void cert_unsupportedAsymmetricAlgorithmCausesUnsupportedAsymAlg() throws IOException, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.CertCannotEncrypt, SOPGPException.BadData {
|
@ExpectSystemExitWithStatus(SOPGPException.UnsupportedAsymmetricAlgo.EXIT_CODE)
|
||||||
|
public void cert_unsupportedAsymmetricAlgorithmCausesExit13() throws IOException, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.CertCannotEncrypt, SOPGPException.BadData {
|
||||||
when(encrypt.withCert((InputStream) any())).thenThrow(new SOPGPException.UnsupportedAsymmetricAlgo("Unsupported asymmetric algorithm.", new Exception()));
|
when(encrypt.withCert((InputStream) any())).thenThrow(new SOPGPException.UnsupportedAsymmetricAlgo("Unsupported asymmetric algorithm.", new Exception()));
|
||||||
File certFile = File.createTempFile("cert", ".asc");
|
File certFile = File.createTempFile("cert", ".asc");
|
||||||
assertUnsupportedAsymmetricAlgo(() ->
|
SopCLI.main(new String[] {"encrypt", certFile.getAbsolutePath()});
|
||||||
SopCLI.execute("encrypt", certFile.getAbsolutePath()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void cert_certCannotEncryptCausesCertCannotEncrypt() throws IOException, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.CertCannotEncrypt, SOPGPException.BadData {
|
@ExpectSystemExitWithStatus(SOPGPException.CertCannotEncrypt.EXIT_CODE)
|
||||||
|
public void cert_certCannotEncryptCausesExit17() throws IOException, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.CertCannotEncrypt, SOPGPException.BadData {
|
||||||
when(encrypt.withCert((InputStream) any())).thenThrow(new SOPGPException.CertCannotEncrypt("Certificate cannot encrypt.", new Exception()));
|
when(encrypt.withCert((InputStream) any())).thenThrow(new SOPGPException.CertCannotEncrypt("Certificate cannot encrypt.", new Exception()));
|
||||||
File certFile = File.createTempFile("cert", ".asc");
|
File certFile = File.createTempFile("cert", ".asc");
|
||||||
assertCertCannotEncrypt(() ->
|
SopCLI.main(new String[] {"encrypt", certFile.getAbsolutePath()});
|
||||||
SopCLI.execute("encrypt", certFile.getAbsolutePath()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void cert_badDataCausesBadData() throws IOException, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.CertCannotEncrypt, SOPGPException.BadData {
|
@ExpectSystemExitWithStatus(SOPGPException.BadData.EXIT_CODE)
|
||||||
|
public void cert_badDataCausesExit41() throws IOException, SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.CertCannotEncrypt, SOPGPException.BadData {
|
||||||
when(encrypt.withCert((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException()));
|
when(encrypt.withCert((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException()));
|
||||||
File certFile = File.createTempFile("cert", ".asc");
|
File certFile = File.createTempFile("cert", ".asc");
|
||||||
assertBadData(() ->
|
SopCLI.main(new String[] {"encrypt", certFile.getAbsolutePath()});
|
||||||
SopCLI.execute("encrypt", certFile.getAbsolutePath()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void noArmor_notCalledByDefault() throws IOException {
|
public void noArmor_notCalledByDefault() throws IOException {
|
||||||
File passwordFile = TestFileUtil.writeTempStringFile("clownfish");
|
File passwordFile = TestFileUtil.writeTempStringFile("clownfish");
|
||||||
assertSuccess(() ->
|
SopCLI.main(new String[] {"encrypt", "--with-password", passwordFile.getAbsolutePath()});
|
||||||
SopCLI.execute("encrypt", "--with-password", passwordFile.getAbsolutePath()));
|
|
||||||
verify(encrypt, never()).noArmor();
|
verify(encrypt, never()).noArmor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void noArmor_callGetsPassedDown() throws IOException {
|
public void noArmor_callGetsPassedDown() throws IOException {
|
||||||
File passwordFile = TestFileUtil.writeTempStringFile("monkey");
|
File passwordFile = TestFileUtil.writeTempStringFile("monkey");
|
||||||
assertSuccess(() ->
|
SopCLI.main(new String[] {"encrypt", "--with-password", passwordFile.getAbsolutePath(), "--no-armor"});
|
||||||
SopCLI.execute("encrypt", "--with-password", passwordFile.getAbsolutePath(), "--no-armor"));
|
|
||||||
verify(encrypt, times(1)).noArmor();
|
verify(encrypt, times(1)).noArmor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void writeTo_ioExceptionCausesGenericError() throws IOException {
|
@ExpectSystemExitWithStatus(1)
|
||||||
|
public void writeTo_ioExceptionCausesExit1() throws IOException {
|
||||||
when(encrypt.plaintext((InputStream) any())).thenReturn(new ReadyWithResult<EncryptionResult>() {
|
when(encrypt.plaintext((InputStream) any())).thenReturn(new ReadyWithResult<EncryptionResult>() {
|
||||||
@Override
|
@Override
|
||||||
public EncryptionResult writeTo(@NotNull OutputStream outputStream) throws IOException, SOPGPException {
|
public EncryptionResult writeTo(@NotNull OutputStream outputStream) throws IOException, SOPGPException {
|
||||||
|
@ -219,7 +199,6 @@ public class EncryptCmdTest {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
File passwordFile = TestFileUtil.writeTempStringFile("wildcat");
|
File passwordFile = TestFileUtil.writeTempStringFile("wildcat");
|
||||||
assertGenericError(() ->
|
SopCLI.main(new String[] {"encrypt", "--with-password", passwordFile.getAbsolutePath()});
|
||||||
SopCLI.execute("encrypt", "--with-password", passwordFile.getAbsolutePath()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,14 +10,12 @@ import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertBadData;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertGenericError;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertSuccess;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
import com.ginsberg.junit.exit.ExpectSystemExitWithStatus;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import sop.Ready;
|
import sop.Ready;
|
||||||
|
@ -47,34 +45,32 @@ public class ExtractCertCmdTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void noArmor_notCalledByDefault() {
|
public void noArmor_notCalledByDefault() {
|
||||||
assertSuccess(() ->
|
SopCLI.main(new String[] {"extract-cert"});
|
||||||
SopCLI.execute("extract-cert"));
|
|
||||||
verify(extractCert, never()).noArmor();
|
verify(extractCert, never()).noArmor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void noArmor_passedDown() {
|
public void noArmor_passedDown() {
|
||||||
assertSuccess(() ->
|
SopCLI.main(new String[] {"extract-cert", "--no-armor"});
|
||||||
SopCLI.execute("extract-cert", "--no-armor"));
|
|
||||||
verify(extractCert, times(1)).noArmor();
|
verify(extractCert, times(1)).noArmor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void key_ioExceptionCausesGenericError() throws IOException, SOPGPException.BadData {
|
@ExpectSystemExitWithStatus(1)
|
||||||
|
public void key_ioExceptionCausesExit1() throws IOException, SOPGPException.BadData {
|
||||||
when(extractCert.key((InputStream) any())).thenReturn(new Ready() {
|
when(extractCert.key((InputStream) any())).thenReturn(new Ready() {
|
||||||
@Override
|
@Override
|
||||||
public void writeTo(OutputStream outputStream) throws IOException {
|
public void writeTo(OutputStream outputStream) throws IOException {
|
||||||
throw new IOException();
|
throw new IOException();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
assertGenericError(() ->
|
SopCLI.main(new String[] {"extract-cert"});
|
||||||
SopCLI.execute("extract-cert"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void key_badDataCausesBadData() throws IOException, SOPGPException.BadData {
|
@ExpectSystemExitWithStatus(SOPGPException.BadData.EXIT_CODE)
|
||||||
|
public void key_badDataCausesExit41() throws IOException, SOPGPException.BadData {
|
||||||
when(extractCert.key((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException()));
|
when(extractCert.key((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException()));
|
||||||
assertBadData(() ->
|
SopCLI.main(new String[] {"extract-cert"});
|
||||||
SopCLI.execute("extract-cert"));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,14 +10,11 @@ import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertGenericError;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertMissingArg;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertSuccess;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertUnsupportedAsymmetricAlgo;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
import com.ginsberg.junit.exit.ExpectSystemExitWithStatus;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.mockito.InOrder;
|
import org.mockito.InOrder;
|
||||||
|
@ -50,22 +47,19 @@ public class GenerateKeyCmdTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void noArmor_notCalledByDefault() {
|
public void noArmor_notCalledByDefault() {
|
||||||
assertSuccess(() ->
|
SopCLI.main(new String[] {"generate-key", "Alice"});
|
||||||
SopCLI.execute("generate-key", "Alice"));
|
|
||||||
verify(generateKey, never()).noArmor();
|
verify(generateKey, never()).noArmor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void noArmor_passedDown() {
|
public void noArmor_passedDown() {
|
||||||
assertSuccess(() ->
|
SopCLI.main(new String[] {"generate-key", "--no-armor", "Alice"});
|
||||||
SopCLI.execute("generate-key", "--no-armor", "Alice"));
|
|
||||||
verify(generateKey, times(1)).noArmor();
|
verify(generateKey, times(1)).noArmor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void userId_multipleUserIdsPassedDownInProperOrder() {
|
public void userId_multipleUserIdsPassedDownInProperOrder() {
|
||||||
assertSuccess(() ->
|
SopCLI.main(new String[] {"generate-key", "Alice <alice@pgpainless.org>", "Bob <bob@pgpainless.org>"});
|
||||||
SopCLI.execute("generate-key", "Alice <alice@pgpainless.org>", "Bob <bob@pgpainless.org>"));
|
|
||||||
|
|
||||||
InOrder inOrder = Mockito.inOrder(generateKey);
|
InOrder inOrder = Mockito.inOrder(generateKey);
|
||||||
inOrder.verify(generateKey).userId("Alice <alice@pgpainless.org>");
|
inOrder.verify(generateKey).userId("Alice <alice@pgpainless.org>");
|
||||||
|
@ -75,32 +69,30 @@ public class GenerateKeyCmdTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.MissingArg.EXIT_CODE)
|
||||||
public void missingArgumentCausesExit19() throws SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.MissingArg, IOException {
|
public void missingArgumentCausesExit19() throws SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.MissingArg, IOException {
|
||||||
// TODO: RFC4880-bis and the current Stateless OpenPGP CLI spec allow keys to have no user-ids,
|
// TODO: RFC4880-bis and the current Stateless OpenPGP CLI spec allow keys to have no user-ids,
|
||||||
// so we might want to change this test in the future.
|
// so we might want to change this test in the future.
|
||||||
when(generateKey.generate()).thenThrow(new SOPGPException.MissingArg("Missing user-id."));
|
when(generateKey.generate()).thenThrow(new SOPGPException.MissingArg("Missing user-id."));
|
||||||
assertMissingArg(() ->
|
SopCLI.main(new String[] {"generate-key"});
|
||||||
SopCLI.execute("generate-key"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.UnsupportedAsymmetricAlgo.EXIT_CODE)
|
||||||
public void unsupportedAsymmetricAlgorithmCausesExit13() throws SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.MissingArg, IOException {
|
public void unsupportedAsymmetricAlgorithmCausesExit13() throws SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.MissingArg, IOException {
|
||||||
when(generateKey.generate()).thenThrow(new SOPGPException.UnsupportedAsymmetricAlgo("Unsupported asymmetric algorithm.", new Exception()));
|
when(generateKey.generate()).thenThrow(new SOPGPException.UnsupportedAsymmetricAlgo("Unsupported asymmetric algorithm.", new Exception()));
|
||||||
assertUnsupportedAsymmetricAlgo(() ->
|
SopCLI.main(new String[] {"generate-key", "Alice"});
|
||||||
SopCLI.execute("generate-key", "Alice"));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void ioExceptionCausesGenericError() throws SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.MissingArg, IOException {
|
@ExpectSystemExitWithStatus(1)
|
||||||
|
public void ioExceptionCausesExit1() throws SOPGPException.UnsupportedAsymmetricAlgo, SOPGPException.MissingArg, IOException {
|
||||||
when(generateKey.generate()).thenReturn(new Ready() {
|
when(generateKey.generate()).thenReturn(new Ready() {
|
||||||
@Override
|
@Override
|
||||||
public void writeTo(OutputStream outputStream) throws IOException {
|
public void writeTo(OutputStream outputStream) throws IOException {
|
||||||
throw new IOException();
|
throw new IOException();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
SopCLI.main(new String[] {"generate-key", "Alice"});
|
||||||
assertGenericError(() ->
|
|
||||||
SopCLI.execute("generate-key", "Alice"));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
package sop.cli.picocli.commands;
|
package sop.cli.picocli.commands;
|
||||||
|
|
||||||
|
import com.ginsberg.junit.exit.ExpectSystemExitWithStatus;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import sop.ReadyWithResult;
|
import sop.ReadyWithResult;
|
||||||
|
@ -25,8 +26,6 @@ import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertMissingArg;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertSuccess;
|
|
||||||
|
|
||||||
public class InlineDetachCmdTest {
|
public class InlineDetachCmdTest {
|
||||||
|
|
||||||
|
@ -42,9 +41,9 @@ public class InlineDetachCmdTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMissingSignaturesOutResultsInMissingArg() {
|
@ExpectSystemExitWithStatus(SOPGPException.MissingArg.EXIT_CODE)
|
||||||
assertMissingArg(() ->
|
public void testMissingSignaturesOutResultsInExit19() {
|
||||||
SopCLI.execute("inline-detach"));
|
SopCLI.main(new String[] {"inline-detach"});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -68,8 +67,7 @@ public class InlineDetachCmdTest {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
assertSuccess(() ->
|
SopCLI.main(new String[] {"inline-detach", "--signatures-out", tempFile.getAbsolutePath(), "--no-armor"});
|
||||||
SopCLI.execute("inline-detach", "--signatures-out", tempFile.getAbsolutePath(), "--no-armor"));
|
|
||||||
verify(inlineDetach, times(1)).noArmor();
|
verify(inlineDetach, times(1)).noArmor();
|
||||||
verify(inlineDetach, times(1)).message((InputStream) any());
|
verify(inlineDetach, times(1)).message((InputStream) any());
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,20 +10,13 @@ import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertBadData;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertExpectedText;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertGenericError;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertKeyIsProtected;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertMissingArg;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertMissingInput;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertSuccess;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertUnsupportedOption;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
import com.ginsberg.junit.exit.ExpectSystemExitWithStatus;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import sop.ReadyWithResult;
|
import sop.ReadyWithResult;
|
||||||
|
@ -61,77 +54,70 @@ public class SignCmdTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void as_optionsAreCaseInsensitive() {
|
public void as_optionsAreCaseInsensitive() {
|
||||||
assertSuccess(() ->
|
SopCLI.main(new String[] {"sign", "--as", "Binary", keyFile.getAbsolutePath()});
|
||||||
SopCLI.execute("sign", "--as", "Binary", keyFile.getAbsolutePath()));
|
SopCLI.main(new String[] {"sign", "--as", "binary", keyFile.getAbsolutePath()});
|
||||||
assertSuccess(() ->
|
SopCLI.main(new String[] {"sign", "--as", "BINARY", keyFile.getAbsolutePath()});
|
||||||
SopCLI.execute("sign", "--as", "binary", keyFile.getAbsolutePath()));
|
|
||||||
assertSuccess(() ->
|
|
||||||
SopCLI.execute("sign", "--as", "BINARY", keyFile.getAbsolutePath()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.UnsupportedOption.EXIT_CODE)
|
||||||
public void as_invalidOptionCausesExit37() {
|
public void as_invalidOptionCausesExit37() {
|
||||||
assertUnsupportedOption(() ->
|
SopCLI.main(new String[] {"sign", "--as", "Invalid", keyFile.getAbsolutePath()});
|
||||||
SopCLI.execute("sign", "--as", "Invalid", keyFile.getAbsolutePath()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.UnsupportedOption.EXIT_CODE)
|
||||||
public void as_unsupportedOptionCausesExit37() throws SOPGPException.UnsupportedOption {
|
public void as_unsupportedOptionCausesExit37() throws SOPGPException.UnsupportedOption {
|
||||||
when(detachedSign.mode(any())).thenThrow(new SOPGPException.UnsupportedOption("Setting signing mode not supported."));
|
when(detachedSign.mode(any())).thenThrow(new SOPGPException.UnsupportedOption("Setting signing mode not supported."));
|
||||||
assertUnsupportedOption(() ->
|
SopCLI.main(new String[] {"sign", "--as", "binary", keyFile.getAbsolutePath()});
|
||||||
SopCLI.execute("sign", "--as", "binary", keyFile.getAbsolutePath()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.MissingInput.EXIT_CODE)
|
||||||
public void key_nonExistentKeyFileCausesExit61() {
|
public void key_nonExistentKeyFileCausesExit61() {
|
||||||
assertMissingInput(() ->
|
SopCLI.main(new String[] {"sign", "invalid.asc"});
|
||||||
SopCLI.execute("sign", "invalid.asc"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.KeyIsProtected.EXIT_CODE)
|
||||||
public void key_keyIsProtectedCausesExit67() throws SOPGPException.KeyIsProtected, IOException, SOPGPException.BadData {
|
public void key_keyIsProtectedCausesExit67() throws SOPGPException.KeyIsProtected, IOException, SOPGPException.BadData {
|
||||||
when(detachedSign.key((InputStream) any())).thenThrow(new SOPGPException.KeyIsProtected());
|
when(detachedSign.key((InputStream) any())).thenThrow(new SOPGPException.KeyIsProtected());
|
||||||
assertKeyIsProtected(() ->
|
SopCLI.main(new String[] {"sign", keyFile.getAbsolutePath()});
|
||||||
SopCLI.execute("sign", keyFile.getAbsolutePath()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.BadData.EXIT_CODE)
|
||||||
public void key_badDataCausesExit41() throws SOPGPException.KeyIsProtected, IOException, SOPGPException.BadData {
|
public void key_badDataCausesExit41() throws SOPGPException.KeyIsProtected, IOException, SOPGPException.BadData {
|
||||||
when(detachedSign.key((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException()));
|
when(detachedSign.key((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException()));
|
||||||
assertBadData(() ->
|
SopCLI.main(new String[] {"sign", keyFile.getAbsolutePath()});
|
||||||
SopCLI.execute("sign", keyFile.getAbsolutePath()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.MissingArg.EXIT_CODE)
|
||||||
public void key_missingKeyFileCausesExit19() {
|
public void key_missingKeyFileCausesExit19() {
|
||||||
assertMissingArg(() ->
|
SopCLI.main(new String[] {"sign"});
|
||||||
SopCLI.execute("sign"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void noArmor_notCalledByDefault() {
|
public void noArmor_notCalledByDefault() {
|
||||||
assertSuccess(() ->
|
SopCLI.main(new String[] {"sign", keyFile.getAbsolutePath()});
|
||||||
SopCLI.execute("sign", keyFile.getAbsolutePath()));
|
|
||||||
verify(detachedSign, never()).noArmor();
|
verify(detachedSign, never()).noArmor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void noArmor_passedDown() {
|
public void noArmor_passedDown() {
|
||||||
assertSuccess(() ->
|
SopCLI.main(new String[] {"sign", "--no-armor", keyFile.getAbsolutePath()});
|
||||||
SopCLI.execute("sign", "--no-armor", keyFile.getAbsolutePath()));
|
|
||||||
verify(detachedSign, times(1)).noArmor();
|
verify(detachedSign, times(1)).noArmor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void withKeyPassword_passedDown() {
|
public void withKeyPassword_passedDown() {
|
||||||
assertSuccess(() ->
|
SopCLI.main(new String[] {"sign", "--with-key-password", passFile.getAbsolutePath(), keyFile.getAbsolutePath()});
|
||||||
SopCLI.execute("sign",
|
|
||||||
"--with-key-password", passFile.getAbsolutePath(),
|
|
||||||
keyFile.getAbsolutePath()));
|
|
||||||
verify(detachedSign, times(1)).withKeyPassword("sw0rdf1sh");
|
verify(detachedSign, times(1)).withKeyPassword("sw0rdf1sh");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(1)
|
||||||
public void data_ioExceptionCausesExit1() throws IOException, SOPGPException.ExpectedText {
|
public void data_ioExceptionCausesExit1() throws IOException, SOPGPException.ExpectedText {
|
||||||
when(detachedSign.data((InputStream) any())).thenReturn(new ReadyWithResult<SigningResult>() {
|
when(detachedSign.data((InputStream) any())).thenReturn(new ReadyWithResult<SigningResult>() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -139,14 +125,13 @@ public class SignCmdTest {
|
||||||
throw new IOException();
|
throw new IOException();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
assertGenericError(() ->
|
SopCLI.main(new String[] {"sign", keyFile.getAbsolutePath()});
|
||||||
SopCLI.execute("sign", keyFile.getAbsolutePath()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.ExpectedText.EXIT_CODE)
|
||||||
public void data_expectedTextExceptionCausesExit53() throws IOException, SOPGPException.ExpectedText {
|
public void data_expectedTextExceptionCausesExit53() throws IOException, SOPGPException.ExpectedText {
|
||||||
when(detachedSign.data((InputStream) any())).thenThrow(new SOPGPException.ExpectedText());
|
when(detachedSign.data((InputStream) any())).thenThrow(new SOPGPException.ExpectedText());
|
||||||
assertExpectedText(() ->
|
SopCLI.main(new String[] {"sign", keyFile.getAbsolutePath()});
|
||||||
SopCLI.execute("sign", keyFile.getAbsolutePath()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,11 +10,6 @@ import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertBadData;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertMissingInput;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertNoSignature;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertSuccess;
|
|
||||||
import static sop.testsuite.assertions.SopExecutionAssertions.assertUnsupportedOption;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -26,6 +21,7 @@ import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
|
import com.ginsberg.junit.exit.ExpectSystemExitWithStatus;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
@ -80,75 +76,60 @@ public class VerifyCmdTest {
|
||||||
@Test
|
@Test
|
||||||
public void notAfter_passedDown() throws SOPGPException.UnsupportedOption, ParseException {
|
public void notAfter_passedDown() throws SOPGPException.UnsupportedOption, ParseException {
|
||||||
Date date = UTCUtil.parseUTCDate("2019-10-29T18:36:45Z");
|
Date date = UTCUtil.parseUTCDate("2019-10-29T18:36:45Z");
|
||||||
assertSuccess(() ->
|
SopCLI.main(new String[] {"verify", "--not-after", "2019-10-29T18:36:45Z", signature.getAbsolutePath(), cert.getAbsolutePath()});
|
||||||
SopCLI.execute("verify", "--not-after", "2019-10-29T18:36:45Z",
|
|
||||||
signature.getAbsolutePath(), cert.getAbsolutePath()));
|
|
||||||
verify(detachedVerify, times(1)).notAfter(date);
|
verify(detachedVerify, times(1)).notAfter(date);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void notAfter_now() throws SOPGPException.UnsupportedOption {
|
public void notAfter_now() throws SOPGPException.UnsupportedOption {
|
||||||
Date now = new Date();
|
Date now = new Date();
|
||||||
assertSuccess(() ->
|
SopCLI.main(new String[] {"verify", "--not-after", "now", signature.getAbsolutePath(), cert.getAbsolutePath()});
|
||||||
SopCLI.execute("verify", "--not-after", "now",
|
|
||||||
signature.getAbsolutePath(), cert.getAbsolutePath()));
|
|
||||||
verify(detachedVerify, times(1)).notAfter(dateMatcher(now));
|
verify(detachedVerify, times(1)).notAfter(dateMatcher(now));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void notAfter_dashCountsAsEndOfTime() throws SOPGPException.UnsupportedOption {
|
public void notAfter_dashCountsAsEndOfTime() throws SOPGPException.UnsupportedOption {
|
||||||
assertSuccess(() ->
|
SopCLI.main(new String[] {"verify", "--not-after", "-", signature.getAbsolutePath(), cert.getAbsolutePath()});
|
||||||
SopCLI.execute("verify", "--not-after", "-",
|
|
||||||
signature.getAbsolutePath(), cert.getAbsolutePath()));
|
|
||||||
verify(detachedVerify, times(1)).notAfter(AbstractSopCmd.END_OF_TIME);
|
verify(detachedVerify, times(1)).notAfter(AbstractSopCmd.END_OF_TIME);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.UnsupportedOption.EXIT_CODE)
|
||||||
public void notAfter_unsupportedOptionCausesExit37() throws SOPGPException.UnsupportedOption {
|
public void notAfter_unsupportedOptionCausesExit37() throws SOPGPException.UnsupportedOption {
|
||||||
when(detachedVerify.notAfter(any())).thenThrow(new SOPGPException.UnsupportedOption("Setting upper signature date boundary not supported."));
|
when(detachedVerify.notAfter(any())).thenThrow(new SOPGPException.UnsupportedOption("Setting upper signature date boundary not supported."));
|
||||||
assertUnsupportedOption(() ->
|
SopCLI.main(new String[] {"verify", "--not-after", "2019-10-29T18:36:45Z", signature.getAbsolutePath(), cert.getAbsolutePath()});
|
||||||
SopCLI.execute("verify", "--not-after", "2019-10-29T18:36:45Z",
|
|
||||||
signature.getAbsolutePath(), cert.getAbsolutePath()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void notBefore_passedDown() throws SOPGPException.UnsupportedOption, ParseException {
|
public void notBefore_passedDown() throws SOPGPException.UnsupportedOption, ParseException {
|
||||||
Date date = UTCUtil.parseUTCDate("2019-10-29T18:36:45Z");
|
Date date = UTCUtil.parseUTCDate("2019-10-29T18:36:45Z");
|
||||||
assertSuccess(() ->
|
SopCLI.main(new String[] {"verify", "--not-before", "2019-10-29T18:36:45Z", signature.getAbsolutePath(), cert.getAbsolutePath()});
|
||||||
SopCLI.execute("verify", "--not-before", "2019-10-29T18:36:45Z",
|
|
||||||
signature.getAbsolutePath(), cert.getAbsolutePath()));
|
|
||||||
verify(detachedVerify, times(1)).notBefore(date);
|
verify(detachedVerify, times(1)).notBefore(date);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void notBefore_now() throws SOPGPException.UnsupportedOption {
|
public void notBefore_now() throws SOPGPException.UnsupportedOption {
|
||||||
Date now = new Date();
|
Date now = new Date();
|
||||||
assertSuccess(() ->
|
SopCLI.main(new String[] {"verify", "--not-before", "now", signature.getAbsolutePath(), cert.getAbsolutePath()});
|
||||||
SopCLI.execute("verify", "--not-before", "now",
|
|
||||||
signature.getAbsolutePath(), cert.getAbsolutePath()));
|
|
||||||
verify(detachedVerify, times(1)).notBefore(dateMatcher(now));
|
verify(detachedVerify, times(1)).notBefore(dateMatcher(now));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void notBefore_dashCountsAsBeginningOfTime() throws SOPGPException.UnsupportedOption {
|
public void notBefore_dashCountsAsBeginningOfTime() throws SOPGPException.UnsupportedOption {
|
||||||
assertSuccess(() ->
|
SopCLI.main(new String[] {"verify", "--not-before", "-", signature.getAbsolutePath(), cert.getAbsolutePath()});
|
||||||
SopCLI.execute("verify", "--not-before", "-",
|
|
||||||
signature.getAbsolutePath(), cert.getAbsolutePath()));
|
|
||||||
verify(detachedVerify, times(1)).notBefore(AbstractSopCmd.BEGINNING_OF_TIME);
|
verify(detachedVerify, times(1)).notBefore(AbstractSopCmd.BEGINNING_OF_TIME);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.UnsupportedOption.EXIT_CODE)
|
||||||
public void notBefore_unsupportedOptionCausesExit37() throws SOPGPException.UnsupportedOption {
|
public void notBefore_unsupportedOptionCausesExit37() throws SOPGPException.UnsupportedOption {
|
||||||
when(detachedVerify.notBefore(any())).thenThrow(new SOPGPException.UnsupportedOption("Setting lower signature date boundary not supported."));
|
when(detachedVerify.notBefore(any())).thenThrow(new SOPGPException.UnsupportedOption("Setting lower signature date boundary not supported."));
|
||||||
assertUnsupportedOption(() ->
|
SopCLI.main(new String[] {"verify", "--not-before", "2019-10-29T18:36:45Z", signature.getAbsolutePath(), cert.getAbsolutePath()});
|
||||||
SopCLI.execute("verify", "--not-before", "2019-10-29T18:36:45Z",
|
|
||||||
signature.getAbsolutePath(), cert.getAbsolutePath()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void notBeforeAndNotAfterAreCalledWithDefaultValues() throws SOPGPException.UnsupportedOption {
|
public void notBeforeAndNotAfterAreCalledWithDefaultValues() throws SOPGPException.UnsupportedOption {
|
||||||
assertSuccess(() ->
|
SopCLI.main(new String[] {"verify", signature.getAbsolutePath(), cert.getAbsolutePath()});
|
||||||
SopCLI.execute("verify", signature.getAbsolutePath(), cert.getAbsolutePath()));
|
|
||||||
verify(detachedVerify, times(1)).notAfter(dateMatcher(new Date()));
|
verify(detachedVerify, times(1)).notAfter(dateMatcher(new Date()));
|
||||||
verify(detachedVerify, times(1)).notBefore(AbstractSopCmd.BEGINNING_OF_TIME);
|
verify(detachedVerify, times(1)).notBefore(AbstractSopCmd.BEGINNING_OF_TIME);
|
||||||
}
|
}
|
||||||
|
@ -158,43 +139,43 @@ public class VerifyCmdTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.MissingInput.EXIT_CODE)
|
||||||
public void cert_fileNotFoundCausesExit61() {
|
public void cert_fileNotFoundCausesExit61() {
|
||||||
assertMissingInput(() ->
|
SopCLI.main(new String[] {"verify", signature.getAbsolutePath(), "invalid.asc"});
|
||||||
SopCLI.execute("verify", signature.getAbsolutePath(), "invalid.asc"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.BadData.EXIT_CODE)
|
||||||
public void cert_badDataCausesExit41() throws SOPGPException.BadData, IOException {
|
public void cert_badDataCausesExit41() throws SOPGPException.BadData, IOException {
|
||||||
when(detachedVerify.cert((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException()));
|
when(detachedVerify.cert((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException()));
|
||||||
assertBadData(() ->
|
SopCLI.main(new String[] {"verify", signature.getAbsolutePath(), cert.getAbsolutePath()});
|
||||||
SopCLI.execute("verify", signature.getAbsolutePath(), cert.getAbsolutePath()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.MissingInput.EXIT_CODE)
|
||||||
public void signature_fileNotFoundCausesExit61() {
|
public void signature_fileNotFoundCausesExit61() {
|
||||||
assertMissingInput(() ->
|
SopCLI.main(new String[] {"verify", "invalid.sig", cert.getAbsolutePath()});
|
||||||
SopCLI.execute("verify", "invalid.sig", cert.getAbsolutePath()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.BadData.EXIT_CODE)
|
||||||
public void signature_badDataCausesExit41() throws SOPGPException.BadData, IOException {
|
public void signature_badDataCausesExit41() throws SOPGPException.BadData, IOException {
|
||||||
when(detachedVerify.signatures((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException()));
|
when(detachedVerify.signatures((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException()));
|
||||||
assertBadData(() ->
|
SopCLI.main(new String[] {"verify", signature.getAbsolutePath(), cert.getAbsolutePath()});
|
||||||
SopCLI.execute("verify", signature.getAbsolutePath(), cert.getAbsolutePath()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.NoSignature.EXIT_CODE)
|
||||||
public void data_noSignaturesCausesExit3() throws SOPGPException.NoSignature, IOException, SOPGPException.BadData {
|
public void data_noSignaturesCausesExit3() throws SOPGPException.NoSignature, IOException, SOPGPException.BadData {
|
||||||
when(detachedVerify.data((InputStream) any())).thenThrow(new SOPGPException.NoSignature());
|
when(detachedVerify.data((InputStream) any())).thenThrow(new SOPGPException.NoSignature());
|
||||||
assertNoSignature(() ->
|
SopCLI.main(new String[] {"verify", signature.getAbsolutePath(), cert.getAbsolutePath()});
|
||||||
SopCLI.execute("verify", signature.getAbsolutePath(), cert.getAbsolutePath()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ExpectSystemExitWithStatus(SOPGPException.BadData.EXIT_CODE)
|
||||||
public void data_badDataCausesExit41() throws SOPGPException.NoSignature, IOException, SOPGPException.BadData {
|
public void data_badDataCausesExit41() throws SOPGPException.NoSignature, IOException, SOPGPException.BadData {
|
||||||
when(detachedVerify.data((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException()));
|
when(detachedVerify.data((InputStream) any())).thenThrow(new SOPGPException.BadData(new IOException()));
|
||||||
assertBadData(() ->
|
SopCLI.main(new String[] {"verify", signature.getAbsolutePath(), cert.getAbsolutePath()});
|
||||||
SopCLI.execute("verify", signature.getAbsolutePath(), cert.getAbsolutePath()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -211,8 +192,7 @@ public class VerifyCmdTest {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
System.setOut(new PrintStream(out));
|
System.setOut(new PrintStream(out));
|
||||||
|
|
||||||
assertSuccess(() ->
|
SopCLI.main(new String[] {"verify", signature.getAbsolutePath(), cert.getAbsolutePath()});
|
||||||
SopCLI.execute("verify", signature.getAbsolutePath(), cert.getAbsolutePath()));
|
|
||||||
|
|
||||||
System.setOut(originalSout);
|
System.setOut(originalSout);
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue