mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-12-22 19:08:00 +01:00
Kotlin conversion: ArmoredOutputStreamFactory
Also allow configuration of CRC calculation for both input and output streams
This commit is contained in:
parent
e16376ca68
commit
aca884e936
5 changed files with 114 additions and 134 deletions
|
@ -1,132 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package org.pgpainless.util;
|
|
||||||
|
|
||||||
import java.io.OutputStream;
|
|
||||||
|
|
||||||
import org.bouncycastle.bcpg.ArmoredOutputStream;
|
|
||||||
import org.pgpainless.encryption_signing.ProducerOptions;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory to create configured {@link ArmoredOutputStream ArmoredOutputStreams}.
|
|
||||||
* The configuration entails setting custom version and comment headers.
|
|
||||||
*/
|
|
||||||
public final class ArmoredOutputStreamFactory {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of the program.
|
|
||||||
*/
|
|
||||||
public static final String PGPAINLESS = "PGPainless";
|
|
||||||
private static String version = PGPAINLESS;
|
|
||||||
private static String[] comment = new String[0];
|
|
||||||
|
|
||||||
private ArmoredOutputStreamFactory() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ArmoredOutputStream.Builder getBuilder() {
|
|
||||||
ArmoredOutputStream.Builder builder = ArmoredOutputStream.builder();
|
|
||||||
builder.clearHeaders();
|
|
||||||
if (version != null && !version.isEmpty()) {
|
|
||||||
builder.setVersion(version);
|
|
||||||
}
|
|
||||||
for (String comment : comment) {
|
|
||||||
builder.addComment(comment);
|
|
||||||
}
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrap an {@link OutputStream} inside a preconfigured {@link ArmoredOutputStream}.
|
|
||||||
*
|
|
||||||
* @param outputStream inner stream
|
|
||||||
* @return armored output stream
|
|
||||||
*/
|
|
||||||
@Nonnull
|
|
||||||
public static ArmoredOutputStream get(@Nonnull OutputStream outputStream) {
|
|
||||||
return getBuilder().build(outputStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return an instance of the {@link ArmoredOutputStream} which might have pre-populated armor headers.
|
|
||||||
*
|
|
||||||
* @param outputStream output stream
|
|
||||||
* @param options options
|
|
||||||
* @return armored output stream
|
|
||||||
*/
|
|
||||||
@Nonnull
|
|
||||||
public static ArmoredOutputStream get(@Nonnull OutputStream outputStream, @Nonnull ProducerOptions options) {
|
|
||||||
ArmoredOutputStream.Builder builder = getBuilder();
|
|
||||||
if (options.isHideArmorHeaders()) {
|
|
||||||
builder.clearHeaders();
|
|
||||||
}
|
|
||||||
if (options.hasVersion()) {
|
|
||||||
builder.setVersion(options.getVersion());
|
|
||||||
}
|
|
||||||
if (options.hasComment()) {
|
|
||||||
builder.setComment(options.getComment());
|
|
||||||
}
|
|
||||||
return builder.build(outputStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Overwrite the version header of ASCII armors with a custom value.
|
|
||||||
* Newlines in the version info string result in multiple version header entries.
|
|
||||||
* If this is set to <pre>null</pre>, then the version header is omitted altogether.
|
|
||||||
*
|
|
||||||
* @param versionString version string
|
|
||||||
*/
|
|
||||||
public static void setVersionInfo(@Nullable String versionString) {
|
|
||||||
if (versionString == null) {
|
|
||||||
version = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String trimmed = versionString.trim();
|
|
||||||
if (trimmed.isEmpty()) {
|
|
||||||
version = null;
|
|
||||||
} else {
|
|
||||||
version = trimmed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset the version header to its default value of {@link #PGPAINLESS}.
|
|
||||||
*/
|
|
||||||
public static void resetVersionInfo() {
|
|
||||||
version = PGPAINLESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a comment header value in the ASCII armor header.
|
|
||||||
* If the comment contains newlines, it will be split into multiple header entries.
|
|
||||||
*
|
|
||||||
* @see org.pgpainless.encryption_signing.ProducerOptions#setComment(String) for how to set comments for
|
|
||||||
* individual messages.
|
|
||||||
*
|
|
||||||
* @param commentString comment
|
|
||||||
*/
|
|
||||||
public static void setComment(@Nullable String commentString) {
|
|
||||||
if (commentString == null) {
|
|
||||||
throw new IllegalArgumentException("Comment cannot be null.");
|
|
||||||
}
|
|
||||||
String trimmed = commentString.trim();
|
|
||||||
if (trimmed.isEmpty()) {
|
|
||||||
throw new IllegalArgumentException("Comment cannot be empty.");
|
|
||||||
}
|
|
||||||
|
|
||||||
String[] lines = commentString.split("\n");
|
|
||||||
comment = lines;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset to the default of no comment headers.
|
|
||||||
*/
|
|
||||||
public static void resetComment() {
|
|
||||||
comment = new String[0];
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -24,6 +24,7 @@ import java.util.*
|
||||||
class ConsumerOptions {
|
class ConsumerOptions {
|
||||||
|
|
||||||
private var ignoreMDCErrors = false
|
private var ignoreMDCErrors = false
|
||||||
|
var isDisableAsciiArmorCRC = false
|
||||||
private var forceNonOpenPgpData = false
|
private var forceNonOpenPgpData = false
|
||||||
private var verifyNotBefore: Date? = null
|
private var verifyNotBefore: Date? = null
|
||||||
private var verifyNotAfter: Date? = Date()
|
private var verifyNotAfter: Date? = Date()
|
||||||
|
|
|
@ -20,6 +20,7 @@ class ProducerOptions private constructor(
|
||||||
private var applyCRLFEncoding = false
|
private var applyCRLFEncoding = false
|
||||||
private var cleartextSigned = false
|
private var cleartextSigned = false
|
||||||
private var _hideArmorHeaders = false
|
private var _hideArmorHeaders = false
|
||||||
|
var isDisableAsciiArmorCRC = false
|
||||||
|
|
||||||
private var _compressionAlgorithmOverride: CompressionAlgorithm = PGPainless.getPolicy().compressionAlgorithmPolicy.defaultCompressionAlgorithm
|
private var _compressionAlgorithmOverride: CompressionAlgorithm = PGPainless.getPolicy().compressionAlgorithmPolicy.defaultCompressionAlgorithm
|
||||||
private var asciiArmor = true
|
private var asciiArmor = true
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
package org.pgpainless.util
|
package org.pgpainless.util
|
||||||
|
|
||||||
import org.bouncycastle.bcpg.ArmoredInputStream
|
import org.bouncycastle.bcpg.ArmoredInputStream
|
||||||
|
import org.pgpainless.decryption_verification.ConsumerOptions
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
|
||||||
|
@ -24,12 +25,19 @@ class ArmoredInputStreamFactory {
|
||||||
* @throws IOException in case of an IO error
|
* @throws IOException in case of an IO error
|
||||||
*/
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
|
@JvmOverloads
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
fun get(inputStream: InputStream): ArmoredInputStream {
|
fun get(inputStream: InputStream, options: ConsumerOptions? = null): ArmoredInputStream {
|
||||||
return when (inputStream) {
|
return when (inputStream) {
|
||||||
is CRCingArmoredInputStreamWrapper -> inputStream
|
is CRCingArmoredInputStreamWrapper -> inputStream
|
||||||
is ArmoredInputStream -> CRCingArmoredInputStreamWrapper(inputStream)
|
is ArmoredInputStream -> CRCingArmoredInputStreamWrapper(inputStream)
|
||||||
else -> CRCingArmoredInputStreamWrapper(ArmoredInputStream(inputStream))
|
else -> CRCingArmoredInputStreamWrapper(
|
||||||
|
ArmoredInputStream.builder().apply {
|
||||||
|
setParseForHeaders(true)
|
||||||
|
options?.let {
|
||||||
|
setIgnoreCRC(it.isDisableAsciiArmorCRC)
|
||||||
|
}
|
||||||
|
}.build(inputStream))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package org.pgpainless.util
|
||||||
|
|
||||||
|
import org.bouncycastle.bcpg.ArmoredOutputStream
|
||||||
|
import org.pgpainless.encryption_signing.ProducerOptions
|
||||||
|
import java.io.OutputStream
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory to create configured [ArmoredOutputStream] instances.
|
||||||
|
* The configuration entails setting custom version and comment headers.
|
||||||
|
*/
|
||||||
|
class ArmoredOutputStreamFactory {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val PGPAINLESS = "PGPainless"
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
private var version: String? = PGPAINLESS
|
||||||
|
private var comment: String? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an instance of the [ArmoredOutputStream] which might have pre-populated armor headers.
|
||||||
|
*
|
||||||
|
* @param outputStream output stream
|
||||||
|
* @param options options
|
||||||
|
* @return armored output stream
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
@JvmOverloads
|
||||||
|
fun get(outputStream: OutputStream, options: ProducerOptions? = null): ArmoredOutputStream {
|
||||||
|
val builder = ArmoredOutputStream.builder().apply {
|
||||||
|
// set fields defined in ArmoredOutputStreamFactory
|
||||||
|
if (!version.isNullOrBlank()) setVersion(version)
|
||||||
|
if (!comment.isNullOrBlank()) setComment(comment)
|
||||||
|
|
||||||
|
// set (and potentially overwrite with) values from ProducerOptions
|
||||||
|
options?.let {
|
||||||
|
enableCRC(!it.isDisableAsciiArmorCRC)
|
||||||
|
if (it.isHideArmorHeaders) clearHeaders()
|
||||||
|
if (it.hasVersion()) setVersion(it.version)
|
||||||
|
if (it.hasComment()) addComment(it.comment)
|
||||||
|
// TODO: configure CRC
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return get(outputStream, builder)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build an [ArmoredOutputStream] around the given [outputStream], configured according to the passed in
|
||||||
|
* [ArmoredOutputStream.Builder] instance.
|
||||||
|
*
|
||||||
|
* @param outputStream output stream
|
||||||
|
* @param builder builder instance
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
fun get(outputStream: OutputStream, builder: ArmoredOutputStream.Builder): ArmoredOutputStream {
|
||||||
|
return builder.build(outputStream)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overwrite the version header of ASCII armors with a custom value.
|
||||||
|
* Newlines in the version info string result in multiple version header entries.
|
||||||
|
* If this is set to <pre>null</pre>, then the version header is omitted altogether.
|
||||||
|
*
|
||||||
|
* @param versionString version string
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
fun setVersionInfo(versionString: String?) {
|
||||||
|
version = if (versionString.isNullOrBlank()) null else versionString.trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset the version header to its default value of [PGPAINLESS].
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
fun resetVersionInfo() {
|
||||||
|
version = PGPAINLESS
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a comment header value in the ASCII armor header.
|
||||||
|
* If the comment contains newlines, it will be split into multiple header entries.
|
||||||
|
*
|
||||||
|
* @see [ProducerOptions.setComment] for how to set comments for individual messages.
|
||||||
|
*
|
||||||
|
* @param commentString comment
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
fun setComment(commentString: String) {
|
||||||
|
require(commentString.isNotBlank()) { "Comment cannot be empty. See resetComment() to clear the comment." }
|
||||||
|
comment = commentString.trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun resetComment() {
|
||||||
|
comment = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue