chore: switch to encryptor module
This commit is contained in:
3
go.mod
3
go.mod
@@ -1,6 +1,6 @@
|
|||||||
module github.com/jkaninda/pg-bkup
|
module github.com/jkaninda/pg-bkup
|
||||||
|
|
||||||
go 1.21.0
|
go 1.23.2
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/ProtonMail/gopenpgp/v2 v2.7.5
|
github.com/ProtonMail/gopenpgp/v2 v2.7.5
|
||||||
@@ -21,6 +21,7 @@ require (
|
|||||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
|
github.com/jkaninda/encryptor v0.0.0-20241013043504-6641402116a4 // indirect
|
||||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
|
|||||||
4
go.sum
4
go.sum
@@ -24,6 +24,10 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l
|
|||||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
|
github.com/jkaninda/encryptor v0.0.0-20241012162628-4c2d36abccd2 h1:UxaO/pwcwKXJvOXs114IiLP5fGcf4EOuh3tUFuJDCD8=
|
||||||
|
github.com/jkaninda/encryptor v0.0.0-20241012162628-4c2d36abccd2/go.mod h1:ZSChjAr+RL0h1fAgnPuINEcwZXxzWrUiTzm/JdVZ8W4=
|
||||||
|
github.com/jkaninda/encryptor v0.0.0-20241013043504-6641402116a4 h1:FfVePubMVwx9LVEisqtgCxP/P83gLhenzYRyyFnKceU=
|
||||||
|
github.com/jkaninda/encryptor v0.0.0-20241013043504-6641402116a4/go.mod h1:9F8ZJ+ZXE8DZBo77+aneGj8LMjrYXX6eFUCC/uqZOUo=
|
||||||
github.com/jlaffaye/ftp v0.2.0 h1:lXNvW7cBu7R/68bknOX3MrRIIqZ61zELs1P2RAiA3lg=
|
github.com/jlaffaye/ftp v0.2.0 h1:lXNvW7cBu7R/68bknOX3MrRIIqZ61zELs1P2RAiA3lg=
|
||||||
github.com/jlaffaye/ftp v0.2.0/go.mod h1:is2Ds5qkhceAPy2xD6RLI6hmp/qysSoymZ+Z2uTnspI=
|
github.com/jlaffaye/ftp v0.2.0/go.mod h1:is2Ds5qkhceAPy2xD6RLI6hmp/qysSoymZ+Z2uTnspI=
|
||||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ package pkg
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/jkaninda/encryptor"
|
||||||
"github.com/jkaninda/pg-bkup/utils"
|
"github.com/jkaninda/pg-bkup/utils"
|
||||||
"github.com/robfig/cron/v3"
|
"github.com/robfig/cron/v3"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@@ -423,16 +424,30 @@ func ftpBackup(db *dbConfig, config *BackupConfig) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func encryptBackup(config *BackupConfig) {
|
func encryptBackup(config *BackupConfig) {
|
||||||
|
backupFile, err := os.ReadFile(filepath.Join(tmpPath, config.backupFileName))
|
||||||
|
outputFile := fmt.Sprintf("%s.%s", filepath.Join(tmpPath, config.backupFileName), gpgExtension)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatal("Error reading backup file: %s ", err)
|
||||||
|
}
|
||||||
if config.usingKey {
|
if config.usingKey {
|
||||||
err := encryptWithGPGPublicKey(filepath.Join(tmpPath, config.backupFileName), config.publicKey)
|
utils.Info("Encrypting backup using public key...")
|
||||||
|
pubKey, err := os.ReadFile(config.publicKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatal("error during encrypting backup %v", err)
|
utils.Fatal("Error reading public key: %s ", err)
|
||||||
}
|
}
|
||||||
|
err = encryptor.EncryptWithPublicKey(backupFile, fmt.Sprintf("%s.%s", filepath.Join(tmpPath, config.backupFileName), gpgExtension), pubKey)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatal("Error encrypting backup file: %v ", err)
|
||||||
|
}
|
||||||
|
utils.Info("Encrypting backup using public key...done")
|
||||||
|
|
||||||
} else if config.passphrase != "" {
|
} else if config.passphrase != "" {
|
||||||
err := encryptWithGPG(filepath.Join(tmpPath, config.backupFileName), config.passphrase)
|
utils.Info("Encrypting backup using passphrase...")
|
||||||
|
err := encryptor.Encrypt(backupFile, outputFile, config.passphrase)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatal("error during encrypting backup %v", err)
|
utils.Fatal("error during encrypting backup %v", err)
|
||||||
}
|
}
|
||||||
|
utils.Info("Encrypting backup using passphrase...done")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
182
pkg/encrypt.go
182
pkg/encrypt.go
@@ -1,182 +0,0 @@
|
|||||||
// Package pkg /
|
|
||||||
/*****
|
|
||||||
@author Jonas Kaninda
|
|
||||||
@license MIT License <https://opensource.org/licenses/MIT>
|
|
||||||
@Copyright © 2024 Jonas Kaninda
|
|
||||||
**/
|
|
||||||
package pkg
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"github.com/ProtonMail/gopenpgp/v2/crypto"
|
|
||||||
"github.com/jkaninda/pg-bkup/utils"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// decryptWithGPG decrypts backup file using a passphrase
|
|
||||||
func decryptWithGPG(inputFile string, passphrase string) error {
|
|
||||||
utils.Info("Decrypting backup using passphrase...")
|
|
||||||
// Read the encrypted file
|
|
||||||
encFileContent, err := os.ReadFile(inputFile)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New(fmt.Sprintf("Error reading encrypted file: %s", err))
|
|
||||||
}
|
|
||||||
// Define the passphrase used to encrypt the file
|
|
||||||
_passphrase := []byte(passphrase)
|
|
||||||
// Create a PGP message object from the encrypted file content
|
|
||||||
encryptedMessage := crypto.NewPGPMessage(encFileContent)
|
|
||||||
// Decrypt the message using the passphrase
|
|
||||||
plainMessage, err := crypto.DecryptMessageWithPassword(encryptedMessage, _passphrase)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New(fmt.Sprintf("Error decrypting file: %s", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save the decrypted file (restore it)
|
|
||||||
err = os.WriteFile(RemoveLastExtension(inputFile), plainMessage.GetBinary(), 0644)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New(fmt.Sprintf("Error saving decrypted file: %s", err))
|
|
||||||
}
|
|
||||||
utils.Info("Decrypting backup using passphrase...done")
|
|
||||||
utils.Info("Backup file decrypted successful!")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// encryptWithGPG encrypts backup using a passphrase
|
|
||||||
func encryptWithGPG(inputFile string, passphrase string) error {
|
|
||||||
utils.Info("Encrypting backup using passphrase...")
|
|
||||||
// Read the file to be encrypted
|
|
||||||
plainFileContent, err := os.ReadFile(inputFile)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New(fmt.Sprintf("Error reading file: %s", err))
|
|
||||||
}
|
|
||||||
// Define the passphrase to encrypt the file
|
|
||||||
_passphrase := []byte(passphrase)
|
|
||||||
|
|
||||||
// Create a message object from the file content
|
|
||||||
message := crypto.NewPlainMessage(plainFileContent)
|
|
||||||
// Encrypt the message using the passphrase
|
|
||||||
encryptedMessage, err := crypto.EncryptMessageWithPassword(message, _passphrase)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New(fmt.Sprintf("Error encrypting backup file: %s", err))
|
|
||||||
}
|
|
||||||
// Save the encrypted .tar file
|
|
||||||
err = os.WriteFile(fmt.Sprintf("%s.%s", inputFile, gpgExtension), encryptedMessage.GetBinary(), 0644)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New(fmt.Sprintf("Error saving encrypted filee: %s", err))
|
|
||||||
}
|
|
||||||
utils.Info("Encrypting backup using passphrase...done")
|
|
||||||
utils.Info("Backup file encrypted successful!")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// encryptWithGPGPublicKey encrypts backup using a public key
|
|
||||||
func encryptWithGPGPublicKey(inputFile string, publicKey string) error {
|
|
||||||
utils.Info("Encrypting backup using public key...")
|
|
||||||
// Read the public key
|
|
||||||
pubKeyBytes, err := os.ReadFile(publicKey)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New(fmt.Sprintf("Error reading public key: %s", err))
|
|
||||||
}
|
|
||||||
// Create a new keyring with the public key
|
|
||||||
publicKeyObj, err := crypto.NewKeyFromArmored(string(pubKeyBytes))
|
|
||||||
if err != nil {
|
|
||||||
return errors.New(fmt.Sprintf("Error parsing public key: %s", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
keyRing, err := crypto.NewKeyRing(publicKeyObj)
|
|
||||||
if err != nil {
|
|
||||||
|
|
||||||
return errors.New(fmt.Sprintf("Error creating key ring: %v", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the file to encryptWithGPGPublicKey
|
|
||||||
fileContent, err := os.ReadFile(inputFile)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New(fmt.Sprintf("Error reading file: %v", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
// encryptWithGPG the file
|
|
||||||
message := crypto.NewPlainMessage(fileContent)
|
|
||||||
encMessage, err := keyRing.Encrypt(message, nil)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New(fmt.Sprintf("Error encrypting file: %v", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save the encrypted file
|
|
||||||
err = os.WriteFile(fmt.Sprintf("%s.%s", inputFile, gpgExtension), encMessage.GetBinary(), 0644)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New(fmt.Sprintf("Error saving encrypted file: %v", err))
|
|
||||||
}
|
|
||||||
utils.Info("Encrypting backup using public key...done")
|
|
||||||
utils.Info("Backup file encrypted successful!")
|
|
||||||
return nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// decryptWithGPGPrivateKey decrypts backup file using a private key and passphrase.
|
|
||||||
// privateKey GPG private key
|
|
||||||
// passphrase GPG passphrase
|
|
||||||
func decryptWithGPGPrivateKey(inputFile, privateKey, passphrase string) error {
|
|
||||||
utils.Info("Encrypting backup using private key...")
|
|
||||||
|
|
||||||
// Read the private key
|
|
||||||
priKeyBytes, err := os.ReadFile(privateKey)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New(fmt.Sprintf("Error reading private key: %s", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the password for the private key (if it’s password-protected)
|
|
||||||
password := []byte(passphrase)
|
|
||||||
|
|
||||||
// Create a key object from the armored private key
|
|
||||||
privateKeyObj, err := crypto.NewKeyFromArmored(string(priKeyBytes))
|
|
||||||
if err != nil {
|
|
||||||
return errors.New(fmt.Sprintf("Error parsing private key: %s", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unlock the private key with the password
|
|
||||||
if passphrase != "" {
|
|
||||||
// Unlock the private key with the password
|
|
||||||
_, err = privateKeyObj.Unlock(password)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New(fmt.Sprintf("Error unlocking private key: %s", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new keyring with the private key
|
|
||||||
keyRing, err := crypto.NewKeyRing(privateKeyObj)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New(fmt.Sprintf("Error creating key ring: %v", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the encrypted file
|
|
||||||
encFileContent, err := os.ReadFile(inputFile)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New(fmt.Sprintf("Error reading encrypted file: %s", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
// decryptWithGPG the file
|
|
||||||
encryptedMessage := crypto.NewPGPMessage(encFileContent)
|
|
||||||
message, err := keyRing.Decrypt(encryptedMessage, nil, 0)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New(fmt.Sprintf("Error decrypting file: %s", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save the decrypted file
|
|
||||||
err = os.WriteFile(RemoveLastExtension(inputFile), message.GetBinary(), 0644)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New(fmt.Sprintf("Error saving decrypted file: %s", err))
|
|
||||||
}
|
|
||||||
utils.Info("Encrypting backup using public key...done")
|
|
||||||
fmt.Println("File successfully decrypted!")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
func RemoveLastExtension(filename string) string {
|
|
||||||
if idx := strings.LastIndex(filename, "."); idx != -1 {
|
|
||||||
return filename[:idx]
|
|
||||||
}
|
|
||||||
return filename
|
|
||||||
}
|
|
||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -233,3 +234,9 @@ func checkConfigFile(filePath string) (string, error) {
|
|||||||
// Return an error if neither file exists
|
// Return an error if neither file exists
|
||||||
return "", fmt.Errorf("no config file found")
|
return "", fmt.Errorf("no config file found")
|
||||||
}
|
}
|
||||||
|
func RemoveLastExtension(filename string) string {
|
||||||
|
if idx := strings.LastIndex(filename, "."); idx != -1 {
|
||||||
|
return filename[:idx]
|
||||||
|
}
|
||||||
|
return filename
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
package pkg
|
package pkg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/jkaninda/encryptor"
|
||||||
"github.com/jkaninda/pg-bkup/utils"
|
"github.com/jkaninda/pg-bkup/utils"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"os"
|
"os"
|
||||||
@@ -68,24 +69,40 @@ func RestoreDatabase(db *dbConfig, conf *RestoreConfig) {
|
|||||||
utils.Fatal("Error, file required")
|
utils.Fatal("Error, file required")
|
||||||
}
|
}
|
||||||
extension := filepath.Ext(filepath.Join(tmpPath, conf.file))
|
extension := filepath.Ext(filepath.Join(tmpPath, conf.file))
|
||||||
|
rFile, err := os.ReadFile(filepath.Join(tmpPath, conf.file))
|
||||||
|
outputFile := RemoveLastExtension(filepath.Join(tmpPath, conf.file))
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatal("Error reading backup file: %s ", err)
|
||||||
|
}
|
||||||
|
|
||||||
if extension == ".gpg" {
|
if extension == ".gpg" {
|
||||||
|
|
||||||
if conf.usingKey {
|
if conf.usingKey {
|
||||||
|
utils.Info("Decrypting backup using private key...")
|
||||||
utils.Warn("Backup decryption using a private key is not fully supported")
|
utils.Warn("Backup decryption using a private key is not fully supported")
|
||||||
err := decryptWithGPGPrivateKey(filepath.Join(tmpPath, conf.file), conf.privateKey, conf.passphrase)
|
prKey, err := os.ReadFile(conf.privateKey)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatal("Error reading public key: %s ", err)
|
||||||
|
}
|
||||||
|
err = encryptor.DecryptWithPrivateKey(rFile, outputFile, prKey, conf.passphrase)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatal("error during decrypting backup %v", err)
|
utils.Fatal("error during decrypting backup %v", err)
|
||||||
}
|
}
|
||||||
|
utils.Info("Decrypting backup using private key...done")
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if conf.passphrase == "" {
|
if conf.passphrase == "" {
|
||||||
utils.Error("Error, passphrase or private key required")
|
utils.Error("Error, passphrase or private key required")
|
||||||
utils.Fatal("Your file seems to be a GPG file.\nYou need to provide GPG keys. GPG_PASSPHRASE or GPG_PRIVATE_KEY environment variable is required.")
|
utils.Fatal("Your file seems to be a GPG file.\nYou need to provide GPG keys. GPG_PASSPHRASE or GPG_PRIVATE_KEY environment variable is required.")
|
||||||
} else {
|
} else {
|
||||||
|
utils.Info("Decrypting backup using passphrase...")
|
||||||
|
|
||||||
//decryptWithGPG file
|
//decryptWithGPG file
|
||||||
err := decryptWithGPG(filepath.Join(tmpPath, conf.file), conf.passphrase)
|
err := encryptor.Decrypt(rFile, outputFile, conf.passphrase)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatal("Error decrypting file %s %v", file, err)
|
utils.Fatal("Error decrypting file %s %v", file, err)
|
||||||
}
|
}
|
||||||
|
utils.Info("Decrypting backup using private key...done")
|
||||||
//Update file name
|
//Update file name
|
||||||
conf.file = RemoveLastExtension(file)
|
conf.file = RemoveLastExtension(file)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user