diff --git a/.reuse/dep5 b/.reuse/dep5 new file mode 100644 index 0000000..f43556c --- /dev/null +++ b/.reuse/dep5 @@ -0,0 +1,29 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: SOP-Java +Upstream-Contact: Paul Schaub +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 + +# Github Issue Templates +Files: .github/ISSUE_TEMPLATE/* +Copyright: 2024 the original author or authors +License: Apache-2.0 diff --git a/.woodpecker/build.yml b/.woodpecker/build.yml index 4c23ffb..2138cb4 100644 --- a/.woodpecker/build.yml +++ b/.woodpecker/build.yml @@ -17,5 +17,5 @@ steps: # Code has coverage - gradle jacocoRootReport coveralls environment: - COVERALLS_REPO_TOKEN: + coveralls_repo_token: from_secret: coveralls_repo_token diff --git a/CHANGELOG.md b/CHANGELOG.md index 0447a9a..49113f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,32 +6,6 @@ SPDX-License-Identifier: Apache-2.0 # 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 diff --git a/README.md b/README.md index 35324c4..f2e207f 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ SPDX-License-Identifier: Apache-2.0 # SOP for Java [![status-badge](https://ci.codeberg.org/api/badges/PGPainless/sop-java/status.svg)](https://ci.codeberg.org/PGPainless/sop-java) -[![Spec Revision: 14](https://img.shields.io/badge/Spec%20Revision-10-blue)](https://datatracker.ietf.org/doc/draft-dkg-openpgp-stateless-cli/14/) +[![Spec Revision: 10](https://img.shields.io/badge/Spec%20Revision-10-blue)](https://datatracker.ietf.org/doc/draft-dkg-openpgp-stateless-cli/10/) [![Coverage Status](https://coveralls.io/repos/github/pgpainless/sop-java/badge.svg?branch=main)](https://coveralls.io/github/pgpainless/sop-java?branch=main) [![REUSE status](https://api.reuse.software/badge/github.com/pgpainless/sop-java)](https://api.reuse.software/info/github.com/pgpainless/sop-java) diff --git a/REUSE.toml b/REUSE.toml deleted file mode 100644 index 7e1b250..0000000 --- a/REUSE.toml +++ /dev/null @@ -1,32 +0,0 @@ -# SPDX-FileCopyrightText: 2025 Paul Schaub -# -# SPDX-License-Identifier: CC0-1.0 - -version = 1 -SPDX-PackageName = "SOP-Java" -SPDX-PackageSupplier = "Paul Schaub " -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" diff --git a/build.gradle b/build.gradle index 10f2b87..577c2aa 100644 --- a/build.gradle +++ b/build.gradle @@ -18,7 +18,8 @@ buildscript { } 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 } @@ -31,9 +32,20 @@ allprojects { apply plugin: 'jacoco' apply plugin: 'checkstyle' apply plugin: 'kotlin' - apply plugin: 'kotlin-kapt' 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 // https://stackoverflow.com/a/25445035 jar { @@ -55,6 +67,8 @@ allprojects { description = "Stateless OpenPGP Protocol API for Java" version = shortVersion + sourceCompatibility = javaSourceCompatibility + repositories { mavenCentral() } @@ -63,13 +77,6 @@ allprojects { tasks.withType(AbstractArchiveTask) { preserveFileTimestamps = false reproducibleFileOrder = true - - dirMode = 0755 - fileMode = 0644 - } - - kotlin { - jvmToolchain(javaSourceCompatibility) } // Compatibility of default implementations in kotlin interfaces with Java implementations. @@ -104,7 +111,7 @@ allprojects { } jacoco { - toolVersion = "0.8.8" + toolVersion = "0.8.7" } jacocoTestReport { @@ -112,7 +119,7 @@ allprojects { sourceDirectories.setFrom(project.files(sourceSets.main.allSource.srcDirs)) classDirectories.setFrom(project.files(sourceSets.main.output)) reports { - xml.required = true + xml.enabled true } } @@ -130,15 +137,15 @@ subprojects { apply plugin: 'signing' task sourcesJar(type: Jar, dependsOn: classes) { - archiveClassifier = 'sources' + classifier = 'sources' from sourceSets.main.allSource } task javadocJar(type: Jar, dependsOn: javadoc) { - archiveClassifier = 'javadoc' + classifier = 'javadoc' from javadoc.destinationDir } task testsJar(type: Jar, dependsOn: testClasses) { - archiveClassifier = 'tests' + classifier = 'tests' from sourceSets.test.output } @@ -235,7 +242,7 @@ task jacocoRootReport(type: JacocoReport) { classDirectories.setFrom(files(subprojects.sourceSets.main.output)) executionData.setFrom(files(subprojects.jacocoTestReport.executionData)) reports { - xml.required = true + xml.enabled true xml.destination file("${buildDir}/reports/jacoco/test/jacocoTestReport.xml") } // We could remove the following setOnlyIf line, but then @@ -246,6 +253,10 @@ task jacocoRootReport(type: JacocoReport) { } task javadocAll(type: Javadoc) { + def currentJavaVersion = JavaVersion.current() + if (currentJavaVersion.compareTo(JavaVersion.VERSION_1_9) >= 0) { + options.addStringOption("-release", "8"); + } source subprojects.collect {project -> project.sourceSets.main.allJava } destinationDir = new File(buildDir, 'javadoc') diff --git a/external-sop/build.gradle b/external-sop/build.gradle index 2dfbf7e..d1a7ffb 100644 --- a/external-sop/build.gradle +++ b/external-sop/build.gradle @@ -15,9 +15,7 @@ repositories { dependencies { testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion" testImplementation "org.junit.jupiter:junit-jupiter-params:$junitVersion" - - testImplementation "org.junit.platform:junit-platform-suite-api:1.13.2" - testRuntimeOnly 'org.junit.platform:junit-platform-suite:1.13.2' + testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitVersion" api project(":sop-java") api "org.slf4j:slf4j-api:$slf4jVersion" diff --git a/external-sop/src/main/kotlin/sop/external/ExternalSOP.kt b/external-sop/src/main/kotlin/sop/external/ExternalSOP.kt index 48a5af9..27c93ae 100644 --- a/external-sop/src/main/kotlin/sop/external/ExternalSOP.kt +++ b/external-sop/src/main/kotlin/sop/external/ExternalSOP.kt @@ -69,14 +69,6 @@ class ExternalSOP( override fun changeKeyPassword(): ChangeKeyPassword = 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 * temporarily store additional results of OpenPGP operations such that the binding classes can @@ -120,9 +112,6 @@ class ExternalSOP( val errorMessage = readString(errIn) when (exitCode) { - UnspecificFailure.EXIT_CODE -> - throw UnspecificFailure( - "External SOP backend reported an unspecific error ($exitCode):\n$errorMessage") NoSignature.EXIT_CODE -> throw NoSignature( "External SOP backend reported error NoSignature ($exitCode):\n$errorMessage") @@ -180,21 +169,6 @@ class ExternalSOP( UnsupportedProfile.EXIT_CODE -> throw UnsupportedProfile( "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? else -> diff --git a/external-sop/src/main/kotlin/sop/external/ExternalSOPV.kt b/external-sop/src/main/kotlin/sop/external/ExternalSOPV.kt index 3341055..f22f947 100644 --- a/external-sop/src/main/kotlin/sop/external/ExternalSOPV.kt +++ b/external-sop/src/main/kotlin/sop/external/ExternalSOPV.kt @@ -10,11 +10,9 @@ 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 /** @@ -39,8 +37,6 @@ class ExternalSOPV( override fun inlineVerify(): InlineVerify = InlineVerifyExternal(binaryName, properties, tempDirProvider) - override fun validateUserId(): ValidateUserId = ValidateUserIdExternal(binaryName, properties) - companion object { /** diff --git a/external-sop/src/main/kotlin/sop/external/operation/CertifyUserIdExternal.kt b/external-sop/src/main/kotlin/sop/external/operation/CertifyUserIdExternal.kt deleted file mode 100644 index e3661db..0000000 --- a/external-sop/src/main/kotlin/sop/external/operation/CertifyUserIdExternal.kt +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-FileCopyrightText: 2024 Paul Schaub -// -// 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 = 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) -} diff --git a/external-sop/src/main/kotlin/sop/external/operation/EncryptExternal.kt b/external-sop/src/main/kotlin/sop/external/operation/EncryptExternal.kt index 679e09b..12d9cff 100644 --- a/external-sop/src/main/kotlin/sop/external/operation/EncryptExternal.kt +++ b/external-sop/src/main/kotlin/sop/external/operation/EncryptExternal.kt @@ -37,7 +37,7 @@ class EncryptExternal( override fun signWith(key: InputStream): Encrypt = apply { 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 } diff --git a/external-sop/src/main/kotlin/sop/external/operation/MergeCertsExternal.kt b/external-sop/src/main/kotlin/sop/external/operation/MergeCertsExternal.kt deleted file mode 100644 index b739eb3..0000000 --- a/external-sop/src/main/kotlin/sop/external/operation/MergeCertsExternal.kt +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-FileCopyrightText: 2024 Paul Schaub -// -// 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) -} diff --git a/external-sop/src/main/kotlin/sop/external/operation/UpdateKeyExternal.kt b/external-sop/src/main/kotlin/sop/external/operation/UpdateKeyExternal.kt deleted file mode 100644 index b84f452..0000000 --- a/external-sop/src/main/kotlin/sop/external/operation/UpdateKeyExternal.kt +++ /dev/null @@ -1,43 +0,0 @@ -// SPDX-FileCopyrightText: 2024 Paul Schaub -// -// 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) -} diff --git a/external-sop/src/main/kotlin/sop/external/operation/ValidateUserIdExternal.kt b/external-sop/src/main/kotlin/sop/external/operation/ValidateUserIdExternal.kt deleted file mode 100644 index cf4742b..0000000 --- a/external-sop/src/main/kotlin/sop/external/operation/ValidateUserIdExternal.kt +++ /dev/null @@ -1,43 +0,0 @@ -// SPDX-FileCopyrightText: 2024 Paul Schaub -// -// 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 = 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)}") - } -} diff --git a/external-sop/src/test/java/sop/testsuite/external/ExternalTestSuite.java b/external-sop/src/test/java/sop/testsuite/external/ExternalTestSuite.java deleted file mode 100644 index aa0ae82..0000000 --- a/external-sop/src/test/java/sop/testsuite/external/ExternalTestSuite.java +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-FileCopyrightText: 2025 Paul Schaub -// -// 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 { - -} diff --git a/external-sop/src/test/java/sop/testsuite/external/operation/ExternalArmorDearmorTest.java b/external-sop/src/test/java/sop/testsuite/external/operation/ExternalArmorDearmorTest.java new file mode 100644 index 0000000..1d8ff2b --- /dev/null +++ b/external-sop/src/test/java/sop/testsuite/external/operation/ExternalArmorDearmorTest.java @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub +// +// 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 { + +} diff --git a/external-sop/src/test/java/sop/testsuite/external/operation/ExternalDecryptWithSessionKeyTest.java b/external-sop/src/test/java/sop/testsuite/external/operation/ExternalDecryptWithSessionKeyTest.java new file mode 100644 index 0000000..0ac03a4 --- /dev/null +++ b/external-sop/src/test/java/sop/testsuite/external/operation/ExternalDecryptWithSessionKeyTest.java @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub +// +// 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 { + +} diff --git a/external-sop/src/test/java/sop/testsuite/external/operation/ExternalDetachedSignDetachedVerifyTest.java b/external-sop/src/test/java/sop/testsuite/external/operation/ExternalDetachedSignDetachedVerifyTest.java new file mode 100644 index 0000000..13959df --- /dev/null +++ b/external-sop/src/test/java/sop/testsuite/external/operation/ExternalDetachedSignDetachedVerifyTest.java @@ -0,0 +1,12 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub +// +// 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 { +} diff --git a/external-sop/src/test/java/sop/testsuite/external/operation/ExternalEncryptDecryptTest.java b/external-sop/src/test/java/sop/testsuite/external/operation/ExternalEncryptDecryptTest.java new file mode 100644 index 0000000..b83ca46 --- /dev/null +++ b/external-sop/src/test/java/sop/testsuite/external/operation/ExternalEncryptDecryptTest.java @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub +// +// 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 { + +} diff --git a/external-sop/src/test/java/sop/testsuite/external/operation/ExternalExtractCertTest.java b/external-sop/src/test/java/sop/testsuite/external/operation/ExternalExtractCertTest.java new file mode 100644 index 0000000..f47656c --- /dev/null +++ b/external-sop/src/test/java/sop/testsuite/external/operation/ExternalExtractCertTest.java @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub +// +// 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 { + +} diff --git a/external-sop/src/test/java/sop/testsuite/external/operation/ExternalGenerateKeyTest.java b/external-sop/src/test/java/sop/testsuite/external/operation/ExternalGenerateKeyTest.java new file mode 100644 index 0000000..7ac971b --- /dev/null +++ b/external-sop/src/test/java/sop/testsuite/external/operation/ExternalGenerateKeyTest.java @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub +// +// 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 { + +} diff --git a/external-sop/src/test/java/sop/testsuite/external/operation/ExternalInlineSignInlineDetachDetachedVerifyTest.java b/external-sop/src/test/java/sop/testsuite/external/operation/ExternalInlineSignInlineDetachDetachedVerifyTest.java new file mode 100644 index 0000000..2dd3396 --- /dev/null +++ b/external-sop/src/test/java/sop/testsuite/external/operation/ExternalInlineSignInlineDetachDetachedVerifyTest.java @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub +// +// 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 { + +} diff --git a/external-sop/src/test/java/sop/testsuite/external/operation/ExternalInlineSignInlineVerifyTest.java b/external-sop/src/test/java/sop/testsuite/external/operation/ExternalInlineSignInlineVerifyTest.java new file mode 100644 index 0000000..24e30aa --- /dev/null +++ b/external-sop/src/test/java/sop/testsuite/external/operation/ExternalInlineSignInlineVerifyTest.java @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub +// +// 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 { + +} diff --git a/external-sop/src/test/java/sop/testsuite/external/operation/ExternalListProfilesTest.java b/external-sop/src/test/java/sop/testsuite/external/operation/ExternalListProfilesTest.java new file mode 100644 index 0000000..18da883 --- /dev/null +++ b/external-sop/src/test/java/sop/testsuite/external/operation/ExternalListProfilesTest.java @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub +// +// 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 { + +} diff --git a/external-sop/src/test/java/sop/testsuite/external/operation/ExternalRevokeKeyTest.java b/external-sop/src/test/java/sop/testsuite/external/operation/ExternalRevokeKeyTest.java new file mode 100644 index 0000000..e2efe03 --- /dev/null +++ b/external-sop/src/test/java/sop/testsuite/external/operation/ExternalRevokeKeyTest.java @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub +// +// 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 { + +} diff --git a/external-sop/src/test/java/sop/testsuite/external/operation/ExternalVersionTest.java b/external-sop/src/test/java/sop/testsuite/external/operation/ExternalVersionTest.java new file mode 100644 index 0000000..ee63f09 --- /dev/null +++ b/external-sop/src/test/java/sop/testsuite/external/operation/ExternalVersionTest.java @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub +// +// 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 { + +} diff --git a/settings.gradle b/settings.gradle index 84dc381..1cb66be 100644 --- a/settings.gradle +++ b/settings.gradle @@ -7,6 +7,5 @@ rootProject.name = 'SOP-Java' include 'sop-java', 'sop-java-picocli', 'sop-java-testfixtures', - 'external-sop', - 'sop-java-json-gson' + 'external-sop' diff --git a/sop-java-json-gson/README.md b/sop-java-json-gson/README.md deleted file mode 100644 index 9feb8ff..0000000 --- a/sop-java-json-gson/README.md +++ /dev/null @@ -1,13 +0,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. diff --git a/sop-java-json-gson/build.gradle b/sop-java-json-gson/build.gradle deleted file mode 100644 index 4105902..0000000 --- a/sop-java-json-gson/build.gradle +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-FileCopyrightText: 2025 Paul Schaub -// -// 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" -} diff --git a/sop-java-json-gson/src/main/kotlin/sop/GsonParser.kt b/sop-java-json-gson/src/main/kotlin/sop/GsonParser.kt deleted file mode 100644 index 06adecb..0000000 --- a/sop-java-json-gson/src/main/kotlin/sop/GsonParser.kt +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-FileCopyrightText: 2025 Paul Schaub -// -// 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(){}.type) - } catch (e: JsonSyntaxException) { - throw ParseException(e.message, 0) - } - } -} \ No newline at end of file diff --git a/sop-java-json-gson/src/main/kotlin/sop/GsonSerializer.kt b/sop-java-json-gson/src/main/kotlin/sop/GsonSerializer.kt deleted file mode 100644 index 410fe49..0000000 --- a/sop-java-json-gson/src/main/kotlin/sop/GsonSerializer.kt +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-FileCopyrightText: 2025 Paul Schaub -// -// 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) - } -} \ No newline at end of file diff --git a/sop-java-json-gson/src/test/kotlin/sop/GsonSerializerAndParserTest.kt b/sop-java-json-gson/src/test/kotlin/sop/GsonSerializerAndParserTest.kt deleted file mode 100644 index 9bbef14..0000000 --- a/sop-java-json-gson/src/test/kotlin/sop/GsonSerializerAndParserTest.kt +++ /dev/null @@ -1,96 +0,0 @@ -// SPDX-FileCopyrightText: 2025 Paul Schaub -// -// 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 { parser.parse("Invalid") } - } - - @Test - fun parseMalformedJSON() { - // Missing '}' - assertThrows { parser.parse("{\"signers\":[\"Alice\"]") } - } -} \ No newline at end of file diff --git a/sop-java-picocli/build.gradle b/sop-java-picocli/build.gradle index 2203abe..dbf0cc1 100644 --- a/sop-java-picocli/build.gradle +++ b/sop-java-picocli/build.gradle @@ -21,7 +21,7 @@ dependencies { // CLI implementation "info.picocli:picocli:$picocliVersion" - kapt "info.picocli:picocli-codegen:$picocliVersion" + annotationProcessor "info.picocli:picocli-codegen:$picocliVersion" // @Nonnull, @Nullable... implementation "com.google.code.findbugs:jsr305:$jsrVersion" @@ -33,10 +33,6 @@ application { mainClass = mainClassName } -compileJava { - options.compilerArgs += ["-Aproject=${project.group}/${project.name}"] -} - jar { dependsOn(":sop-java:jar") duplicatesStrategy(DuplicatesStrategy.EXCLUDE) diff --git a/sop-java-picocli/src/main/kotlin/sop/cli/picocli/SopCLI.kt b/sop-java-picocli/src/main/kotlin/sop/cli/picocli/SopCLI.kt index 07caa03..b919370 100644 --- a/sop-java-picocli/src/main/kotlin/sop/cli/picocli/SopCLI.kt +++ b/sop-java-picocli/src/main/kotlin/sop/cli/picocli/SopCLI.kt @@ -27,10 +27,6 @@ import sop.exception.SOPGPException ChangeKeyPasswordCmd::class, RevokeKeyCmd::class, ExtractCertCmd::class, - UpdateKeyCmd::class, - MergeCertsCmd::class, - CertifyUserIdCmd::class, - ValidateUserIdCmd::class, // Messaging subcommands SignCmd::class, VerifyCmd::class, @@ -64,7 +60,7 @@ class SopCLI { @JvmField var EXECUTABLE_NAME = "sop" @JvmField - @Option(names = ["--stacktrace", "--debug"], scope = ScopeType.INHERIT) + @Option(names = ["--stacktrace"], scope = CommandLine.ScopeType.INHERIT) var stacktrace = false @JvmStatic @@ -87,12 +83,6 @@ class SopCLI { .apply { // Hide generate-completion command 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 commandName = EXECUTABLE_NAME // setup exception handling diff --git a/sop-java-picocli/src/main/kotlin/sop/cli/picocli/SopVCLI.kt b/sop-java-picocli/src/main/kotlin/sop/cli/picocli/SopVCLI.kt index 311a446..9a8b4b4 100644 --- a/sop-java-picocli/src/main/kotlin/sop/cli/picocli/SopVCLI.kt +++ b/sop-java-picocli/src/main/kotlin/sop/cli/picocli/SopVCLI.kt @@ -45,8 +45,7 @@ class SopVCLI { @JvmField var EXECUTABLE_NAME = "sopv" @JvmField - @CommandLine.Option( - names = ["--stacktrace", "--debug"], scope = CommandLine.ScopeType.INHERIT) + @CommandLine.Option(names = ["--stacktrace"], scope = CommandLine.ScopeType.INHERIT) var stacktrace = false @JvmStatic diff --git a/sop-java-picocli/src/main/kotlin/sop/cli/picocli/commands/AbstractSopCmd.kt b/sop-java-picocli/src/main/kotlin/sop/cli/picocli/commands/AbstractSopCmd.kt index 65be1be..4629e57 100644 --- a/sop-java-picocli/src/main/kotlin/sop/cli/picocli/commands/AbstractSopCmd.kt +++ b/sop-java-picocli/src/main/kotlin/sop/cli/picocli/commands/AbstractSopCmd.kt @@ -7,11 +7,6 @@ package sop.cli.picocli.commands import java.io.* import java.text.ParseException 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.exception.SOPGPException.* 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) : - 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, header: String, details: String): List { - 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 { const val PRFX_ENV = "@ENV:" 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 diff --git a/sop-java-picocli/src/main/kotlin/sop/cli/picocli/commands/CertifyUserIdCmd.kt b/sop-java-picocli/src/main/kotlin/sop/cli/picocli/commands/CertifyUserIdCmd.kt deleted file mode 100644 index 228809b..0000000 --- a/sop-java-picocli/src/main/kotlin/sop/cli/picocli/commands/CertifyUserIdCmd.kt +++ /dev/null @@ -1,84 +0,0 @@ -// SPDX-FileCopyrightText: 2024 Paul Schaub -// -// 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 = listOf() - - @Option(names = ["--with-key-password"], paramLabel = "PASSWORD") - var withKeyPassword: List = listOf() - - @Option(names = ["--no-require-self-sig"]) var noRequireSelfSig = false - - @Parameters(paramLabel = "KEYS", arity = "1..*") var keys: List = 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) - } - } -} diff --git a/sop-java-picocli/src/main/kotlin/sop/cli/picocli/commands/MergeCertsCmd.kt b/sop-java-picocli/src/main/kotlin/sop/cli/picocli/commands/MergeCertsCmd.kt deleted file mode 100644 index 3dcef38..0000000 --- a/sop-java-picocli/src/main/kotlin/sop/cli/picocli/commands/MergeCertsCmd.kt +++ /dev/null @@ -1,46 +0,0 @@ -// SPDX-FileCopyrightText: 2024 Paul Schaub -// -// 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 = 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) - } - } -} diff --git a/sop-java-picocli/src/main/kotlin/sop/cli/picocli/commands/UpdateKeyCmd.kt b/sop-java-picocli/src/main/kotlin/sop/cli/picocli/commands/UpdateKeyCmd.kt deleted file mode 100644 index 931f241..0000000 --- a/sop-java-picocli/src/main/kotlin/sop/cli/picocli/commands/UpdateKeyCmd.kt +++ /dev/null @@ -1,79 +0,0 @@ -// SPDX-FileCopyrightText: 2024 Paul Schaub -// -// 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 = listOf() - - @Option(names = ["--merge-certs"], paramLabel = "CERTS") var mergeCerts: List = 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) - } - } -} diff --git a/sop-java-picocli/src/main/kotlin/sop/cli/picocli/commands/ValidateUserIdCmd.kt b/sop-java-picocli/src/main/kotlin/sop/cli/picocli/commands/ValidateUserIdCmd.kt deleted file mode 100644 index b83e5a8..0000000 --- a/sop-java-picocli/src/main/kotlin/sop/cli/picocli/commands/ValidateUserIdCmd.kt +++ /dev/null @@ -1,82 +0,0 @@ -// SPDX-FileCopyrightText: 2024 Paul Schaub -// -// 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 = 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) - } - } -} diff --git a/sop-java-picocli/src/main/resources/msg_armor.properties b/sop-java-picocli/src/main/resources/msg_armor.properties index 1b7c1fb..b4dcb59 100644 --- a/sop-java-picocli/src/main/resources/msg_armor.properties +++ b/sop-java-picocli/src/main/resources/msg_armor.properties @@ -3,13 +3,9 @@ # SPDX-License-Identifier: Apache-2.0 usage.header=Add ASCII Armor to standard input -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 # Generic TODO: Remove when bumping picocli to 4.7.0 usage.synopsisHeading=Usage:\u0020 -usage.optionListHeading=%nOptions:%n +usage.commandListHeading = %nCommands:%n +usage.optionListHeading = %nOptions:%n usage.footerHeading=Powered by picocli%n diff --git a/sop-java-picocli/src/main/resources/msg_armor_de.properties b/sop-java-picocli/src/main/resources/msg_armor_de.properties index 34383c8..4c365a8 100644 --- a/sop-java-picocli/src/main/resources/msg_armor_de.properties +++ b/sop-java-picocli/src/main/resources/msg_armor_de.properties @@ -3,11 +3,9 @@ # SPDX-License-Identifier: Apache-2.0 usage.header=Schütze Standard-Eingabe mit 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 # Generic TODO: Remove when bumping picocli to 4.7.0 usage.synopsisHeading=Aufruf:\u0020 -usage.optionListHeading=%nOptionen:%n +usage.commandListHeading=%nBefehle:%n +usage.optionListHeading = %nOptionen:%n usage.footerHeading=Powered by Picocli%n diff --git a/sop-java-picocli/src/main/resources/msg_certify-userid.properties b/sop-java-picocli/src/main/resources/msg_certify-userid.properties deleted file mode 100644 index 36dc6f4..0000000 --- a/sop-java-picocli/src/main/resources/msg_certify-userid.properties +++ /dev/null @@ -1,25 +0,0 @@ -# SPDX-FileCopyrightText: 2024 Paul Schaub -# -# 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 diff --git a/sop-java-picocli/src/main/resources/msg_certify-userid_de.properties b/sop-java-picocli/src/main/resources/msg_certify-userid_de.properties deleted file mode 100644 index d634c59..0000000 --- a/sop-java-picocli/src/main/resources/msg_certify-userid_de.properties +++ /dev/null @@ -1,22 +0,0 @@ -# SPDX-FileCopyrightText: 2024 Paul Schaub -# -# 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 diff --git a/sop-java-picocli/src/main/resources/msg_change-key-password.properties b/sop-java-picocli/src/main/resources/msg_change-key-password.properties index 79bc11b..3de3608 100644 --- a/sop-java-picocli/src/main/resources/msg_change-key-password.properties +++ b/sop-java-picocli/src/main/resources/msg_change-key-password.properties @@ -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.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 # Generic TODO: Remove when bumping picocli to 4.7.0 usage.descriptionHeading=%nDescription:%n usage.synopsisHeading=Usage:\u0020 -usage.commandListHeading=%nCommands:%n -usage.optionListHeading=%nOptions:%n +usage.commandListHeading = %nCommands:%n +usage.optionListHeading = %nOptions:%n usage.footerHeading=Powered by picocli%n diff --git a/sop-java-picocli/src/main/resources/msg_change-key-password_de.properties b/sop-java-picocli/src/main/resources/msg_change-key-password_de.properties index 5515c1d..014c3e7 100644 --- a/sop-java-picocli/src/main/resources/msg_change-key-password_de.properties +++ b/sop-java-picocli/src/main/resources/msg_change-key-password_de.properties @@ -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.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 # Generic TODO: Remove when bumping picocli to 4.7.0 usage.descriptionHeading=%nBeschreibung:%n usage.synopsisHeading=Aufruf:\u0020 usage.commandListHeading=%nBefehle:%n -usage.optionListHeading=%nOptionen:%n +usage.optionListHeading = %nOptionen:%n usage.footerHeading=Powered by Picocli%n diff --git a/sop-java-picocli/src/main/resources/msg_dearmor.properties b/sop-java-picocli/src/main/resources/msg_dearmor.properties index 55cbf45..b088de1 100644 --- a/sop-java-picocli/src/main/resources/msg_dearmor.properties +++ b/sop-java-picocli/src/main/resources/msg_dearmor.properties @@ -3,14 +3,9 @@ # SPDX-License-Identifier: Apache-2.0 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 # Generic TODO: Remove when bumping picocli to 4.7.0 usage.synopsisHeading=Usage:\u0020 -usage.commandListHeading=%nCommands:%n -usage.optionListHeading=%nOptions:%n +usage.commandListHeading = %nCommands:%n +usage.optionListHeading = %nOptions:%n usage.footerHeading=Powered by picocli%n diff --git a/sop-java-picocli/src/main/resources/msg_dearmor_de.properties b/sop-java-picocli/src/main/resources/msg_dearmor_de.properties index e01ab7a..362ccef 100644 --- a/sop-java-picocli/src/main/resources/msg_dearmor_de.properties +++ b/sop-java-picocli/src/main/resources/msg_dearmor_de.properties @@ -3,12 +3,9 @@ # SPDX-License-Identifier: Apache-2.0 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 # Generic TODO: Remove when bumping picocli to 4.7.0 usage.synopsisHeading=Aufruf:\u0020 usage.commandListHeading=%nBefehle:%n -usage.optionListHeading=%nOptionen:%n +usage.optionListHeading = %nOptionen:%n usage.footerHeading=Powered by Picocli%n diff --git a/sop-java-picocli/src/main/resources/msg_decrypt.properties b/sop-java-picocli/src/main/resources/msg_decrypt.properties index bec315f..5903ded 100644 --- a/sop-java-picocli/src/main/resources/msg_decrypt.properties +++ b/sop-java-picocli/src/main/resources/msg_decrypt.properties @@ -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...). KEY[0..*]=Secret keys to attempt decryption with -standardInput=CIPHERTEXT -standardInputDescription=Encrypted OpenPGP message -standardOutput=DATA -standardOutputDescription=Decrypted OpenPGP message - 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.commandListHeading = %nCommands:%n +usage.optionListHeading = %nOptions:%n usage.footerHeading=Powered by picocli%n diff --git a/sop-java-picocli/src/main/resources/msg_decrypt_de.properties b/sop-java-picocli/src/main/resources/msg_decrypt_de.properties index 395a89f..ba40897 100644 --- a/sop-java-picocli/src/main/resources/msg_decrypt_de.properties +++ b/sop-java-picocli/src/main/resources/msg_decrypt_de.properties @@ -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...). KEY[0..*]=Private Schlüssel zum Entschlüsseln der Nachricht -standardInputDescription=Verschlüsselte OpenPGP Nachricht -standardOutputDescription=Entschlüsselte OpenPGP Nachricht - stacktrace=Stacktrace ausgeben # 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.optionListHeading = %nOptionen:%n usage.footerHeading=Powered by Picocli%n diff --git a/sop-java-picocli/src/main/resources/msg_detached-sign.properties b/sop-java-picocli/src/main/resources/msg_detached-sign.properties index 6ebfd0b..83359a6 100644 --- a/sop-java-picocli/src/main/resources/msg_detached-sign.properties +++ b/sop-java-picocli/src/main/resources/msg_detached-sign.properties @@ -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). 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 # 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.commandListHeading = %nCommands:%n +usage.optionListHeading = %nOptions:%n usage.footerHeading=Powered by picocli%n diff --git a/sop-java-picocli/src/main/resources/msg_detached-sign_de.properties b/sop-java-picocli/src/main/resources/msg_detached-sign_de.properties index 39b59b5..b943da5 100644 --- a/sop-java-picocli/src/main/resources/msg_detached-sign_de.properties +++ b/sop-java-picocli/src/main/resources/msg_detached-sign_de.properties @@ -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. KEYS[0..*]=Private Signaturschlüssel -standardInputDescription=Daten die signiert werden sollen -standardOutputDescription=Abgetrennte OpenPGP Signatur(en) - stacktrace=Stacktrace ausgeben # 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.optionListHeading = %nOptionen:%n usage.footerHeading=Powered by Picocli%n diff --git a/sop-java-picocli/src/main/resources/msg_detached-verify.properties b/sop-java-picocli/src/main/resources/msg_detached-verify.properties index 074a318..ee1a468 100644 --- a/sop-java-picocli/src/main/resources/msg_detached-verify.properties +++ b/sop-java-picocli/src/main/resources/msg_detached-verify.properties @@ -13,16 +13,11 @@ not-after.3=Accepts special value "-" for end of time. SIGNATURE[0]=Detached signature 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 # Generic TODO: Remove when bumping picocli to 4.7.0 usage.descriptionHeading=%nDescription:%n usage.parameterListHeading=%nParameters:%n usage.synopsisHeading=Usage:\u0020 -usage.commandListHeading=%nCommands:%n -usage.optionListHeading=%nOptions:%n +usage.commandListHeading = %nCommands:%n +usage.optionListHeading = %nOptions:%n usage.footerHeading=Powered by picocli%n diff --git a/sop-java-picocli/src/main/resources/msg_detached-verify_de.properties b/sop-java-picocli/src/main/resources/msg_detached-verify_de.properties index e21ee2a..332bff6 100644 --- a/sop-java-picocli/src/main/resources/msg_detached-verify_de.properties +++ b/sop-java-picocli/src/main/resources/msg_detached-verify_de.properties @@ -13,14 +13,11 @@ not-after.3=Akzeptiert speziellen Wert '-' f SIGNATURE[0]=Abgetrennte Signatur 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 # Generic TODO: Remove when bumping picocli to 4.7.0 usage.descriptionHeading=%nBeschreibung:%n usage.parameterListHeading=%nParameter:%n usage.synopsisHeading=Aufruf:\u0020 usage.commandListHeading=%nBefehle:%n -usage.optionListHeading=%nOptionen:%n +usage.optionListHeading = %nOptionen:%n usage.footerHeading=Powered by Picocli%n diff --git a/sop-java-picocli/src/main/resources/msg_encrypt.properties b/sop-java-picocli/src/main/resources/msg_encrypt.properties index 7bbf593..c0f7f7d 100644 --- a/sop-java-picocli/src/main/resources/msg_encrypt.properties +++ b/sop-java-picocli/src/main/resources/msg_encrypt.properties @@ -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...). 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 # 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.commandListHeading = %nCommands:%n +usage.optionListHeading = %nOptions:%n usage.footerHeading=Powered by picocli%n diff --git a/sop-java-picocli/src/main/resources/msg_encrypt_de.properties b/sop-java-picocli/src/main/resources/msg_encrypt_de.properties index 55b0338..6a3055c 100644 --- a/sop-java-picocli/src/main/resources/msg_encrypt_de.properties +++ b/sop-java-picocli/src/main/resources/msg_encrypt_de.properties @@ -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...). 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 # 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.optionListHeading = %nOptionen:%n usage.footerHeading=Powered by Picocli%n diff --git a/sop-java-picocli/src/main/resources/msg_extract-cert.properties b/sop-java-picocli/src/main/resources/msg_extract-cert.properties index 1d1dee4..82cac0f 100644 --- a/sop-java-picocli/src/main/resources/msg_extract-cert.properties +++ b/sop-java-picocli/src/main/resources/msg_extract-cert.properties @@ -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. 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 # Generic TODO: Remove when bumping picocli to 4.7.0 usage.descriptionHeading=%nDescription:%n usage.synopsisHeading=Usage:\u0020 -usage.commandListHeading=%nCommands:%n -usage.optionListHeading=%nOptions:%n +usage.commandListHeading = %nCommands:%n +usage.optionListHeading = %nOptions:%n usage.footerHeading=Powered by picocli%n diff --git a/sop-java-picocli/src/main/resources/msg_extract-cert_de.properties b/sop-java-picocli/src/main/resources/msg_extract-cert_de.properties index c92d31d..0946cfc 100644 --- a/sop-java-picocli/src/main/resources/msg_extract-cert_de.properties +++ b/sop-java-picocli/src/main/resources/msg_extract-cert_de.properties @@ -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. no-armor=Schütze Ausgabe mit ASCII Armor -standardInputDescription=Private Schlüssel, deren Zertifikate extrahiert werden sollen -standardOutputDescription=Extrahierte Zertifikate - stacktrace=Stacktrace ausgeben # Generic TODO: Remove when bumping picocli to 4.7.0 usage.descriptionHeading=%nBeschreibung:%n usage.synopsisHeading=Aufruf:\u0020 usage.commandListHeading=%nBefehle:%n -usage.optionListHeading=%nOptionen:%n +usage.optionListHeading = %nOptionen:%n usage.footerHeading=Powered by Picocli%n diff --git a/sop-java-picocli/src/main/resources/msg_generate-key.properties b/sop-java-picocli/src/main/resources/msg_generate-key.properties index c17f7f6..60ff4a4 100644 --- a/sop-java-picocli/src/main/resources/msg_generate-key.properties +++ b/sop-java-picocli/src/main/resources/msg_generate-key.properties @@ -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.1=Is an INDIRECT data type (e.g. file, environment variable, file descriptor...). -standardOutput=KEYS -standardOutputDescription=Generated 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.commandListHeading = %nCommands:%n +usage.optionListHeading = %nOptions:%n usage.footerHeading=Powered by picocli%n diff --git a/sop-java-picocli/src/main/resources/msg_generate-key_de.properties b/sop-java-picocli/src/main/resources/msg_generate-key_de.properties index 84db04d..6a0ce13 100644 --- a/sop-java-picocli/src/main/resources/msg_generate-key_de.properties +++ b/sop-java-picocli/src/main/resources/msg_generate-key_de.properties @@ -9,12 +9,10 @@ signing-only=Generiere einen Schl with-key-password.0=Passwort zum Schutz des privaten Schlüssels with-key-password.1=Ist ein INDIREKTER Datentyp (z.B.. Datei, Umgebungsvariable, Dateideskriptor...). -standardOutputDescription=Erzeugter OpenPGP Schlüssel - stacktrace=Stacktrace ausgeben # 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.optionListHeading = %nOptionen:%n usage.footerHeading=Powered by Picocli%n diff --git a/sop-java-picocli/src/main/resources/msg_help.properties b/sop-java-picocli/src/main/resources/msg_help.properties index 637c1d0..797cc79 100644 --- a/sop-java-picocli/src/main/resources/msg_help.properties +++ b/sop-java-picocli/src/main/resources/msg_help.properties @@ -6,6 +6,6 @@ usage.header=Display usage information for the specified subcommand stacktrace=Print stacktrace # Generic TODO: Remove when bumping picocli to 4.7.0 usage.synopsisHeading=Usage:\u0020 -usage.commandListHeading=%nCommands:%n -usage.optionListHeading=%nOptions:%n +usage.commandListHeading = %nCommands:%n +usage.optionListHeading = %nOptions:%n usage.footerHeading=Powered by picocli%n diff --git a/sop-java-picocli/src/main/resources/msg_help_de.properties b/sop-java-picocli/src/main/resources/msg_help_de.properties index 8471188..beea45c 100644 --- a/sop-java-picocli/src/main/resources/msg_help_de.properties +++ b/sop-java-picocli/src/main/resources/msg_help_de.properties @@ -7,5 +7,5 @@ stacktrace=Stacktrace ausgeben # Generic TODO: Remove when bumping picocli to 4.7.0 usage.synopsisHeading=Aufruf:\u0020 usage.commandListHeading=%nBefehle:%n -usage.optionListHeading=%nOptionen:%n +usage.optionListHeading = %nOptionen:%n usage.footerHeading=Powered by Picocli%n diff --git a/sop-java-picocli/src/main/resources/msg_inline-detach.properties b/sop-java-picocli/src/main/resources/msg_inline-detach.properties index ca0ed6b..c100c51 100644 --- a/sop-java-picocli/src/main/resources/msg_inline-detach.properties +++ b/sop-java-picocli/src/main/resources/msg_inline-detach.properties @@ -5,14 +5,9 @@ usage.header=Split signatures from a clearsigned message no-armor=ASCII armor the output 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 # Generic TODO: Remove when bumping picocli to 4.7.0 usage.synopsisHeading=Usage:\u0020 -usage.commandListHeading=%nCommands:%n -usage.optionListHeading=%nOptions:%n +usage.commandListHeading = %nCommands:%n +usage.optionListHeading = %nOptions:%n usage.footerHeading=Powered by picocli%n diff --git a/sop-java-picocli/src/main/resources/msg_inline-detach_de.properties b/sop-java-picocli/src/main/resources/msg_inline-detach_de.properties index 84b8c47..e59aa34 100644 --- a/sop-java-picocli/src/main/resources/msg_inline-detach_de.properties +++ b/sop-java-picocli/src/main/resources/msg_inline-detach_de.properties @@ -5,12 +5,9 @@ usage.header=Trenne Signaturen von Klartext-signierter Nachricht no-armor=Schütze Ausgabe mit ASCII Armor signatures-out=Schreibe abgetrennte Signaturen in Ausgabe -standardInputDescription=Klartext-signierte OpenPGP Nachricht -standardOutputDescription=Nachricht ohne Signaturen - stacktrace=Stacktrace ausgeben # Generic TODO: Remove when bumping picocli to 4.7.0 usage.synopsisHeading=Aufruf:\u0020 usage.commandListHeading=%nBefehle:%n -usage.optionListHeading=%nOptionen:%n +usage.optionListHeading = %nOptionen:%n usage.footerHeading=Powered by Picocli%n diff --git a/sop-java-picocli/src/main/resources/msg_inline-sign.properties b/sop-java-picocli/src/main/resources/msg_inline-sign.properties index 936b417..f5143bb 100644 --- a/sop-java-picocli/src/main/resources/msg_inline-sign.properties +++ b/sop-java-picocli/src/main/resources/msg_inline-sign.properties @@ -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). 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 # 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.commandListHeading = %nCommands:%n +usage.optionListHeading = %nOptions:%n usage.footerHeading=Powered by picocli%n diff --git a/sop-java-picocli/src/main/resources/msg_inline-sign_de.properties b/sop-java-picocli/src/main/resources/msg_inline-sign_de.properties index f8fe906..b09b7e4 100644 --- a/sop-java-picocli/src/main/resources/msg_inline-sign_de.properties +++ b/sop-java-picocli/src/main/resources/msg_inline-sign_de.properties @@ -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. KEYS[0..*]=Private Signaturschlüssel -standardInputDescription=Daten, die signiert werden sollen -standardOutputDescription=Inline-signierte OpenPGP Nachricht - stacktrace=Stacktrace ausgeben # 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.optionListHeading = %nOptionen:%n usage.footerHeading=Powered by Picocli%n diff --git a/sop-java-picocli/src/main/resources/msg_inline-verify.properties b/sop-java-picocli/src/main/resources/msg_inline-verify.properties index 2e0d69f..dfa94d7 100644 --- a/sop-java-picocli/src/main/resources/msg_inline-verify.properties +++ b/sop-java-picocli/src/main/resources/msg_inline-verify.properties @@ -12,15 +12,10 @@ not-after.3=Accepts special value "-" for end of time. verifications-out=File to write details over successful verifications to 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 # 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.commandListHeading = %nCommands:%n +usage.optionListHeading = %nOptions:%n usage.footerHeading=Powered by picocli%n diff --git a/sop-java-picocli/src/main/resources/msg_inline-verify_de.properties b/sop-java-picocli/src/main/resources/msg_inline-verify_de.properties index 9b70504..a9a5722 100644 --- a/sop-java-picocli/src/main/resources/msg_inline-verify_de.properties +++ b/sop-java-picocli/src/main/resources/msg_inline-verify_de.properties @@ -12,13 +12,10 @@ not-after.3=Akzeptiert speziellen Wert '-' f verifications-out=Schreibe Status der Signaturprüfung in angegebene Ausgabe CERT[0..*]=Zertifikate (öffentlich Schlüssel) zur Signaturprüfung -standardInputDescription=Inline-signierte OpenPGP Nachricht -standardOutputDescription=Nachricht ohne Signaturen - stacktrace=Stacktrace ausgeben # 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.optionListHeading = %nOptionen:%n usage.footerHeading=Powered by Picocli%n diff --git a/sop-java-picocli/src/main/resources/msg_list-profiles.properties b/sop-java-picocli/src/main/resources/msg_list-profiles.properties index 3defe8e..6d5f1a8 100644 --- a/sop-java-picocli/src/main/resources/msg_list-profiles.properties +++ b/sop-java-picocli/src/main/resources/msg_list-profiles.properties @@ -4,13 +4,10 @@ usage.header=Emit a list of profiles supported by the identified subcommand subcommand=Subcommand for which to list profiles -standardOutput=PROFILELIST -standardOutputDescription=List of profiles supported by the identified subcommand - 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.commandListHeading = %nCommands:%n +usage.optionListHeading = %nOptions:%n usage.footerHeading=Powered by picocli%n diff --git a/sop-java-picocli/src/main/resources/msg_list-profiles_de.properties b/sop-java-picocli/src/main/resources/msg_list-profiles_de.properties index 093aeb3..ac03c0d 100644 --- a/sop-java-picocli/src/main/resources/msg_list-profiles_de.properties +++ b/sop-java-picocli/src/main/resources/msg_list-profiles_de.properties @@ -4,12 +4,10 @@ usage.header=Gebe eine Liste von Profilen aus, welche vom angegebenen Unterbefehl unterstützt werden subcommand=Unterbefehl, für welchen Profile gelistet werden sollen -standardOutputDescription=Liste von Profilen, die der identifizierte Unterbefehl unterstützt - stacktrace=Stacktrace ausgeben # 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.optionListHeading = %nOptionen:%n usage.footerHeading=Powered by Picocli%n diff --git a/sop-java-picocli/src/main/resources/msg_merge-certs.properties b/sop-java-picocli/src/main/resources/msg_merge-certs.properties deleted file mode 100644 index 8c0bfa3..0000000 --- a/sop-java-picocli/src/main/resources/msg_merge-certs.properties +++ /dev/null @@ -1,22 +0,0 @@ -# SPDX-FileCopyrightText: 2024 Paul Schaub -# -# 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 diff --git a/sop-java-picocli/src/main/resources/msg_merge-certs_de.properties b/sop-java-picocli/src/main/resources/msg_merge-certs_de.properties deleted file mode 100644 index b1f008c..0000000 --- a/sop-java-picocli/src/main/resources/msg_merge-certs_de.properties +++ /dev/null @@ -1,19 +0,0 @@ -# SPDX-FileCopyrightText: 2024 Paul Schaub -# -# 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 diff --git a/sop-java-picocli/src/main/resources/msg_revoke-key.properties b/sop-java-picocli/src/main/resources/msg_revoke-key.properties index f68b774..c7d72b3 100644 --- a/sop-java-picocli/src/main/resources/msg_revoke-key.properties +++ b/sop-java-picocli/src/main/resources/msg_revoke-key.properties @@ -7,15 +7,10 @@ no-armor=ASCII armor the output 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...). -standardInput=KEYS -standardInputDescription=OpenPGP key that shall be revoked -standardOutput=CERTS -standardOutputDescription=Revocation certificate - stacktrace=Print stacktrace # Generic TODO: Remove when bumping picocli to 4.7.0 -usage.descriptionHeading=D%nescription:%n +usage.descriptionHeading=%nDescription:%n usage.synopsisHeading=Usage:\u0020 -usage.commandListHeading=%nCommands:%n -usage.optionListHeading=%nOptions:%n +usage.commandListHeading = %nCommands:%n +usage.optionListHeading = %nOptions:%n usage.footerHeading=Powered by picocli%n diff --git a/sop-java-picocli/src/main/resources/msg_revoke-key_de.properties b/sop-java-picocli/src/main/resources/msg_revoke-key_de.properties index fa8c5b4..95db272 100644 --- a/sop-java-picocli/src/main/resources/msg_revoke-key_de.properties +++ b/sop-java-picocli/src/main/resources/msg_revoke-key_de.properties @@ -7,13 +7,10 @@ no-armor=Sch with-key-password.0=Passwort zum Entsperren der privaten Schlüssel 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 # Generic TODO: Remove when bumping picocli to 4.7.0 usage.descriptionHeading=%nBeschreibung:%n usage.synopsisHeading=Aufruf:\u0020 usage.commandListHeading=%nBefehle:%n -usage.optionListHeading=%nOptionen:%n +usage.optionListHeading = %nOptionen:%n usage.footerHeading=Powered by Picocli%n diff --git a/sop-java-picocli/src/main/resources/msg_sop.properties b/sop-java-picocli/src/main/resources/msg_sop.properties index 520533a..94e4dc0 100644 --- a/sop-java-picocli/src/main/resources/msg_sop.properties +++ b/sop-java-picocli/src/main/resources/msg_sop.properties @@ -9,14 +9,10 @@ locale=Locale for description texts # Generic usage.synopsisHeading=Usage:\u0020 -usage.commandListHeading=%nCommands:%n -usage.optionListHeading=%nOptions:%n -usage.parameterListHeading=%nParameters:%n +usage.commandListHeading = %nCommands:%n +usage.optionListHeading = %nOptions:%n usage.footerHeading=Powered by picocli%n -standardInputHeading=%nInput:%n -standardOutputHeading=%nOutput:%n - # Exit Codes usage.exitCodeListHeading=%nExit Codes:%n usage.exitCodeList.0=\u00200:Successful program execution @@ -42,8 +38,6 @@ usage.exitCodeList.19=83:Options were supplied that are incompatible with each o 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 stacktrace=Print stacktrace @@ -80,8 +74,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_verifiable_signature_found=No verifiable signature found. 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 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. diff --git a/sop-java-picocli/src/main/resources/msg_sop_de.properties b/sop-java-picocli/src/main/resources/msg_sop_de.properties index 99d28a7..786fa36 100644 --- a/sop-java-picocli/src/main/resources/msg_sop_de.properties +++ b/sop-java-picocli/src/main/resources/msg_sop_de.properties @@ -10,13 +10,9 @@ locale=Gebietsschema f # Generic usage.synopsisHeading=Aufruf:\u0020 usage.commandListHeading=%nBefehle:%n -usage.optionListHeading=%nOptionen:%n -usage.parameterListHeading=%nParameter:%n +usage.optionListHeading = %nOptionen:%n usage.footerHeading=Powered by Picocli%n -standardInputHeading=%nEingabe:%n -standardOutputHeading=%nAusgabe:%n - # Exit Codes usage.exitCodeListHeading=%nExit Codes:%n usage.exitCodeList.0=\u00200:Erfolgreiche Programmausführung @@ -42,8 +38,6 @@ 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.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 stacktrace=Stacktrace ausgeben diff --git a/sop-java-picocli/src/main/resources/msg_update-key.properties b/sop-java-picocli/src/main/resources/msg_update-key.properties deleted file mode 100644 index 0b5243e..0000000 --- a/sop-java-picocli/src/main/resources/msg_update-key.properties +++ /dev/null @@ -1,24 +0,0 @@ -# SPDX-FileCopyrightText: 2024 Paul Schaub -# -# 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 diff --git a/sop-java-picocli/src/main/resources/msg_update-key_de.properties b/sop-java-picocli/src/main/resources/msg_update-key_de.properties deleted file mode 100644 index 91e5532..0000000 --- a/sop-java-picocli/src/main/resources/msg_update-key_de.properties +++ /dev/null @@ -1,21 +0,0 @@ -# SPDX-FileCopyrightText: 2024 Paul Schaub -# -# 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 diff --git a/sop-java-picocli/src/main/resources/msg_validate-userid.properties b/sop-java-picocli/src/main/resources/msg_validate-userid.properties deleted file mode 100644 index d25fa3a..0000000 --- a/sop-java-picocli/src/main/resources/msg_validate-userid.properties +++ /dev/null @@ -1,20 +0,0 @@ -# SPDX-FileCopyrightText: 2024 Paul Schaub -# -# 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 diff --git a/sop-java-picocli/src/main/resources/msg_validate-userid_de.properties b/sop-java-picocli/src/main/resources/msg_validate-userid_de.properties deleted file mode 100644 index f919465..0000000 --- a/sop-java-picocli/src/main/resources/msg_validate-userid_de.properties +++ /dev/null @@ -1,20 +0,0 @@ -# SPDX-FileCopyrightText: 2024 Paul Schaub -# -# 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 diff --git a/sop-java-picocli/src/main/resources/msg_version.properties b/sop-java-picocli/src/main/resources/msg_version.properties index 1327a78..9e1451b 100644 --- a/sop-java-picocli/src/main/resources/msg_version.properties +++ b/sop-java-picocli/src/main/resources/msg_version.properties @@ -5,13 +5,10 @@ usage.header=Display version information about the tool extended=Print an extended version string backend=Print information about the cryptographic backend 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 # Generic TODO: Remove when bumping picocli to 4.7.0 usage.synopsisHeading=Usage:\u0020 -usage.commandListHeading=%nCommands:%n -usage.optionListHeading=%nOptions:%n +usage.commandListHeading = %nCommands:%n +usage.optionListHeading = %nOptions:%n usage.footerHeading=Powered by picocli%n diff --git a/sop-java-picocli/src/main/resources/msg_version_de.properties b/sop-java-picocli/src/main/resources/msg_version_de.properties index c99045c..608b0c6 100644 --- a/sop-java-picocli/src/main/resources/msg_version_de.properties +++ b/sop-java-picocli/src/main/resources/msg_version_de.properties @@ -5,13 +5,10 @@ usage.header=Zeige Versionsinformationen extended=Gebe erweiterte Versionsinformationen 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 -sopv=Gebe die SOPV API Version aus - -standardOutput=Versionsinformationen stacktrace=Stacktrace ausgeben # Generic TODO: Remove when bumping picocli to 4.7.0 usage.synopsisHeading=Aufruf:\u0020 usage.commandListHeading=%nBefehle:%n -usage.optionListHeading=%nOptionen:%n +usage.optionListHeading = %nOptionen:%n usage.footerHeading=Powered by Picocli%n diff --git a/sop-java-picocli/src/test/java/sop/cli/picocli/SOPTest.java b/sop-java-picocli/src/test/java/sop/cli/picocli/SOPTest.java index 62c7581..fe49472 100644 --- a/sop-java-picocli/src/test/java/sop/cli/picocli/SOPTest.java +++ b/sop-java-picocli/src/test/java/sop/cli/picocli/SOPTest.java @@ -17,7 +17,6 @@ import org.junit.jupiter.api.Test; import sop.SOP; import sop.exception.SOPGPException; import sop.operation.Armor; -import sop.operation.CertifyUserId; import sop.operation.ChangeKeyPassword; import sop.operation.Dearmor; import sop.operation.Decrypt; @@ -30,10 +29,7 @@ import sop.operation.InlineVerify; import sop.operation.DetachedSign; import sop.operation.DetachedVerify; import sop.operation.ListProfiles; -import sop.operation.MergeCerts; import sop.operation.RevokeKey; -import sop.operation.UpdateKey; -import sop.operation.ValidateUserId; import sop.operation.Version; public class SOPTest { @@ -56,26 +52,6 @@ public class SOPTest { @Test public void UnsupportedSubcommandsTest() { 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 public Version version() { return null; @@ -164,11 +140,6 @@ public class SOPTest { commands.add(new String[] {"sign"}); commands.add(new String[] {"verify", "signature.asc", "cert.asc"}); commands.add(new String[] {"version"}); - commands.add(new String[] {"list-profiles", "generate-key"}); - commands.add(new String[] {"certify-userid", "--userid", "Alice ", "--", "alice.pgp"}); - commands.add(new String[] {"validate-userid", "Alice ", "bob.pgp", "--", "alice.pgp"}); - commands.add(new String[] {"update-key"}); - commands.add(new String[] {"merge-certs"}); for (String[] command : commands) { int exit = SopCLI.execute(command); diff --git a/sop-java-testfixtures/src/main/java/sop/testsuite/AbortOnUnsupportedOption.java b/sop-java-testfixtures/src/main/java/sop/testsuite/AbortOnUnsupportedOption.java deleted file mode 100644 index cbd0746..0000000 --- a/sop-java-testfixtures/src/main/java/sop/testsuite/AbortOnUnsupportedOption.java +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-FileCopyrightText: 2025 Paul Schaub -// -// SPDX-License-Identifier: Apache-2.0 - -package sop.testsuite; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -@Inherited -public @interface AbortOnUnsupportedOption { - -} diff --git a/sop-java-testfixtures/src/main/java/sop/testsuite/AbortOnUnsupportedOptionExtension.java b/sop-java-testfixtures/src/main/java/sop/testsuite/AbortOnUnsupportedOptionExtension.java deleted file mode 100644 index 0bf366d..0000000 --- a/sop-java-testfixtures/src/main/java/sop/testsuite/AbortOnUnsupportedOptionExtension.java +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-FileCopyrightText: 2025 Paul Schaub -// -// SPDX-License-Identifier: Apache-2.0 - -package sop.testsuite; - -import org.junit.jupiter.api.extension.ExtensionContext; -import org.junit.jupiter.api.extension.TestExecutionExceptionHandler; -import sop.exception.SOPGPException; - -import java.lang.annotation.Annotation; - -import static org.junit.jupiter.api.Assumptions.assumeTrue; - -public class AbortOnUnsupportedOptionExtension implements TestExecutionExceptionHandler { - - @Override - public void handleTestExecutionException(ExtensionContext extensionContext, Throwable throwable) throws Throwable { - Class testClass = extensionContext.getRequiredTestClass(); - Annotation annotation = testClass.getAnnotation(AbortOnUnsupportedOption.class); - if (annotation != null && throwable instanceof SOPGPException.UnsupportedOption) { - assumeTrue(false, "Test aborted due to: " + throwable.getMessage()); - } - throw throwable; - } -} diff --git a/sop-java-testfixtures/src/main/java/sop/testsuite/assertions/VerificationAssert.java b/sop-java-testfixtures/src/main/java/sop/testsuite/assertions/VerificationAssert.java index dea8717..63fd237 100644 --- a/sop-java-testfixtures/src/main/java/sop/testsuite/assertions/VerificationAssert.java +++ b/sop-java-testfixtures/src/main/java/sop/testsuite/assertions/VerificationAssert.java @@ -8,13 +8,9 @@ import sop.Verification; import sop.enums.SignatureMode; import sop.testsuite.JUtils; -import java.text.ParseException; import java.util.Date; -import java.util.function.Predicate; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; public final class VerificationAssert { @@ -49,39 +45,18 @@ public final class VerificationAssert { } public VerificationAssert hasDescription(String description) { - assertEquals(description, verification.getJsonOrDescription().get()); + assertEquals(description, verification.getDescription().get()); return this; } public VerificationAssert hasDescriptionOrNull(String description) { - if (verification.getJsonOrDescription().isEmpty()) { + if (verification.getDescription().isEmpty()) { return this; } return hasDescription(description); } - public VerificationAssert hasValidJSONOrNull(Verification.JSONParser parser) - throws ParseException { - if (!verification.getJsonOrDescription().isPresent()) { - // missing description - return this; - } - - return hasJSON(parser, null); - } - - public VerificationAssert hasJSON(Verification.JSONParser parser, Predicate predicate) { - assertTrue(verification.getContainsJson(), "Verification does not appear to contain JSON extension"); - - Verification.JSON json = verification.getJson(parser); - assertNotNull(verification.getJson(parser), "Verification does not appear to contain valid JSON extension."); - if (predicate != null) { - assertTrue(predicate.test(json), "JSON object does not match predicate."); - } - return this; - } - public VerificationAssert hasMode(SignatureMode mode) { assertEquals(mode, verification.getSignatureMode().get()); return this; diff --git a/sop-java-testfixtures/src/main/java/sop/testsuite/operation/AbstractSOPTest.java b/sop-java-testfixtures/src/main/java/sop/testsuite/operation/AbstractSOPTest.java index 16ae256..6c163f7 100644 --- a/sop-java-testfixtures/src/main/java/sop/testsuite/operation/AbstractSOPTest.java +++ b/sop-java-testfixtures/src/main/java/sop/testsuite/operation/AbstractSOPTest.java @@ -4,13 +4,10 @@ package sop.testsuite.operation; -import kotlin.jvm.functions.Function0; -import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Named; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.provider.Arguments; import sop.SOP; -import sop.exception.SOPGPException; import sop.testsuite.AbortOnUnsupportedOption; import sop.testsuite.AbortOnUnsupportedOptionExtension; import sop.testsuite.SOPInstanceFactory; @@ -21,8 +18,6 @@ import java.util.List; import java.util.Map; import java.util.stream.Stream; -import static org.junit.jupiter.api.Assumptions.assumeTrue; - @ExtendWith(AbortOnUnsupportedOptionExtension.class) @AbortOnUnsupportedOption public abstract class AbstractSOPTest { @@ -56,17 +51,6 @@ public abstract class AbstractSOPTest { } } - public T assumeSupported(Function0 f) { - try { - T t = f.invoke(); - assumeTrue(t != null, "Unsupported operation."); - return t; - } catch (SOPGPException.UnsupportedSubcommand e) { - assumeTrue(false, e.getMessage()); - return null; - } - } - public static Stream provideBackends() { return backends.stream(); } diff --git a/sop-java-testfixtures/src/main/java/sop/testsuite/operation/ArmorDearmorTest.java b/sop-java-testfixtures/src/main/java/sop/testsuite/operation/ArmorDearmorTest.java index 00488e1..35959b0 100644 --- a/sop-java-testfixtures/src/main/java/sop/testsuite/operation/ArmorDearmorTest.java +++ b/sop-java-testfixtures/src/main/java/sop/testsuite/operation/ArmorDearmorTest.java @@ -20,7 +20,7 @@ import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.assertArrayEquals; @EnabledIf("sop.testsuite.operation.AbstractSOPTest#hasBackends") -public class ArmorDearmorTest extends AbstractSOPTest { +public class ArmorDearmorTest { static Stream provideInstances() { return AbstractSOPTest.provideBackends(); @@ -31,13 +31,13 @@ public class ArmorDearmorTest extends AbstractSOPTest { public void dearmorArmorAliceKey(SOP sop) throws IOException { byte[] aliceKey = TestData.ALICE_KEY.getBytes(StandardCharsets.UTF_8); - byte[] dearmored = assumeSupported(sop::dearmor) + byte[] dearmored = sop.dearmor() .data(aliceKey) .getBytes(); Assertions.assertFalse(JUtils.arrayStartsWith(dearmored, TestData.BEGIN_PGP_PRIVATE_KEY_BLOCK)); - byte[] armored = assumeSupported(sop::armor) + byte[] armored = sop.armor() .data(dearmored) .getBytes(); @@ -52,13 +52,13 @@ public class ArmorDearmorTest extends AbstractSOPTest { public void dearmorArmorAliceCert(SOP sop) throws IOException { byte[] aliceCert = TestData.ALICE_CERT.getBytes(StandardCharsets.UTF_8); - byte[] dearmored = assumeSupported(sop::dearmor) + byte[] dearmored = sop.dearmor() .data(aliceCert) .getBytes(); Assertions.assertFalse(JUtils.arrayStartsWith(dearmored, TestData.BEGIN_PGP_PUBLIC_KEY_BLOCK)); - byte[] armored = assumeSupported(sop::armor) + byte[] armored = sop.armor() .data(dearmored) .getBytes(); @@ -73,13 +73,13 @@ public class ArmorDearmorTest extends AbstractSOPTest { public void dearmorArmorBobKey(SOP sop) throws IOException { byte[] bobKey = TestData.BOB_KEY.getBytes(StandardCharsets.UTF_8); - byte[] dearmored = assumeSupported(sop::dearmor) + byte[] dearmored = sop.dearmor() .data(bobKey) .getBytes(); Assertions.assertFalse(JUtils.arrayStartsWith(dearmored, TestData.BEGIN_PGP_PRIVATE_KEY_BLOCK)); - byte[] armored = assumeSupported(sop::armor) + byte[] armored = sop.armor() .data(dearmored) .getBytes(); @@ -94,13 +94,13 @@ public class ArmorDearmorTest extends AbstractSOPTest { public void dearmorArmorBobCert(SOP sop) throws IOException { byte[] bobCert = TestData.BOB_CERT.getBytes(StandardCharsets.UTF_8); - byte[] dearmored = assumeSupported(sop::dearmor) + byte[] dearmored = sop.dearmor() .data(bobCert) .getBytes(); Assertions.assertFalse(JUtils.arrayStartsWith(dearmored, TestData.BEGIN_PGP_PUBLIC_KEY_BLOCK)); - byte[] armored = assumeSupported(sop::armor) + byte[] armored = sop.armor() .data(dearmored) .getBytes(); @@ -115,13 +115,13 @@ public class ArmorDearmorTest extends AbstractSOPTest { public void dearmorArmorCarolKey(SOP sop) throws IOException { byte[] carolKey = TestData.CAROL_KEY.getBytes(StandardCharsets.UTF_8); - byte[] dearmored = assumeSupported(sop::dearmor) + byte[] dearmored = sop.dearmor() .data(carolKey) .getBytes(); Assertions.assertFalse(JUtils.arrayStartsWith(dearmored, TestData.BEGIN_PGP_PRIVATE_KEY_BLOCK)); - byte[] armored = assumeSupported(sop::armor) + byte[] armored = sop.armor() .data(dearmored) .getBytes(); @@ -136,13 +136,13 @@ public class ArmorDearmorTest extends AbstractSOPTest { public void dearmorArmorCarolCert(SOP sop) throws IOException { byte[] carolCert = TestData.CAROL_CERT.getBytes(StandardCharsets.UTF_8); - byte[] dearmored = assumeSupported(sop::dearmor) + byte[] dearmored = sop.dearmor() .data(carolCert) .getBytes(); Assertions.assertFalse(JUtils.arrayStartsWith(dearmored, TestData.BEGIN_PGP_PUBLIC_KEY_BLOCK)); - byte[] armored = assumeSupported(sop::armor) + byte[] armored = sop.armor() .data(dearmored) .getBytes(); @@ -163,13 +163,13 @@ public class ArmorDearmorTest extends AbstractSOPTest { "CePQFpprprnGEzpE3flQLUc=\n" + "=ZiFR\n" + "-----END PGP MESSAGE-----\n").getBytes(StandardCharsets.UTF_8); - byte[] dearmored = assumeSupported(sop::dearmor) + byte[] dearmored = sop.dearmor() .data(message) .getBytes(); Assertions.assertFalse(JUtils.arrayStartsWith(dearmored, TestData.BEGIN_PGP_MESSAGE)); - byte[] armored = assumeSupported(sop::armor) + byte[] armored = sop.armor() .data(dearmored) .getBytes(); @@ -191,13 +191,13 @@ public class ArmorDearmorTest extends AbstractSOPTest { "=GHvQ\n" + "-----END PGP SIGNATURE-----\n").getBytes(StandardCharsets.UTF_8); - byte[] dearmored = assumeSupported(sop::dearmor) + byte[] dearmored = sop.dearmor() .data(signature) .getBytes(); Assertions.assertFalse(JUtils.arrayStartsWith(dearmored, TestData.BEGIN_PGP_SIGNATURE)); - byte[] armored = assumeSupported(sop::armor) + byte[] armored = sop.armor() .data(dearmored) .getBytes(); @@ -210,11 +210,11 @@ public class ArmorDearmorTest extends AbstractSOPTest { @ParameterizedTest @MethodSource("provideInstances") public void testDearmoringTwiceIsIdempotent(SOP sop) throws IOException { - byte[] dearmored = assumeSupported(sop::dearmor) + byte[] dearmored = sop.dearmor() .data(TestData.ALICE_KEY.getBytes(StandardCharsets.UTF_8)) .getBytes(); - byte[] dearmoredAgain = assumeSupported(sop::dearmor) + byte[] dearmoredAgain = sop.dearmor() .data(dearmored) .getBytes(); @@ -233,7 +233,7 @@ public class ArmorDearmorTest extends AbstractSOPTest { "=GHvQ\n" + "-----END PGP SIGNATURE-----\n").getBytes(StandardCharsets.UTF_8); - byte[] armoredAgain = assumeSupported(sop::armor) + byte[] armoredAgain = sop.armor() .data(armored) .getBytes(); diff --git a/sop-java-testfixtures/src/main/java/sop/testsuite/operation/CertifyValidateUserIdTest.java b/sop-java-testfixtures/src/main/java/sop/testsuite/operation/CertifyValidateUserIdTest.java deleted file mode 100644 index 855c23d..0000000 --- a/sop-java-testfixtures/src/main/java/sop/testsuite/operation/CertifyValidateUserIdTest.java +++ /dev/null @@ -1,193 +0,0 @@ -// SPDX-FileCopyrightText: 2025 Paul Schaub -// -// SPDX-License-Identifier: Apache-2.0 - -package sop.testsuite.operation; - -import org.junit.jupiter.api.condition.EnabledIf; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; -import sop.SOP; -import sop.exception.SOPGPException; - -import java.io.IOException; -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -@EnabledIf("sop.testsuite.operation.AbstractSOPTest#hasBackends") -public class CertifyValidateUserIdTest extends AbstractSOPTest { - - static Stream provideInstances() { - return AbstractSOPTest.provideBackends(); - } - - @ParameterizedTest - @MethodSource("provideInstances") - public void certifyUserId(SOP sop) throws IOException { - byte[] aliceKey = assumeSupported(sop::generateKey) - .withKeyPassword("sw0rdf1sh") - .userId("Alice ") - .generate() - .getBytes(); - byte[] aliceCert = assumeSupported(sop::extractCert) - .key(aliceKey) - .getBytes(); - - byte[] bobKey = assumeSupported(sop::generateKey) - .userId("Bob ") - .generate() - .getBytes(); - byte[] bobCert = assumeSupported(sop::extractCert) - .key(bobKey) - .getBytes(); - - // Alice has her own user-id self-certified - assertTrue(assumeSupported(sop::validateUserId) - .authorities(aliceCert) - .userId("Alice ") - .subjects(aliceCert), - "Alice accepts her own self-certified user-id"); - - // Alice has not yet certified Bobs user-id - assertThrows(SOPGPException.CertUserIdNoMatch.class, () -> - assumeSupported(sop::validateUserId) - .authorities(aliceCert) - .userId("Bob ") - .subjects(bobCert), - "Alice has not yet certified Bobs user-id"); - - byte[] bobCertifiedByAlice = assumeSupported(sop::certifyUserId) - .userId("Bob ") - .withKeyPassword("sw0rdf1sh") - .keys(aliceKey) - .certs(bobCert) - .getBytes(); - - assertTrue(assumeSupported(sop::validateUserId) - .userId("Bob ") - .authorities(aliceCert) - .subjects(bobCertifiedByAlice), - "Alice accepts Bobs user-id after she certified it"); - } - - @ParameterizedTest - @MethodSource("provideInstances") - public void certifyUserIdUnarmored(SOP sop) throws IOException { - byte[] aliceKey = assumeSupported(sop::generateKey) - .noArmor() - .withKeyPassword("sw0rdf1sh") - .userId("Alice ") - .generate() - .getBytes(); - byte[] aliceCert = assumeSupported(sop::extractCert) - .noArmor() - .key(aliceKey) - .getBytes(); - - byte[] bobKey = assumeSupported(sop::generateKey) - .noArmor() - .userId("Bob ") - .generate() - .getBytes(); - byte[] bobCert = assumeSupported(sop::extractCert) - .noArmor() - .key(bobKey) - .getBytes(); - - byte[] bobCertifiedByAlice = assumeSupported(sop::certifyUserId) - .noArmor() - .userId("Bob ") - .withKeyPassword("sw0rdf1sh") - .keys(aliceKey) - .certs(bobCert) - .getBytes(); - - assertTrue(assumeSupported(sop::validateUserId) - .userId("Bob ") - .authorities(aliceCert) - .subjects(bobCertifiedByAlice), - "Alice accepts Bobs user-id after she certified it"); - } - - @ParameterizedTest - @MethodSource("provideInstances") - public void addPetName(SOP sop) throws IOException { - byte[] aliceKey = assumeSupported(sop::generateKey) - .userId("Alice ") - .generate() - .getBytes(); - byte[] aliceCert = assumeSupported(sop::extractCert) - .key(aliceKey) - .getBytes(); - - byte[] bobKey = assumeSupported(sop::generateKey) - .userId("Bob ") - .generate() - .getBytes(); - byte[] bobCert = assumeSupported(sop::extractCert) - .key(bobKey) - .getBytes(); - - assertThrows(SOPGPException.CertUserIdNoMatch.class, () -> - assumeSupported(sop::certifyUserId) - .userId("Bobby") - .keys(aliceKey) - .certs(bobCert) - .getBytes(), - "Alice cannot create a pet-name for Bob without the --no-require-self-sig flag"); - - byte[] bobWithPetName = assumeSupported(sop::certifyUserId) - .userId("Bobby") - .noRequireSelfSig() - .keys(aliceKey) - .certs(bobCert) - .getBytes(); - - assertTrue(assumeSupported(sop::validateUserId) - .userId("Bobby") - .authorities(aliceCert) - .subjects(bobWithPetName), - "Alice accepts the pet-name she gave to Bob"); - - assertThrows(SOPGPException.CertUserIdNoMatch.class, () -> - assumeSupported(sop::validateUserId) - .userId("Bobby") - .authorities(bobWithPetName) - .subjects(bobWithPetName), - "Bob does not accept the pet-name Alice gave him"); - } - - @ParameterizedTest - @MethodSource("provideInstances") - public void certifyWithRevokedKey(SOP sop) throws IOException { - byte[] aliceKey = assumeSupported(sop::generateKey) - .userId("Alice ") - .generate() - .getBytes(); - byte[] aliceRevokedCert = assumeSupported(sop::revokeKey) - .keys(aliceKey) - .getBytes(); - byte[] aliceRevokedKey = assumeSupported(sop::updateKey) - .mergeCerts(aliceRevokedCert) - .key(aliceKey) - .getBytes(); - - byte[] bobKey = assumeSupported(sop::generateKey) - .userId("Bob ") - .generate() - .getBytes(); - byte[] bobCert = assumeSupported(sop::extractCert) - .key(bobKey) - .getBytes(); - - assertThrows(SOPGPException.KeyCannotCertify.class, () -> - assumeSupported(sop::certifyUserId) - .userId("Bob ") - .keys(aliceRevokedKey) - .certs(bobCert) - .getBytes()); - } -} diff --git a/sop-java-testfixtures/src/main/java/sop/testsuite/operation/ChangeKeyPasswordTest.java b/sop-java-testfixtures/src/main/java/sop/testsuite/operation/ChangeKeyPasswordTest.java index a62cbb8..8948dda 100644 --- a/sop-java-testfixtures/src/main/java/sop/testsuite/operation/ChangeKeyPasswordTest.java +++ b/sop-java-testfixtures/src/main/java/sop/testsuite/operation/ChangeKeyPasswordTest.java @@ -32,18 +32,18 @@ public class ChangeKeyPasswordTest extends AbstractSOPTest { @ParameterizedTest @MethodSource("provideInstances") public void changePasswordFromUnprotectedToProtected(SOP sop) throws IOException { - byte[] unprotectedKey = assumeSupported(sop::generateKey).generate().getBytes(); + byte[] unprotectedKey = sop.generateKey().generate().getBytes(); byte[] password = "sw0rdf1sh".getBytes(UTF8Util.UTF8); - byte[] protectedKey = assumeSupported(sop::changeKeyPassword).newKeyPassphrase(password).keys(unprotectedKey).getBytes(); + byte[] protectedKey = sop.changeKeyPassword().newKeyPassphrase(password).keys(unprotectedKey).getBytes(); - assumeSupported(sop::sign).withKeyPassword(password).key(protectedKey).data("Test123".getBytes(StandardCharsets.UTF_8)); + sop.sign().withKeyPassword(password).key(protectedKey).data("Test123".getBytes(StandardCharsets.UTF_8)); } @ParameterizedTest @MethodSource("provideInstances") public void changePasswordFromUnprotectedToUnprotected(SOP sop) throws IOException { - byte[] unprotectedKey = assumeSupported(sop::generateKey).noArmor().generate().getBytes(); - byte[] stillUnprotectedKey = assumeSupported(sop::changeKeyPassword).noArmor().keys(unprotectedKey).getBytes(); + byte[] unprotectedKey = sop.generateKey().noArmor().generate().getBytes(); + byte[] stillUnprotectedKey = sop.changeKeyPassword().noArmor().keys(unprotectedKey).getBytes(); assertArrayEquals(unprotectedKey, stillUnprotectedKey); } @@ -52,12 +52,12 @@ public class ChangeKeyPasswordTest extends AbstractSOPTest { @MethodSource("provideInstances") public void changePasswordFromProtectedToUnprotected(SOP sop) throws IOException { byte[] password = "sw0rdf1sh".getBytes(UTF8Util.UTF8); - byte[] protectedKey = assumeSupported(sop::generateKey).withKeyPassword(password).generate().getBytes(); - byte[] unprotectedKey = assumeSupported(sop::changeKeyPassword) + byte[] protectedKey = sop.generateKey().withKeyPassword(password).generate().getBytes(); + byte[] unprotectedKey = sop.changeKeyPassword() .oldKeyPassphrase(password) .keys(protectedKey).getBytes(); - assumeSupported(sop::sign).key(unprotectedKey).data("Test123".getBytes(StandardCharsets.UTF_8)); + sop.sign().key(unprotectedKey).data("Test123".getBytes(StandardCharsets.UTF_8)); } @ParameterizedTest @@ -65,13 +65,13 @@ public class ChangeKeyPasswordTest extends AbstractSOPTest { public void changePasswordFromProtectedToDifferentProtected(SOP sop) throws IOException { byte[] oldPassword = "sw0rdf1sh".getBytes(UTF8Util.UTF8); byte[] newPassword = "0r4ng3".getBytes(UTF8Util.UTF8); - byte[] protectedKey = assumeSupported(sop::generateKey).withKeyPassword(oldPassword).generate().getBytes(); - byte[] reprotectedKey = assumeSupported(sop::changeKeyPassword) + byte[] protectedKey = sop.generateKey().withKeyPassword(oldPassword).generate().getBytes(); + byte[] reprotectedKey = sop.changeKeyPassword() .oldKeyPassphrase(oldPassword) .newKeyPassphrase(newPassword) .keys(protectedKey).getBytes(); - assumeSupported(sop::sign).key(reprotectedKey).withKeyPassword(newPassword).data("Test123".getBytes(StandardCharsets.UTF_8)); + sop.sign().key(reprotectedKey).withKeyPassword(newPassword).data("Test123".getBytes(StandardCharsets.UTF_8)); } @@ -82,8 +82,8 @@ public class ChangeKeyPasswordTest extends AbstractSOPTest { byte[] newPassword = "monkey123".getBytes(UTF8Util.UTF8); byte[] wrongPassword = "0r4ng3".getBytes(UTF8Util.UTF8); - byte[] protectedKey = assumeSupported(sop::generateKey).withKeyPassword(oldPassword).generate().getBytes(); - assertThrows(SOPGPException.KeyIsProtected.class, () -> assumeSupported(sop::changeKeyPassword) + byte[] protectedKey = sop.generateKey().withKeyPassword(oldPassword).generate().getBytes(); + assertThrows(SOPGPException.KeyIsProtected.class, () -> sop.changeKeyPassword() .oldKeyPassphrase(wrongPassword) .newKeyPassphrase(newPassword) .keys(protectedKey).getBytes()); @@ -93,9 +93,9 @@ public class ChangeKeyPasswordTest extends AbstractSOPTest { @MethodSource("provideInstances") public void nonUtf8PasswordsFail(SOP sop) { assertThrows(SOPGPException.PasswordNotHumanReadable.class, () -> - assumeSupported(sop::changeKeyPassword).oldKeyPassphrase(new byte[] {(byte) 0xff, (byte) 0xfe})); + sop.changeKeyPassword().oldKeyPassphrase(new byte[] {(byte) 0xff, (byte) 0xfe})); assertThrows(SOPGPException.PasswordNotHumanReadable.class, () -> - assumeSupported(sop::changeKeyPassword).newKeyPassphrase(new byte[] {(byte) 0xff, (byte) 0xfe})); + sop.changeKeyPassword().newKeyPassphrase(new byte[] {(byte) 0xff, (byte) 0xfe})); } @@ -104,16 +104,16 @@ public class ChangeKeyPasswordTest extends AbstractSOPTest { public void testNoArmor(SOP sop) throws IOException { byte[] oldPassword = "sw0rdf1sh".getBytes(UTF8Util.UTF8); byte[] newPassword = "0r4ng3".getBytes(UTF8Util.UTF8); - byte[] protectedKey = assumeSupported(sop::generateKey).withKeyPassword(oldPassword).generate().getBytes(); + byte[] protectedKey = sop.generateKey().withKeyPassword(oldPassword).generate().getBytes(); - byte[] armored = assumeSupported(sop::changeKeyPassword) + byte[] armored = sop.changeKeyPassword() .oldKeyPassphrase(oldPassword) .newKeyPassphrase(newPassword) .keys(protectedKey) .getBytes(); JUtils.assertArrayStartsWith(armored, TestData.BEGIN_PGP_PRIVATE_KEY_BLOCK); - byte[] unarmored = assumeSupported(sop::changeKeyPassword) + byte[] unarmored = sop.changeKeyPassword() .noArmor() .oldKeyPassphrase(oldPassword) .newKeyPassphrase(newPassword) diff --git a/sop-java-testfixtures/src/main/java/sop/testsuite/operation/DecryptWithSessionKeyTest.java b/sop-java-testfixtures/src/main/java/sop/testsuite/operation/DecryptWithSessionKeyTest.java index 8fd201a..65ec4a5 100644 --- a/sop-java-testfixtures/src/main/java/sop/testsuite/operation/DecryptWithSessionKeyTest.java +++ b/sop-java-testfixtures/src/main/java/sop/testsuite/operation/DecryptWithSessionKeyTest.java @@ -41,7 +41,7 @@ public class DecryptWithSessionKeyTest extends AbstractSOPTest { @ParameterizedTest @MethodSource("provideInstances") public void testDecryptAndExtractSessionKey(SOP sop) throws IOException { - ByteArrayAndResult bytesAndResult = assumeSupported(sop::decrypt) + ByteArrayAndResult bytesAndResult = sop.decrypt() .withKey(TestData.ALICE_KEY.getBytes(StandardCharsets.UTF_8)) .ciphertext(CIPHERTEXT.getBytes(StandardCharsets.UTF_8)) .toByteArrayAndResult(); @@ -54,7 +54,7 @@ public class DecryptWithSessionKeyTest extends AbstractSOPTest { @ParameterizedTest @MethodSource("provideInstances") public void testDecryptWithSessionKey(SOP sop) throws IOException { - byte[] decrypted = assumeSupported(sop::decrypt) + byte[] decrypted = sop.decrypt() .withSessionKey(SessionKey.fromString(SESSION_KEY)) .ciphertext(CIPHERTEXT.getBytes(StandardCharsets.UTF_8)) .toByteArrayAndResult() diff --git a/sop-java-testfixtures/src/main/java/sop/testsuite/operation/DetachedSignDetachedVerifyTest.java b/sop-java-testfixtures/src/main/java/sop/testsuite/operation/DetachedSignDetachedVerifyTest.java index 415b9db..e404599 100644 --- a/sop-java-testfixtures/src/main/java/sop/testsuite/operation/DetachedSignDetachedVerifyTest.java +++ b/sop-java-testfixtures/src/main/java/sop/testsuite/operation/DetachedSignDetachedVerifyTest.java @@ -37,13 +37,13 @@ public class DetachedSignDetachedVerifyTest extends AbstractSOPTest { public void signVerifyWithAliceKey(SOP sop) throws IOException { byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8); - byte[] signature = assumeSupported(sop::detachedSign) + byte[] signature = sop.detachedSign() .key(TestData.ALICE_KEY.getBytes(StandardCharsets.UTF_8)) .data(message) .toByteArrayAndResult() .getBytes(); - List verificationList = assumeSupported(sop::detachedVerify) + List verificationList = sop.detachedVerify() .cert(TestData.ALICE_CERT.getBytes(StandardCharsets.UTF_8)) .signatures(signature) .data(message); @@ -60,14 +60,14 @@ public class DetachedSignDetachedVerifyTest extends AbstractSOPTest { public void signVerifyTextModeWithAliceKey(SOP sop) throws IOException { byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8); - byte[] signature = assumeSupported(sop::detachedSign) + byte[] signature = sop.detachedSign() .key(TestData.ALICE_KEY.getBytes(StandardCharsets.UTF_8)) .mode(SignAs.text) .data(message) .toByteArrayAndResult() .getBytes(); - List verificationList = assumeSupported(sop::detachedVerify) + List verificationList = sop.detachedVerify() .cert(TestData.ALICE_CERT.getBytes(StandardCharsets.UTF_8)) .signatures(signature) .data(message); @@ -85,7 +85,7 @@ public class DetachedSignDetachedVerifyTest extends AbstractSOPTest { byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8); byte[] signature = TestData.ALICE_DETACHED_SIGNED_MESSAGE.getBytes(StandardCharsets.UTF_8); - List verificationList = assumeSupported(sop::detachedVerify) + List verificationList = sop.detachedVerify() .cert(TestData.ALICE_CERT.getBytes(StandardCharsets.UTF_8)) .signatures(signature) .data(message); @@ -101,13 +101,13 @@ public class DetachedSignDetachedVerifyTest extends AbstractSOPTest { public void signVerifyWithBobKey(SOP sop) throws IOException { byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8); - byte[] signature = assumeSupported(sop::detachedSign) + byte[] signature = sop.detachedSign() .key(TestData.BOB_KEY.getBytes(StandardCharsets.UTF_8)) .data(message) .toByteArrayAndResult() .getBytes(); - List verificationList = assumeSupported(sop::detachedVerify) + List verificationList = sop.detachedVerify() .cert(TestData.BOB_CERT.getBytes(StandardCharsets.UTF_8)) .signatures(signature) .data(message); @@ -123,13 +123,13 @@ public class DetachedSignDetachedVerifyTest extends AbstractSOPTest { public void signVerifyWithCarolKey(SOP sop) throws IOException { byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8); - byte[] signature = assumeSupported(sop::detachedSign) + byte[] signature = sop.detachedSign() .key(TestData.CAROL_KEY.getBytes(StandardCharsets.UTF_8)) .data(message) .toByteArrayAndResult() .getBytes(); - List verificationList = assumeSupported(sop::detachedVerify) + List verificationList = sop.detachedVerify() .cert(TestData.CAROL_CERT.getBytes(StandardCharsets.UTF_8)) .signatures(signature) .data(message); @@ -145,7 +145,7 @@ public class DetachedSignDetachedVerifyTest extends AbstractSOPTest { public void signVerifyWithEncryptedKey(SOP sop) throws IOException { byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8); - byte[] signature = assumeSupported(sop::detachedSign) + byte[] signature = sop.detachedSign() .key(TestData.PASSWORD_PROTECTED_KEY.getBytes(StandardCharsets.UTF_8)) .withKeyPassword(TestData.PASSWORD) .data(message) @@ -154,7 +154,7 @@ public class DetachedSignDetachedVerifyTest extends AbstractSOPTest { JUtils.assertArrayStartsWith(signature, TestData.BEGIN_PGP_SIGNATURE); - List verificationList = assumeSupported(sop::detachedVerify) + List verificationList = sop.detachedVerify() .cert(TestData.PASSWORD_PROTECTED_CERT.getBytes(StandardCharsets.UTF_8)) .signatures(signature) .data(message); @@ -170,18 +170,18 @@ public class DetachedSignDetachedVerifyTest extends AbstractSOPTest { public void signArmorVerifyWithBobKey(SOP sop) throws IOException { byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8); - byte[] signature = assumeSupported(sop::detachedSign) + byte[] signature = sop.detachedSign() .key(TestData.BOB_KEY.getBytes(StandardCharsets.UTF_8)) .noArmor() .data(message) .toByteArrayAndResult() .getBytes(); - byte[] armored = assumeSupported(sop::armor) + byte[] armored = sop.armor() .data(signature) .getBytes(); - List verificationList = assumeSupported(sop::detachedVerify) + List verificationList = sop.detachedVerify() .cert(TestData.BOB_CERT.getBytes(StandardCharsets.UTF_8)) .signatures(armored) .data(message); @@ -199,7 +199,7 @@ public class DetachedSignDetachedVerifyTest extends AbstractSOPTest { byte[] signature = TestData.ALICE_DETACHED_SIGNED_MESSAGE.getBytes(StandardCharsets.UTF_8); Date beforeSignature = new Date(TestData.ALICE_DETACHED_SIGNED_MESSAGE_DATE.getTime() - 1000); // 1 sec before sig - assertThrows(SOPGPException.NoSignature.class, () -> assumeSupported(sop::detachedVerify) + assertThrows(SOPGPException.NoSignature.class, () -> sop.detachedVerify() .cert(TestData.ALICE_CERT.getBytes(StandardCharsets.UTF_8)) .notAfter(beforeSignature) .signatures(signature) @@ -213,7 +213,7 @@ public class DetachedSignDetachedVerifyTest extends AbstractSOPTest { byte[] signature = TestData.ALICE_DETACHED_SIGNED_MESSAGE.getBytes(StandardCharsets.UTF_8); Date afterSignature = new Date(TestData.ALICE_DETACHED_SIGNED_MESSAGE_DATE.getTime() + 1000); // 1 sec after sig - assertThrows(SOPGPException.NoSignature.class, () -> assumeSupported(sop::detachedVerify) + assertThrows(SOPGPException.NoSignature.class, () -> sop.detachedVerify() .cert(TestData.ALICE_CERT.getBytes(StandardCharsets.UTF_8)) .notBefore(afterSignature) .signatures(signature) @@ -224,13 +224,13 @@ public class DetachedSignDetachedVerifyTest extends AbstractSOPTest { @MethodSource("provideInstances") public void signWithAliceVerifyWithBobThrowsNoSignature(SOP sop) throws IOException { byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8); - byte[] signatures = assumeSupported(sop::detachedSign) + byte[] signatures = sop.detachedSign() .key(TestData.ALICE_KEY.getBytes(StandardCharsets.UTF_8)) .data(message) .toByteArrayAndResult() .getBytes(); - assertThrows(SOPGPException.NoSignature.class, () -> assumeSupported(sop::detachedVerify) + assertThrows(SOPGPException.NoSignature.class, () -> sop.detachedVerify() .cert(TestData.BOB_CERT.getBytes(StandardCharsets.UTF_8)) .signatures(signatures) .data(message)); @@ -240,7 +240,7 @@ public class DetachedSignDetachedVerifyTest extends AbstractSOPTest { @MethodSource("provideInstances") public void signVerifyWithEncryptedKeyWithoutPassphraseFails(SOP sop) { assertThrows(SOPGPException.KeyIsProtected.class, () -> - assumeSupported(sop::detachedSign) + sop.detachedSign() .key(TestData.PASSWORD_PROTECTED_KEY.getBytes(StandardCharsets.UTF_8)) .data(TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8)) .toByteArrayAndResult() @@ -253,7 +253,7 @@ public class DetachedSignDetachedVerifyTest extends AbstractSOPTest { throws IOException { byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8); - byte[] signature = assumeSupported(sop::sign) + byte[] signature = sop.sign() .key(TestData.PASSWORD_PROTECTED_KEY.getBytes(StandardCharsets.UTF_8)) .withKeyPassword("wrong") .withKeyPassword(TestData.PASSWORD) // correct @@ -262,7 +262,7 @@ public class DetachedSignDetachedVerifyTest extends AbstractSOPTest { .toByteArrayAndResult() .getBytes(); - List verificationList = assumeSupported(sop::verify) + List verificationList = sop.verify() .cert(TestData.PASSWORD_PROTECTED_CERT.getBytes(StandardCharsets.UTF_8)) .signatures(signature) .data(message); @@ -279,7 +279,7 @@ public class DetachedSignDetachedVerifyTest extends AbstractSOPTest { byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8); assertThrows(SOPGPException.MissingArg.class, () -> - assumeSupported(sop::verify) + sop.verify() .signatures(TestData.ALICE_DETACHED_SIGNED_MESSAGE.getBytes(StandardCharsets.UTF_8)) .data(message)); } @@ -288,14 +288,14 @@ public class DetachedSignDetachedVerifyTest extends AbstractSOPTest { @MethodSource("provideInstances") public void signVerifyWithMultipleKeys(SOP sop) throws IOException { byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8); - byte[] signatures = assumeSupported(sop::detachedSign) + byte[] signatures = sop.detachedSign() .key(TestData.ALICE_KEY.getBytes(StandardCharsets.UTF_8)) .key(TestData.BOB_KEY.getBytes(StandardCharsets.UTF_8)) .data(message) .toByteArrayAndResult() .getBytes(); - List verificationList = assumeSupported(sop::detachedVerify) + List verificationList = sop.detachedVerify() .cert(TestData.ALICE_CERT.getBytes(StandardCharsets.UTF_8)) .cert(TestData.BOB_CERT.getBytes(StandardCharsets.UTF_8)) .signatures(signatures) diff --git a/sop-java-testfixtures/src/main/java/sop/testsuite/operation/EncryptDecryptTest.java b/sop-java-testfixtures/src/main/java/sop/testsuite/operation/EncryptDecryptTest.java index 937b5b7..df824ca 100644 --- a/sop-java-testfixtures/src/main/java/sop/testsuite/operation/EncryptDecryptTest.java +++ b/sop-java-testfixtures/src/main/java/sop/testsuite/operation/EncryptDecryptTest.java @@ -11,15 +11,12 @@ import org.junit.jupiter.params.provider.MethodSource; import sop.ByteArrayAndResult; import sop.DecryptionResult; import sop.EncryptionResult; -import sop.Profile; import sop.SOP; import sop.SessionKey; import sop.Verification; import sop.enums.EncryptAs; import sop.enums.SignatureMode; import sop.exception.SOPGPException; -import sop.operation.Decrypt; -import sop.operation.Encrypt; import sop.testsuite.TestData; import sop.testsuite.assertions.VerificationListAssert; import sop.util.Optional; @@ -28,7 +25,6 @@ import sop.util.UTCUtil; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.text.ParseException; -import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.stream.Stream; @@ -49,7 +45,7 @@ public class EncryptDecryptTest extends AbstractSOPTest { @MethodSource("provideInstances") public void encryptDecryptRoundTripPasswordTest(SOP sop) throws IOException { byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8); - ByteArrayAndResult encResult = assumeSupported(sop::encrypt) + ByteArrayAndResult encResult = sop.encrypt() .withPassword("sw0rdf1sh") .plaintext(message) .toByteArrayAndResult(); @@ -57,7 +53,7 @@ public class EncryptDecryptTest extends AbstractSOPTest { byte[] ciphertext = encResult.getBytes(); Optional encSessionKey = encResult.getResult().getSessionKey(); - ByteArrayAndResult decResult = assumeSupported(sop::decrypt) + ByteArrayAndResult decResult = sop.decrypt() .withPassword("sw0rdf1sh") .ciphertext(ciphertext) .toByteArrayAndResult(); @@ -65,10 +61,9 @@ public class EncryptDecryptTest extends AbstractSOPTest { byte[] plaintext = decResult.getBytes(); Optional decSessionKey = decResult.getResult().getSessionKey(); - assertArrayEquals(message, plaintext, "Decrypted plaintext does not match original plaintext."); + assertArrayEquals(message, plaintext); if (encSessionKey.isPresent() && decSessionKey.isPresent()) { - assertEquals(encSessionKey.get(), decSessionKey.get(), - "Extracted Session Key mismatch."); + assertEquals(encSessionKey.get(), decSessionKey.get()); } } @@ -76,93 +71,91 @@ public class EncryptDecryptTest extends AbstractSOPTest { @MethodSource("provideInstances") public void encryptDecryptRoundTripAliceTest(SOP sop) throws IOException { byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8); - byte[] ciphertext = assumeSupported(sop::encrypt) + byte[] ciphertext = sop.encrypt() .withCert(TestData.ALICE_CERT.getBytes(StandardCharsets.UTF_8)) .plaintext(message) .toByteArrayAndResult() .getBytes(); - ByteArrayAndResult bytesAndResult = assumeSupported(sop::decrypt) + ByteArrayAndResult bytesAndResult = sop.decrypt() .withKey(TestData.ALICE_KEY.getBytes(StandardCharsets.UTF_8)) .ciphertext(ciphertext) .toByteArrayAndResult(); byte[] plaintext = bytesAndResult.getBytes(); - assertArrayEquals(message, plaintext, "Decrypted plaintext does not match original plaintext."); + assertArrayEquals(message, plaintext); DecryptionResult result = bytesAndResult.getResult(); - if (result.getSessionKey().isPresent()) { - assertNotNull(result.getSessionKey().get(), "Session key MUST NOT be null."); - } + assertNotNull(result.getSessionKey().get()); } @ParameterizedTest @MethodSource("provideInstances") public void encryptDecryptRoundTripBobTest(SOP sop) throws IOException { byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8); - byte[] ciphertext = assumeSupported(sop::encrypt) + byte[] ciphertext = sop.encrypt() .withCert(TestData.BOB_CERT.getBytes(StandardCharsets.UTF_8)) .plaintext(message) .toByteArrayAndResult() .getBytes(); - byte[] plaintext = assumeSupported(sop::decrypt) + byte[] plaintext = sop.decrypt() .withKey(TestData.BOB_KEY.getBytes(StandardCharsets.UTF_8)) .ciphertext(ciphertext) .toByteArrayAndResult() .getBytes(); - assertArrayEquals(message, plaintext, "Decrypted plaintext does not match original plaintext."); + assertArrayEquals(message, plaintext); } @ParameterizedTest @MethodSource("provideInstances") public void encryptDecryptRoundTripCarolTest(SOP sop) throws IOException { byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8); - byte[] ciphertext = assumeSupported(sop::encrypt) + byte[] ciphertext = sop.encrypt() .withCert(TestData.CAROL_CERT.getBytes(StandardCharsets.UTF_8)) .plaintext(message) .toByteArrayAndResult() .getBytes(); - byte[] plaintext = assumeSupported(sop::decrypt) + byte[] plaintext = sop.decrypt() .withKey(TestData.CAROL_KEY.getBytes(StandardCharsets.UTF_8)) .ciphertext(ciphertext) .toByteArrayAndResult() .getBytes(); - assertArrayEquals(message, plaintext, "Decrypted plaintext does not match original plaintext."); + assertArrayEquals(message, plaintext); } @ParameterizedTest @MethodSource("provideInstances") public void encryptNoArmorThenArmorThenDecryptRoundTrip(SOP sop) throws IOException { byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8); - byte[] ciphertext = assumeSupported(sop::encrypt) + byte[] ciphertext = sop.encrypt() .withCert(TestData.ALICE_CERT.getBytes(StandardCharsets.UTF_8)) .noArmor() .plaintext(message) .toByteArrayAndResult() .getBytes(); - byte[] armored = assumeSupported(sop::armor) + byte[] armored = sop.armor() .data(ciphertext) .getBytes(); - ByteArrayAndResult bytesAndResult = assumeSupported(sop::decrypt) + ByteArrayAndResult bytesAndResult = sop.decrypt() .withKey(TestData.ALICE_KEY.getBytes(StandardCharsets.UTF_8)) .ciphertext(armored) .toByteArrayAndResult(); byte[] plaintext = bytesAndResult.getBytes(); - assertArrayEquals(message, plaintext, "Decrypted plaintext does not match original plaintext."); + assertArrayEquals(message, plaintext); } @ParameterizedTest @MethodSource("provideInstances") public void encryptSignDecryptVerifyRoundTripAliceTest(SOP sop) throws IOException { byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8); - byte[] ciphertext = assumeSupported(sop::encrypt) + byte[] ciphertext = sop.encrypt() .withCert(TestData.ALICE_CERT.getBytes(StandardCharsets.UTF_8)) .signWith(TestData.ALICE_KEY.getBytes(StandardCharsets.UTF_8)) .mode(EncryptAs.binary) @@ -170,19 +163,17 @@ public class EncryptDecryptTest extends AbstractSOPTest { .toByteArrayAndResult() .getBytes(); - ByteArrayAndResult bytesAndResult = assumeSupported(sop::decrypt) + ByteArrayAndResult bytesAndResult = sop.decrypt() .withKey(TestData.ALICE_KEY.getBytes(StandardCharsets.UTF_8)) .verifyWithCert(TestData.ALICE_CERT.getBytes(StandardCharsets.UTF_8)) .ciphertext(ciphertext) .toByteArrayAndResult(); byte[] plaintext = bytesAndResult.getBytes(); - assertArrayEquals(message, plaintext, "Decrypted plaintext does not match original plaintext."); + assertArrayEquals(message, plaintext); DecryptionResult result = bytesAndResult.getResult(); - if (result.getSessionKey().isPresent()) { - assertNotNull(result.getSessionKey().get(), "Session key MUST NOT be null."); - } + assertNotNull(result.getSessionKey().get()); List verificationList = result.getVerifications(); VerificationListAssert.assertThatVerificationList(verificationList) @@ -196,7 +187,7 @@ public class EncryptDecryptTest extends AbstractSOPTest { @MethodSource("provideInstances") public void encryptSignAsTextDecryptVerifyRoundTripAliceTest(SOP sop) throws IOException { byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8); - byte[] ciphertext = assumeSupported(sop::encrypt) + byte[] ciphertext = sop.encrypt() .withCert(TestData.ALICE_CERT.getBytes(StandardCharsets.UTF_8)) .signWith(TestData.ALICE_KEY.getBytes(StandardCharsets.UTF_8)) .mode(EncryptAs.text) @@ -204,14 +195,14 @@ public class EncryptDecryptTest extends AbstractSOPTest { .toByteArrayAndResult() .getBytes(); - ByteArrayAndResult bytesAndResult = assumeSupported(sop::decrypt) + ByteArrayAndResult bytesAndResult = sop.decrypt() .withKey(TestData.ALICE_KEY.getBytes(StandardCharsets.UTF_8)) .verifyWithCert(TestData.ALICE_CERT.getBytes(StandardCharsets.UTF_8)) .ciphertext(ciphertext) .toByteArrayAndResult(); byte[] plaintext = bytesAndResult.getBytes(); - assertArrayEquals(message, plaintext, "Decrypted plaintext does not match original plaintext."); + assertArrayEquals(message, plaintext); DecryptionResult result = bytesAndResult.getResult(); assertNotNull(result.getSessionKey().get()); @@ -227,17 +218,17 @@ public class EncryptDecryptTest extends AbstractSOPTest { @MethodSource("provideInstances") public void encryptSignDecryptVerifyRoundTripWithFreshEncryptedKeyTest(SOP sop) throws IOException { byte[] keyPassword = "sw0rdf1sh".getBytes(StandardCharsets.UTF_8); - byte[] key = assumeSupported(sop::generateKey) + byte[] key = sop.generateKey() .withKeyPassword(keyPassword) .userId("Alice ") .generate() .getBytes(); - byte[] cert = assumeSupported(sop::extractCert) + byte[] cert = sop.extractCert() .key(key) .getBytes(); byte[] message = "Hello, World!\n".getBytes(StandardCharsets.UTF_8); - byte[] ciphertext = assumeSupported(sop::encrypt) + byte[] ciphertext = sop.encrypt() .withCert(cert) .signWith(key) .withKeyPassword(keyPassword) @@ -245,7 +236,7 @@ public class EncryptDecryptTest extends AbstractSOPTest { .toByteArrayAndResult() .getBytes(); - ByteArrayAndResult bytesAndResult = assumeSupported(sop::decrypt) + ByteArrayAndResult bytesAndResult = sop.decrypt() .withKey(key) .withKeyPassword(keyPassword) .verifyWithCert(cert) @@ -278,7 +269,7 @@ public class EncryptDecryptTest extends AbstractSOPTest { Date beforeSignature = new Date(signatureDate.getTime() - 1000); // 1 sec before signing date assertThrows(SOPGPException.NoSignature.class, () -> { - ByteArrayAndResult bytesAndResult = assumeSupported(sop::decrypt) + ByteArrayAndResult bytesAndResult = sop.decrypt() .withKey(TestData.ALICE_KEY.getBytes(StandardCharsets.UTF_8)) .verifyWithCert(TestData.ALICE_CERT.getBytes(StandardCharsets.UTF_8)) .verifyNotAfter(beforeSignature) @@ -312,7 +303,7 @@ public class EncryptDecryptTest extends AbstractSOPTest { Date afterSignature = new Date(signatureDate.getTime() + 1000); // 1 sec after signing date assertThrows(SOPGPException.NoSignature.class, () -> { - ByteArrayAndResult bytesAndResult = assumeSupported(sop::decrypt) + ByteArrayAndResult bytesAndResult = sop.decrypt() .withKey(TestData.ALICE_KEY.getBytes(StandardCharsets.UTF_8)) .verifyWithCert(TestData.ALICE_CERT.getBytes(StandardCharsets.UTF_8)) .verifyNotBefore(afterSignature) @@ -331,7 +322,7 @@ public class EncryptDecryptTest extends AbstractSOPTest { public void missingArgsTest(SOP sop) { byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8); - assertThrows(SOPGPException.MissingArg.class, () -> assumeSupported(sop::encrypt) + assertThrows(SOPGPException.MissingArg.class, () -> sop.encrypt() .plaintext(message) .toByteArrayAndResult() .getBytes()); @@ -341,61 +332,10 @@ public class EncryptDecryptTest extends AbstractSOPTest { @MethodSource("provideInstances") public void passingSecretKeysForPublicKeysFails(SOP sop) { assertThrows(SOPGPException.BadData.class, () -> - assumeSupported(sop::encrypt) + sop.encrypt() .withCert(TestData.ALICE_KEY.getBytes(StandardCharsets.UTF_8)) .plaintext(TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8)) .toByteArrayAndResult() .getBytes()); } - - @ParameterizedTest - @MethodSource("provideInstances") - public void encryptDecryptWithAllSupportedKeyGenerationProfiles(SOP sop) throws IOException { - List profiles = assumeSupported(sop::listProfiles).generateKey(); - - List keys = new ArrayList<>(); - List certs = new ArrayList<>(); - for (Profile p : profiles) { - byte[] k = assumeSupported(sop::generateKey) - .profile(p) - .userId(p.getName()) - .generate() - .getBytes(); - keys.add(k); - - byte[] c = assumeSupported(sop::extractCert) - .key(k) - .getBytes(); - certs.add(c); - } - - byte[] plaintext = "Hello, World!\n".getBytes(); - - Encrypt encrypt = assumeSupported(sop::encrypt); - for (byte[] c : certs) { - encrypt.withCert(c); - } - for (byte[] k : keys) { - encrypt.signWith(k); - } - - ByteArrayAndResult encRes = encrypt.plaintext(plaintext) - .toByteArrayAndResult(); - EncryptionResult eResult = encRes.getResult(); - byte[] ciphertext = encRes.getBytes(); - - for (byte[] k : keys) { - Decrypt decrypt = assumeSupported(sop::decrypt) - .withKey(k); - for (byte[] c : certs) { - decrypt.verifyWithCert(c); - } - ByteArrayAndResult decRes = decrypt.ciphertext(ciphertext) - .toByteArrayAndResult(); - DecryptionResult dResult = decRes.getResult(); - byte[] decPlaintext = decRes.getBytes(); - assertArrayEquals(plaintext, decPlaintext, "Decrypted plaintext does not match original plaintext."); - assertEquals(certs.size(), dResult.getVerifications().size()); - } - } } diff --git a/sop-java-testfixtures/src/main/java/sop/testsuite/operation/ExtractCertTest.java b/sop-java-testfixtures/src/main/java/sop/testsuite/operation/ExtractCertTest.java index 94d9927..99acf81 100644 --- a/sop-java-testfixtures/src/main/java/sop/testsuite/operation/ExtractCertTest.java +++ b/sop-java-testfixtures/src/main/java/sop/testsuite/operation/ExtractCertTest.java @@ -28,12 +28,12 @@ public class ExtractCertTest extends AbstractSOPTest { @ParameterizedTest @MethodSource("provideInstances") public void extractArmoredCertFromArmoredKeyTest(SOP sop) throws IOException { - InputStream keyIn = assumeSupported(sop::generateKey) + InputStream keyIn = sop.generateKey() .userId("Alice ") .generate() .getInputStream(); - byte[] cert = assumeSupported(sop::extractCert).key(keyIn).getBytes(); + byte[] cert = sop.extractCert().key(keyIn).getBytes(); JUtils.assertArrayStartsWith(cert, TestData.BEGIN_PGP_PUBLIC_KEY_BLOCK); JUtils.assertArrayEndsWithIgnoreNewlines(cert, TestData.END_PGP_PUBLIC_KEY_BLOCK); } @@ -41,7 +41,7 @@ public class ExtractCertTest extends AbstractSOPTest { @ParameterizedTest @MethodSource("provideInstances") public void extractAliceCertFromAliceKeyTest(SOP sop) throws IOException { - byte[] armoredCert = assumeSupported(sop::extractCert) + byte[] armoredCert = sop.extractCert() .key(TestData.ALICE_KEY.getBytes(StandardCharsets.UTF_8)) .getBytes(); JUtils.assertAsciiArmorEquals(TestData.ALICE_CERT.getBytes(StandardCharsets.UTF_8), armoredCert); @@ -50,7 +50,7 @@ public class ExtractCertTest extends AbstractSOPTest { @ParameterizedTest @MethodSource("provideInstances") public void extractBobsCertFromBobsKeyTest(SOP sop) throws IOException { - byte[] armoredCert = assumeSupported(sop::extractCert) + byte[] armoredCert = sop.extractCert() .key(TestData.BOB_KEY.getBytes(StandardCharsets.UTF_8)) .getBytes(); JUtils.assertAsciiArmorEquals(TestData.BOB_CERT.getBytes(StandardCharsets.UTF_8), armoredCert); @@ -59,7 +59,7 @@ public class ExtractCertTest extends AbstractSOPTest { @ParameterizedTest @MethodSource("provideInstances") public void extractCarolsCertFromCarolsKeyTest(SOP sop) throws IOException { - byte[] armoredCert = assumeSupported(sop::extractCert) + byte[] armoredCert = sop.extractCert() .key(TestData.CAROL_KEY.getBytes(StandardCharsets.UTF_8)) .getBytes(); JUtils.assertAsciiArmorEquals(TestData.CAROL_CERT.getBytes(StandardCharsets.UTF_8), armoredCert); @@ -68,12 +68,12 @@ public class ExtractCertTest extends AbstractSOPTest { @ParameterizedTest @MethodSource("provideInstances") public void extractUnarmoredCertFromArmoredKeyTest(SOP sop) throws IOException { - InputStream keyIn = assumeSupported(sop::generateKey) + InputStream keyIn = sop.generateKey() .userId("Alice ") .generate() .getInputStream(); - byte[] cert = assumeSupported(sop::extractCert) + byte[] cert = sop.extractCert() .noArmor() .key(keyIn) .getBytes(); @@ -84,13 +84,13 @@ public class ExtractCertTest extends AbstractSOPTest { @ParameterizedTest @MethodSource("provideInstances") public void extractArmoredCertFromUnarmoredKeyTest(SOP sop) throws IOException { - InputStream keyIn = assumeSupported(sop::generateKey) + InputStream keyIn = sop.generateKey() .userId("Alice ") .noArmor() .generate() .getInputStream(); - byte[] cert = assumeSupported(sop::extractCert) + byte[] cert = sop.extractCert() .key(keyIn) .getBytes(); @@ -101,13 +101,13 @@ public class ExtractCertTest extends AbstractSOPTest { @ParameterizedTest @MethodSource("provideInstances") public void extractUnarmoredCertFromUnarmoredKeyTest(SOP sop) throws IOException { - InputStream keyIn = assumeSupported(sop::generateKey) + InputStream keyIn = sop.generateKey() .noArmor() .userId("Alice ") .generate() .getInputStream(); - byte[] cert = assumeSupported(sop::extractCert) + byte[] cert = sop.extractCert() .noArmor() .key(keyIn) .getBytes(); diff --git a/sop-java-testfixtures/src/main/java/sop/testsuite/operation/GenerateKeyTest.java b/sop-java-testfixtures/src/main/java/sop/testsuite/operation/GenerateKeyTest.java index 787cf62..4a5da58 100644 --- a/sop-java-testfixtures/src/main/java/sop/testsuite/operation/GenerateKeyTest.java +++ b/sop-java-testfixtures/src/main/java/sop/testsuite/operation/GenerateKeyTest.java @@ -9,7 +9,6 @@ import org.junit.jupiter.api.condition.EnabledIf; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import sop.Profile; import sop.SOP; import sop.exception.SOPGPException; import sop.testsuite.JUtils; @@ -17,11 +16,9 @@ import sop.testsuite.TestData; import java.io.IOException; import java.nio.charset.StandardCharsets; -import java.util.List; import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assumptions.assumeTrue; @EnabledIf("sop.testsuite.operation.AbstractSOPTest#hasBackends") public class GenerateKeyTest extends AbstractSOPTest { @@ -33,7 +30,7 @@ public class GenerateKeyTest extends AbstractSOPTest { @ParameterizedTest @MethodSource("provideInstances") public void generateKeyTest(SOP sop) throws IOException { - byte[] key = assumeSupported(sop::generateKey) + byte[] key = sop.generateKey() .userId("Alice ") .generate() .getBytes(); @@ -45,7 +42,7 @@ public class GenerateKeyTest extends AbstractSOPTest { @ParameterizedTest @MethodSource("provideInstances") public void generateKeyNoArmor(SOP sop) throws IOException { - byte[] key = assumeSupported(sop::generateKey) + byte[] key = sop.generateKey() .userId("Alice ") .noArmor() .generate() @@ -57,7 +54,7 @@ public class GenerateKeyTest extends AbstractSOPTest { @ParameterizedTest @MethodSource("provideInstances") public void generateKeyWithMultipleUserIdsTest(SOP sop) throws IOException { - byte[] key = assumeSupported(sop::generateKey) + byte[] key = sop.generateKey() .userId("Alice ") .userId("Bob ") .generate() @@ -70,7 +67,7 @@ public class GenerateKeyTest extends AbstractSOPTest { @ParameterizedTest @MethodSource("provideInstances") public void generateKeyWithoutUserIdTest(SOP sop) throws IOException { - byte[] key = assumeSupported(sop::generateKey) + byte[] key = sop.generateKey() .generate() .getBytes(); @@ -81,7 +78,7 @@ public class GenerateKeyTest extends AbstractSOPTest { @ParameterizedTest @MethodSource("provideInstances") public void generateKeyWithPasswordTest(SOP sop) throws IOException { - byte[] key = assumeSupported(sop::generateKey) + byte[] key = sop.generateKey() .userId("Alice ") .withKeyPassword("sw0rdf1sh") .generate() @@ -94,7 +91,7 @@ public class GenerateKeyTest extends AbstractSOPTest { @ParameterizedTest @MethodSource("provideInstances") public void generateKeyWithMultipleUserIdsAndPassword(SOP sop) throws IOException { - byte[] key = assumeSupported(sop::generateKey) + byte[] key = sop.generateKey() .userId("Alice ") .userId("Bob ") .withKeyPassword("sw0rdf1sh") @@ -108,45 +105,17 @@ public class GenerateKeyTest extends AbstractSOPTest { @ParameterizedTest @MethodSource("provideInstances") public void generateSigningOnlyKey(SOP sop) throws IOException { - byte[] signingOnlyKey = assumeSupported(sop::generateKey) + byte[] signingOnlyKey = sop.generateKey() .signingOnly() .userId("Alice ") .generate() .getBytes(); - byte[] signingOnlyCert = assumeSupported(sop::extractCert) + byte[] signingOnlyCert = sop.extractCert() .key(signingOnlyKey) .getBytes(); assertThrows(SOPGPException.CertCannotEncrypt.class, () -> - assumeSupported(sop::encrypt).withCert(signingOnlyCert) - .plaintext(TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8)) - .toByteArrayAndResult() - .getBytes()); - } - - @ParameterizedTest - @MethodSource("provideInstances") - public void generateKeyWithSupportedProfiles(SOP sop) throws IOException { - List profiles = assumeSupported(sop::listProfiles) - .generateKey(); - - for (Profile profile : profiles) { - generateKeyWithProfile(sop, profile.getName()); - } - } - - private void generateKeyWithProfile(SOP sop, String profile) throws IOException { - byte[] key; - try { - key = assumeSupported(sop::generateKey) - .profile(profile) - .userId("Alice ") - .generate() - .getBytes(); - } catch (SOPGPException.UnsupportedProfile e) { - key = null; - } - assumeTrue(key != null, "'generate-key' does not support profile '" + profile + "'."); - JUtils.assertArrayStartsWith(key, TestData.BEGIN_PGP_PRIVATE_KEY_BLOCK); + sop.encrypt().withCert(signingOnlyCert) + .plaintext(TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8))); } } diff --git a/sop-java-testfixtures/src/main/java/sop/testsuite/operation/InlineSignInlineDetachDetachedVerifyTest.java b/sop-java-testfixtures/src/main/java/sop/testsuite/operation/InlineSignInlineDetachDetachedVerifyTest.java index ac043b3..3e20a09 100644 --- a/sop-java-testfixtures/src/main/java/sop/testsuite/operation/InlineSignInlineDetachDetachedVerifyTest.java +++ b/sop-java-testfixtures/src/main/java/sop/testsuite/operation/InlineSignInlineDetachDetachedVerifyTest.java @@ -36,12 +36,12 @@ public class InlineSignInlineDetachDetachedVerifyTest extends AbstractSOPTest { public void inlineSignThenDetachThenDetachedVerifyTest(SOP sop) throws IOException { byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8); - byte[] inlineSigned = assumeSupported(sop::inlineSign) + byte[] inlineSigned = sop.inlineSign() .key(TestData.ALICE_KEY.getBytes(StandardCharsets.UTF_8)) .data(message) .getBytes(); - ByteArrayAndResult bytesAndResult = assumeSupported(sop::inlineDetach) + ByteArrayAndResult bytesAndResult = sop.inlineDetach() .message(inlineSigned) .toByteArrayAndResult(); @@ -51,7 +51,7 @@ public class InlineSignInlineDetachDetachedVerifyTest extends AbstractSOPTest { byte[] signatures = bytesAndResult.getResult() .getBytes(); - List verifications = assumeSupported(sop::detachedVerify) + List verifications = sop.detachedVerify() .cert(TestData.ALICE_CERT.getBytes(StandardCharsets.UTF_8)) .signatures(signatures) .data(plaintext); @@ -64,12 +64,12 @@ public class InlineSignInlineDetachDetachedVerifyTest extends AbstractSOPTest { public void inlineSignThenDetachNoArmorThenArmorThenDetachedVerifyTest(SOP sop) throws IOException { byte[] message = "Hello, World!\n".getBytes(StandardCharsets.UTF_8); - byte[] inlineSigned = assumeSupported(sop::inlineSign) + byte[] inlineSigned = sop.inlineSign() .key(TestData.ALICE_KEY.getBytes(StandardCharsets.UTF_8)) .data(message) .getBytes(); - ByteArrayAndResult bytesAndResult = assumeSupported(sop::inlineDetach) + ByteArrayAndResult bytesAndResult = sop.inlineDetach() .noArmor() .message(inlineSigned) .toByteArrayAndResult(); @@ -81,12 +81,12 @@ public class InlineSignInlineDetachDetachedVerifyTest extends AbstractSOPTest { .getBytes(); Assertions.assertFalse(JUtils.arrayStartsWith(signatures, TestData.BEGIN_PGP_SIGNATURE)); - byte[] armored = assumeSupported(sop::armor) + byte[] armored = sop.armor() .data(signatures) .getBytes(); JUtils.assertArrayStartsWith(armored, TestData.BEGIN_PGP_SIGNATURE); - List verifications = assumeSupported(sop::detachedVerify) + List verifications = sop.detachedVerify() .cert(TestData.ALICE_CERT.getBytes(StandardCharsets.UTF_8)) .signatures(armored) .data(plaintext); diff --git a/sop-java-testfixtures/src/main/java/sop/testsuite/operation/InlineSignInlineVerifyTest.java b/sop-java-testfixtures/src/main/java/sop/testsuite/operation/InlineSignInlineVerifyTest.java index d751ee8..39a26c6 100644 --- a/sop-java-testfixtures/src/main/java/sop/testsuite/operation/InlineSignInlineVerifyTest.java +++ b/sop-java-testfixtures/src/main/java/sop/testsuite/operation/InlineSignInlineVerifyTest.java @@ -40,14 +40,14 @@ public class InlineSignInlineVerifyTest extends AbstractSOPTest { public void inlineSignVerifyAlice(SOP sop) throws IOException { byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8); - byte[] inlineSigned = assumeSupported(sop::inlineSign) + byte[] inlineSigned = sop.inlineSign() .key(TestData.ALICE_KEY.getBytes(StandardCharsets.UTF_8)) .data(message) .getBytes(); JUtils.assertArrayStartsWith(inlineSigned, TestData.BEGIN_PGP_MESSAGE); - ByteArrayAndResult> bytesAndResult = assumeSupported(sop::inlineVerify) + ByteArrayAndResult> bytesAndResult = sop.inlineVerify() .cert(TestData.ALICE_CERT.getBytes(StandardCharsets.UTF_8)) .data(inlineSigned) .toByteArrayAndResult(); @@ -66,7 +66,7 @@ public class InlineSignInlineVerifyTest extends AbstractSOPTest { public void inlineSignVerifyAliceNoArmor(SOP sop) throws IOException { byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8); - byte[] inlineSigned = assumeSupported(sop::inlineSign) + byte[] inlineSigned = sop.inlineSign() .key(TestData.ALICE_KEY.getBytes(StandardCharsets.UTF_8)) .noArmor() .data(message) @@ -74,7 +74,7 @@ public class InlineSignInlineVerifyTest extends AbstractSOPTest { Assertions.assertFalse(JUtils.arrayStartsWith(inlineSigned, TestData.BEGIN_PGP_MESSAGE)); - ByteArrayAndResult> bytesAndResult = assumeSupported(sop::inlineVerify) + ByteArrayAndResult> bytesAndResult = sop.inlineVerify() .cert(TestData.ALICE_CERT.getBytes(StandardCharsets.UTF_8)) .data(inlineSigned) .toByteArrayAndResult(); @@ -93,7 +93,7 @@ public class InlineSignInlineVerifyTest extends AbstractSOPTest { public void clearsignVerifyAlice(SOP sop) throws IOException { byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8); - byte[] clearsigned = assumeSupported(sop::inlineSign) + byte[] clearsigned = sop.inlineSign() .key(TestData.ALICE_KEY.getBytes(StandardCharsets.UTF_8)) .mode(InlineSignAs.clearsigned) .data(message) @@ -101,13 +101,12 @@ public class InlineSignInlineVerifyTest extends AbstractSOPTest { JUtils.assertArrayStartsWith(clearsigned, TestData.BEGIN_PGP_SIGNED_MESSAGE); - ByteArrayAndResult> bytesAndResult = assumeSupported(sop::inlineVerify) + ByteArrayAndResult> bytesAndResult = sop.inlineVerify() .cert(TestData.ALICE_CERT.getBytes(StandardCharsets.UTF_8)) .data(clearsigned) .toByteArrayAndResult(); - assertArrayEquals(message, bytesAndResult.getBytes(), - "ASCII armored message does not appear to start with the 'BEGIN PGP SIGNED MESSAGE' header."); + assertArrayEquals(message, bytesAndResult.getBytes()); List verificationList = bytesAndResult.getResult(); VerificationListAssert.assertThatVerificationList(verificationList) @@ -122,7 +121,7 @@ public class InlineSignInlineVerifyTest extends AbstractSOPTest { byte[] message = TestData.ALICE_INLINE_SIGNED_MESSAGE.getBytes(StandardCharsets.UTF_8); Date signatureDate = TestData.ALICE_INLINE_SIGNED_MESSAGE_DATE; - ByteArrayAndResult> bytesAndResult = assumeSupported(sop::inlineVerify) + ByteArrayAndResult> bytesAndResult = sop.inlineVerify() .cert(TestData.ALICE_CERT.getBytes(StandardCharsets.UTF_8)) .data(message) .toByteArrayAndResult(); @@ -142,7 +141,7 @@ public class InlineSignInlineVerifyTest extends AbstractSOPTest { Date signatureDate = TestData.ALICE_INLINE_SIGNED_MESSAGE_DATE; Date afterSignature = new Date(signatureDate.getTime() + 1000); // 1 sec before sig - assertThrows(SOPGPException.NoSignature.class, () -> assumeSupported(sop::inlineVerify) + assertThrows(SOPGPException.NoSignature.class, () -> sop.inlineVerify() .notBefore(afterSignature) .cert(TestData.ALICE_CERT.getBytes(StandardCharsets.UTF_8)) .data(message) @@ -156,7 +155,7 @@ public class InlineSignInlineVerifyTest extends AbstractSOPTest { Date signatureDate = TestData.ALICE_INLINE_SIGNED_MESSAGE_DATE; Date beforeSignature = new Date(signatureDate.getTime() - 1000); // 1 sec before sig - assertThrows(SOPGPException.NoSignature.class, () -> assumeSupported(sop::inlineVerify) + assertThrows(SOPGPException.NoSignature.class, () -> sop.inlineVerify() .notAfter(beforeSignature) .cert(TestData.ALICE_CERT.getBytes(StandardCharsets.UTF_8)) .data(message) @@ -168,14 +167,14 @@ public class InlineSignInlineVerifyTest extends AbstractSOPTest { public void inlineSignVerifyBob(SOP sop) throws IOException { byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8); - byte[] inlineSigned = assumeSupported(sop::inlineSign) + byte[] inlineSigned = sop.inlineSign() .key(TestData.BOB_KEY.getBytes(StandardCharsets.UTF_8)) .data(message) .getBytes(); JUtils.assertArrayStartsWith(inlineSigned, TestData.BEGIN_PGP_MESSAGE); - ByteArrayAndResult> bytesAndResult = assumeSupported(sop::inlineVerify) + ByteArrayAndResult> bytesAndResult = sop.inlineVerify() .cert(TestData.BOB_CERT.getBytes(StandardCharsets.UTF_8)) .data(inlineSigned) .toByteArrayAndResult(); @@ -194,14 +193,14 @@ public class InlineSignInlineVerifyTest extends AbstractSOPTest { public void inlineSignVerifyCarol(SOP sop) throws IOException { byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8); - byte[] inlineSigned = assumeSupported(sop::inlineSign) + byte[] inlineSigned = sop.inlineSign() .key(TestData.CAROL_KEY.getBytes(StandardCharsets.UTF_8)) .data(message) .getBytes(); JUtils.assertArrayStartsWith(inlineSigned, TestData.BEGIN_PGP_MESSAGE); - ByteArrayAndResult> bytesAndResult = assumeSupported(sop::inlineVerify) + ByteArrayAndResult> bytesAndResult = sop.inlineVerify() .cert(TestData.CAROL_CERT.getBytes(StandardCharsets.UTF_8)) .data(inlineSigned) .toByteArrayAndResult(); @@ -220,14 +219,14 @@ public class InlineSignInlineVerifyTest extends AbstractSOPTest { public void inlineSignVerifyProtectedKey(SOP sop) throws IOException { byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8); - byte[] inlineSigned = assumeSupported(sop::inlineSign) + byte[] inlineSigned = sop.inlineSign() .withKeyPassword(TestData.PASSWORD) .key(TestData.PASSWORD_PROTECTED_KEY.getBytes(StandardCharsets.UTF_8)) .mode(InlineSignAs.binary) .data(message) .getBytes(); - ByteArrayAndResult> bytesAndResult = assumeSupported(sop::inlineVerify) + ByteArrayAndResult> bytesAndResult = sop.inlineVerify() .cert(TestData.PASSWORD_PROTECTED_CERT.getBytes(StandardCharsets.UTF_8)) .data(inlineSigned) .toByteArrayAndResult(); diff --git a/sop-java-testfixtures/src/main/java/sop/testsuite/operation/ListProfilesTest.java b/sop-java-testfixtures/src/main/java/sop/testsuite/operation/ListProfilesTest.java index 4faa1b3..6d3c4c4 100644 --- a/sop-java-testfixtures/src/main/java/sop/testsuite/operation/ListProfilesTest.java +++ b/sop-java-testfixtures/src/main/java/sop/testsuite/operation/ListProfilesTest.java @@ -26,7 +26,8 @@ public class ListProfilesTest extends AbstractSOPTest { @ParameterizedTest @MethodSource("provideInstances") public void listGenerateKeyProfiles(SOP sop) { - List profiles = assumeSupported(sop::listProfiles) + List profiles = sop + .listProfiles() .generateKey(); assertFalse(profiles.isEmpty()); @@ -35,7 +36,8 @@ public class ListProfilesTest extends AbstractSOPTest { @ParameterizedTest @MethodSource("provideInstances") public void listEncryptProfiles(SOP sop) { - List profiles = assumeSupported(sop::listProfiles) + List profiles = sop + .listProfiles() .encrypt(); assertFalse(profiles.isEmpty()); @@ -44,7 +46,8 @@ public class ListProfilesTest extends AbstractSOPTest { @ParameterizedTest @MethodSource("provideInstances") public void listUnsupportedProfiles(SOP sop) { - assertThrows(SOPGPException.UnsupportedProfile.class, () -> assumeSupported(sop::listProfiles) + assertThrows(SOPGPException.UnsupportedProfile.class, () -> sop + .listProfiles() .subcommand("invalid")); } } diff --git a/sop-java-testfixtures/src/main/java/sop/testsuite/operation/MergeCertsTest.java b/sop-java-testfixtures/src/main/java/sop/testsuite/operation/MergeCertsTest.java deleted file mode 100644 index 501f53c..0000000 --- a/sop-java-testfixtures/src/main/java/sop/testsuite/operation/MergeCertsTest.java +++ /dev/null @@ -1,164 +0,0 @@ -// SPDX-FileCopyrightText: 2025 Paul Schaub -// -// SPDX-License-Identifier: Apache-2.0 - -package sop.testsuite.operation; - -import kotlin.collections.ArraysKt; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; -import sop.SOP; - -import java.io.IOException; -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.assertArrayEquals; - -public class MergeCertsTest extends AbstractSOPTest { - - static Stream provideInstances() { - return provideBackends(); - } - - @ParameterizedTest - @MethodSource("provideInstances") - public void testMergeWithItself(SOP sop) throws IOException { - byte[] key = assumeSupported(sop::generateKey) - .userId("Alice ") - .generate() - .getBytes(); - - byte[] cert = assumeSupported(sop::extractCert) - .key(key) - .getBytes(); - - byte[] merged = assumeSupported(sop::mergeCerts) - .updates(cert) - .baseCertificates(cert) - .getBytes(); - - assertArrayEquals(cert, merged); - } - - @ParameterizedTest - @MethodSource("provideInstances") - public void testMergeWithItselfArmored(SOP sop) throws IOException { - byte[] key = assumeSupported(sop::generateKey) - .noArmor() - .userId("Alice ") - .generate() - .getBytes(); - - byte[] cert = assumeSupported(sop::extractCert) - .key(key) - .getBytes(); - - byte[] merged = assumeSupported(sop::mergeCerts) - .updates(cert) - .baseCertificates(cert) - .getBytes(); - - assertArrayEquals(cert, merged); - } - - @ParameterizedTest - @MethodSource("provideInstances") - public void testMergeWithItselfViaBase(SOP sop) throws IOException { - byte[] key = assumeSupported(sop::generateKey) - .userId("Alice ") - .generate() - .getBytes(); - - byte[] cert = assumeSupported(sop::extractCert) - .key(key) - .getBytes(); - - byte[] certs = ArraysKt.plus(cert, cert); - - byte[] merged = assumeSupported(sop::mergeCerts) - .updates(cert) - .baseCertificates(certs) - .getBytes(); - - assertArrayEquals(cert, merged); - } - - @ParameterizedTest - @MethodSource("provideInstances") - public void testApplyBaseToUpdate(SOP sop) throws IOException { - byte[] key = assumeSupported(sop::generateKey) - .userId("Alice ") - .generate() - .getBytes(); - - byte[] cert = assumeSupported(sop::extractCert) - .key(key) - .getBytes(); - - byte[] update = assumeSupported(sop::revokeKey) - .keys(key) - .getBytes(); - - byte[] merged = assumeSupported(sop::mergeCerts) - .updates(cert) - .baseCertificates(update) - .getBytes(); - - assertArrayEquals(update, merged); - } - - @ParameterizedTest - @MethodSource("provideInstances") - public void testApplyUpdateToBase(SOP sop) throws IOException { - byte[] key = assumeSupported(sop::generateKey) - .userId("Alice ") - .generate() - .getBytes(); - - byte[] cert = assumeSupported(sop::extractCert) - .key(key) - .getBytes(); - - byte[] update = assumeSupported(sop::revokeKey) - .keys(key) - .getBytes(); - - byte[] merged = assumeSupported(sop::mergeCerts) - .updates(update) - .baseCertificates(cert) - .getBytes(); - - assertArrayEquals(update, merged); - } - - @ParameterizedTest - @MethodSource("provideInstances") - public void testApplyUpdateToMissingBaseDoesNothing(SOP sop) throws IOException { - byte[] aliceKey = assumeSupported(sop::generateKey) - .userId("Alice ") - .generate() - .getBytes(); - - byte[] aliceCert = assumeSupported(sop::extractCert) - .key(aliceKey) - .getBytes(); - - byte[] bobKey = assumeSupported(sop::generateKey) - .userId("Bob ") - .generate() - .getBytes(); - - byte[] bobCert = assumeSupported(sop::extractCert) - .key(bobKey) - .getBytes(); - - byte[] merged = assumeSupported(sop::mergeCerts) - .updates(bobCert) - .baseCertificates(aliceCert) - .getBytes(); - - assertArrayEquals(aliceCert, merged); - } - -} diff --git a/sop-java-testfixtures/src/main/java/sop/testsuite/operation/RevokeKeyTest.java b/sop-java-testfixtures/src/main/java/sop/testsuite/operation/RevokeKeyTest.java index 1880d58..cb51332 100644 --- a/sop-java-testfixtures/src/main/java/sop/testsuite/operation/RevokeKeyTest.java +++ b/sop-java-testfixtures/src/main/java/sop/testsuite/operation/RevokeKeyTest.java @@ -36,8 +36,8 @@ public class RevokeKeyTest extends AbstractSOPTest { @ParameterizedTest @MethodSource("provideInstances") public void revokeUnprotectedKey(SOP sop) throws IOException { - byte[] secretKey = assumeSupported(sop::generateKey).userId("Alice ").generate().getBytes(); - byte[] revocation = assumeSupported(sop::revokeKey).keys(secretKey).getBytes(); + byte[] secretKey = sop.generateKey().userId("Alice ").generate().getBytes(); + byte[] revocation = sop.revokeKey().keys(secretKey).getBytes(); assertTrue(JUtils.arrayStartsWith(revocation, TestData.BEGIN_PGP_PUBLIC_KEY_BLOCK)); assertFalse(Arrays.equals(secretKey, revocation)); @@ -46,8 +46,8 @@ public class RevokeKeyTest extends AbstractSOPTest { @ParameterizedTest @MethodSource("provideInstances") public void revokeUnprotectedKeyNoArmor(SOP sop) throws IOException { - byte[] secretKey = assumeSupported(sop::generateKey).userId("Alice ").generate().getBytes(); - byte[] revocation = assumeSupported(sop::revokeKey).noArmor().keys(secretKey).getBytes(); + byte[] secretKey = sop.generateKey().userId("Alice ").generate().getBytes(); + byte[] revocation = sop.revokeKey().noArmor().keys(secretKey).getBytes(); assertFalse(JUtils.arrayStartsWith(revocation, TestData.BEGIN_PGP_PUBLIC_KEY_BLOCK)); } @@ -55,8 +55,8 @@ public class RevokeKeyTest extends AbstractSOPTest { @ParameterizedTest @MethodSource("provideInstances") public void revokeUnprotectedKeyUnarmored(SOP sop) throws IOException { - byte[] secretKey = assumeSupported(sop::generateKey).userId("Alice ").noArmor().generate().getBytes(); - byte[] revocation = assumeSupported(sop::revokeKey).noArmor().keys(secretKey).getBytes(); + byte[] secretKey = sop.generateKey().userId("Alice ").noArmor().generate().getBytes(); + byte[] revocation = sop.revokeKey().noArmor().keys(secretKey).getBytes(); assertFalse(JUtils.arrayStartsWith(revocation, TestData.BEGIN_PGP_PUBLIC_KEY_BLOCK)); assertFalse(Arrays.equals(secretKey, revocation)); @@ -65,18 +65,18 @@ public class RevokeKeyTest extends AbstractSOPTest { @ParameterizedTest @MethodSource("provideInstances") public void revokeCertificateFails(SOP sop) throws IOException { - byte[] secretKey = assumeSupported(sop::generateKey).generate().getBytes(); - byte[] certificate = assumeSupported(sop::extractCert).key(secretKey).getBytes(); + byte[] secretKey = sop.generateKey().generate().getBytes(); + byte[] certificate = sop.extractCert().key(secretKey).getBytes(); - assertThrows(SOPGPException.BadData.class, () -> assumeSupported(sop::revokeKey).keys(certificate).getBytes()); + assertThrows(SOPGPException.BadData.class, () -> sop.revokeKey().keys(certificate).getBytes()); } @ParameterizedTest @MethodSource("provideInstances") public void revokeProtectedKey(SOP sop) throws IOException { byte[] password = "sw0rdf1sh".getBytes(UTF8Util.UTF8); - byte[] secretKey = assumeSupported(sop::generateKey).withKeyPassword(password).userId("Alice ").generate().getBytes(); - byte[] revocation = assumeSupported(sop::revokeKey).withKeyPassword(password).keys(secretKey).getBytes(); + byte[] secretKey = sop.generateKey().withKeyPassword(password).userId("Alice ").generate().getBytes(); + byte[] revocation = sop.revokeKey().withKeyPassword(password).keys(secretKey).getBytes(); assertFalse(Arrays.equals(secretKey, revocation)); } @@ -86,8 +86,8 @@ public class RevokeKeyTest extends AbstractSOPTest { public void revokeProtectedKeyWithMultiplePasswordOptions(SOP sop) throws IOException { byte[] password = "sw0rdf1sh".getBytes(UTF8Util.UTF8); byte[] wrongPassword = "0r4ng3".getBytes(UTF8Util.UTF8); - byte[] secretKey = assumeSupported(sop::generateKey).withKeyPassword(password).userId("Alice ").generate().getBytes(); - byte[] revocation = assumeSupported(sop::revokeKey).withKeyPassword(wrongPassword).withKeyPassword(password).keys(secretKey).getBytes(); + byte[] secretKey = sop.generateKey().withKeyPassword(password).userId("Alice ").generate().getBytes(); + byte[] revocation = sop.revokeKey().withKeyPassword(wrongPassword).withKeyPassword(password).keys(secretKey).getBytes(); assertFalse(Arrays.equals(secretKey, revocation)); } @@ -96,9 +96,9 @@ public class RevokeKeyTest extends AbstractSOPTest { @MethodSource("provideInstances") public void revokeProtectedKeyWithMissingPassphraseFails(SOP sop) throws IOException { byte[] password = "sw0rdf1sh".getBytes(UTF8Util.UTF8); - byte[] secretKey = assumeSupported(sop::generateKey).withKeyPassword(password).userId("Alice ").generate().getBytes(); + byte[] secretKey = sop.generateKey().withKeyPassword(password).userId("Alice ").generate().getBytes(); - assertThrows(SOPGPException.KeyIsProtected.class, () -> assumeSupported(sop::revokeKey).keys(secretKey).getBytes()); + assertThrows(SOPGPException.KeyIsProtected.class, () -> sop.revokeKey().keys(secretKey).getBytes()); } @ParameterizedTest @@ -106,27 +106,27 @@ public class RevokeKeyTest extends AbstractSOPTest { public void revokeProtectedKeyWithWrongPassphraseFails(SOP sop) throws IOException { byte[] password = "sw0rdf1sh".getBytes(UTF8Util.UTF8); String wrongPassword = "or4ng3"; - byte[] secretKey = assumeSupported(sop::generateKey).withKeyPassword(password).userId("Alice ").generate().getBytes(); + byte[] secretKey = sop.generateKey().withKeyPassword(password).userId("Alice ").generate().getBytes(); - assertThrows(SOPGPException.KeyIsProtected.class, () -> assumeSupported(sop::revokeKey).withKeyPassword(wrongPassword).keys(secretKey).getBytes()); + assertThrows(SOPGPException.KeyIsProtected.class, () -> sop.revokeKey().withKeyPassword(wrongPassword).keys(secretKey).getBytes()); } @ParameterizedTest @MethodSource("provideInstances") public void revokeKeyIsNowHardRevoked(SOP sop) throws IOException { - byte[] key = assumeSupported(sop::generateKey).generate().getBytes(); - byte[] cert = assumeSupported(sop::extractCert).key(key).getBytes(); + byte[] key = sop.generateKey().generate().getBytes(); + byte[] cert = sop.extractCert().key(key).getBytes(); // Sign a message with the key byte[] msg = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8); - byte[] signedMsg = assumeSupported(sop::inlineSign).key(key).data(msg).getBytes(); + byte[] signedMsg = sop.inlineSign().key(key).data(msg).getBytes(); // Verifying the message with the valid cert works - List result = assumeSupported(sop::inlineVerify).cert(cert).data(signedMsg).toByteArrayAndResult().getResult(); + List result = sop.inlineVerify().cert(cert).data(signedMsg).toByteArrayAndResult().getResult(); VerificationListAssert.assertThatVerificationList(result).hasSingleItem(); // Now hard revoke the key and re-check signature, expecting no valid certification - byte[] revokedCert = assumeSupported(sop::revokeKey).keys(key).getBytes(); - assertThrows(SOPGPException.NoSignature.class, () -> assumeSupported(sop::inlineVerify).cert(revokedCert).data(signedMsg).toByteArrayAndResult()); + byte[] revokedCert = sop.revokeKey().keys(key).getBytes(); + assertThrows(SOPGPException.NoSignature.class, () -> sop.inlineVerify().cert(revokedCert).data(signedMsg).toByteArrayAndResult()); } } diff --git a/sop-java-testfixtures/src/main/java/sop/testsuite/operation/VersionTest.java b/sop-java-testfixtures/src/main/java/sop/testsuite/operation/VersionTest.java index 71f7efd..f836935 100644 --- a/sop-java-testfixtures/src/main/java/sop/testsuite/operation/VersionTest.java +++ b/sop-java-testfixtures/src/main/java/sop/testsuite/operation/VersionTest.java @@ -28,7 +28,7 @@ public class VersionTest extends AbstractSOPTest { @ParameterizedTest @MethodSource("provideInstances") public void versionNameTest(SOP sop) { - String name = assumeSupported(sop::version).getName(); + String name = sop.version().getName(); assertNotNull(name); assertFalse(name.isEmpty()); } @@ -36,21 +36,21 @@ public class VersionTest extends AbstractSOPTest { @ParameterizedTest @MethodSource("provideInstances") public void versionVersionTest(SOP sop) { - String version = assumeSupported(sop::version).getVersion(); + String version = sop.version().getVersion(); assertFalse(version.isEmpty()); } @ParameterizedTest @MethodSource("provideInstances") public void backendVersionTest(SOP sop) { - String backend = assumeSupported(sop::version).getBackendVersion(); + String backend = sop.version().getBackendVersion(); assertFalse(backend.isEmpty()); } @ParameterizedTest @MethodSource("provideInstances") public void extendedVersionTest(SOP sop) { - String extended = assumeSupported(sop::version).getExtendedVersion(); + String extended = sop.version().getExtendedVersion(); assertFalse(extended.isEmpty()); } @@ -58,27 +58,27 @@ public class VersionTest extends AbstractSOPTest { @MethodSource("provideInstances") public void sopSpecVersionTest(SOP sop) { try { - assumeSupported(sop::version).getSopSpecVersion(); + sop.version().getSopSpecVersion(); } catch (RuntimeException e) { throw new TestAbortedException("SOP backend does not support 'version --sop-spec' yet."); } - String sopSpec = assumeSupported(sop::version).getSopSpecVersion(); - if (assumeSupported(sop::version).isSopSpecImplementationIncomplete()) { + String sopSpec = sop.version().getSopSpecVersion(); + if (sop.version().isSopSpecImplementationIncomplete()) { assertTrue(sopSpec.startsWith("~draft-dkg-openpgp-stateless-cli-")); } else { assertTrue(sopSpec.startsWith("draft-dkg-openpgp-stateless-cli-")); } - int sopRevision = assumeSupported(sop::version).getSopSpecRevisionNumber(); - assertTrue(assumeSupported(sop::version).getSopSpecRevisionName().endsWith("" + sopRevision)); + int sopRevision = sop.version().getSopSpecRevisionNumber(); + assertTrue(sop.version().getSopSpecRevisionName().endsWith("" + sopRevision)); } @ParameterizedTest @MethodSource("provideInstances") public void sopVVersionTest(SOP sop) { try { - assumeSupported(sop::version).getSopVVersion(); + sop.version().getSopVVersion(); } catch (SOPGPException.UnsupportedOption e) { throw new TestAbortedException( "Implementation does (gracefully) not provide coverage for any sopv interface version."); @@ -86,10 +86,4 @@ public class VersionTest extends AbstractSOPTest { throw new TestAbortedException("Implementation does not provide coverage for any sopv interface version."); } } - - @ParameterizedTest - @MethodSource("provideInstances") - public void sopJavaVersionTest(SOP sop) { - assertNotNull(assumeSupported(sop::version).getSopJavaVersion()); - } } diff --git a/sop-java-testfixtures/src/main/kotlin/sop/testsuite/AbortOnUnsupportedOption.kt b/sop-java-testfixtures/src/main/kotlin/sop/testsuite/AbortOnUnsupportedOption.kt new file mode 100644 index 0000000..cf99671 --- /dev/null +++ b/sop-java-testfixtures/src/main/kotlin/sop/testsuite/AbortOnUnsupportedOption.kt @@ -0,0 +1,12 @@ +// SPDX-FileCopyrightText: 2024 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package sop.testsuite + +import java.lang.annotation.Inherited + +@Target(AnnotationTarget.TYPE) +@Retention(AnnotationRetention.RUNTIME) +@Inherited +annotation class AbortOnUnsupportedOption diff --git a/sop-java-testfixtures/src/main/kotlin/sop/testsuite/AbortOnUnsupportedOptionExtension.kt b/sop-java-testfixtures/src/main/kotlin/sop/testsuite/AbortOnUnsupportedOptionExtension.kt new file mode 100644 index 0000000..809c78f --- /dev/null +++ b/sop-java-testfixtures/src/main/kotlin/sop/testsuite/AbortOnUnsupportedOptionExtension.kt @@ -0,0 +1,21 @@ +// SPDX-FileCopyrightText: 2024 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package sop.testsuite + +import org.junit.jupiter.api.Assumptions +import org.junit.jupiter.api.extension.ExtensionContext +import org.junit.jupiter.api.extension.TestExecutionExceptionHandler +import sop.exception.SOPGPException + +class AbortOnUnsupportedOptionExtension : TestExecutionExceptionHandler { + override fun handleTestExecutionException(context: ExtensionContext, throwable: Throwable) { + val testClass = context.requiredTestClass + val annotation = testClass.getAnnotation(AbortOnUnsupportedOption::class.java) + if (annotation != null && SOPGPException.UnsupportedOption::class.isInstance(throwable)) { + Assumptions.assumeTrue(false, "Test aborted due to: " + throwable.message) + } + throw throwable + } +} diff --git a/sop-java/src/main/kotlin/sop/Profile.kt b/sop-java/src/main/kotlin/sop/Profile.kt index fd58c63..2125c57 100644 --- a/sop-java/src/main/kotlin/sop/Profile.kt +++ b/sop-java/src/main/kotlin/sop/Profile.kt @@ -20,22 +20,17 @@ import sop.util.UTF8Util * in the IETF namespace that begins with the string `draft-` should have semantics that hew as * closely as possible to the referenced Internet Draft. * @param description a free-form description of the profile. - * @param aliases list of optional profile alias names - * @see - * [SOP Spec - Profile](https://www.ietf.org/archive/id/draft-dkg-openpgp-stateless-cli-05.html#name-profile) + * @see + * SOP Spec - Profile */ -data class Profile( - val name: String, - val description: Optional, - val aliases: List = listOf() -) { +data class Profile(val name: String, val description: Optional) { @JvmOverloads constructor( name: String, - description: String? = null, - aliases: List = listOf() - ) : this(name, Optional.ofNullable(description?.trim()?.ifBlank { null }), aliases) + description: String? = null + ) : this(name, Optional.ofNullable(description?.trim()?.ifBlank { null })) init { require(name.trim().isNotBlank()) { "Name cannot be empty." } @@ -50,33 +45,13 @@ data class Profile( fun hasDescription() = description.isPresent - /** - * Return a copy of this [Profile] with the aliases set to the given strings. - * - * @param alias one or more alias names - * @return profile with aliases - */ - fun withAliases(vararg alias: String): Profile { - return Profile(name, description, alias.toList()) - } - /** * Convert the profile into a String for displaying. * * @return string */ - override fun toString(): String = buildString { - append(name) - if (!description.isEmpty || !aliases.isEmpty()) { - append(":") - } - if (!description.isEmpty) { - append(" ${description.get()}") - } - if (!aliases.isEmpty()) { - append(" (aliases: ${aliases.joinToString(separator = ", ")})") - } - } + override fun toString(): String = + if (description.isEmpty) name else "$name: ${description.get()}" companion object { @@ -89,21 +64,9 @@ data class Profile( @JvmStatic fun parse(string: String): Profile { return if (string.contains(": ")) { - val name = string.substring(0, string.indexOf(": ")) - var description = string.substring(string.indexOf(": ") + 2).trim() - if (description.contains("(aliases: ")) { - val aliases = - description.substring( - description.indexOf("(aliases: ") + 10, description.indexOf(")")) - description = description.substring(0, description.indexOf("(aliases: ")).trim() - Profile(name, description, aliases.split(", ").toList()) - } else { - if (description.isNotBlank()) { - Profile(name, description) - } else { - Profile(name) - } - } + Profile( + string.substring(0, string.indexOf(": ")), + string.substring(string.indexOf(": ") + 2).trim()) } else if (string.endsWith(":")) { Profile(string.substring(0, string.length - 1)) } else { diff --git a/sop-java/src/main/kotlin/sop/SOP.kt b/sop-java/src/main/kotlin/sop/SOP.kt index a942c56..7fdd414 100644 --- a/sop-java/src/main/kotlin/sop/SOP.kt +++ b/sop-java/src/main/kotlin/sop/SOP.kt @@ -4,7 +4,18 @@ package sop -import sop.operation.* +import sop.operation.Armor +import sop.operation.ChangeKeyPassword +import sop.operation.Dearmor +import sop.operation.Decrypt +import sop.operation.DetachedSign +import sop.operation.Encrypt +import sop.operation.ExtractCert +import sop.operation.GenerateKey +import sop.operation.InlineDetach +import sop.operation.InlineSign +import sop.operation.ListProfiles +import sop.operation.RevokeKey /** * Stateless OpenPGP Interface. This class provides a stateless interface to various OpenPGP related @@ -15,57 +26,48 @@ import sop.operation.* interface SOP : SOPV { /** Generate a secret key. */ - fun generateKey(): GenerateKey? + fun generateKey(): GenerateKey /** Extract a certificate (public key) from a secret key. */ - fun extractCert(): ExtractCert? + fun extractCert(): ExtractCert /** * Create detached signatures. If you want to sign a message inline, use [inlineSign] instead. */ - fun sign(): DetachedSign? = detachedSign() + fun sign(): DetachedSign = detachedSign() /** * Create detached signatures. If you want to sign a message inline, use [inlineSign] instead. */ - fun detachedSign(): DetachedSign? + fun detachedSign(): DetachedSign /** * Sign a message using inline signatures. If you need to create detached signatures, use * [detachedSign] instead. */ - fun inlineSign(): InlineSign? + fun inlineSign(): InlineSign /** Detach signatures from an inline signed message. */ - fun inlineDetach(): InlineDetach? + fun inlineDetach(): InlineDetach /** Encrypt a message. */ - fun encrypt(): Encrypt? + fun encrypt(): Encrypt /** Decrypt a message. */ - fun decrypt(): Decrypt? + fun decrypt(): Decrypt /** Convert binary OpenPGP data to ASCII. */ - fun armor(): Armor? + fun armor(): Armor /** Converts ASCII armored OpenPGP data to binary. */ - fun dearmor(): Dearmor? + fun dearmor(): Dearmor /** List supported [Profiles][Profile] of a subcommand. */ - fun listProfiles(): ListProfiles? + fun listProfiles(): ListProfiles /** Revoke one or more secret keys. */ - fun revokeKey(): RevokeKey? + fun revokeKey(): RevokeKey /** Update a key's password. */ - fun changeKeyPassword(): ChangeKeyPassword? - - /** Keep a secret key up-to-date. */ - fun updateKey(): UpdateKey? - - /** Merge OpenPGP certificates. */ - fun mergeCerts(): MergeCerts? - - /** Certify OpenPGP Certificate User-IDs. */ - fun certifyUserId(): CertifyUserId? + fun changeKeyPassword(): ChangeKeyPassword } diff --git a/sop-java/src/main/kotlin/sop/SOPV.kt b/sop-java/src/main/kotlin/sop/SOPV.kt index d483194..d331559 100644 --- a/sop-java/src/main/kotlin/sop/SOPV.kt +++ b/sop-java/src/main/kotlin/sop/SOPV.kt @@ -6,47 +6,29 @@ package sop import sop.operation.DetachedVerify import sop.operation.InlineVerify -import sop.operation.ValidateUserId import sop.operation.Version /** Subset of [SOP] implementing only OpenPGP signature verification. */ interface SOPV { - /** - * Get information about the implementations name and version. - * - * @since sopv 1.0 - */ - fun version(): Version? + /** Get information about the implementations name and version. */ + fun version(): Version /** * Verify detached signatures. If you need to verify an inline-signed message, use * [inlineVerify] instead. - * - * @since sopv 1.0 */ - fun verify(): DetachedVerify? = detachedVerify() + fun verify(): DetachedVerify = detachedVerify() /** * Verify detached signatures. If you need to verify an inline-signed message, use * [inlineVerify] instead. - * - * @since sopv 1.0 */ - fun detachedVerify(): DetachedVerify? + fun detachedVerify(): DetachedVerify /** * Verify signatures of an inline-signed message. If you need to verify detached signatures over * a message, use [detachedVerify] instead. - * - * @since sopv 1.0 */ - fun inlineVerify(): InlineVerify? - - /** - * Validate a UserID in an OpenPGP certificate. - * - * @since sopv 1.2 - */ - fun validateUserId(): ValidateUserId? + fun inlineVerify(): InlineVerify } diff --git a/sop-java/src/main/kotlin/sop/SigningResult.kt b/sop-java/src/main/kotlin/sop/SigningResult.kt index 651f8c1..29304ea 100644 --- a/sop-java/src/main/kotlin/sop/SigningResult.kt +++ b/sop-java/src/main/kotlin/sop/SigningResult.kt @@ -9,10 +9,8 @@ package sop * * @param micAlg string identifying the digest mechanism used to create the signed message. This is * useful for setting the `micalg=` parameter for the multipart/signed content-type of a PGP/MIME - * object as described in section 5 of - * [RFC3156](https://www.rfc-editor.org/rfc/rfc3156#section-5). If more than one signature was - * generated and different digest mechanisms were used, the value of the micalg object is an empty - * string. + * object as described in section 5 of [RFC3156]. If more than one signature was generated and + * different digest mechanisms were used, the value of the micalg object is an empty string. */ data class SigningResult(val micAlg: MicAlg) { diff --git a/sop-java/src/main/kotlin/sop/Verification.kt b/sop-java/src/main/kotlin/sop/Verification.kt index 982e691..20401a9 100644 --- a/sop-java/src/main/kotlin/sop/Verification.kt +++ b/sop-java/src/main/kotlin/sop/Verification.kt @@ -10,23 +10,13 @@ import sop.enums.SignatureMode import sop.util.Optional import sop.util.UTCUtil -/** - * Metadata about a verified signature. - * - * @param creationTime creation time of the signature - * @param signingKeyFingerprint fingerprint of the (sub-)key that issued the signature - * @param signingCertFingerprint fingerprint of the certificate that contains the signing key - * @param signatureMode optional signature mode (text/binary) - * @param jsonOrDescription arbitrary text or JSON data - */ data class Verification( val creationTime: Date, val signingKeyFingerprint: String, val signingCertFingerprint: String, val signatureMode: Optional, - val jsonOrDescription: Optional + val description: Optional ) { - @JvmOverloads constructor( creationTime: Date, @@ -41,49 +31,10 @@ data class Verification( Optional.ofNullable(signatureMode), Optional.ofNullable(description?.trim())) - @JvmOverloads - constructor( - creationTime: Date, - signingKeyFingerprint: String, - signingCertFingerprint: String, - signatureMode: SignatureMode? = null, - json: JSON, - jsonSerializer: JSONSerializer - ) : this( - creationTime, - signingKeyFingerprint, - signingCertFingerprint, - Optional.ofNullable(signatureMode), - Optional.of(jsonSerializer.serialize(json))) - - @Deprecated("Replaced by jsonOrDescription", replaceWith = ReplaceWith("jsonOrDescription")) - val description = jsonOrDescription - - /** This value is `true` if the [Verification] contains extension JSON. */ - val containsJson: Boolean = - jsonOrDescription.get()?.trim()?.let { it.startsWith("{") && it.endsWith("}") } ?: false - - /** - * Attempt to parse the [jsonOrDescription] field using the provided [JSONParser] and return the - * result. This method returns `null` if parsing fails. - * - * @param parser [JSONParser] implementation - * @return successfully parsed [JSON] POJO or `null`. - */ - fun getJson(parser: JSONParser): JSON? { - return jsonOrDescription.get()?.let { - try { - parser.parse(it) - } catch (e: ParseException) { - null - } - } - } - override fun toString(): String = "${UTCUtil.formatUTCDate(creationTime)} $signingKeyFingerprint $signingCertFingerprint" + (if (signatureMode.isPresent) " mode:${signatureMode.get()}" else "") + - (if (jsonOrDescription.isPresent) " ${jsonOrDescription.get()}" else "") + (if (description.isPresent) " ${description.get()}" else "") companion object { @JvmStatic @@ -122,50 +73,4 @@ data class Verification( } } } - - /** - * POJO data class representing JSON metadata. - * - * @param signers list of supplied CERTS objects that could have issued the signature, - * identified by the name given on the command line. - * @param comment a freeform UTF-8 encoded text describing the verification - * @param ext an extension object containing arbitrary, implementation-specific data - */ - data class JSON(val signers: List, val comment: String?, val ext: Any?) { - - /** Create a JSON object with only a list of signers. */ - constructor(signers: List) : this(signers, null, null) - - /** Create a JSON object with only a single signer. */ - constructor(signer: String) : this(listOf(signer)) - } - - /** Interface abstracting a JSON parser that parses [JSON] POJOs from single-line strings. */ - fun interface JSONParser { - /** - * Parse a [JSON] POJO from the given single-line [string]. If the string does not represent - * a JSON object matching the [JSON] definition, this method throws a [ParseException]. - * - * @param string [String] representation of the [JSON] object. - * @return parsed [JSON] POJO - * @throws ParseException if the [string] is not a JSON string representing the [JSON] - * object. - */ - @Throws(ParseException::class) fun parse(string: String): JSON - } - - /** - * Interface abstracting a JSON serializer that converts [JSON] POJOs into single-line JSON - * strings. - */ - fun interface JSONSerializer { - - /** - * Serialize the given [JSON] object into a single-line JSON string. - * - * @param json JSON POJO - * @return JSON string - */ - fun serialize(json: JSON): String - } } diff --git a/sop-java/src/main/kotlin/sop/exception/SOPGPException.kt b/sop-java/src/main/kotlin/sop/exception/SOPGPException.kt index 9df1628..bc9131f 100644 --- a/sop-java/src/main/kotlin/sop/exception/SOPGPException.kt +++ b/sop-java/src/main/kotlin/sop/exception/SOPGPException.kt @@ -16,22 +16,6 @@ abstract class SOPGPException : RuntimeException { abstract fun getExitCode(): Int - /** An otherwise unspecified failure occurred */ - class UnspecificFailure : SOPGPException { - - constructor(message: String) : super(message) - - constructor(message: String, e: Throwable) : super(message, e) - - constructor(e: Throwable) : super(e) - - override fun getExitCode(): Int = EXIT_CODE - - companion object { - const val EXIT_CODE = 1 - } - } - /** No acceptable signatures found (sop verify, inline-verify). */ class NoSignature : SOPGPException { @JvmOverloads @@ -353,64 +337,4 @@ abstract class SOPGPException : RuntimeException { const val EXIT_CODE = 101 } } - - /** The primary key of a KEYS object is too weak or revoked. */ - class PrimaryKeyBad : SOPGPException { - constructor() : super() - - constructor(errorMsg: String) : super(errorMsg) - - override fun getExitCode(): Int = EXIT_CODE - - companion object { - const val EXIT_CODE = 103 - } - } - - /** The CERTS object has no matching User ID. */ - class CertUserIdNoMatch : SOPGPException { - - val fingerprint: ByteArray? - - constructor() : super() { - fingerprint = null - } - - constructor(fingerprint: ByteArray) : super() { - this.fingerprint = fingerprint - } - - constructor(errorMsg: String) : super(errorMsg) { - fingerprint = null - } - - constructor(errorMsg: String, cause: Throwable) : super(errorMsg, cause) { - fingerprint = null - } - - override fun getExitCode(): Int = EXIT_CODE - - companion object { - const val EXIT_CODE = 107 - } - } - - /** - * Key not certification-capable (e.g., expired, revoked, unacceptable usage flags) (sop - * certify-userid) - */ - class KeyCannotCertify : SOPGPException { - - constructor(message: String) : super(message) - - constructor(message: String, e: Throwable) : super(message, e) - - constructor(e: Throwable) : super(e) - - override fun getExitCode(): Int = EXIT_CODE - - companion object { - const val EXIT_CODE = 109 - } - } } diff --git a/sop-java/src/main/kotlin/sop/operation/AbstractSign.kt b/sop-java/src/main/kotlin/sop/operation/AbstractSign.kt index 72b8f72..0258432 100644 --- a/sop-java/src/main/kotlin/sop/operation/AbstractSign.kt +++ b/sop-java/src/main/kotlin/sop/operation/AbstractSign.kt @@ -61,18 +61,9 @@ interface AbstractSign { * @param password password * @return builder instance * @throws UnsupportedOption if key passwords are not supported + * @throws PasswordNotHumanReadable if the provided passphrase is not human-readable */ - @Throws(UnsupportedOption::class) - fun withKeyPassword(password: CharArray): T = withKeyPassword(password.concatToString()) - - /** - * Provide the password for the secret key used for signing. - * - * @param password password - * @return builder instance - * @throws UnsupportedOption if key passwords are not supported - */ - @Throws(UnsupportedOption::class) + @Throws(UnsupportedOption::class, PasswordNotHumanReadable::class) fun withKeyPassword(password: String): T = withKeyPassword(password.toByteArray(UTF8Util.UTF8)) /** diff --git a/sop-java/src/main/kotlin/sop/operation/Armor.kt b/sop-java/src/main/kotlin/sop/operation/Armor.kt index b54aed7..be7f1a3 100644 --- a/sop-java/src/main/kotlin/sop/operation/Armor.kt +++ b/sop-java/src/main/kotlin/sop/operation/Armor.kt @@ -9,7 +9,6 @@ import java.io.InputStream import sop.Ready import sop.exception.SOPGPException.BadData -/** Interface for armoring binary OpenPGP data. */ interface Armor { /** diff --git a/sop-java/src/main/kotlin/sop/operation/CertifyUserId.kt b/sop-java/src/main/kotlin/sop/operation/CertifyUserId.kt deleted file mode 100644 index d59f9f0..0000000 --- a/sop-java/src/main/kotlin/sop/operation/CertifyUserId.kt +++ /dev/null @@ -1,117 +0,0 @@ -// SPDX-FileCopyrightText: 2024 Paul Schaub -// -// SPDX-License-Identifier: Apache-2.0 - -package sop.operation - -import java.io.IOException -import java.io.InputStream -import sop.Ready -import sop.exception.SOPGPException.* -import sop.util.UTF8Util - -/** Interface for issuing certifications over UserIDs on certificates. */ -interface CertifyUserId { - - /** Disable ASCII armor for the output. */ - @Throws(UnsupportedOption::class) fun noArmor(): CertifyUserId - - /** - * Add a user-id that shall be certified on the certificates. - * - * @param userId user-id - * @return builder instance - * @throws UnsupportedOption if this option is not supported - */ - @Throws(UnsupportedOption::class) fun userId(userId: String): CertifyUserId - - /** - * Provide the password for the secret key used for signing. - * - * @param password password - * @return builder instance - * @throws UnsupportedOption if key passwords are not supported - */ - @Throws(UnsupportedOption::class) - fun withKeyPassword(password: CharArray): CertifyUserId = - withKeyPassword(password.concatToString()) - - /** - * Provide the password for the secret key used for signing. - * - * @param password password - * @return builder instance - * @throws UnsupportedOption if key passwords are not supported - */ - @Throws(UnsupportedOption::class) - fun withKeyPassword(password: String): CertifyUserId = - withKeyPassword(password.toByteArray(UTF8Util.UTF8)) - - /** - * Provide the password for the secret key used for signing. - * - * @param password password - * @return builder instance - * @throws UnsupportedOption if key passwords are not supported - * @throws PasswordNotHumanReadable if the provided password is not human-readable - */ - @Throws(PasswordNotHumanReadable::class, UnsupportedOption::class) - fun withKeyPassword(password: ByteArray): CertifyUserId - - /** - * If this option is provided, it is possible to certify user-ids on certificates, which do not - * have a self-certification for the user-id. You can use this option to add pet-name - * certifications to certificates, e.g. "Mom". - * - * @return builder instance - * @throws UnsupportedOption if this option is not supported - */ - @Throws(UnsupportedOption::class) fun noRequireSelfSig(): CertifyUserId - - /** - * Provide signing keys for issuing the certifications. - * - * @param keys input stream containing one or more signing key - * @return builder instance - * @throws BadData if the keys cannot be read - * @throws IOException if an IO error occurs - */ - @Throws(BadData::class, IOException::class) fun keys(keys: InputStream): CertifyUserId - - /** - * Provide signing keys for issuing the certifications. - * - * @param keys byte array containing one or more signing key - * @return builder instance - * @throws BadData if the keys cannot be read - * @throws IOException if an IO error occurs - */ - @Throws(BadData::class, IOException::class) - fun keys(keys: ByteArray): CertifyUserId = keys(keys.inputStream()) - - /** - * Provide the certificates that you want to create certifications for. - * - * @param certs input stream containing the certificates - * @return object to require the certified certificates from - * @throws BadData if the certificates cannot be read - * @throws IOException if an IO error occurs - * @throws KeyIsProtected if one or more signing keys are passphrase protected and cannot be - * unlocked - */ - @Throws(BadData::class, IOException::class, CertUserIdNoMatch::class, KeyIsProtected::class) - fun certs(certs: InputStream): Ready - - /** - * Provide the certificates that you want to create certifications for. - * - * @param certs byte array containing the certificates - * @return object to require the certified certificates from - * @throws BadData if the certificates cannot be read - * @throws IOException if an IO error occurs - * @throws KeyIsProtected if one or more signing keys are passphrase protected and cannot be - * unlocked - */ - @Throws(BadData::class, IOException::class, CertUserIdNoMatch::class, KeyIsProtected::class) - fun certs(certs: ByteArray): Ready = certs(certs.inputStream()) -} diff --git a/sop-java/src/main/kotlin/sop/operation/ChangeKeyPassword.kt b/sop-java/src/main/kotlin/sop/operation/ChangeKeyPassword.kt index fe9b8c9..224e0f4 100644 --- a/sop-java/src/main/kotlin/sop/operation/ChangeKeyPassword.kt +++ b/sop-java/src/main/kotlin/sop/operation/ChangeKeyPassword.kt @@ -11,7 +11,6 @@ import sop.exception.SOPGPException.KeyIsProtected import sop.exception.SOPGPException.PasswordNotHumanReadable import sop.util.UTF8Util -/** Interface for changing key passwords. */ interface ChangeKeyPassword { /** @@ -29,8 +28,13 @@ interface ChangeKeyPassword { * @param oldPassphrase old passphrase * @return builder instance */ - fun oldKeyPassphrase(oldPassphrase: CharArray): ChangeKeyPassword = - oldKeyPassphrase(oldPassphrase.concatToString()) + @Throws(PasswordNotHumanReadable::class) + fun oldKeyPassphrase(oldPassphrase: ByteArray): ChangeKeyPassword = + try { + oldKeyPassphrase(UTF8Util.decodeUTF8(oldPassphrase)) + } catch (e: CharacterCodingException) { + throw PasswordNotHumanReadable("Password MUST be a valid UTF8 string.") + } /** * Provide a passphrase to unlock the secret key. This method can be provided multiple times to @@ -42,23 +46,6 @@ interface ChangeKeyPassword { */ fun oldKeyPassphrase(oldPassphrase: String): ChangeKeyPassword - /** - * Provide a passphrase to unlock the secret key. This method can be provided multiple times to - * provide separate passphrases that are tried as a means to unlock any secret key material - * encountered. - * - * @param oldPassphrase old passphrase - * @return builder instance - * @throws PasswordNotHumanReadable if the old key passphrase is not human-readable - */ - @Throws(PasswordNotHumanReadable::class) - fun oldKeyPassphrase(oldPassphrase: ByteArray): ChangeKeyPassword = - try { - oldKeyPassphrase(UTF8Util.decodeUTF8(oldPassphrase)) - } catch (e: CharacterCodingException) { - throw PasswordNotHumanReadable("Password MUST be a valid UTF8 string.") - } - /** * Provide a passphrase to re-lock the secret key with. This method can only be used once, and * all key material encountered will be encrypted with the given passphrase. If this method is @@ -67,8 +54,13 @@ interface ChangeKeyPassword { * @param newPassphrase new passphrase * @return builder instance */ - fun newKeyPassphrase(newPassphrase: CharArray): ChangeKeyPassword = - newKeyPassphrase(newPassphrase.concatToString()) + @Throws(PasswordNotHumanReadable::class) + fun newKeyPassphrase(newPassphrase: ByteArray): ChangeKeyPassword = + try { + newKeyPassphrase(UTF8Util.decodeUTF8(newPassphrase)) + } catch (e: CharacterCodingException) { + throw PasswordNotHumanReadable("Password MUST be a valid UTF8 string.") + } /** * Provide a passphrase to re-lock the secret key with. This method can only be used once, and @@ -80,23 +72,6 @@ interface ChangeKeyPassword { */ fun newKeyPassphrase(newPassphrase: String): ChangeKeyPassword - /** - * Provide a passphrase to re-lock the secret key with. This method can only be used once, and - * all key material encountered will be encrypted with the given passphrase. If this method is - * not called, the key material will not be protected. - * - * @param newPassphrase new passphrase - * @return builder instance - * @throws PasswordNotHumanReadable if the passphrase is not human-readable - */ - @Throws(PasswordNotHumanReadable::class) - fun newKeyPassphrase(newPassphrase: ByteArray): ChangeKeyPassword = - try { - newKeyPassphrase(UTF8Util.decodeUTF8(newPassphrase)) - } catch (e: CharacterCodingException) { - throw PasswordNotHumanReadable("Password MUST be a valid UTF8 string.") - } - /** * Provide the key material. * diff --git a/sop-java/src/main/kotlin/sop/operation/Dearmor.kt b/sop-java/src/main/kotlin/sop/operation/Dearmor.kt index 2984f27..cc5e98d 100644 --- a/sop-java/src/main/kotlin/sop/operation/Dearmor.kt +++ b/sop-java/src/main/kotlin/sop/operation/Dearmor.kt @@ -10,7 +10,6 @@ import sop.Ready import sop.exception.SOPGPException.BadData import sop.util.UTF8Util -/** Interface for removing ASCII armor from OpenPGP data. */ interface Dearmor { /** diff --git a/sop-java/src/main/kotlin/sop/operation/Decrypt.kt b/sop-java/src/main/kotlin/sop/operation/Decrypt.kt index 4d009f9..ae228e9 100644 --- a/sop-java/src/main/kotlin/sop/operation/Decrypt.kt +++ b/sop-java/src/main/kotlin/sop/operation/Decrypt.kt @@ -13,7 +13,6 @@ import sop.SessionKey import sop.exception.SOPGPException.* import sop.util.UTF8Util -/** Interface for decrypting encrypted OpenPGP messages. */ interface Decrypt { /** diff --git a/sop-java/src/main/kotlin/sop/operation/DetachedSign.kt b/sop-java/src/main/kotlin/sop/operation/DetachedSign.kt index 4aaadc1..c0e62dd 100644 --- a/sop-java/src/main/kotlin/sop/operation/DetachedSign.kt +++ b/sop-java/src/main/kotlin/sop/operation/DetachedSign.kt @@ -11,7 +11,6 @@ import sop.SigningResult import sop.enums.SignAs import sop.exception.SOPGPException.* -/** Interface for creating detached signatures over plaintext messages. */ interface DetachedSign : AbstractSign { /** diff --git a/sop-java/src/main/kotlin/sop/operation/DetachedVerify.kt b/sop-java/src/main/kotlin/sop/operation/DetachedVerify.kt index 319658d..d899b54 100644 --- a/sop-java/src/main/kotlin/sop/operation/DetachedVerify.kt +++ b/sop-java/src/main/kotlin/sop/operation/DetachedVerify.kt @@ -8,7 +8,6 @@ import java.io.IOException import java.io.InputStream import sop.exception.SOPGPException.BadData -/** Interface for verifying detached OpenPGP signatures over plaintext messages. */ interface DetachedVerify : AbstractVerify, VerifySignatures { /** diff --git a/sop-java/src/main/kotlin/sop/operation/Encrypt.kt b/sop-java/src/main/kotlin/sop/operation/Encrypt.kt index 02c7f97..71c04cb 100644 --- a/sop-java/src/main/kotlin/sop/operation/Encrypt.kt +++ b/sop-java/src/main/kotlin/sop/operation/Encrypt.kt @@ -13,7 +13,6 @@ import sop.enums.EncryptAs import sop.exception.SOPGPException.* import sop.util.UTF8Util -/** Interface for creating encrypted OpenPGP messages. */ interface Encrypt { /** diff --git a/sop-java/src/main/kotlin/sop/operation/ExtractCert.kt b/sop-java/src/main/kotlin/sop/operation/ExtractCert.kt index 6485bc2..e2ce1cc 100644 --- a/sop-java/src/main/kotlin/sop/operation/ExtractCert.kt +++ b/sop-java/src/main/kotlin/sop/operation/ExtractCert.kt @@ -9,7 +9,6 @@ import java.io.InputStream import sop.Ready import sop.exception.SOPGPException.BadData -/** Interface for extracting certificates from OpenPGP keys. */ interface ExtractCert { /** diff --git a/sop-java/src/main/kotlin/sop/operation/GenerateKey.kt b/sop-java/src/main/kotlin/sop/operation/GenerateKey.kt index bccd372..3b83b99 100644 --- a/sop-java/src/main/kotlin/sop/operation/GenerateKey.kt +++ b/sop-java/src/main/kotlin/sop/operation/GenerateKey.kt @@ -10,7 +10,6 @@ import sop.Ready import sop.exception.SOPGPException.* import sop.util.UTF8Util -/** Interface for generating OpenPGP keys. */ interface GenerateKey { /** @@ -79,7 +78,7 @@ interface GenerateKey { fun signingOnly(): GenerateKey /** - * Generate the OpenPGP key and return it encoded as an [java.io.InputStream]. + * Generate the OpenPGP key and return it encoded as an [InputStream]. * * @return key * @throws MissingArg if no user-id was provided diff --git a/sop-java/src/main/kotlin/sop/operation/InlineDetach.kt b/sop-java/src/main/kotlin/sop/operation/InlineDetach.kt index 1cc64ce..941a9bf 100644 --- a/sop-java/src/main/kotlin/sop/operation/InlineDetach.kt +++ b/sop-java/src/main/kotlin/sop/operation/InlineDetach.kt @@ -10,7 +10,6 @@ import sop.ReadyWithResult import sop.Signatures import sop.exception.SOPGPException.BadData -/** Interface for detaching inline signatures from OpenPGP messages. */ interface InlineDetach { /** diff --git a/sop-java/src/main/kotlin/sop/operation/InlineSign.kt b/sop-java/src/main/kotlin/sop/operation/InlineSign.kt index 6855a61..11b5668 100644 --- a/sop-java/src/main/kotlin/sop/operation/InlineSign.kt +++ b/sop-java/src/main/kotlin/sop/operation/InlineSign.kt @@ -10,7 +10,6 @@ import sop.Ready import sop.enums.InlineSignAs import sop.exception.SOPGPException.* -/** Interface for creating inline-signed OpenPGP messages. */ interface InlineSign : AbstractSign { /** diff --git a/sop-java/src/main/kotlin/sop/operation/InlineVerify.kt b/sop-java/src/main/kotlin/sop/operation/InlineVerify.kt index a944957..c16b269 100644 --- a/sop-java/src/main/kotlin/sop/operation/InlineVerify.kt +++ b/sop-java/src/main/kotlin/sop/operation/InlineVerify.kt @@ -11,7 +11,7 @@ import sop.Verification import sop.exception.SOPGPException.BadData import sop.exception.SOPGPException.NoSignature -/** Interface for verification of inline-signed messages. */ +/** API for verification of inline-signed messages. */ interface InlineVerify : AbstractVerify { /** diff --git a/sop-java/src/main/kotlin/sop/operation/ListProfiles.kt b/sop-java/src/main/kotlin/sop/operation/ListProfiles.kt index 0bed1f8..315faf2 100644 --- a/sop-java/src/main/kotlin/sop/operation/ListProfiles.kt +++ b/sop-java/src/main/kotlin/sop/operation/ListProfiles.kt @@ -6,7 +6,7 @@ package sop.operation import sop.Profile -/** Interface to list supported profiles of other subcommands. */ +/** Subcommand to list supported profiles of other subcommands. */ interface ListProfiles { /** diff --git a/sop-java/src/main/kotlin/sop/operation/MergeCerts.kt b/sop-java/src/main/kotlin/sop/operation/MergeCerts.kt deleted file mode 100644 index 20469cb..0000000 --- a/sop-java/src/main/kotlin/sop/operation/MergeCerts.kt +++ /dev/null @@ -1,64 +0,0 @@ -// SPDX-FileCopyrightText: 2024 Paul Schaub -// -// SPDX-License-Identifier: Apache-2.0 - -package sop.operation - -import java.io.IOException -import java.io.InputStream -import sop.Ready -import sop.exception.SOPGPException.* - -/** Interface for merging multiple copies of the same certificate into one. */ -interface MergeCerts { - - /** - * Disable ASCII armor for the output certificate. - * - * @return builder instance - * @throws UnsupportedOption if this option is not supported - */ - @Throws(UnsupportedOption::class) fun noArmor(): MergeCerts - - /** - * Provide updated copies of the base certificate. - * - * @param updateCerts input stream containing an updated copy of the base cert - * @return builder instance - * @throws BadData if the update cannot be read - * @throws IOException if an IO error occurs - */ - @Throws(BadData::class, IOException::class) fun updates(updateCerts: InputStream): MergeCerts - - /** - * Provide updated copies of the base certificate. - * - * @param updateCerts byte array containing an updated copy of the base cert - * @return builder instance - * @throws BadData if the update cannot be read - * @throws IOException if an IO error occurs - */ - @Throws(BadData::class, IOException::class) - fun updates(updateCerts: ByteArray): MergeCerts = updates(updateCerts.inputStream()) - - /** - * Provide the base certificate into which updates shall be merged. - * - * @param certs input stream containing the base OpenPGP certificate - * @return object to require the merged certificate from - * @throws BadData if the base certificate cannot be read - * @throws IOException if an IO error occurs - */ - @Throws(BadData::class, IOException::class) fun baseCertificates(certs: InputStream): Ready - - /** - * Provide the base certificate into which updates shall be merged. - * - * @param certs byte array containing the base OpenPGP certificate - * @return object to require the merged certificate from - * @throws BadData if the base certificate cannot be read - * @throws IOException if an IO error occurs - */ - @Throws(BadData::class, IOException::class) - fun baseCertificates(certs: ByteArray): Ready = baseCertificates(certs.inputStream()) -} diff --git a/sop-java/src/main/kotlin/sop/operation/RevokeKey.kt b/sop-java/src/main/kotlin/sop/operation/RevokeKey.kt index 13c6712..f3cbe5c 100644 --- a/sop-java/src/main/kotlin/sop/operation/RevokeKey.kt +++ b/sop-java/src/main/kotlin/sop/operation/RevokeKey.kt @@ -4,13 +4,12 @@ package sop.operation -import java.io.IOException import java.io.InputStream import sop.Ready -import sop.exception.SOPGPException.* +import sop.exception.SOPGPException.PasswordNotHumanReadable +import sop.exception.SOPGPException.UnsupportedOption import sop.util.UTF8Util -/** Interface for creating certificate revocations. */ interface RevokeKey { /** @@ -26,18 +25,9 @@ interface RevokeKey { * @param password password * @return builder instance * @throws UnsupportedOption if the implementation does not support key passwords + * @throws PasswordNotHumanReadable if the password is not human-readable */ - @Throws(UnsupportedOption::class) - fun withKeyPassword(password: CharArray): RevokeKey = withKeyPassword(password.concatToString()) - - /** - * Provide the decryption password for the secret key. - * - * @param password password - * @return builder instance - * @throws UnsupportedOption if the implementation does not support key passwords - */ - @Throws(UnsupportedOption::class) + @Throws(UnsupportedOption::class, PasswordNotHumanReadable::class) fun withKeyPassword(password: String): RevokeKey = withKeyPassword(password.toByteArray(UTF8Util.UTF8)) @@ -52,27 +42,7 @@ interface RevokeKey { @Throws(UnsupportedOption::class, PasswordNotHumanReadable::class) fun withKeyPassword(password: ByteArray): RevokeKey - /** - * Provide the key that you want to revoke. - * - * @param bytes byte array containing the OpenPGP key - * @return object to require the revocation certificate from - * @throws BadData if the key cannot be read - * @throws KeyIsProtected if the key is protected and cannot be unlocked - * @throws IOException if an IO error occurs - */ - @Throws(BadData::class, KeyIsProtected::class, IOException::class) fun keys(bytes: ByteArray): Ready = keys(bytes.inputStream()) - /** - * Provide the key that you want to revoke. - * - * @param keys input stream containing the OpenPGP key - * @return object to require the revocation certificate from - * @throws BadData if the key cannot be read - * @throws KeyIsProtected if the key is protected and cannot be unlocked - * @throws IOException if an IO error occurs - */ - @Throws(BadData::class, KeyIsProtected::class, IOException::class) fun keys(keys: InputStream): Ready } diff --git a/sop-java/src/main/kotlin/sop/operation/UpdateKey.kt b/sop-java/src/main/kotlin/sop/operation/UpdateKey.kt deleted file mode 100644 index 13a4bdc..0000000 --- a/sop-java/src/main/kotlin/sop/operation/UpdateKey.kt +++ /dev/null @@ -1,124 +0,0 @@ -// SPDX-FileCopyrightText: 2024 Paul Schaub -// -// SPDX-License-Identifier: Apache-2.0 - -package sop.operation - -import java.io.IOException -import java.io.InputStream -import sop.Ready -import sop.exception.SOPGPException.* -import sop.util.UTF8Util - -/** Interface for bringing an OpenPGP key up to date. */ -interface UpdateKey { - - /** - * Disable ASCII armor encoding of the output. - * - * @return builder instance - */ - fun noArmor(): UpdateKey - - /** - * Allow key to be used for signing only. If this option is not present, the operation may add a - * new, encryption-capable component key. - * - * @return builder instance - * @throws UnsupportedOption if this option is not supported - */ - @Throws(UnsupportedOption::class) fun signingOnly(): UpdateKey - - /** - * Do not allow adding new capabilities to the key. If this option is not present, the operation - * may add support for new capabilities to the key. - * - * @return builder instance - * @throws UnsupportedOption if this option is not supported - */ - @Throws(UnsupportedOption::class) fun noAddedCapabilities(): UpdateKey - - /** - * Provide a passphrase for unlocking the secret key. - * - * @param password password - * @return builder instance - * @throws UnsupportedOption if this option is not supported - */ - @Throws(UnsupportedOption::class) - fun withKeyPassword(password: CharArray): UpdateKey = withKeyPassword(password.concatToString()) - - /** - * Provide a passphrase for unlocking the secret key. - * - * @param password password - * @return builder instance - * @throws UnsupportedOption if this option is not supported - */ - @Throws(UnsupportedOption::class) - fun withKeyPassword(password: String): UpdateKey = - withKeyPassword(password.toByteArray(UTF8Util.UTF8)) - - /** - * Provide a passphrase for unlocking the secret key. - * - * @param password password - * @return builder instance - * @throws PasswordNotHumanReadable if the password is not human-readable - * @throws UnsupportedOption if this option is not supported - */ - @Throws(PasswordNotHumanReadable::class, UnsupportedOption::class) - fun withKeyPassword(password: ByteArray): UpdateKey - - /** - * Provide certificates that might contain updated signatures or third-party certifications. - * These certificates will be merged into the key. - * - * @param certs input stream of certificates - * @return builder instance - * @throws UnsupportedOption if this option is not supported - * @throws BadData if the certificate cannot be read - * @throws IOException if an IO error occurs - */ - @Throws(UnsupportedOption::class, BadData::class, IOException::class) - fun mergeCerts(certs: InputStream): UpdateKey - - /** - * Provide certificates that might contain updated signatures or third-party certifications. - * These certificates will be merged into the key. - * - * @param certs binary certificates - * @return builder instance - * @throws UnsupportedOption if this option is not supported - * @throws BadData if the certificate cannot be read - * @throws IOException if an IO error occurs - */ - @Throws(UnsupportedOption::class, BadData::class, IOException::class) - fun mergeCerts(certs: ByteArray): UpdateKey = mergeCerts(certs.inputStream()) - - /** - * Provide the OpenPGP key to update. - * - * @param key input stream containing the key - * @return handle to acquire the updated OpenPGP key from - * @throws BadData if the key cannot be read - * @throws IOException if an IO error occurs - * @throws KeyIsProtected if the key is passphrase protected and cannot be unlocked - * @throws PrimaryKeyBad if the primary key is bad (e.g. expired, too weak) - */ - @Throws(BadData::class, IOException::class, KeyIsProtected::class, PrimaryKeyBad::class) - fun key(key: InputStream): Ready - - /** - * Provide the OpenPGP key to update. - * - * @param key binary OpenPGP key - * @return handle to acquire the updated OpenPGP key from - * @throws BadData if the key cannot be read - * @throws IOException if an IO error occurs - * @throws KeyIsProtected if the key is passphrase protected and cannot be unlocked - * @throws PrimaryKeyBad if the primary key is bad (e.g. expired, too weak) - */ - @Throws(BadData::class, IOException::class, KeyIsProtected::class, PrimaryKeyBad::class) - fun key(key: ByteArray): Ready = key(key.inputStream()) -} diff --git a/sop-java/src/main/kotlin/sop/operation/ValidateUserId.kt b/sop-java/src/main/kotlin/sop/operation/ValidateUserId.kt deleted file mode 100644 index 971de25..0000000 --- a/sop-java/src/main/kotlin/sop/operation/ValidateUserId.kt +++ /dev/null @@ -1,90 +0,0 @@ -// SPDX-FileCopyrightText: 2024 Paul Schaub -// -// SPDX-License-Identifier: Apache-2.0 - -package sop.operation - -import java.io.IOException -import java.io.InputStream -import java.util.* -import sop.exception.SOPGPException.* - -/** Interface to validate UserIDs on certificates. */ -interface ValidateUserId { - - /** - * If this is set, then the USERID is treated as an e-mail address, and matched only against the - * e-mail address part of each correctly bound User ID. The rest of each correctly bound User ID - * is ignored. - * - * @return builder instance - * @throws UnsupportedOption if this option is not supported - */ - @Throws(UnsupportedOption::class) fun addrSpecOnly(): ValidateUserId - - /** - * Set the UserID to validate. To match only the email address, call [addrSpecOnly]. - * - * @param userId UserID or email address - * @return builder instance - */ - fun userId(userId: String): ValidateUserId - - /** - * Add certificates, which act as authorities. The [userId] is only considered correctly bound, - * if it was bound by an authoritative certificate. - * - * @param certs authoritative certificates - * @return builder instance - * @throws BadData if the authority certificates cannot be read - * @throws IOException if an IO error occurs - */ - @Throws(BadData::class, IOException::class) fun authorities(certs: InputStream): ValidateUserId - - /** - * Add certificates, which act as authorities. The [userId] is only considered correctly bound, - * if it was bound by an authoritative certificate. - * - * @param certs authoritative certificates - * @return builder instance - * @throws BadData if the authority certificates cannot be read - * @throws IOException if an IO error occurs - */ - @Throws(BadData::class, IOException::class) - fun authorities(certs: ByteArray): ValidateUserId = authorities(certs.inputStream()) - - /** - * Add subject certificates, on which UserID bindings are validated. - * - * @param certs subject certificates - * @return true if all subject certificates have a correct binding to the UserID. - * @throws BadData if the subject certificates are malformed - * @throws IOException if a parser exception happens - * @throws CertUserIdNoMatch if any subject certificate does not have a correctly bound UserID - * that matches [userId]. - */ - @Throws(BadData::class, IOException::class, CertUserIdNoMatch::class) - fun subjects(certs: InputStream): Boolean - - /** - * Add subject certificates, on which UserID bindings are validated. - * - * @param certs subject certificates - * @return true if all subject certificates have a correct binding to the UserID. - * @throws BadData if the subject certificates are malformed - * @throws IOException if a parser exception happens - * @throws CertUserIdNoMatch if any subject certificate does not have a correctly bound UserID - * that matches [userId]. - */ - @Throws(BadData::class, IOException::class, CertUserIdNoMatch::class) - fun subjects(certs: ByteArray): Boolean = subjects(certs.inputStream()) - - /** - * Provide a reference time for user-id validation. - * - * @param date reference time - * @return builder instance - * @throws UnsupportedOption if this option is not supported - */ - @Throws(UnsupportedOption::class) fun validateAt(date: Date): ValidateUserId -} diff --git a/sop-java/src/main/kotlin/sop/operation/VerifySignatures.kt b/sop-java/src/main/kotlin/sop/operation/VerifySignatures.kt index 00a64aa..b75e4a5 100644 --- a/sop-java/src/main/kotlin/sop/operation/VerifySignatures.kt +++ b/sop-java/src/main/kotlin/sop/operation/VerifySignatures.kt @@ -10,7 +10,6 @@ import sop.Verification import sop.exception.SOPGPException.BadData import sop.exception.SOPGPException.NoSignature -/** API handle for verifying signatures. */ interface VerifySignatures { /** diff --git a/sop-java/src/main/kotlin/sop/operation/Version.kt b/sop-java/src/main/kotlin/sop/operation/Version.kt index 8a4c808..a10fe7c 100644 --- a/sop-java/src/main/kotlin/sop/operation/Version.kt +++ b/sop-java/src/main/kotlin/sop/operation/Version.kt @@ -10,7 +10,6 @@ import java.util.* import kotlin.jvm.Throws import sop.exception.SOPGPException -/** Interface for acquiring version information about the SOP implementation. */ interface Version { /** @@ -116,12 +115,12 @@ interface Version { fun getSopJavaVersion(): String? { return try { val resourceIn: InputStream = - Version::class.java.getResourceAsStream("/sop-java-version.properties") + javaClass.getResourceAsStream("/sop-java-version.properties") ?: throw IOException("File sop-java-version.properties not found.") val properties = Properties().apply { load(resourceIn) } properties.getProperty("sop-java-version") } catch (e: IOException) { - "DEVELOPMENT" + null } } } diff --git a/sop-java/src/main/kotlin/sop/util/ProxyOutputStream.kt b/sop-java/src/main/kotlin/sop/util/ProxyOutputStream.kt new file mode 100644 index 0000000..a608c89 --- /dev/null +++ b/sop-java/src/main/kotlin/sop/util/ProxyOutputStream.kt @@ -0,0 +1,76 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package sop.util + +import java.io.ByteArrayOutputStream +import java.io.IOException +import java.io.OutputStream + +/** + * [OutputStream] that buffers data being written into it, until its underlying output stream is + * being replaced. At that point, first all the buffered data is being written to the underlying + * stream, followed by any successive data that may get written to the [ProxyOutputStream]. This + * class is useful if we need to provide an [OutputStream] at one point in time when the final + * target output stream is not yet known. + */ +@Deprecated("Marked for removal.") +class ProxyOutputStream : OutputStream() { + private val buffer = ByteArrayOutputStream() + private var swapped: OutputStream? = null + + @Synchronized + fun replaceOutputStream(underlying: OutputStream) { + this.swapped = underlying + swapped!!.write(buffer.toByteArray()) + } + + @Synchronized + @Throws(IOException::class) + override fun write(b: ByteArray) { + if (swapped == null) { + buffer.write(b) + } else { + swapped!!.write(b) + } + } + + @Synchronized + @Throws(IOException::class) + override fun write(b: ByteArray, off: Int, len: Int) { + if (swapped == null) { + buffer.write(b, off, len) + } else { + swapped!!.write(b, off, len) + } + } + + @Synchronized + @Throws(IOException::class) + override fun flush() { + buffer.flush() + if (swapped != null) { + swapped!!.flush() + } + } + + @Synchronized + @Throws(IOException::class) + override fun close() { + buffer.close() + if (swapped != null) { + swapped!!.close() + } + } + + @Synchronized + @Throws(IOException::class) + override fun write(i: Int) { + if (swapped == null) { + buffer.write(i) + } else { + swapped!!.write(i) + } + } +} diff --git a/sop-java/src/test/java/sop/ProfileTest.java b/sop-java/src/test/java/sop/ProfileTest.java index f418672..564a6af 100644 --- a/sop-java/src/test/java/sop/ProfileTest.java +++ b/sop-java/src/test/java/sop/ProfileTest.java @@ -5,9 +5,6 @@ package sop; import org.junit.jupiter.api.Test; -import sop.util.Optional; - -import java.util.Arrays; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -22,37 +19,6 @@ public class ProfileTest { assertEquals("default: Use the implementers recommendations.", profile.toString()); } - @Test - public void withAliasesToString() { - Profile profile = new Profile( - "Foo", - Optional.of("Something something"), - Arrays.asList("Bar", "Baz")); - assertEquals("Foo: Something something (aliases: Bar, Baz)", profile.toString()); - } - - @Test - public void parseWithAliases() { - Profile profile = Profile.parse("Foo: Something something (aliases: Bar, Baz)"); - assertEquals("Foo", profile.getName()); - assertEquals("Something something", profile.getDescription().get()); - assertEquals(Arrays.asList("Bar", "Baz"), profile.getAliases()); - } - - @Test - public void changeAliasesWithWithAliases() { - Profile p = new Profile("Foo", "Bar any Baz", Arrays.asList("tinitus", "particle")); - p = p.withAliases("fnord", "qbit"); - - assertEquals("Foo", p.getName()); - assertEquals("Bar any Baz", p.getDescription().get()); - - assertTrue(p.getAliases().contains("fnord")); - assertTrue(p.getAliases().contains("qbit")); - assertFalse(p.getAliases().contains("tinitus")); - assertFalse(p.getAliases().contains("particle")); - } - @Test public void toStringNameOnly() { Profile profile = new Profile("default"); diff --git a/sop-java/src/test/java/sop/VerificationJSONTest.java b/sop-java/src/test/java/sop/VerificationJSONTest.java deleted file mode 100644 index a6e5d96..0000000 --- a/sop-java/src/test/java/sop/VerificationJSONTest.java +++ /dev/null @@ -1,166 +0,0 @@ -// SPDX-FileCopyrightText: 2025 Paul Schaub -// -// SPDX-License-Identifier: Apache-2.0 - -package sop; - -import org.jetbrains.annotations.NotNull; -import org.junit.jupiter.api.Test; -import sop.enums.SignatureMode; -import sop.testsuite.assertions.VerificationAssert; - -import java.text.ParseException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -public class VerificationJSONTest { - - // A hacky self-made "JSON parser" stand-in. - // Only used for testing, do not use in production! - private Verification.JSONParser dummyParser = new Verification.JSONParser() { - @NotNull - @Override - public Verification.JSON parse(@NotNull String string) throws ParseException { - if (!string.startsWith("{")) { - throw new ParseException("Alleged JSON String does not begin with '{'", 0); - } - if (!string.endsWith("}")) { - throw new ParseException("Alleged JSON String does not end with '}'", string.length() - 1); - } - - List signersList = new ArrayList<>(); - Matcher signersMat = Pattern.compile("\"signers\": \\[(.*?)\\]").matcher(string); - if (signersMat.find()) { - String signersCat = signersMat.group(1); - String[] split = signersCat.split(","); - for (String s : split) { - s = s.trim(); - signersList.add(s.substring(1, s.length() - 1)); - } - } - - String comment = null; - Matcher commentMat = Pattern.compile("\"comment\": \"(.*?)\"").matcher(string); - if (commentMat.find()) { - comment = commentMat.group(1); - } - - String ext = null; - Matcher extMat = Pattern.compile("\"ext\": (.*?})}").matcher(string); - if (extMat.find()) { - ext = extMat.group(1); - } - - return new Verification.JSON(signersList, comment, ext); - } - }; - - // A just as hacky "JSON Serializer" lookalike. - // Also don't use in production, for testing only! - private Verification.JSONSerializer dummySerializer = new Verification.JSONSerializer() { - @NotNull - @Override - public String serialize(@NotNull Verification.JSON json) { - if (json.getSigners().isEmpty() && json.getComment() == null && json.getExt() == null) { - return ""; - } - StringBuilder sb = new StringBuilder("{"); - boolean comma = false; - - if (!json.getSigners().isEmpty()) { - comma = true; - sb.append("\"signers\": ["); - for (Iterator iterator = json.getSigners().iterator(); iterator.hasNext(); ) { - String signer = iterator.next(); - sb.append('\"').append(signer).append('\"'); - if (iterator.hasNext()) { - sb.append(", "); - } - } - sb.append(']'); - } - - if (json.getComment() != null) { - if (comma) { - sb.append(", "); - } - comma = true; - sb.append("\"comment\": \"").append(json.getComment()).append('\"'); - } - - if (json.getExt() != null) { - if (comma) { - sb.append(", "); - } - comma = true; - sb.append("\"ext\": ").append(json.getExt().toString()); - } - return sb.append('}').toString(); - } - }; - - @Test - public void testSimpleSerializeParse() throws ParseException { - String signer = "alice.pub"; - Verification.JSON json = new Verification.JSON(signer); - - String string = dummySerializer.serialize(json); - assertEquals("{\"signers\": [\"alice.pub\"]}", string); - - Verification.JSON parsed = dummyParser.parse(string); - assertEquals(signer, parsed.getSigners().get(0)); - assertEquals(1, parsed.getSigners().size()); - assertNull(parsed.getComment()); - assertNull(parsed.getExt()); - } - - @Test - public void testAdvancedSerializeParse() throws ParseException { - Verification.JSON json = new Verification.JSON( - Arrays.asList("../certs/alice.pub", "/etc/pgp/certs.pgp"), - "This is a comment", - "{\"Foo\": \"Bar\"}"); - - String serialized = dummySerializer.serialize(json); - assertEquals("{\"signers\": [\"../certs/alice.pub\", \"/etc/pgp/certs.pgp\"], \"comment\": \"This is a comment\", \"ext\": {\"Foo\": \"Bar\"}}", - serialized); - - Verification.JSON parsed = dummyParser.parse(serialized); - assertEquals(json.getSigners(), parsed.getSigners()); - assertEquals(json.getComment(), parsed.getComment()); - assertEquals(json.getExt(), parsed.getExt()); - } - - @Test - public void testVerificationWithSimpleJson() { - String string = "2019-10-29T18:36:45Z EB85BB5FA33A75E15E944E63F231550C4F47E38E EB85BB5FA33A75E15E944E63F231550C4F47E38E mode:text {\"signers\": [\"alice.pgp\"]}"; - Verification verification = Verification.fromString(string); - - assertTrue(verification.getContainsJson()); - assertEquals("EB85BB5FA33A75E15E944E63F231550C4F47E38E", verification.getSigningKeyFingerprint()); - assertEquals("EB85BB5FA33A75E15E944E63F231550C4F47E38E", verification.getSigningCertFingerprint()); - assertEquals(SignatureMode.text, verification.getSignatureMode().get()); - - Verification.JSON json = verification.getJson(dummyParser); - assertNotNull(json, "The verification string MUST contain valid extension json"); - - assertEquals(Collections.singletonList("alice.pgp"), json.getSigners()); - assertNull(json.getComment()); - assertNull(json.getExt()); - - verification = new Verification(verification.getCreationTime(), verification.getSigningKeyFingerprint(), verification.getSigningCertFingerprint(), verification.getSignatureMode().get(), json, dummySerializer); - VerificationAssert.assertThatVerification(verification) - .hasJSON(dummyParser, j -> j.getSigners().contains("alice.pgp")); - assertEquals(string, verification.toString()); - } -} diff --git a/sop-java/src/test/java/sop/VerificationTest.java b/sop-java/src/test/java/sop/VerificationTest.java index 1e10f61..e956435 100644 --- a/sop-java/src/test/java/sop/VerificationTest.java +++ b/sop-java/src/test/java/sop/VerificationTest.java @@ -13,7 +13,6 @@ import java.text.ParseException; import java.util.Date; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; public class VerificationTest { @@ -26,8 +25,6 @@ public class VerificationTest { Verification verification = new Verification(signDate, keyFP, certFP); assertEquals("2022-11-07T15:01:24Z F9E6F53F7201C60A87064EAB0B27F2B0760A1209 4E2C78519512C2AE9A8BFE7EB3298EB2FBE5F51B", verification.toString()); - assertFalse(verification.getContainsJson()); - VerificationAssert.assertThatVerification(verification) .issuedBy(certFP) .isBySigningKey(keyFP) diff --git a/sop-java/src/test/java/sop/util/ProxyOutputStreamTest.java b/sop-java/src/test/java/sop/util/ProxyOutputStreamTest.java new file mode 100644 index 0000000..9d99fd4 --- /dev/null +++ b/sop-java/src/test/java/sop/util/ProxyOutputStreamTest.java @@ -0,0 +1,40 @@ +// SPDX-FileCopyrightText: 2021 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package sop.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import org.junit.jupiter.api.Test; + +public class ProxyOutputStreamTest { + + @Test + public void replaceOutputStreamThrowsNPEForNull() { + ProxyOutputStream proxy = new ProxyOutputStream(); + assertThrows(NullPointerException.class, () -> proxy.replaceOutputStream(null)); + } + + @Test + public void testSwappingStreamPreservesWrittenBytes() throws IOException { + byte[] firstSection = "Foo\nBar\n".getBytes(StandardCharsets.UTF_8); + byte[] secondSection = "Baz\n".getBytes(StandardCharsets.UTF_8); + + ProxyOutputStream proxy = new ProxyOutputStream(); + proxy.write(firstSection); + + ByteArrayOutputStream swappedStream = new ByteArrayOutputStream(); + proxy.replaceOutputStream(swappedStream); + + proxy.write(secondSection); + proxy.close(); + + assertEquals("Foo\nBar\nBaz\n", swappedStream.toString()); + } +} diff --git a/version.gradle b/version.gradle index bac96da..13c3b5f 100644 --- a/version.gradle +++ b/version.gradle @@ -4,13 +4,15 @@ allprojects { ext { - shortVersion = '14.0.1' - isSnapshot = true - javaSourceCompatibility = 11 + shortVersion = '10.1.0' + isSnapshot = false + minAndroidSdk = 10 + javaSourceCompatibility = 1.8 gsonVersion = '2.10.1' jsrVersion = '3.0.2' junitVersion = '5.8.2' - logbackVersion = '1.5.13' + junitSysExitVersion = '1.1.2' + logbackVersion = '1.2.13' // 1.4+ cause CLI spam mockitoVersion = '4.5.1' picocliVersion = '4.6.3' slf4jVersion = '1.7.36'