Implement profiles

This commit is contained in:
Paul Schaub 2023-04-14 14:06:34 +02:00
parent b8544396f8
commit 5935d65c90
Signed by: vanitasvitae
GPG Key ID: 62BEE9264BF17311
11 changed files with 75 additions and 43 deletions

View File

@ -4,12 +4,12 @@
package sop.external.operation; package sop.external.operation;
import sop.Profile;
import sop.external.ExternalSOP; import sop.external.ExternalSOP;
import sop.operation.ListProfiles; import sop.operation.ListProfiles;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Properties; import java.util.Properties;
@ -25,23 +25,22 @@ public class ListProfilesExternal implements ListProfiles {
} }
@Override @Override
public List<String> ofCommand(String command) { public List<Profile> subcommand(String command) {
commandList.add(command); commandList.add(command);
try { try {
String output = new String(ExternalSOP.executeProducingOperation(Runtime.getRuntime(), commandList, envList).getBytes()); String output = new String(ExternalSOP.executeProducingOperation(Runtime.getRuntime(), commandList, envList).getBytes());
return Arrays.asList(output.split("\n")); return toProfiles(output);
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
@Override private List<Profile> toProfiles(String output) {
public List<String> global() { List<Profile> profiles = new ArrayList<>();
try { for (String line : output.split("\n")) {
String output = new String(ExternalSOP.executeProducingOperation(Runtime.getRuntime(), commandList, envList).getBytes()); String[] split = line.split(": ");
return Arrays.asList(output.split("\n")); profiles.add(new Profile(split[0], split[1]));
} catch (IOException e) {
throw new RuntimeException(e);
} }
return profiles;
} }
} }

View File

@ -31,7 +31,7 @@ public class GenerateKeyCmd extends AbstractSopCmd {
String withKeyPassword; String withKeyPassword;
@CommandLine.Option(names = "--profile", @CommandLine.Option(names = "--profile",
paramLabel = "PROFILE") paramLabel = "PROFILE")
String profile = "default"; String profile = "default";
@Override @Override
@ -47,7 +47,12 @@ public class GenerateKeyCmd extends AbstractSopCmd {
generateKey.noArmor(); generateKey.noArmor();
} }
generateKey.profile(profile); try {
generateKey.profile(profile);
} catch (SOPGPException.UnsupportedProfile e) {
String errorMsg = getMsg("sop.error.usage.profile_not_supported", "generate-key", profile);
throw new SOPGPException.UnsupportedProfile(errorMsg, e);
}
if (withKeyPassword != null) { if (withKeyPassword != null) {
try { try {

View File

@ -5,7 +5,9 @@
package sop.cli.picocli.commands; package sop.cli.picocli.commands;
import picocli.CommandLine; import picocli.CommandLine;
import sop.Profile;
import sop.cli.picocli.SopCLI; import sop.cli.picocli.SopCLI;
import sop.exception.SOPGPException;
import sop.operation.ListProfiles; import sop.operation.ListProfiles;
@CommandLine.Command(name = "list-profiles", @CommandLine.Command(name = "list-profiles",
@ -13,7 +15,7 @@ import sop.operation.ListProfiles;
exitCodeOnInvalidInput = 37) exitCodeOnInvalidInput = 37)
public class ListProfilesCmd extends AbstractSopCmd { public class ListProfilesCmd extends AbstractSopCmd {
@CommandLine.Parameters(paramLabel = "COMMAND", arity="0..1", descriptionKey = "subcommand") @CommandLine.Parameters(paramLabel = "COMMAND", arity="1", descriptionKey = "subcommand")
String subcommand; String subcommand;
@Override @Override
@ -21,19 +23,15 @@ public class ListProfilesCmd extends AbstractSopCmd {
ListProfiles listProfiles = throwIfUnsupportedSubcommand( ListProfiles listProfiles = throwIfUnsupportedSubcommand(
SopCLI.getSop().listProfiles(), "list-profiles"); SopCLI.getSop().listProfiles(), "list-profiles");
if (subcommand == null) { try {
for (String profile : listProfiles.global()) { for (Profile profile : listProfiles.subcommand(subcommand)) {
// CHECKSTYLE:OFF // CHECKSTYLE:OFF
System.out.println(profile); System.out.println(profile);
// CHECKSTYLE:ON // CHECKSTYLE:ON
} }
return; } catch (SOPGPException.UnsupportedProfile e) {
} String errorMsg = getMsg("sop.error.feature_support.subcommand_does_not_support_profiles", subcommand);
throw new SOPGPException.UnsupportedProfile(errorMsg, e);
for (String profile : listProfiles.ofCommand(subcommand)) {
// CHECKSTYLE:OFF
System.out.println(profile);
// CHECKSTYLE:ON
} }
} }
} }

View File

@ -4,6 +4,7 @@
usage.header=Generate a secret key usage.header=Generate a secret key
no-armor=ASCII armor the output no-armor=ASCII armor the output
USERID[0..*]=User-ID, e.g. "Alice <alice@example.com>" USERID[0..*]=User-ID, e.g. "Alice <alice@example.com>"
profile=Profile identifier to switch between profiles
with-key-password.0=Password to protect the private key with with-key-password.0=Password to protect the private key with
with-key-password.1=Is an INDIRECT data type (e.g. file, environment variable, file descriptor...). with-key-password.1=Is an INDIRECT data type (e.g. file, environment variable, file descriptor...).

View File

@ -4,6 +4,7 @@
usage.header=Generiere einen privaten Schlüssel usage.header=Generiere einen privaten Schlüssel
no-armor=Schütze Ausgabe mit ASCII Armor no-armor=Schütze Ausgabe mit ASCII Armor
USERID[0..*]=Nutzer-ID, z.B.. "Alice <alice@example.com>" USERID[0..*]=Nutzer-ID, z.B.. "Alice <alice@example.com>"
profile=Profil-Identifikator um zwischen Profilen zu wechseln
with-key-password.0=Passwort zum Schutz des privaten Schlüssels with-key-password.0=Passwort zum Schutz des privaten Schlüssels
with-key-password.1=Ist ein INDIREKTER Datentyp (z.B.. Datei, Umgebungsvariable, Dateideskriptor...). with-key-password.1=Ist ein INDIREKTER Datentyp (z.B.. Datei, Umgebungsvariable, Dateideskriptor...).

View File

@ -74,8 +74,10 @@ sop.error.runtime.cannot_decrypt_message=Message could not be decrypted.
sop.error.usage.password_or_cert_required=At least one password file or cert file required for encryption. sop.error.usage.password_or_cert_required=At least one password file or cert file required for encryption.
sop.error.usage.argument_required=Argument '%s' is required. sop.error.usage.argument_required=Argument '%s' is required.
sop.error.usage.parameter_required=Parameter '%s' is required. sop.error.usage.parameter_required=Parameter '%s' is required.
sop.error.usage.profile_not_supported=Subcommand '%s' does not support profile '%s'.
sop.error.usage.option_requires_other_option=Option '%s' is requested, but no option %s was provided. sop.error.usage.option_requires_other_option=Option '%s' is requested, but no option %s was provided.
sop.error.usage.incompatible_options.clearsigned_no_armor=Options '--no-armor' and '--as=clearsigned' are incompatible. sop.error.usage.incompatible_options.clearsigned_no_armor=Options '--no-armor' and '--as=clearsigned' are incompatible.
# Feature Support # Feature Support
sop.error.feature_support.subcommand_not_supported=Subcommand '%s' is not supported. sop.error.feature_support.subcommand_not_supported=Subcommand '%s' is not supported.
sop.error.feature_support.option_not_supported=Option '%s' not supported. sop.error.feature_support.option_not_supported=Option '%s' not supported.
sop.error.feature_support.subcommand_does_not_support_profiles=Subcommand '%s' does not support any profiles.

View File

@ -73,8 +73,10 @@ sop.error.runtime.cannot_decrypt_message=Nachricht konnte nicht entschl
sop.error.usage.password_or_cert_required=Es wird mindestens ein Passwort und/oder Zertifikat zur Verschlüsselung benötigt. sop.error.usage.password_or_cert_required=Es wird mindestens ein Passwort und/oder Zertifikat zur Verschlüsselung benötigt.
sop.error.usage.argument_required=Argument '%s' ist erforderlich. sop.error.usage.argument_required=Argument '%s' ist erforderlich.
sop.error.usage.parameter_required=Parameter '%s' ist erforderlich. sop.error.usage.parameter_required=Parameter '%s' ist erforderlich.
sop.error.usage.profile_not_supported=Unterbefehl '%s' unterstützt Profil '%s' nicht.
sop.error.usage.option_requires_other_option=Option '%s' wurde angegeben, jedoch kein Wert für %s. sop.error.usage.option_requires_other_option=Option '%s' wurde angegeben, jedoch kein Wert für %s.
sop.error.usage.incompatible_options.clearsigned_no_armor=Optionen '--no-armor' und '--as=clearsigned' sind inkompatibel. sop.error.usage.incompatible_options.clearsigned_no_armor=Optionen '--no-armor' und '--as=clearsigned' sind inkompatibel.
# Feature Support # Feature Support
sop.error.feature_support.subcommand_not_supported=Unterbefehl '%s' wird nicht unterstützt. sop.error.feature_support.subcommand_not_supported=Unterbefehl '%s' wird nicht unterstützt.
sop.error.feature_support.option_not_supported=Option '%s' wird nicht unterstützt. sop.error.feature_support.option_not_supported=Option '%s' wird nicht unterstützt.
sop.error.feature_support.subcommand_does_not_support_profiles=Unterbefehl '%s' unterstützt keine Profile.

View File

@ -401,12 +401,33 @@ public abstract class SOPGPException extends RuntimeException {
public static final int EXIT_CODE = 89; public static final int EXIT_CODE = 89;
public UnsupportedProfile() { private final String subcommand;
super(); private final String profile;
public UnsupportedProfile(String subcommand) {
super("Subcommand '" + subcommand + "' does not support any profiles.");
this.subcommand = subcommand;
this.profile = null;
} }
public UnsupportedProfile(String errorMessage) { public UnsupportedProfile(String subcommand, String profile) {
super(errorMessage); super("Subcommand '" + subcommand + "' does not support profile '" + profile + "'.");
this.subcommand = subcommand;
this.profile = profile;
}
public UnsupportedProfile(String errorMsg, UnsupportedProfile e) {
super(errorMsg, e);
this.subcommand = e.getSubcommand();
this.profile = e.getProfile();
}
public String getSubcommand() {
return subcommand;
}
public String getProfile() {
return profile;
} }
@Override @Override

View File

@ -6,8 +6,8 @@ package sop.operation;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.List;
import sop.Profile;
import sop.Ready; import sop.Ready;
import sop.exception.SOPGPException; import sop.exception.SOPGPException;
import sop.util.UTF8Util; import sop.util.UTF8Util;
@ -57,11 +57,21 @@ public interface GenerateKey {
return withKeyPassword(UTF8Util.decodeUTF8(password)); return withKeyPassword(UTF8Util.decodeUTF8(password));
} }
/**
* Pass in a profile.
*
* @param profile profile
* @return builder instance
*/
default GenerateKey profile(Profile profile) {
return profile(profile.getName());
}
/** /**
* Pass in a profile identifier. * Pass in a profile identifier.
* *
* @param profile profile identifier * @param profile profile identifier
* @return this * @return builder instance
*/ */
GenerateKey profile(String profile); GenerateKey profile(String profile);

View File

@ -4,12 +4,12 @@
package sop.operation; package sop.operation;
import sop.Profile;
import java.util.List; import java.util.List;
public interface ListProfiles { public interface ListProfiles {
List<String> ofCommand(String command); List<Profile> subcommand(String command);
List<String> global();
} }

View File

@ -7,6 +7,7 @@ package sop.testsuite.operation;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
import sop.Profile;
import sop.SOP; import sop.SOP;
import java.io.IOException; import java.io.IOException;
@ -21,19 +22,11 @@ public class ListProfilesTest extends AbstractSOPTest {
return provideBackends(); return provideBackends();
} }
@ParameterizedTest
@MethodSource("provideInstances")
public void listGlobalProfiles(SOP sop) throws IOException {
List<String> profiles = sop.listProfiles()
.global();
assertFalse(profiles.isEmpty());
}
@ParameterizedTest @ParameterizedTest
@MethodSource("provideInstances") @MethodSource("provideInstances")
public void listGenerateKeyProfiles(SOP sop) throws IOException { public void listGenerateKeyProfiles(SOP sop) throws IOException {
List<String> profiles = sop.listProfiles() List<Profile> profiles = sop.listProfiles()
.ofCommand("generate-key"); .subcommand("generate-key");
assertFalse(profiles.isEmpty()); assertFalse(profiles.isEmpty());
} }