refactor: Decompose all utilities from cmd package

This commit is contained in:
Felicitas Pojtinger
2021-12-08 00:27:46 +01:00
parent c5e7cab4f3
commit 0be10a7698
23 changed files with 208 additions and 270 deletions

View File

@@ -3,11 +3,9 @@ package cmd
import ( import (
"archive/tar" "archive/tar"
"context" "context"
"errors"
"fmt" "fmt"
"io/ioutil"
"os"
"github.com/pojntfx/stfs/internal/compression"
"github.com/pojntfx/stfs/internal/keys" "github.com/pojntfx/stfs/internal/keys"
"github.com/pojntfx/stfs/internal/persisters" "github.com/pojntfx/stfs/internal/persisters"
"github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/config"
@@ -23,29 +21,9 @@ const (
fromFlag = "from" fromFlag = "from"
overwriteFlag = "overwrite" overwriteFlag = "overwrite"
compressionLevelFlag = "compression-level" compressionLevelFlag = "compression-level"
recipientFlag = "recipient"
recipientFlag = "recipient" identityFlag = "identity"
identityFlag = "identity" passwordFlag = "password"
passwordFlag = "password"
)
var (
knownCompressionLevels = []string{config.CompressionLevelFastest, config.CompressionLevelBalanced, config.CompressionLevelSmallest}
errUnknownCompressionLevel = errors.New("unknown compression level")
errUnsupportedCompressionLevel = errors.New("unsupported compression level")
errKeyNotAccessible = errors.New("key not found or accessible")
errMissingTarHeader = errors.New("tar header is missing")
errRecipientUnparsable = errors.New("recipient could not be parsed")
errCompressionFormatRequiresLargerRecordSize = errors.New("this compression format requires a larger record size")
errCompressionFormatOnlyRegularSupport = errors.New("this compression format only supports regular files, not i.e. tape drives")
errSignatureFormatOnlyRegularSupport = errors.New("this signature format only supports regular files, not i.e. tape drives")
) )
var archiveCmd = &cobra.Command{ var archiveCmd = &cobra.Command{
@@ -57,15 +35,15 @@ var archiveCmd = &cobra.Command{
return err return err
} }
if err := checkCompressionLevel(viper.GetString(compressionLevelFlag)); err != nil { if err := compression.CheckCompressionLevel(viper.GetString(compressionLevelFlag)); err != nil {
return err return err
} }
if err := checkKeyAccessible(viper.GetString(encryptionFlag), viper.GetString(recipientFlag)); err != nil { if err := keys.CheckKeyAccessible(viper.GetString(encryptionFlag), viper.GetString(recipientFlag)); err != nil {
return err return err
} }
return checkKeyAccessible(viper.GetString(signatureFlag), viper.GetString(identityFlag)) return keys.CheckKeyAccessible(viper.GetString(signatureFlag), viper.GetString(identityFlag))
}, },
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
if viper.GetBool(verboseFlag) { if viper.GetBool(verboseFlag) {
@@ -89,7 +67,7 @@ var archiveCmd = &cobra.Command{
lastIndexedBlock = b lastIndexedBlock = b
} }
pubkey, err := readKey(viper.GetString(encryptionFlag), viper.GetString(recipientFlag)) pubkey, err := keys.ReadKey(viper.GetString(encryptionFlag), viper.GetString(recipientFlag))
if err != nil { if err != nil {
return err return err
} }
@@ -99,7 +77,7 @@ var archiveCmd = &cobra.Command{
return err return err
} }
privkey, err := readKey(viper.GetString(signatureFlag), viper.GetString(identityFlag)) privkey, err := keys.ReadKey(viper.GetString(signatureFlag), viper.GetString(identityFlag))
if err != nil { if err != nil {
return err return err
} }
@@ -130,6 +108,9 @@ var archiveCmd = &cobra.Command{
viper.GetBool(overwriteFlag), viper.GetBool(overwriteFlag),
viper.GetString(compressionLevelFlag), viper.GetString(compressionLevelFlag),
) )
if err != nil {
return nil
}
return recovery.Index( return recovery.Index(
config.StateConfig{ config.StateConfig{
@@ -159,7 +140,7 @@ var archiveCmd = &cobra.Command{
} }
if len(hdrs) <= i-1 { if len(hdrs) <= i-1 {
return errMissingTarHeader return config.ErrMissingTarHeader
} }
*hdr = *hdrs[i-1] *hdr = *hdrs[i-1]
@@ -173,47 +154,11 @@ var archiveCmd = &cobra.Command{
}, },
} }
func checkKeyAccessible(encryptionFormat string, pathToKey string) error {
if encryptionFormat == noneKey {
return nil
}
if _, err := os.Stat(pathToKey); err != nil {
return errKeyNotAccessible
}
return nil
}
func readKey(encryptionFormat string, pathToKey string) ([]byte, error) {
if encryptionFormat == noneKey {
return []byte{}, nil
}
return ioutil.ReadFile(pathToKey)
}
func checkCompressionLevel(compressionLevel string) error {
compressionLevelIsKnown := false
for _, candidate := range knownCompressionLevels {
if compressionLevel == candidate {
compressionLevelIsKnown = true
}
}
if !compressionLevelIsKnown {
return errUnknownCompressionLevel
}
return nil
}
func init() { func init() {
archiveCmd.PersistentFlags().IntP(recordSizeFlag, "z", 20, "Amount of 512-bit blocks per record") archiveCmd.PersistentFlags().IntP(recordSizeFlag, "z", 20, "Amount of 512-bit blocks per record")
archiveCmd.PersistentFlags().StringP(fromFlag, "f", ".", "File or directory to archive") archiveCmd.PersistentFlags().StringP(fromFlag, "f", ".", "File or directory to archive")
archiveCmd.PersistentFlags().BoolP(overwriteFlag, "o", false, "Start writing from the start instead of from the end of the tape or tar file") archiveCmd.PersistentFlags().BoolP(overwriteFlag, "o", false, "Start writing from the start instead of from the end of the tape or tar file")
archiveCmd.PersistentFlags().StringP(compressionLevelFlag, "l", config.CompressionLevelBalanced, fmt.Sprintf("Compression level to use (default %v, available are %v)", config.CompressionLevelBalanced, knownCompressionLevels)) archiveCmd.PersistentFlags().StringP(compressionLevelFlag, "l", config.CompressionLevelBalanced, fmt.Sprintf("Compression level to use (default %v, available are %v)", config.CompressionLevelBalanced, config.KnownCompressionLevels))
archiveCmd.PersistentFlags().StringP(recipientFlag, "r", "", "Path to public key of recipient to encrypt for") archiveCmd.PersistentFlags().StringP(recipientFlag, "r", "", "Path to public key of recipient to encrypt for")
archiveCmd.PersistentFlags().StringP(identityFlag, "i", "", "Path to private key to sign with") archiveCmd.PersistentFlags().StringP(identityFlag, "i", "", "Path to private key to sign with")
archiveCmd.PersistentFlags().StringP(passwordFlag, "p", "", "Password for the private key") archiveCmd.PersistentFlags().StringP(passwordFlag, "p", "", "Password for the private key")

View File

@@ -22,22 +22,18 @@ var deleteCmd = &cobra.Command{
return err return err
} }
if err := checkKeyAccessible(viper.GetString(encryptionFlag), viper.GetString(recipientFlag)); err != nil { if err := keys.CheckKeyAccessible(viper.GetString(encryptionFlag), viper.GetString(recipientFlag)); err != nil {
return err return err
} }
return checkKeyAccessible(viper.GetString(signatureFlag), viper.GetString(identityFlag)) return keys.CheckKeyAccessible(viper.GetString(signatureFlag), viper.GetString(identityFlag))
}, },
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
if err := viper.BindPFlags(cmd.PersistentFlags()); err != nil {
return err
}
if viper.GetBool(verboseFlag) { if viper.GetBool(verboseFlag) {
boil.DebugMode = true boil.DebugMode = true
} }
pubkey, err := readKey(viper.GetString(encryptionFlag), viper.GetString(recipientFlag)) pubkey, err := keys.ReadKey(viper.GetString(encryptionFlag), viper.GetString(recipientFlag))
if err != nil { if err != nil {
return err return err
} }
@@ -47,7 +43,7 @@ var deleteCmd = &cobra.Command{
return err return err
} }
privkey, err := readKey(viper.GetString(signatureFlag), viper.GetString(identityFlag)) privkey, err := keys.ReadKey(viper.GetString(signatureFlag), viper.GetString(identityFlag))
if err != nil { if err != nil {
return err return err
} }

View File

@@ -4,7 +4,6 @@ import (
"github.com/pojntfx/stfs/pkg/hardware" "github.com/pojntfx/stfs/pkg/hardware"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
"github.com/volatiletech/sqlboiler/v4/boil"
) )
var driveEjectCmd = &cobra.Command{ var driveEjectCmd = &cobra.Command{
@@ -15,10 +14,6 @@ var driveEjectCmd = &cobra.Command{
return err return err
} }
if viper.GetBool(verboseFlag) {
boil.DebugMode = true
}
return hardware.Eject( return hardware.Eject(
hardware.DriveConfig{ hardware.DriveConfig{
Drive: viper.GetString(driveFlag), Drive: viper.GetString(driveFlag),

View File

@@ -6,7 +6,6 @@ import (
"github.com/pojntfx/stfs/pkg/hardware" "github.com/pojntfx/stfs/pkg/hardware"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
"github.com/volatiletech/sqlboiler/v4/boil"
) )
var driveTellCmd = &cobra.Command{ var driveTellCmd = &cobra.Command{
@@ -17,10 +16,6 @@ var driveTellCmd = &cobra.Command{
return err return err
} }
if viper.GetBool(verboseFlag) {
boil.DebugMode = true
}
currentRecord, err := hardware.Tell( currentRecord, err := hardware.Tell(
hardware.DriveConfig{ hardware.DriveConfig{
Drive: viper.GetString(driveFlag), Drive: viper.GetString(driveFlag),

View File

@@ -9,22 +9,17 @@ import (
"github.com/pojntfx/stfs/pkg/utility" "github.com/pojntfx/stfs/pkg/utility"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
"github.com/volatiletech/sqlboiler/v4/boil"
) )
var keygenCmd = &cobra.Command{ var keygenCmd = &cobra.Command{
Use: "keygen", Use: "keygen",
Aliases: []string{"key", "k"}, Aliases: []string{"key", "k"},
Short: "Restore a file or directory from tape or tar file", Short: "Generate a encryption or signature key",
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
if err := viper.BindPFlags(cmd.PersistentFlags()); err != nil { if err := viper.BindPFlags(cmd.PersistentFlags()); err != nil {
return err return err
} }
if viper.GetBool(verboseFlag) {
boil.DebugMode = true
}
pubkey, privkey, err := utility.Keygen( pubkey, privkey, err := utility.Keygen(
config.PipeConfig{ config.PipeConfig{
Compression: viper.GetString(compressionFlag), Compression: viper.GetString(compressionFlag),

View File

@@ -18,22 +18,18 @@ var moveCmd = &cobra.Command{
return err return err
} }
if err := checkKeyAccessible(viper.GetString(encryptionFlag), viper.GetString(recipientFlag)); err != nil { if err := keys.CheckKeyAccessible(viper.GetString(encryptionFlag), viper.GetString(recipientFlag)); err != nil {
return err return err
} }
return checkKeyAccessible(viper.GetString(signatureFlag), viper.GetString(identityFlag)) return keys.CheckKeyAccessible(viper.GetString(signatureFlag), viper.GetString(identityFlag))
}, },
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
if err := viper.BindPFlags(cmd.PersistentFlags()); err != nil {
return err
}
if viper.GetBool(verboseFlag) { if viper.GetBool(verboseFlag) {
boil.DebugMode = true boil.DebugMode = true
} }
pubkey, err := readKey(viper.GetString(encryptionFlag), viper.GetString(recipientFlag)) pubkey, err := keys.ReadKey(viper.GetString(encryptionFlag), viper.GetString(recipientFlag))
if err != nil { if err != nil {
return err return err
} }
@@ -43,7 +39,7 @@ var moveCmd = &cobra.Command{
return err return err
} }
privkey, err := readKey(viper.GetString(signatureFlag), viper.GetString(identityFlag)) privkey, err := keys.ReadKey(viper.GetString(signatureFlag), viper.GetString(identityFlag))
if err != nil { if err != nil {
return err return err
} }

View File

@@ -1,14 +1,12 @@
package cmd package cmd
import ( import (
"errors"
"github.com/pojntfx/stfs/internal/keys" "github.com/pojntfx/stfs/internal/keys"
"github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/config"
"github.com/pojntfx/stfs/pkg/hardware"
"github.com/pojntfx/stfs/pkg/recovery" "github.com/pojntfx/stfs/pkg/recovery"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
"github.com/volatiletech/sqlboiler/v4/boil"
) )
const ( const (
@@ -18,40 +16,22 @@ const (
previewFlag = "preview" previewFlag = "preview"
) )
var (
errEmbeddedHeaderMissing = errors.New("embedded header is missing")
errIdentityUnparsable = errors.New("recipient could not be parsed")
errInvalidSignature = errors.New("invalid signature")
errSignatureMissing = errors.New("missing signature")
)
var recoveryFetchCmd = &cobra.Command{ var recoveryFetchCmd = &cobra.Command{
Use: "fetch", Use: "fetch",
Short: "Fetch a file or directory from tape or tar file by record and block", Short: "Fetch a file or directory from tape or tar file by record and block without the index",
PersistentPreRunE: func(cmd *cobra.Command, args []string) error { PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
if err := viper.BindPFlags(cmd.PersistentFlags()); err != nil { if err := viper.BindPFlags(cmd.PersistentFlags()); err != nil {
return err return err
} }
if err := checkKeyAccessible(viper.GetString(encryptionFlag), viper.GetString(identityFlag)); err != nil { if err := keys.CheckKeyAccessible(viper.GetString(encryptionFlag), viper.GetString(identityFlag)); err != nil {
return err return err
} }
return checkKeyAccessible(viper.GetString(signatureFlag), viper.GetString(recipientFlag)) return keys.CheckKeyAccessible(viper.GetString(signatureFlag), viper.GetString(recipientFlag))
}, },
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
if err := viper.BindPFlags(cmd.PersistentFlags()); err != nil { pubkey, err := keys.ReadKey(viper.GetString(signatureFlag), viper.GetString(recipientFlag))
return err
}
if viper.GetBool(verboseFlag) {
boil.DebugMode = true
}
pubkey, err := readKey(viper.GetString(signatureFlag), viper.GetString(recipientFlag))
if err != nil { if err != nil {
return err return err
} }
@@ -61,7 +41,7 @@ var recoveryFetchCmd = &cobra.Command{
return err return err
} }
privkey, err := readKey(viper.GetString(encryptionFlag), viper.GetString(identityFlag)) privkey, err := keys.ReadKey(viper.GetString(encryptionFlag), viper.GetString(identityFlag))
if err != nil { if err != nil {
return err return err
} }
@@ -72,9 +52,8 @@ var recoveryFetchCmd = &cobra.Command{
} }
return recovery.Fetch( return recovery.Fetch(
config.StateConfig{ hardware.DriveConfig{
Drive: viper.GetString(driveFlag), Drive: viper.GetString(driveFlag),
Metadata: viper.GetString(metadataFlag),
}, },
config.PipeConfig{ config.PipeConfig{
Compression: viper.GetString(compressionFlag), Compression: viper.GetString(compressionFlag),

View File

@@ -21,22 +21,18 @@ var recoveryIndexCmd = &cobra.Command{
return err return err
} }
if err := checkKeyAccessible(viper.GetString(encryptionFlag), viper.GetString(identityFlag)); err != nil { if err := keys.CheckKeyAccessible(viper.GetString(encryptionFlag), viper.GetString(identityFlag)); err != nil {
return err return err
} }
return checkKeyAccessible(viper.GetString(signatureFlag), viper.GetString(recipientFlag)) return keys.CheckKeyAccessible(viper.GetString(signatureFlag), viper.GetString(recipientFlag))
}, },
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
if err := viper.BindPFlags(cmd.PersistentFlags()); err != nil {
return err
}
if viper.GetBool(verboseFlag) { if viper.GetBool(verboseFlag) {
boil.DebugMode = true boil.DebugMode = true
} }
pubkey, err := readKey(viper.GetString(signatureFlag), viper.GetString(recipientFlag)) pubkey, err := keys.ReadKey(viper.GetString(signatureFlag), viper.GetString(recipientFlag))
if err != nil { if err != nil {
return err return err
} }
@@ -46,7 +42,7 @@ var recoveryIndexCmd = &cobra.Command{
return err return err
} }
privkey, err := readKey(viper.GetString(encryptionFlag), viper.GetString(identityFlag)) privkey, err := keys.ReadKey(viper.GetString(encryptionFlag), viper.GetString(identityFlag))
if err != nil { if err != nil {
return err return err
} }

View File

@@ -3,10 +3,10 @@ package cmd
import ( import (
"github.com/pojntfx/stfs/internal/keys" "github.com/pojntfx/stfs/internal/keys"
"github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/config"
"github.com/pojntfx/stfs/pkg/hardware"
"github.com/pojntfx/stfs/pkg/recovery" "github.com/pojntfx/stfs/pkg/recovery"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
"github.com/volatiletech/sqlboiler/v4/boil"
) )
var recoveryQueryCmd = &cobra.Command{ var recoveryQueryCmd = &cobra.Command{
@@ -17,22 +17,14 @@ var recoveryQueryCmd = &cobra.Command{
return err return err
} }
if err := checkKeyAccessible(viper.GetString(encryptionFlag), viper.GetString(identityFlag)); err != nil { if err := keys.CheckKeyAccessible(viper.GetString(encryptionFlag), viper.GetString(identityFlag)); err != nil {
return err return err
} }
return checkKeyAccessible(viper.GetString(signatureFlag), viper.GetString(recipientFlag)) return keys.CheckKeyAccessible(viper.GetString(signatureFlag), viper.GetString(recipientFlag))
}, },
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
if err := viper.BindPFlags(cmd.PersistentFlags()); err != nil { pubkey, err := keys.ReadKey(viper.GetString(signatureFlag), viper.GetString(recipientFlag))
return err
}
if viper.GetBool(verboseFlag) {
boil.DebugMode = true
}
pubkey, err := readKey(viper.GetString(signatureFlag), viper.GetString(recipientFlag))
if err != nil { if err != nil {
return err return err
} }
@@ -42,7 +34,7 @@ var recoveryQueryCmd = &cobra.Command{
return err return err
} }
privkey, err := readKey(viper.GetString(encryptionFlag), viper.GetString(identityFlag)) privkey, err := keys.ReadKey(viper.GetString(encryptionFlag), viper.GetString(identityFlag))
if err != nil { if err != nil {
return err return err
} }
@@ -53,9 +45,8 @@ var recoveryQueryCmd = &cobra.Command{
} }
if _, err := recovery.Query( if _, err := recovery.Query(
config.StateConfig{ hardware.DriveConfig{
Drive: viper.GetString(driveFlag), Drive: viper.GetString(driveFlag),
Metadata: viper.GetString(metadataFlag),
}, },
config.PipeConfig{ config.PipeConfig{
Compression: viper.GetString(compressionFlag), Compression: viper.GetString(compressionFlag),

View File

@@ -22,22 +22,18 @@ var restoreCmd = &cobra.Command{
return err return err
} }
if err := checkKeyAccessible(viper.GetString(encryptionFlag), viper.GetString(identityFlag)); err != nil { if err := keys.CheckKeyAccessible(viper.GetString(encryptionFlag), viper.GetString(identityFlag)); err != nil {
return err return err
} }
return checkKeyAccessible(viper.GetString(signatureFlag), viper.GetString(recipientFlag)) return keys.CheckKeyAccessible(viper.GetString(signatureFlag), viper.GetString(recipientFlag))
}, },
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
if err := viper.BindPFlags(cmd.PersistentFlags()); err != nil {
return err
}
if viper.GetBool(verboseFlag) { if viper.GetBool(verboseFlag) {
boil.DebugMode = true boil.DebugMode = true
} }
pubkey, err := readKey(viper.GetString(signatureFlag), viper.GetString(recipientFlag)) pubkey, err := keys.ReadKey(viper.GetString(signatureFlag), viper.GetString(recipientFlag))
if err != nil { if err != nil {
return err return err
} }
@@ -47,7 +43,7 @@ var restoreCmd = &cobra.Command{
return err return err
} }
privkey, err := readKey(viper.GetString(encryptionFlag), viper.GetString(identityFlag)) privkey, err := keys.ReadKey(viper.GetString(encryptionFlag), viper.GetString(identityFlag))
if err != nil { if err != nil {
return err return err
} }

View File

@@ -1,75 +1,26 @@
package cmd package cmd
import ( import (
"errors"
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/pojntfx/stfs/internal/compression"
"github.com/pojntfx/stfs/internal/encryption"
"github.com/pojntfx/stfs/internal/signature"
"github.com/pojntfx/stfs/pkg/config"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
) )
const ( const (
driveFlag = "drive" driveFlag = "drive"
metadataFlag = "metadata" metadataFlag = "metadata"
verboseFlag = "verbose" verboseFlag = "verbose"
compressionFlag = "compression" compressionFlag = "compression"
encryptionFlag = "encryption"
noneKey = "none" signatureFlag = "signature"
compressionFormatGZipKey = "gzip"
compressionFormatGZipSuffix = ".gz"
compressionFormatParallelGZipKey = "parallelgzip"
compressionFormatLZ4Key = "lz4"
compressionFormatLZ4Suffix = ".lz4"
compressionFormatZStandardKey = "zstandard"
compressionFormatZStandardSuffix = ".zst"
compressionFormatBrotliKey = "brotli"
compressionFormatBrotliSuffix = ".br"
compressionFormatBzip2Key = "bzip2"
compressionFormatBzip2Suffix = ".bz2"
compressionFormatBzip2ParallelKey = "parallelbzip2"
encryptionFlag = "encryption"
encryptionFormatAgeKey = "age"
encryptionFormatAgeSuffix = ".age"
encryptionFormatPGPKey = "pgp"
encryptionFormatPGPSuffix = ".pgp"
signatureFlag = "signature"
signatureFormatMinisignKey = "minisign"
signatureFormatPGPKey = "pgp"
)
var (
knownCompressionFormats = []string{noneKey, compressionFormatGZipKey, compressionFormatParallelGZipKey, compressionFormatLZ4Key, compressionFormatZStandardKey, compressionFormatBrotliKey, compressionFormatBzip2Key, compressionFormatBzip2ParallelKey}
errUnknownCompressionFormat = errors.New("unknown compression format")
errUnsupportedCompressionFormat = errors.New("unsupported compression format")
knownEncryptionFormats = []string{noneKey, encryptionFormatAgeKey, encryptionFormatPGPKey}
errUnknownEncryptionFormat = errors.New("unknown encryption format")
errUnsupportedEncryptionFormat = errors.New("unsupported encryption format")
errKeygenForFormatUnsupported = errors.New("can not generate keys for this format")
knownSignatureFormats = []string{noneKey, signatureFormatMinisignKey, signatureFormatPGPKey}
errUnknownSignatureFormat = errors.New("unknown signature format")
errUnsupportedSignatureFormat = errors.New("unsupported signature format")
) )
var rootCmd = &cobra.Command{ var rootCmd = &cobra.Command{
@@ -83,46 +34,15 @@ https://github.com/pojntfx/stfs`,
viper.SetEnvPrefix("stbak") viper.SetEnvPrefix("stbak")
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_", ".", "_")) viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_", ".", "_"))
compressionFormatIsKnown := false if err := compression.CheckCompressionFormat(viper.GetString(compressionFlag)); err != nil {
compressionFormat := viper.GetString(compressionFlag) return err
for _, candidate := range knownCompressionFormats {
if compressionFormat == candidate {
compressionFormatIsKnown = true
}
} }
if !compressionFormatIsKnown { if err := encryption.CheckEncryptionFormat(viper.GetString(encryptionFlag)); err != nil {
return errUnknownCompressionFormat return err
} }
encryptionFormatIsKnown := false return signature.CheckSignatureFormat(viper.GetString(signatureFlag))
encryptionFormat := viper.GetString(encryptionFlag)
for _, candidate := range knownEncryptionFormats {
if encryptionFormat == candidate {
encryptionFormatIsKnown = true
}
}
if !encryptionFormatIsKnown {
return errUnknownEncryptionFormat
}
signatureFormatIsKnown := false
signatureFormat := viper.GetString(signatureFlag)
for _, candidate := range knownSignatureFormats {
if signatureFormat == candidate {
signatureFormatIsKnown = true
}
}
if !signatureFormatIsKnown {
return errUnknownSignatureFormat
}
return nil
}, },
} }
@@ -137,9 +57,9 @@ func Execute() {
rootCmd.PersistentFlags().StringP(driveFlag, "d", "/dev/nst0", "Tape or tar file to use") rootCmd.PersistentFlags().StringP(driveFlag, "d", "/dev/nst0", "Tape or tar file to use")
rootCmd.PersistentFlags().StringP(metadataFlag, "m", metadataPath, "Metadata database to use") rootCmd.PersistentFlags().StringP(metadataFlag, "m", metadataPath, "Metadata database to use")
rootCmd.PersistentFlags().BoolP(verboseFlag, "v", false, "Enable verbose logging") rootCmd.PersistentFlags().BoolP(verboseFlag, "v", false, "Enable verbose logging")
rootCmd.PersistentFlags().StringP(compressionFlag, "c", noneKey, fmt.Sprintf("Compression format to use (default %v, available are %v)", noneKey, knownCompressionFormats)) rootCmd.PersistentFlags().StringP(compressionFlag, "c", config.NoneKey, fmt.Sprintf("Compression format to use (default %v, available are %v)", config.NoneKey, config.KnownCompressionFormats))
rootCmd.PersistentFlags().StringP(encryptionFlag, "e", noneKey, fmt.Sprintf("Encryption format to use (default %v, available are %v)", noneKey, knownEncryptionFormats)) rootCmd.PersistentFlags().StringP(encryptionFlag, "e", config.NoneKey, fmt.Sprintf("Encryption format to use (default %v, available are %v)", config.NoneKey, config.KnownEncryptionFormats))
rootCmd.PersistentFlags().StringP(signatureFlag, "s", noneKey, fmt.Sprintf("Signature format to use (default %v, available are %v)", noneKey, knownSignatureFormats)) rootCmd.PersistentFlags().StringP(signatureFlag, "s", config.NoneKey, fmt.Sprintf("Signature format to use (default %v, available are %v)", config.NoneKey, config.KnownSignatureFormats))
if err := viper.BindPFlags(rootCmd.PersistentFlags()); err != nil { if err := viper.BindPFlags(rootCmd.PersistentFlags()); err != nil {
panic(err) panic(err)

View File

@@ -5,6 +5,7 @@ import (
"context" "context"
"fmt" "fmt"
"github.com/pojntfx/stfs/internal/compression"
"github.com/pojntfx/stfs/internal/keys" "github.com/pojntfx/stfs/internal/keys"
"github.com/pojntfx/stfs/internal/persisters" "github.com/pojntfx/stfs/internal/persisters"
"github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/config"
@@ -24,15 +25,15 @@ var updateCmd = &cobra.Command{
return err return err
} }
if err := checkCompressionLevel(viper.GetString(compressionLevelFlag)); err != nil { if err := compression.CheckCompressionLevel(viper.GetString(compressionLevelFlag)); err != nil {
return err return err
} }
if err := checkKeyAccessible(viper.GetString(encryptionFlag), viper.GetString(recipientFlag)); err != nil { if err := keys.CheckKeyAccessible(viper.GetString(encryptionFlag), viper.GetString(recipientFlag)); err != nil {
return err return err
} }
return checkKeyAccessible(viper.GetString(signatureFlag), viper.GetString(identityFlag)) return keys.CheckKeyAccessible(viper.GetString(signatureFlag), viper.GetString(identityFlag))
}, },
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
if err := viper.BindPFlags(cmd.PersistentFlags()); err != nil { if err := viper.BindPFlags(cmd.PersistentFlags()); err != nil {
@@ -53,7 +54,7 @@ var updateCmd = &cobra.Command{
return err return err
} }
pubkey, err := readKey(viper.GetString(encryptionFlag), viper.GetString(recipientFlag)) pubkey, err := keys.ReadKey(viper.GetString(encryptionFlag), viper.GetString(recipientFlag))
if err != nil { if err != nil {
return err return err
} }
@@ -63,7 +64,7 @@ var updateCmd = &cobra.Command{
return err return err
} }
privkey, err := readKey(viper.GetString(signatureFlag), viper.GetString(identityFlag)) privkey, err := keys.ReadKey(viper.GetString(signatureFlag), viper.GetString(identityFlag))
if err != nil { if err != nil {
return err return err
} }
@@ -126,7 +127,7 @@ var updateCmd = &cobra.Command{
} }
if len(hdrs) <= i-1 { if len(hdrs) <= i-1 {
return errMissingTarHeader return config.ErrMissingTarHeader
} }
*hdr = *hdrs[i-1] *hdr = *hdrs[i-1]
@@ -144,7 +145,7 @@ func init() {
updateCmd.PersistentFlags().IntP(recordSizeFlag, "z", 20, "Amount of 512-bit blocks per record") updateCmd.PersistentFlags().IntP(recordSizeFlag, "z", 20, "Amount of 512-bit blocks per record")
updateCmd.PersistentFlags().StringP(fromFlag, "f", "", "Path of the file or directory to update") updateCmd.PersistentFlags().StringP(fromFlag, "f", "", "Path of the file or directory to update")
updateCmd.PersistentFlags().BoolP(overwriteFlag, "o", false, "Replace the content on the tape or tar file") updateCmd.PersistentFlags().BoolP(overwriteFlag, "o", false, "Replace the content on the tape or tar file")
updateCmd.PersistentFlags().StringP(compressionLevelFlag, "l", config.CompressionLevelBalanced, fmt.Sprintf("Compression level to use (default %v, available are %v)", config.CompressionLevelBalanced, knownCompressionLevels)) updateCmd.PersistentFlags().StringP(compressionLevelFlag, "l", config.CompressionLevelBalanced, fmt.Sprintf("Compression level to use (default %v, available are %v)", config.CompressionLevelBalanced, config.KnownCompressionLevels))
updateCmd.PersistentFlags().StringP(recipientFlag, "r", "", "Path to public key of recipient to encrypt for") updateCmd.PersistentFlags().StringP(recipientFlag, "r", "", "Path to public key of recipient to encrypt for")
updateCmd.PersistentFlags().StringP(identityFlag, "i", "", "Path to private key to sign with") updateCmd.PersistentFlags().StringP(identityFlag, "i", "", "Path to private key to sign with")
updateCmd.PersistentFlags().StringP(passwordFlag, "p", "", "Password for the private key") updateCmd.PersistentFlags().StringP(passwordFlag, "p", "", "Password for the private key")

View File

@@ -0,0 +1,37 @@
package compression
import (
"github.com/pojntfx/stfs/pkg/config"
)
func CheckCompressionFormat(compressionFormat string) error {
compressionFormatIsKnown := false
for _, candidate := range config.KnownCompressionFormats {
if compressionFormat == candidate {
compressionFormatIsKnown = true
}
}
if !compressionFormatIsKnown {
return config.ErrCompressionFormatUnknown
}
return nil
}
func CheckCompressionLevel(compressionLevel string) error {
compressionLevelIsKnown := false
for _, candidate := range config.KnownCompressionLevels {
if compressionLevel == candidate {
compressionLevelIsKnown = true
}
}
if !compressionLevelIsKnown {
return config.ErrCompressionLevelUnknown
}
return nil
}

View File

@@ -0,0 +1,19 @@
package encryption
import "github.com/pojntfx/stfs/pkg/config"
func CheckEncryptionFormat(encryptionFormat string) error {
encryptionFormatIsKnown := false
for _, candidate := range config.KnownEncryptionFormats {
if encryptionFormat == candidate {
encryptionFormatIsKnown = true
}
}
if !encryptionFormatIsKnown {
return config.ErrEncryptionFormatUnknown
}
return nil
}

View File

@@ -8,10 +8,10 @@ import (
"io" "io"
"filippo.io/age" "filippo.io/age"
"github.com/ProtonMail/go-crypto/openpgp"
"github.com/pojntfx/stfs/internal/noop" "github.com/pojntfx/stfs/internal/noop"
"github.com/pojntfx/stfs/internal/pax" "github.com/pojntfx/stfs/internal/pax"
"github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/config"
"golang.org/x/crypto/openpgp"
) )
func Encrypt( func Encrypt(

24
internal/keys/check.go Normal file
View File

@@ -0,0 +1,24 @@
package keys
import (
"errors"
"os"
"github.com/pojntfx/stfs/pkg/config"
)
var (
ErrKeyNotAccessible = errors.New("key not found or accessible")
)
func CheckKeyAccessible(encryptionFormat string, pathToKey string) error {
if encryptionFormat == config.NoneKey {
return nil
}
if _, err := os.Stat(pathToKey); err != nil {
return ErrKeyNotAccessible
}
return nil
}

15
internal/keys/read.go Normal file
View File

@@ -0,0 +1,15 @@
package keys
import (
"io/ioutil"
"github.com/pojntfx/stfs/pkg/config"
)
func ReadKey(encryptionFormat string, pathToKey string) ([]byte, error) {
if encryptionFormat == config.NoneKey {
return []byte{}, nil
}
return ioutil.ReadFile(pathToKey)
}

View File

@@ -0,0 +1,19 @@
package signature
import "github.com/pojntfx/stfs/pkg/config"
func CheckSignatureFormat(signatureFormat string) error {
signatureFormatIsKnown := false
for _, candidate := range config.KnownSignatureFormats {
if signatureFormat == candidate {
signatureFormatIsKnown = true
}
}
if !signatureFormatIsKnown {
return config.ErrSignatureFormatUnknown
}
return nil
}

View File

@@ -21,3 +21,13 @@ const (
CompressionLevelBalanced = "balanced" CompressionLevelBalanced = "balanced"
CompressionLevelSmallest = "smallest" CompressionLevelSmallest = "smallest"
) )
var (
KnownCompressionLevels = []string{CompressionLevelFastest, CompressionLevelBalanced, CompressionLevelSmallest}
KnownCompressionFormats = []string{NoneKey, CompressionFormatGZipKey, CompressionFormatParallelGZipKey, CompressionFormatLZ4Key, CompressionFormatZStandardKey, CompressionFormatBrotliKey, CompressionFormatBzip2Key, CompressionFormatBzip2ParallelKey}
KnownEncryptionFormats = []string{NoneKey, EncryptionFormatAgeKey, EncryptionFormatPGPKey}
KnownSignatureFormats = []string{NoneKey, SignatureFormatMinisignKey, SignatureFormatPGPKey}
)

View File

@@ -3,6 +3,7 @@ package config
import "errors" import "errors"
var ( var (
ErrEncryptionFormatUnknown = errors.New("unknown encryption format")
ErrEncryptionFormatUnsupported = errors.New("unsupported encryption format") ErrEncryptionFormatUnsupported = errors.New("unsupported encryption format")
ErrIdentityUnparsable = errors.New("recipient could not be parsed") ErrIdentityUnparsable = errors.New("recipient could not be parsed")
@@ -10,6 +11,7 @@ var (
ErrEmbeddedHeaderMissing = errors.New("embedded header is missing") ErrEmbeddedHeaderMissing = errors.New("embedded header is missing")
ErrSignatureFormatUnknown = errors.New("unknown signature format")
ErrSignatureFormatUnsupported = errors.New("unsupported signature format") ErrSignatureFormatUnsupported = errors.New("unsupported signature format")
ErrSignatureFormatOnlyRegularSupport = errors.New("this signature format only supports regular files, not i.e. tape drives") ErrSignatureFormatOnlyRegularSupport = errors.New("this signature format only supports regular files, not i.e. tape drives")
ErrSignatureInvalid = errors.New("signature is invalid") ErrSignatureInvalid = errors.New("signature is invalid")
@@ -17,10 +19,12 @@ var (
ErrKeygenForFormatUnsupported = errors.New("can not generate keys for this format") ErrKeygenForFormatUnsupported = errors.New("can not generate keys for this format")
ErrCompressionFormatUnknown = errors.New("unknown compression format")
ErrCompressionFormatUnsupported = errors.New("unsupported compression format") ErrCompressionFormatUnsupported = errors.New("unsupported compression format")
ErrCompressionFormatOnlyRegularSupport = errors.New("this compression format only supports regular files, not i.e. tape drives") ErrCompressionFormatOnlyRegularSupport = errors.New("this compression format only supports regular files, not i.e. tape drives")
ErrCompressionFormatRequiresLargerRecordSize = errors.New("this compression format requires a larger record size") ErrCompressionFormatRequiresLargerRecordSize = errors.New("this compression format requires a larger record size")
ErrCompressionLevelUnsupported = errors.New("compression level is unsupported") ErrCompressionLevelUnsupported = errors.New("compression level is unsupported")
ErrCompressionLevelUnknown = errors.New("unknown compression level")
ErrMissingTarHeader = errors.New("tar header is missing") ErrMissingTarHeader = errors.New("tar header is missing")
) )

View File

@@ -13,6 +13,7 @@ import (
"github.com/pojntfx/stfs/internal/formatting" "github.com/pojntfx/stfs/internal/formatting"
"github.com/pojntfx/stfs/internal/persisters" "github.com/pojntfx/stfs/internal/persisters"
"github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/config"
"github.com/pojntfx/stfs/pkg/hardware"
"github.com/pojntfx/stfs/pkg/recovery" "github.com/pojntfx/stfs/pkg/recovery"
) )
@@ -88,7 +89,9 @@ func Restore(
} }
if err := recovery.Fetch( if err := recovery.Fetch(
state, hardware.DriveConfig{
Drive: state.Drive,
},
pipes, pipes,
crypto, crypto,

View File

@@ -15,10 +15,11 @@ import (
"github.com/pojntfx/stfs/internal/signature" "github.com/pojntfx/stfs/internal/signature"
"github.com/pojntfx/stfs/internal/tape" "github.com/pojntfx/stfs/internal/tape"
"github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/config"
"github.com/pojntfx/stfs/pkg/hardware"
) )
func Fetch( func Fetch(
state config.StateConfig, state hardware.DriveConfig,
pipes config.PipeConfig, pipes config.PipeConfig,
crypto config.CryptoConfig, crypto config.CryptoConfig,

View File

@@ -14,10 +14,11 @@ import (
"github.com/pojntfx/stfs/internal/signature" "github.com/pojntfx/stfs/internal/signature"
"github.com/pojntfx/stfs/internal/tape" "github.com/pojntfx/stfs/internal/tape"
"github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/config"
"github.com/pojntfx/stfs/pkg/hardware"
) )
func Query( func Query(
state config.StateConfig, state hardware.DriveConfig,
pipes config.PipeConfig, pipes config.PipeConfig,
crypto config.CryptoConfig, crypto config.CryptoConfig,