From 43e23190bc822e30c96c0d93042e0a259a331455 Mon Sep 17 00:00:00 2001 From: Felix Pojtinger Date: Sat, 4 Dec 2021 16:44:31 +0100 Subject: [PATCH] feat: Add basic signature support to `archive` cmd based on Minisign --- cmd/stbak/cmd/archive.go | 104 ++++++++++++++++++++++++++------ cmd/stbak/cmd/delete.go | 2 +- cmd/stbak/cmd/drive_eject.go | 2 +- cmd/stbak/cmd/drive_tell.go | 2 +- cmd/stbak/cmd/move.go | 10 +-- cmd/stbak/cmd/recovery_fetch.go | 18 +++--- cmd/stbak/cmd/recovery_index.go | 6 +- cmd/stbak/cmd/recovery_query.go | 2 +- cmd/stbak/cmd/restore.go | 18 +++--- cmd/stbak/cmd/root.go | 44 ++++++++++---- cmd/stbak/cmd/update.go | 8 +-- go.mod | 1 + go.sum | 5 ++ pkg/pax/stfs.go | 2 + 14 files changed, 162 insertions(+), 62 deletions(-) diff --git a/cmd/stbak/cmd/archive.go b/cmd/stbak/cmd/archive.go index 2f11a3f..e2a5927 100644 --- a/cmd/stbak/cmd/archive.go +++ b/cmd/stbak/cmd/archive.go @@ -16,6 +16,7 @@ import ( "path/filepath" "strconv" + "aead.dev/minisign" "filippo.io/age" "github.com/ProtonMail/go-crypto/openpgp" "github.com/andybalholm/brotli" @@ -37,7 +38,7 @@ import ( const ( recordSizeFlag = "record-size" - srcFlag = "src" + fromFlag = "from" overwriteFlag = "overwrite" compressionLevelFlag = "compression-level" @@ -76,7 +77,11 @@ var archiveCmd = &cobra.Command{ return err } - return checkKeyAccessible(viper.GetString(encryptionFlag), viper.GetString(recipientFlag)) + if err := checkKeyAccessible(viper.GetString(encryptionFlag), viper.GetString(recipientFlag)); err != nil { + return err + } + + return checkKeyAccessible(viper.GetString(signatureFlag), viper.GetString(identityFlag)) }, RunE: func(cmd *cobra.Command, args []string) error { if viper.GetBool(verboseFlag) { @@ -110,22 +115,34 @@ var archiveCmd = &cobra.Command{ return err } + privkey, err := readKey(viper.GetString(signatureFlag), viper.GetString(identityFlag)) + if err != nil { + return err + } + + identity, err := parseSignerIdentity(viper.GetString(signatureFlag), privkey, viper.GetString(passwordFlag)) + if err != nil { + return err + } + hdrs, err := archive( - viper.GetString(tapeFlag), + viper.GetString(driveFlag), viper.GetInt(recordSizeFlag), - viper.GetString(srcFlag), + viper.GetString(fromFlag), viper.GetBool(overwriteFlag), viper.GetString(compressionFlag), viper.GetString(compressionLevelFlag), viper.GetString(encryptionFlag), recipient, + viper.GetString(signatureFlag), + identity, ) if err != nil { return err } return index( - viper.GetString(tapeFlag), + viper.GetString(driveFlag), viper.GetString(metadataFlag), viper.GetInt(recordSizeFlag), int(lastIndexedRecord), @@ -156,6 +173,8 @@ func archive( compressionLevel string, encryptionFormat string, recipient interface{}, + signatureFormat string, + identity interface{}, ) ([]*tar.Header, error) { dirty := false tw, isRegular, cleanup, err := openTapeWriter(tape) @@ -268,13 +287,18 @@ func archive( return err } + signer, sign, err := sign(file, signatureFormat, identity) + if err != nil { + return err + } + if isRegular { - if _, err := io.Copy(compressor, file); err != nil { + if _, err := io.Copy(compressor, signer); err != nil { return err } } else { buf := make([]byte, controllers.BlockSize*recordSize) - if _, err := io.CopyBuffer(compressor, file, buf); err != nil { + if _, err := io.CopyBuffer(compressor, signer, buf); err != nil { return err } } @@ -299,6 +323,9 @@ func archive( hdr.PAXRecords = map[string]string{} } hdr.PAXRecords[pax.STFSRecordUncompressedSize] = strconv.Itoa(int(hdr.Size)) + if signature := sign(); signature != "" { + hdr.PAXRecords[pax.STFSRecordSignature] = signature + } hdr.Size = int64(fileSizeCounter.BytesRead) hdr.Name, err = addSuffix(hdr.Name, compressionFormat, encryptionFormat) @@ -390,7 +417,7 @@ func archive( } func checkKeyAccessible(encryptionFormat string, pathToKey string) error { - if encryptionFormat == encryptionFormatNoneKey { + if encryptionFormat == noneKey { return nil } @@ -402,7 +429,7 @@ func checkKeyAccessible(encryptionFormat string, pathToKey string) error { } func readKey(encryptionFormat string, pathToKey string) ([]byte, error) { - if encryptionFormat == encryptionFormatNoneKey { + if encryptionFormat == noneKey { return []byte{}, nil } @@ -430,7 +457,7 @@ func encryptHeader( encryptionFormat string, recipient interface{}, ) error { - if encryptionFormat == encryptionFormatNoneKey { + if encryptionFormat == noneKey { return nil } @@ -471,7 +498,7 @@ func addSuffix(name string, compressionFormat string, encryptionFormat string) ( fallthrough case compressionFormatBzip2ParallelKey: name += compressionFormatBzip2Suffix - case compressionFormatNoneKey: + case noneKey: default: return "", errUnsupportedCompressionFormat } @@ -481,7 +508,7 @@ func addSuffix(name string, compressionFormat string, encryptionFormat string) ( name += encryptionFormatAgeSuffix case encryptionFormatPGPKey: name += encryptionFormatPGPSuffix - case compressionFormatNoneKey: + case noneKey: default: return "", errUnsupportedEncryptionFormat } @@ -498,7 +525,7 @@ func parseRecipient( return age.ParseX25519Recipient(string(pubkey)) case encryptionFormatPGPKey: return openpgp.ReadKeyRing(bytes.NewBuffer(pubkey)) - case encryptionFormatNoneKey: + case noneKey: return pubkey, nil default: return nil, errUnsupportedEncryptionFormat @@ -525,13 +552,54 @@ func encrypt( } return openpgp.Encrypt(dst, recipient, nil, nil, nil) - case encryptionFormatNoneKey: + case noneKey: return noop.AddClose(dst), nil default: return nil, errUnsupportedEncryptionFormat } } +func parseSignerIdentity( + signatureFormat string, + privkey []byte, + password string, +) (interface{}, error) { + switch signatureFormat { + case signatureFormatMinisignKey: + return minisign.DecryptKey(password, privkey) + case noneKey: + return privkey, nil + default: + return nil, errUnsupportedSignatureFormat + } +} + +func sign( + src io.Reader, + signatureFormat string, + identity interface{}, +) (io.Reader, func() string, error) { + switch signatureFormat { + case signatureFormatMinisignKey: + identity, ok := identity.(minisign.PrivateKey) + if !ok { + return nil, nil, errIdentityUnparsable + } + + signer := minisign.NewReader(src) + + return signer, func() string { + return base64.StdEncoding.EncodeToString(signer.Sign(identity)) + }, nil + case noneKey: + return io.NopCloser(src), func() string { + return "" + }, nil + default: + return nil, nil, errUnsupportedSignatureFormat + } +} + func encryptString( src string, encryptionFormat string, @@ -580,7 +648,7 @@ func encryptString( } return base64.StdEncoding.EncodeToString(out.Bytes()), nil - case encryptionFormatNoneKey: + case noneKey: return src, nil default: return "", errUnsupportedEncryptionFormat @@ -704,7 +772,7 @@ func compress( } return noop.AddFlush(bz), nil - case compressionFormatNoneKey: + case noneKey: return noop.AddFlush(noop.AddClose(dst)), nil default: return nil, errUnsupportedCompressionFormat @@ -713,10 +781,12 @@ func compress( func init() { archiveCmd.PersistentFlags().IntP(recordSizeFlag, "z", 20, "Amount of 512-bit blocks per record") - archiveCmd.PersistentFlags().StringP(srcFlag, "s", ".", "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().StringP(compressionLevelFlag, "l", compressionLevelBalanced, fmt.Sprintf("Compression level to use (default %v, available are %v)", compressionLevelBalanced, knownCompressionLevels)) 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(passwordFlag, "p", "", "Password for the private key") viper.AutomaticEnv() diff --git a/cmd/stbak/cmd/delete.go b/cmd/stbak/cmd/delete.go index 831563b..10ae79a 100644 --- a/cmd/stbak/cmd/delete.go +++ b/cmd/stbak/cmd/delete.go @@ -53,7 +53,7 @@ var deleteCmd = &cobra.Command{ } return delete( - viper.GetString(tapeFlag), + viper.GetString(driveFlag), viper.GetString(metadataFlag), viper.GetString(nameFlag), viper.GetString(encryptionFlag), diff --git a/cmd/stbak/cmd/drive_eject.go b/cmd/stbak/cmd/drive_eject.go index 584feeb..0ec9f12 100644 --- a/cmd/stbak/cmd/drive_eject.go +++ b/cmd/stbak/cmd/drive_eject.go @@ -21,7 +21,7 @@ var driveEjectCmd = &cobra.Command{ boil.DebugMode = true } - f, err := os.OpenFile(viper.GetString(tapeFlag), os.O_RDONLY, os.ModeCharDevice) + f, err := os.OpenFile(viper.GetString(driveFlag), os.O_RDONLY, os.ModeCharDevice) if err != nil { panic(err) } diff --git a/cmd/stbak/cmd/drive_tell.go b/cmd/stbak/cmd/drive_tell.go index 2af96fa..dbc84ed 100644 --- a/cmd/stbak/cmd/drive_tell.go +++ b/cmd/stbak/cmd/drive_tell.go @@ -22,7 +22,7 @@ var driveTellCmd = &cobra.Command{ boil.DebugMode = true } - f, err := os.OpenFile(viper.GetString(tapeFlag), os.O_RDONLY, os.ModeCharDevice) + f, err := os.OpenFile(viper.GetString(driveFlag), os.O_RDONLY, os.ModeCharDevice) if err != nil { panic(err) } diff --git a/cmd/stbak/cmd/move.go b/cmd/stbak/cmd/move.go index f22282d..8d5551f 100644 --- a/cmd/stbak/cmd/move.go +++ b/cmd/stbak/cmd/move.go @@ -46,10 +46,10 @@ var moveCmd = &cobra.Command{ } return move( - viper.GetString(tapeFlag), + viper.GetString(driveFlag), viper.GetString(metadataFlag), - viper.GetString(srcFlag), - viper.GetString(dstFlag), + viper.GetString(fromFlag), + viper.GetString(toFlag), viper.GetString(encryptionFlag), recipient, ) @@ -135,8 +135,8 @@ func move( func init() { moveCmd.PersistentFlags().IntP(recordSizeFlag, "z", 20, "Amount of 512-bit blocks per record") - moveCmd.PersistentFlags().StringP(srcFlag, "s", "", "Current path of the file or directory to move") - moveCmd.PersistentFlags().StringP(dstFlag, "d", "", "Path to move the file or directory to") + moveCmd.PersistentFlags().StringP(fromFlag, "f", "", "Current path of the file or directory to move") + moveCmd.PersistentFlags().StringP(toFlag, "t", "", "Path to move the file or directory to") moveCmd.PersistentFlags().StringP(recipientFlag, "r", "", "Path to public key of recipient to encrypt for") viper.AutomaticEnv() diff --git a/cmd/stbak/cmd/recovery_fetch.go b/cmd/stbak/cmd/recovery_fetch.go index 26231a4..0f60284 100644 --- a/cmd/stbak/cmd/recovery_fetch.go +++ b/cmd/stbak/cmd/recovery_fetch.go @@ -32,7 +32,7 @@ import ( const ( recordFlag = "record" blockFlag = "block" - dstFlag = "dst" + toFlag = "to" previewFlag = "preview" ) @@ -72,11 +72,11 @@ var recoveryFetchCmd = &cobra.Command{ } return restoreFromRecordAndBlock( - viper.GetString(tapeFlag), + viper.GetString(driveFlag), viper.GetInt(recordSizeFlag), viper.GetInt(recordFlag), viper.GetInt(blockFlag), - viper.GetString(dstFlag), + viper.GetString(toFlag), viper.GetBool(previewFlag), true, viper.GetString(compressionFlag), @@ -240,7 +240,7 @@ func decompress( bz := pbzip2.NewReader(context.Background(), src) return io.NopCloser(bz), nil - case compressionFormatNoneKey: + case noneKey: return io.NopCloser(src), nil default: return nil, errUnsupportedCompressionFormat @@ -252,7 +252,7 @@ func decryptHeader( encryptionFormat string, identity interface{}, ) error { - if encryptionFormat == encryptionFormatNoneKey { + if encryptionFormat == noneKey { return nil } @@ -328,7 +328,7 @@ func parseIdentity( } return identities, nil - case encryptionFormatNoneKey: + case noneKey: return privkey, nil default: return nil, errUnsupportedEncryptionFormat @@ -385,7 +385,7 @@ func decryptString( } return out.String(), nil - case encryptionFormatNoneKey: + case noneKey: return src, nil default: return "", errUnsupportedEncryptionFormat @@ -422,7 +422,7 @@ func decrypt( } return io.NopCloser(r.UnverifiedBody), nil - case encryptionFormatNoneKey: + case noneKey: return io.NopCloser(src), nil default: return nil, errUnsupportedEncryptionFormat @@ -433,7 +433,7 @@ func init() { recoveryFetchCmd.PersistentFlags().IntP(recordSizeFlag, "z", 20, "Amount of 512-bit blocks per record") recoveryFetchCmd.PersistentFlags().IntP(recordFlag, "k", 0, "Record to seek too") recoveryFetchCmd.PersistentFlags().IntP(blockFlag, "b", 0, "Block in record to seek too") - recoveryFetchCmd.PersistentFlags().StringP(dstFlag, "d", "", "File to restore to (archived name by default)") + recoveryFetchCmd.PersistentFlags().StringP(toFlag, "t", "", "File to restore to (archived name by default)") recoveryFetchCmd.PersistentFlags().BoolP(previewFlag, "w", false, "Only read the header") recoveryFetchCmd.PersistentFlags().StringP(identityFlag, "i", "", "Path to private key of recipient that has been encrypted for") recoveryFetchCmd.PersistentFlags().StringP(passwordFlag, "p", "", "Password for the private key") diff --git a/cmd/stbak/cmd/recovery_index.go b/cmd/stbak/cmd/recovery_index.go index 1a827f1..fb19ee4 100644 --- a/cmd/stbak/cmd/recovery_index.go +++ b/cmd/stbak/cmd/recovery_index.go @@ -53,7 +53,7 @@ var recoveryIndexCmd = &cobra.Command{ } return index( - viper.GetString(tapeFlag), + viper.GetString(driveFlag), viper.GetString(metadataFlag), viper.GetInt(recordSizeFlag), viper.GetInt(recordFlag), @@ -421,7 +421,7 @@ func removeSuffix(name string, compressionFormat string, encryptionFormat string name = strings.TrimSuffix(name, encryptionFormatAgeSuffix) case encryptionFormatPGPKey: name = strings.TrimSuffix(name, encryptionFormatPGPSuffix) - case encryptionFormatNoneKey: + case noneKey: default: return "", errUnsupportedEncryptionFormat } @@ -441,7 +441,7 @@ func removeSuffix(name string, compressionFormat string, encryptionFormat string fallthrough case compressionFormatBzip2ParallelKey: name = strings.TrimSuffix(name, compressionFormatBzip2Suffix) - case compressionFormatNoneKey: + case noneKey: default: return "", errUnsupportedCompressionFormat } diff --git a/cmd/stbak/cmd/recovery_query.go b/cmd/stbak/cmd/recovery_query.go index a02afb3..5743b86 100644 --- a/cmd/stbak/cmd/recovery_query.go +++ b/cmd/stbak/cmd/recovery_query.go @@ -45,7 +45,7 @@ var recoveryQueryCmd = &cobra.Command{ } return query( - viper.GetString(tapeFlag), + viper.GetString(driveFlag), viper.GetInt(recordFlag), viper.GetInt(blockFlag), viper.GetInt(recordSizeFlag), diff --git a/cmd/stbak/cmd/restore.go b/cmd/stbak/cmd/restore.go index 30ee1b8..dc99b9a 100644 --- a/cmd/stbak/cmd/restore.go +++ b/cmd/stbak/cmd/restore.go @@ -57,7 +57,7 @@ var restoreCmd = &cobra.Command{ } headersToRestore := []*models.Header{} - src := strings.TrimSuffix(viper.GetString(srcFlag), "/") + src := strings.TrimSuffix(viper.GetString(fromFlag), "/") dbhdr, err := metadataPersister.GetHeader(context.Background(), src) if err != nil { if err == sql.ErrNoRows { @@ -100,20 +100,20 @@ var restoreCmd = &cobra.Command{ } dst := dbhdr.Name - if viper.GetString(dstFlag) != "" { + if viper.GetString(toFlag) != "" { if viper.GetBool(flattenFlag) { - dst = viper.GetString(dstFlag) + dst = viper.GetString(toFlag) } else { - dst = filepath.Join(viper.GetString(dstFlag), strings.TrimPrefix(dst, viper.GetString(srcFlag))) + dst = filepath.Join(viper.GetString(toFlag), strings.TrimPrefix(dst, viper.GetString(fromFlag))) - if strings.TrimSuffix(dst, "/") == strings.TrimSuffix(viper.GetString(dstFlag), "/") { + if strings.TrimSuffix(dst, "/") == strings.TrimSuffix(viper.GetString(toFlag), "/") { dst = filepath.Join(dst, path.Base(dbhdr.Name)) // Append the name so we don't overwrite } } } if err := restoreFromRecordAndBlock( - viper.GetString(tapeFlag), + viper.GetString(driveFlag), viper.GetInt(recordSizeFlag), int(dbhdr.Record), int(dbhdr.Block), @@ -134,9 +134,9 @@ var restoreCmd = &cobra.Command{ func init() { restoreCmd.PersistentFlags().IntP(recordSizeFlag, "z", 20, "Amount of 512-bit blocks per record") - restoreCmd.PersistentFlags().StringP(srcFlag, "s", "", "File or directory to restore") - restoreCmd.PersistentFlags().StringP(dstFlag, "d", "", "File or directory restore to (archived name by default)") - restoreCmd.PersistentFlags().BoolP(flattenFlag, "f", false, "Ignore the folder hierarchy on the tape or tar file") + restoreCmd.PersistentFlags().StringP(fromFlag, "f", "", "File or directory to restore") + restoreCmd.PersistentFlags().StringP(toFlag, "t", "", "File or directory restore to (archived name by default)") + restoreCmd.PersistentFlags().BoolP(flattenFlag, "a", false, "Ignore the folder hierarchy on the tape or tar file") restoreCmd.PersistentFlags().StringP(identityFlag, "i", "", "Path to private key of recipient that has been encrypted for") restoreCmd.PersistentFlags().StringP(passwordFlag, "p", "", "Password for the private key") diff --git a/cmd/stbak/cmd/root.go b/cmd/stbak/cmd/root.go index a357809..e9c4139 100644 --- a/cmd/stbak/cmd/root.go +++ b/cmd/stbak/cmd/root.go @@ -12,12 +12,13 @@ import ( ) const ( - tapeFlag = "tape" - metadataFlag = "metadata" - verboseFlag = "verbose" + driveFlag = "drive" + metadataFlag = "metadata" + verboseFlag = "verbose" + compressionFlag = "compression" - compressionFormatNoneKey = "none" + noneKey = "none" compressionFormatGZipKey = "gzip" compressionFormatGZipSuffix = ".gz" @@ -40,26 +41,33 @@ const ( encryptionFlag = "encryption" - encryptionFormatNoneKey = "none" - encryptionFormatAgeKey = "age" encryptionFormatAgeSuffix = ".age" encryptionFormatPGPKey = "pgp" encryptionFormatPGPSuffix = ".pgp" + + signatureFlag = "signature" + + signatureFormatMinisignKey = "minisign" ) var ( - knownCompressionFormats = []string{compressionFormatNoneKey, compressionFormatGZipKey, compressionFormatParallelGZipKey, compressionFormatLZ4Key, compressionFormatZStandardKey, compressionFormatBrotliKey, compressionFormatBzip2Key, compressionFormatBzip2ParallelKey} + knownCompressionFormats = []string{noneKey, compressionFormatGZipKey, compressionFormatParallelGZipKey, compressionFormatLZ4Key, compressionFormatZStandardKey, compressionFormatBrotliKey, compressionFormatBzip2Key, compressionFormatBzip2ParallelKey} errUnknownCompressionFormat = errors.New("unknown compression format") errUnsupportedCompressionFormat = errors.New("unsupported compression format") - knownEncryptionFormats = []string{encryptionFormatNoneKey, encryptionFormatAgeKey, encryptionFormatPGPKey} + knownEncryptionFormats = []string{noneKey, encryptionFormatAgeKey, encryptionFormatPGPKey} errUnknownEncryptionFormat = errors.New("unknown encryption format") errUnsupportedEncryptionFormat = errors.New("unsupported encryption format") errKeygenForEncryptionFormatUnsupported = errors.New("can not generate keys for this encryption format") + + knownSignatureFormats = []string{noneKey, signatureFormatMinisignKey} + + errUnknownSignatureFormat = errors.New("unknown signature format") + errUnsupportedSignatureFormat = errors.New("unsupported signature format") ) var rootCmd = &cobra.Command{ @@ -99,6 +107,19 @@ https://github.com/pojntfx/stfs`, return errUnknownEncryptionFormat } + signatureFormatIsKnown := false + signatureFormat := viper.GetString(signatureFlag) + + for _, candidate := range knownSignatureFormats { + if signatureFormat == candidate { + signatureFormatIsKnown = true + } + } + + if !signatureFormatIsKnown { + return errUnknownSignatureFormat + } + return nil }, } @@ -111,11 +132,12 @@ func Execute() { } metadataPath := filepath.Join(home, ".local", "share", "stbak", "var", "lib", "stbak", "metadata.sqlite") - rootCmd.PersistentFlags().StringP(tapeFlag, "t", "/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().BoolP(verboseFlag, "v", false, "Enable verbose logging") - rootCmd.PersistentFlags().StringP(compressionFlag, "c", compressionFormatNoneKey, fmt.Sprintf("Compression format to use (default %v, available are %v)", compressionFormatNoneKey, knownCompressionFormats)) - rootCmd.PersistentFlags().StringP(encryptionFlag, "e", encryptionFormatNoneKey, fmt.Sprintf("Encryption format to use (default %v, available are %v)", encryptionFormatNoneKey, knownEncryptionFormats)) + rootCmd.PersistentFlags().StringP(compressionFlag, "c", noneKey, fmt.Sprintf("Compression format to use (default %v, available are %v)", noneKey, knownCompressionFormats)) + rootCmd.PersistentFlags().StringP(encryptionFlag, "e", noneKey, fmt.Sprintf("Encryption format to use (default %v, available are %v)", noneKey, knownEncryptionFormats)) + rootCmd.PersistentFlags().StringP(signatureFlag, "s", noneKey, fmt.Sprintf("Signature format to use (default %v, available are %v)", noneKey, knownSignatureFormats)) if err := viper.BindPFlags(rootCmd.PersistentFlags()); err != nil { panic(err) diff --git a/cmd/stbak/cmd/update.go b/cmd/stbak/cmd/update.go index adb8804..c0450a1 100644 --- a/cmd/stbak/cmd/update.go +++ b/cmd/stbak/cmd/update.go @@ -66,9 +66,9 @@ var updateCmd = &cobra.Command{ } hdrs, err := update( - viper.GetString(tapeFlag), + viper.GetString(driveFlag), viper.GetInt(recordSizeFlag), - viper.GetString(srcFlag), + viper.GetString(fromFlag), viper.GetBool(overwriteFlag), viper.GetString(compressionFlag), viper.GetString(compressionLevelFlag), @@ -80,7 +80,7 @@ var updateCmd = &cobra.Command{ } return index( - viper.GetString(tapeFlag), + viper.GetString(driveFlag), viper.GetString(metadataFlag), viper.GetInt(recordSizeFlag), int(lastIndexedRecord), @@ -321,7 +321,7 @@ func update( func init() { updateCmd.PersistentFlags().IntP(recordSizeFlag, "z", 20, "Amount of 512-bit blocks per record") - updateCmd.PersistentFlags().StringP(srcFlag, "s", "", "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().StringP(compressionLevelFlag, "l", compressionLevelBalanced, fmt.Sprintf("Compression level to use (default %v, available are %v)", compressionLevelBalanced, knownCompressionLevels)) updateCmd.PersistentFlags().StringP(recipientFlag, "r", "", "Path to public key of recipient to encrypt for") diff --git a/go.mod b/go.mod index e272c87..02a490a 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/pojntfx/stfs go 1.17 require ( + aead.dev/minisign v0.2.0 filippo.io/age v1.0.0 github.com/ProtonMail/go-crypto v0.0.0-20211112122917-428f8eabeeb3 github.com/ProtonMail/gopenpgp/v2 v2.3.0 diff --git a/go.sum b/go.sum index 4207798..3b2bc02 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +aead.dev/minisign v0.2.0 h1:kAWrq/hBRu4AARY6AlciO83xhNnW9UaC8YipS2uhLPk= +aead.dev/minisign v0.2.0/go.mod h1:zdq6LdSd9TbuSxchxwhpA9zEb9YXcVGoE8JakuiGaIQ= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -468,6 +470,7 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= @@ -623,6 +626,7 @@ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210228012217-479acdf4ea46/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -640,6 +644,7 @@ golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1 h1:kwrAHlwJ0DUBZwQ238v+Uod/3eZ8B2K5rYsUHBQvzmI= golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= diff --git a/pkg/pax/stfs.go b/pkg/pax/stfs.go index ddf1f2d..f978151 100644 --- a/pkg/pax/stfs.go +++ b/pkg/pax/stfs.go @@ -21,6 +21,8 @@ const ( STFSRecordUncompressedSize = STFSPrefix + "UncompressedSize" + STFSRecordSignature = STFSPrefix + "Signature" + STFSEmbeddedHeader = STFSPrefix + "EmbeddedHeader" )