132 lines
3.5 KiB
Go
132 lines
3.5 KiB
Go
package crypto
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"fmt"
|
|
"log"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/hashicorp/vault/api"
|
|
)
|
|
|
|
type VaultManager struct {
|
|
client *api.Client
|
|
}
|
|
|
|
func NewVaultManager() (*VaultManager, error) {
|
|
config := api.DefaultConfig()
|
|
config.Address = "http://192.168.0.59:8200"
|
|
|
|
client, err := api.NewClient(config)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create Vault client: %v", err)
|
|
}
|
|
|
|
// Аутентификация через username/password
|
|
authData := map[string]interface{}{
|
|
"password": "2T6sDQ3PyG6x+0Z950ojAA+lWQ8HhUqd",
|
|
}
|
|
|
|
secret, err := client.Logical().Write("auth/userpass/login/tailly-app", authData)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to authenticate with Vault: %v", err)
|
|
}
|
|
|
|
if secret == nil || secret.Auth == nil {
|
|
return nil, fmt.Errorf("empty authentication response from Vault")
|
|
}
|
|
|
|
client.SetToken(secret.Auth.ClientToken)
|
|
|
|
// Настраиваем автоматическое обновление токена
|
|
go func() {
|
|
for {
|
|
time.Sleep(30 * time.Minute)
|
|
secret, err := client.Auth().Token().RenewSelf(0)
|
|
if err != nil {
|
|
log.Printf("Failed to renew Vault token: %v", err)
|
|
} else if secret != nil && secret.Auth != nil {
|
|
client.SetToken(secret.Auth.ClientToken)
|
|
}
|
|
}
|
|
}()
|
|
|
|
return &VaultManager{client: client}, nil
|
|
}
|
|
|
|
func (v *VaultManager) GetMasterPrivateKey() ([]byte, error) {
|
|
secret, err := v.client.Logical().Read("kv/data/keys/master")
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to read master key: %v", err)
|
|
}
|
|
|
|
if secret == nil || secret.Data == nil {
|
|
return nil, fmt.Errorf("master key not found")
|
|
}
|
|
|
|
// Получаем данные из секрета
|
|
data, ok := secret.Data["data"].(map[string]interface{})
|
|
if !ok {
|
|
return nil, fmt.Errorf("invalid data format in Vault secret")
|
|
}
|
|
|
|
// Получаем приватный ключ в base64
|
|
keyInterface, ok := data["private_key_base64"]
|
|
if !ok {
|
|
return nil, fmt.Errorf("private_key_base64 not found in Vault data")
|
|
}
|
|
|
|
keyBase64, ok := keyInterface.(string)
|
|
if !ok {
|
|
return nil, fmt.Errorf("private_key_base64 is not a string")
|
|
}
|
|
|
|
// Очищаем строку от лишних символов
|
|
keyBase64 = strings.TrimSpace(keyBase64)
|
|
keyBase64 = strings.ReplaceAll(keyBase64, "\n", "")
|
|
keyBase64 = strings.ReplaceAll(keyBase64, "\r", "")
|
|
keyBase64 = strings.ReplaceAll(keyBase64, " ", "")
|
|
|
|
// Декодируем base64
|
|
keyBytes, err := base64.StdEncoding.DecodeString(keyBase64)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to decode base64 private key: %v. Input: %s", err, keyBase64)
|
|
}
|
|
|
|
return keyBytes, nil
|
|
}
|
|
|
|
func (v *VaultManager) StoreSessionKey(chatID int, messageID int, encryptedKey []byte) error {
|
|
path := fmt.Sprintf("kv/data/keys/chat_%d/message_%d", chatID, messageID)
|
|
|
|
_, err := v.client.Logical().Write(path, map[string]interface{}{
|
|
"data": map[string]interface{}{
|
|
"encrypted_key": base64.StdEncoding.EncodeToString(encryptedKey),
|
|
"timestamp": time.Now().Unix(),
|
|
"chat_id": chatID,
|
|
"message_id": messageID,
|
|
},
|
|
})
|
|
|
|
return err
|
|
}
|
|
|
|
func (v *VaultManager) GetSessionKey(chatID int, messageID int) ([]byte, error) {
|
|
path := fmt.Sprintf("kv/data/keys/chat_%d/message_%d", chatID, messageID)
|
|
|
|
secret, err := v.client.Logical().Read(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if secret == nil || secret.Data == nil {
|
|
return nil, fmt.Errorf("session key not found")
|
|
}
|
|
|
|
data := secret.Data["data"].(map[string]interface{})
|
|
keyBase64 := data["encrypted_key"].(string)
|
|
|
|
return base64.StdEncoding.DecodeString(keyBase64)
|
|
}
|