Skip to content

Commit

Permalink
Encrypt package created
Browse files Browse the repository at this point in the history
  • Loading branch information
vpoluyaktov committed Nov 5, 2023
1 parent 49bc421 commit 1fe6004
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 7 deletions.
25 changes: 23 additions & 2 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ func Load() {
config.SampleRate = "44100"
config.MaxFileSize = "100 Mb"
config.CopyToAudiobookshelf = true
config.AudiobookshelfUser = "admin"
config.AudiobookshelfDir = "/mnt/NAS/Audiobooks/Internet Archive"
config.ShortenTitles = true
config.Genres = []string{
Expand Down Expand Up @@ -250,11 +251,31 @@ func SetAudiobookshelfUser(u string) {
}

func AudiobookshelfPassword() string {
return configInstance.AudiobookshelfPassword
base64 := configInstance.AudiobookshelfPassword
if base64 == "" {
return ""
}
encrypted, err := utils.DecodeBase64(base64)
if err != nil {
logger.Error("Can't decode base64 password: " + err.Error())
return ""
}
decrypted, err := utils.DecryptString(encrypted)
if err != nil {
logger.Error("Can't decrypt password: " + err.Error())
return ""
}
return decrypted
}

func SetAudiobookshelfPassword(p string) {
configInstance.AudiobookshelfPassword = p

encrypted, err := utils.EncryptString(p)
if err != nil {
logger.Error("Can't encrypt password: " + err.Error())
}
base64 := utils.EncodeBase64(encrypted)
configInstance.AudiobookshelfPassword = base64
}

func AudiobookshelfLibrary() string {
Expand Down
23 changes: 18 additions & 5 deletions internal/ui/configPage.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,14 @@ type ConfigPage struct {
configCopy config.Config
configSection *tview.Grid

logFileNameField *tview.InputField
logLevelField *tview.DropDown
useMockField *tview.Checkbox
saveMockField *tview.Checkbox
logFileNameField *tview.InputField
logLevelField *tview.DropDown
useMockField *tview.Checkbox
saveMockField *tview.Checkbox
audiobookshelfUrl *tview.InputField
audiobookshelfDir *tview.InputField
audiobookshelfUser *tview.InputField
audiobookshelfPassword *tview.InputField

saveConfigButton *tview.Button
cancelButton *tview.Button
Expand All @@ -34,7 +38,7 @@ func newConfigPage(dispatcher *mq.Dispatcher) *ConfigPage {
p.mq.RegisterListener(mq.ConfigPage, p.dispatchMessage)

p.grid = tview.NewGrid()
p.grid.SetRows(-1, -1, -1)
p.grid.SetRows(-1)
p.grid.SetColumns(0)

// config section
Expand All @@ -50,6 +54,11 @@ func newConfigPage(dispatcher *mq.Dispatcher) *ConfigPage {
p.useMockField = f.AddCheckbox("Use mock:", false, func(t bool) { p.configCopy.UseMock = t })
p.saveMockField = f.AddCheckbox("Save mock:", false, func(t bool) { p.configCopy.SaveMock = t })

p.audiobookshelfUrl = f.AddInputField("Audiobookshelf Server URL:", "", 40, nil, func(t string) { p.configCopy.AudiobookshelfUrl = t })
p.audiobookshelfDir = f.AddInputField("Audiobookshelf Server Directory:", "", 60, nil, func(t string) { p.configCopy.AudiobookshelfDir = t })
p.audiobookshelfUser = f.AddInputField("Audiobookshelf Server User:", "", 40, nil, func(t string) { p.configCopy.AudiobookshelfUser = t })
p.audiobookshelfPassword = f.AddInputField("Audiobookshelf Server Password:", "", 40, nil, func(t string) { p.configCopy.AudiobookshelfPassword = t })

p.configSection.AddItem(f.f, 0, 0, 1, 1, 0, 0, true)
f = newForm()
f.SetHorizontal(false)
Expand Down Expand Up @@ -83,6 +92,10 @@ func (p *ConfigPage) displayConfig(c *dto.DisplayConfigCommand) {
p.logLevelField.SetCurrentOption(utils.GetIndex(logger.LogLeves(), p.configCopy.LogLevel))
p.useMockField.SetChecked(p.configCopy.UseMock)
p.saveMockField.SetChecked(p.configCopy.SaveMock)
p.audiobookshelfUrl.SetText(p.configCopy.AudiobookshelfUrl)
p.audiobookshelfDir.SetText(p.configCopy.AudiobookshelfDir)
p.audiobookshelfUser.SetText(p.configCopy.AudiobookshelfUser)
p.audiobookshelfPassword.SetText(p.configCopy.AudiobookshelfPassword)

p.mq.SendMessage(mq.ConfigPage, mq.TUI, &dto.DrawCommand{Primitive: nil}, true)
p.mq.SendMessage(mq.ConfigPage, mq.TUI, &dto.SetFocusCommand{Primitive: p.configSection}, true)
Expand Down
93 changes: 93 additions & 0 deletions internal/utils/encrypt.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package utils

import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/sha256"
"encoding/base64"
"encoding/binary"
"fmt"
"net"
)

func GetMachineIdentifier() ([]byte, error) {
// Retrieve MAC address
ifas, err := net.Interfaces()
if err != nil {
return nil, fmt.Errorf("failed to get network interfaces: %v", err)
}
var macAddr string
for _, ifa := range ifas {
if ifa.Flags&net.FlagLoopback == 0 && ifa.Flags&net.FlagUp != 0 {
macAddr = ifa.HardwareAddr.String()
break
}
}

// Hash the MAC address to create a unique identifier
hash := sha256.Sum256([]byte(macAddr))
return hash[:], nil
}

func GenerateEncryptionKey() ([]byte, error) {
machineIdentifier, err := GetMachineIdentifier()
if err != nil {
return nil, fmt.Errorf("failed to get machine identifier: %v", err)
}

// Use the machine identifier to generate an encryption key
key := make([]byte, 32) // 256-bit key
for i := 0; i < len(machineIdentifier); i += 4 {
binary.LittleEndian.PutUint32(key[i:], binary.LittleEndian.Uint32(machineIdentifier[i:]))
}

return key, nil
}

func EncryptString(text string) ([]byte, error) {
key, err := GenerateEncryptionKey()
if err != nil {
return nil, fmt.Errorf("failed to get encryption token: %v", err)
}
block, err := aes.NewCipher(key)
if err != nil {
return nil, fmt.Errorf("failed to get chipher: %v", err)
}
ciphertext := make([]byte, aes.BlockSize+len(text))
iv := ciphertext[:aes.BlockSize]
if _, err := rand.Read(iv); err != nil {
return nil, fmt.Errorf("failed to random key for encryption: %v", err)
}
stream := cipher.NewCTR(block, iv)
stream.XORKeyStream(ciphertext[aes.BlockSize:], []byte(text))
return ciphertext, nil
}

func DecryptString(ciphertext []byte) (string, error) {
key, err := GenerateEncryptionKey()
if err != nil {
return "", fmt.Errorf("failed to get encryption token: %v", err)
}

block, err := aes.NewCipher(key)
if err != nil {
return "", fmt.Errorf("failed to get chipher: %v", err)
}
if len(ciphertext) < aes.BlockSize {
return "", fmt.Errorf("ciphertext too short: %v", err)
}
iv := ciphertext[:aes.BlockSize]
ciphertext = ciphertext[aes.BlockSize:]
stream := cipher.NewCTR(block, iv)
stream.XORKeyStream(ciphertext, ciphertext)
return string(ciphertext), nil
}

func EncodeBase64(data []byte) string {
return base64.StdEncoding.EncodeToString(data)
}

func DecodeBase64(encoded string) ([]byte, error) {
return base64.StdEncoding.DecodeString(encoded)
}
29 changes: 29 additions & 0 deletions internal/utils/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,33 @@ func TestHumanToBytes(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, tc.expected, actual)
}
}


func TestGetMachineIdentifier(t *testing.T) {
machineID, err := utils.GetMachineIdentifier()
assert.NoError(t, err)
assert.NotEmpty(t, machineID)
}

func TestGenerateEncryptionKey(t *testing.T) {
encryptionKey, err := utils.GenerateEncryptionKey()
assert.NoError(t, err)
assert.NotEmpty(t, encryptionKey)
}

func TestEncryptString(t *testing.T) {
text := "Decrypted String"
encryptedString, err := utils.EncryptString(text)
assert.NoError(t, err)
assert.NotEmpty(t, encryptedString)
}

func TestDecryptString(t *testing.T) {
text := "Decrypted String"
encryptedString, err := utils.EncryptString(text)
assert.NoError(t, err)
decryptedString, err := utils.DecryptString(encryptedString)
assert.NoError(t, err)
assert.Equal(t, text, decryptedString)
}

0 comments on commit 1fe6004

Please sign in to comment.