v.0.0.4.5 Добавлено шифрование сообщения
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
madipo2611 2025-08-21 00:29:14 +03:00
parent fe9f706e1b
commit 261f14b451

181
server.go
View File

@ -3,6 +3,7 @@ package main
import (
"context"
"database/sql"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
@ -146,9 +147,31 @@ func (s *server) SendMessage(ctx context.Context, req *proto.SendMessageRequest)
return nil, fmt.Errorf("failed to encrypt message: %v", err)
}
// Кодируем в base64 для хранения в TEXT поле
encodedContent := base64.StdEncoding.EncodeToString(encryptedContent)
encodedKey := base64.StdEncoding.EncodeToString(encryptedKey)
encodedNonce := base64.StdEncoding.EncodeToString(nonce)
s.logger.Printf("Base64 encoded: content_len=%d, key_len=%d, nonce_len=%d",
len(encodedContent), len(encodedKey), len(encodedNonce))
// Тестовая расшифровка сразу после шифрования
testDecrypted, err := s.crypto.DecryptMessage(encryptedContent, encryptedKey, nonce)
if err != nil {
s.logger.Printf("IMMEDIATE DECRYPTION TEST FAILED: %v", err)
return nil, fmt.Errorf("encryption/decryption test failed: %v", err)
}
if testDecrypted != req.Content {
s.logger.Printf("IMMEDIATE DECRYPTION CONTENT MISMATCH")
return nil, fmt.Errorf("encryption/decryption content mismatch")
}
s.logger.Printf("Immediate decryption test passed")
// Сохранение сессионного ключа в Vault
s.logger.Printf("Storing session key in Vault for chat_id=%d, message", req.ChatId)
err = s.crypto.Vault.StoreSessionKey(int(req.ChatId), 0, encryptedKey) // messageID будет 0 до вставки
s.logger.Printf("Storing session key in Vault for chat_id=%d", req.ChatId)
err = s.crypto.Vault.StoreSessionKey(int(req.ChatId), 0, encryptedKey)
if err != nil {
s.logger.Printf("Failed to store session key: %v", err)
return nil, fmt.Errorf("failed to store session key: %v", err)
@ -178,11 +201,12 @@ func (s *server) SendMessage(ctx context.Context, req *proto.SendMessageRequest)
var message proto.Message
var createdAt time.Time
// Используем закодированные base64 строки
err = s.db.QueryRow(ctx, `
INSERT INTO messages (chat_id, sender_id, receiver_id, content, encrypted_key, nonce)
VALUES ($1, $2, $3, $4, $5, $6)
RETURNING id, chat_id, sender_id, receiver_id, status, created_at
`, req.ChatId, req.SenderId, receiverId, encryptedContent, encryptedKey, nonce).Scan(
`, req.ChatId, req.SenderId, receiverId, encodedContent, encodedKey, encodedNonce).Scan(
&message.Id, &message.ChatId, &message.SenderId, &message.ReceiverId, &message.Status, &createdAt,
)
if err != nil {
@ -197,7 +221,6 @@ func (s *server) SendMessage(ctx context.Context, req *proto.SendMessageRequest)
err = s.crypto.Vault.StoreSessionKey(int(req.ChatId), int(message.Id), encryptedKey)
if err != nil {
s.logger.Printf("Failed to update session key with message ID: %v", err)
// Не прерываем выполнение, так как ключ уже сохранен с chatID
}
s.logger.Printf("Updating chat updated_at for chat_id=%d", req.ChatId)
@ -207,14 +230,13 @@ func (s *server) SendMessage(ctx context.Context, req *proto.SendMessageRequest)
return nil, err
}
// Расшифровка для отправки через RabbitMQ (получателю нужен расшифрованный текст)
// Расшифровка для отправки через RabbitMQ
decryptedContent, err := s.crypto.DecryptMessage(encryptedContent, encryptedKey, nonce)
if err != nil {
s.logger.Printf("Failed to decrypt message for RabbitMQ: %v", err)
return nil, fmt.Errorf("failed to decrypt message: %v", err)
}
// Создаем копию сообщения с расшифрованным содержимым для RabbitMQ
rabbitMsg := proto.Message{
Id: message.Id,
ChatId: message.ChatId,
@ -276,7 +298,7 @@ func (s *server) GetChat(ctx context.Context, req *proto.GetChatRequest) (*proto
var chat proto.Chat
var createdAt, updatedAt time.Time
var lastMessageID sql.NullInt32
var lastMessageContent, lastMessageEncryptedKey, lastMessageNonce []byte
var lastMessageContentBase64, lastMessageEncryptedKeyBase64, lastMessageNonceBase64 sql.NullString
var lastMessageStatus sql.NullString
var lastMessageCreatedAt sql.NullTime
@ -297,8 +319,8 @@ func (s *server) GetChat(ctx context.Context, req *proto.GetChatRequest) (*proto
WHERE c.user1_id = $1 AND c.user2_id = $2
`, user1, user2).Scan(
&chat.Id, &chat.User1Id, &chat.User2Id, &createdAt, &updatedAt,
&lastMessageID, &lastMessageContent, &lastMessageEncryptedKey,
&lastMessageNonce, &lastMessageStatus, &lastMessageCreatedAt,
&lastMessageID, &lastMessageContentBase64, &lastMessageEncryptedKeyBase64,
&lastMessageNonceBase64, &lastMessageStatus, &lastMessageCreatedAt,
)
if err != nil {
s.logger.Printf("Failed to get chat: %v", err)
@ -311,16 +333,38 @@ func (s *server) GetChat(ctx context.Context, req *proto.GetChatRequest) (*proto
if lastMessageID.Valid {
// Расшифровываем последнее сообщение
var decryptedContent string
if len(lastMessageContent) > 0 && len(lastMessageEncryptedKey) > 0 && len(lastMessageNonce) > 0 {
decrypted, err := s.crypto.DecryptMessage(lastMessageContent, lastMessageEncryptedKey, lastMessageNonce)
if lastMessageContentBase64.Valid && lastMessageEncryptedKeyBase64.Valid && lastMessageNonceBase64.Valid {
// Декодируем из base64
encryptedContent, err := base64.StdEncoding.DecodeString(lastMessageContentBase64.String)
if err != nil {
s.logger.Printf("Failed to decrypt last message %d: %v", lastMessageID.Int32, err)
decryptedContent = "[encrypted message]"
s.logger.Printf("Failed to decode content for last message %d: %v", lastMessageID.Int32, err)
decryptedContent = "[decode error: content]"
} else {
decryptedContent = decrypted
encryptedKey, err := base64.StdEncoding.DecodeString(lastMessageEncryptedKeyBase64.String)
if err != nil {
s.logger.Printf("Failed to decode key for last message %d: %v", lastMessageID.Int32, err)
decryptedContent = "[decode error: key]"
} else {
nonce, err := base64.StdEncoding.DecodeString(lastMessageNonceBase64.String)
if err != nil {
s.logger.Printf("Failed to decode nonce for last message %d: %v", lastMessageID.Int32, err)
decryptedContent = "[decode error: nonce]"
} else {
// Расшифровка сообщения
decrypted, err := s.crypto.DecryptMessage(encryptedContent, encryptedKey, nonce)
if err != nil {
s.logger.Printf("Failed to decrypt last message %d: %v", lastMessageID.Int32, err)
decryptedContent = "[encrypted message]"
} else {
decryptedContent = decrypted
s.logger.Printf("Successfully decrypted last message for chat %d", chat.Id)
}
}
}
}
} else {
decryptedContent = "[no message]"
decryptedContent = "[no message content]"
}
chat.LastMessage = &proto.Message{
@ -330,7 +374,7 @@ func (s *server) GetChat(ctx context.Context, req *proto.GetChatRequest) (*proto
Status: lastMessageStatus.String,
CreatedAt: timestamppb.New(lastMessageCreatedAt.Time),
}
s.logger.Printf("Found and decrypted last message for chat %d: message_id=%d", chat.Id, lastMessageID.Int32)
s.logger.Printf("Found last message for chat %d: message_id=%d", chat.Id, lastMessageID.Int32)
}
resp := &proto.ChatResponse{Chat: &chat}
@ -346,12 +390,12 @@ func (s *server) GetChatMessages(ctx context.Context, req *proto.GetChatMessages
s.logger.Printf("Querying messages for chat_id=%d, limit=%d, offset=%d", req.ChatId, req.Limit, req.Offset)
rows, err := s.db.Query(ctx, `
SELECT id, chat_id, sender_id, receiver_id, content, encrypted_key, nonce, status, created_at
FROM messages
WHERE chat_id = $1
ORDER BY created_at DESC
LIMIT $2 OFFSET $3
`, req.ChatId, req.Limit, req.Offset)
SELECT id, chat_id, sender_id, receiver_id, content, encrypted_key, nonce, status, created_at
FROM messages
WHERE chat_id = $1
ORDER BY created_at DESC
LIMIT $2 OFFSET $3
`, req.ChatId, req.Limit, req.Offset)
if err != nil {
s.logger.Printf("Failed to query messages: %v", err)
return nil, err
@ -362,24 +406,69 @@ func (s *server) GetChatMessages(ctx context.Context, req *proto.GetChatMessages
for rows.Next() {
var msg proto.Message
var createdAt time.Time
var encryptedKey, nonce, encryptedContent []byte
var encryptedKeyBase64, nonceBase64, encryptedContentBase64 string
err := rows.Scan(
&msg.Id, &msg.ChatId, &msg.SenderId, &msg.ReceiverId,
&encryptedContent, &encryptedKey, &nonce, &msg.Status, &createdAt,
&encryptedContentBase64, &encryptedKeyBase64, &nonceBase64, &msg.Status, &createdAt,
)
if err != nil {
s.logger.Printf("Failed to scan message row: %v", err)
return nil, err
}
s.logger.Printf("Processing message %d: content_len=%d, key_len=%d, nonce_len=%d",
msg.Id, len(encryptedContentBase64), len(encryptedKeyBase64), len(nonceBase64))
// Декодируем из base64
encryptedContent, err := base64.StdEncoding.DecodeString(encryptedContentBase64)
if err != nil {
s.logger.Printf("Failed to decode content for message %d: %v", msg.Id, err)
msg.Content = "[base64 decode error: content]"
continue
}
encryptedKey, err := base64.StdEncoding.DecodeString(encryptedKeyBase64)
if err != nil {
s.logger.Printf("Failed to decode key for message %d: %v", msg.Id, err)
msg.Content = "[base64 decode error: key]"
continue
}
nonce, err := base64.StdEncoding.DecodeString(nonceBase64)
if err != nil {
s.logger.Printf("Failed to decode nonce for message %d: %v", msg.Id, err)
msg.Content = "[base64 decode error: nonce]"
continue
}
// Проверяем что данные не пустые после декодирования
if len(encryptedContent) == 0 {
s.logger.Printf("Empty content after base64 decode for message %d", msg.Id)
msg.Content = "[empty content after decode]"
continue
}
if len(encryptedKey) == 0 {
s.logger.Printf("Empty key after base64 decode for message %d", msg.Id)
msg.Content = "[empty key after decode]"
continue
}
if len(nonce) == 0 {
s.logger.Printf("Empty nonce after base64 decode for message %d", msg.Id)
msg.Content = "[empty nonce after decode]"
continue
}
// Расшифровка сообщения
decryptedContent, err := s.crypto.DecryptMessage(encryptedContent, encryptedKey, nonce)
if err != nil {
s.logger.Printf("Failed to decrypt message %d: %v", msg.Id, err)
msg.Content = "[encrypted - decryption failed]"
s.logger.Printf("Decryption failed details: content_len=%d, key_len=%d, nonce_len=%d",
len(encryptedContent), len(encryptedKey), len(nonce))
msg.Content = "[decryption failed: " + err.Error() + "]"
} else {
msg.Content = decryptedContent
s.logger.Printf("Successfully decrypted message %d", msg.Id)
}
msg.CreatedAt = timestamppb.New(createdAt)
@ -426,14 +515,14 @@ func (s *server) GetUserChats(ctx context.Context, req *proto.GetUserChatsReques
var chat proto.Chat
var createdAt, updatedAt time.Time
var lastMessageID sql.NullInt32
var lastMessageContent, lastMessageEncryptedKey, lastMessageNonce []byte
var lastMessageContentBase64, lastMessageEncryptedKeyBase64, lastMessageNonceBase64 sql.NullString
var lastMessageStatus sql.NullString
var lastMessageCreatedAt sql.NullTime
err := rows.Scan(
&chat.Id, &chat.User1Id, &chat.User2Id, &createdAt, &updatedAt,
&lastMessageID, &lastMessageContent, &lastMessageEncryptedKey,
&lastMessageNonce, &lastMessageStatus, &lastMessageCreatedAt,
&lastMessageID, &lastMessageContentBase64, &lastMessageEncryptedKeyBase64,
&lastMessageNonceBase64, &lastMessageStatus, &lastMessageCreatedAt,
)
if err != nil {
s.logger.Printf("Failed to scan chat row: %v", err)
@ -446,16 +535,38 @@ func (s *server) GetUserChats(ctx context.Context, req *proto.GetUserChatsReques
if lastMessageID.Valid {
// Расшифровываем последнее сообщение
var decryptedContent string
if len(lastMessageContent) > 0 && len(lastMessageEncryptedKey) > 0 && len(lastMessageNonce) > 0 {
decrypted, err := s.crypto.DecryptMessage(lastMessageContent, lastMessageEncryptedKey, lastMessageNonce)
if lastMessageContentBase64.Valid && lastMessageEncryptedKeyBase64.Valid && lastMessageNonceBase64.Valid {
// Декодируем из base64
encryptedContent, err := base64.StdEncoding.DecodeString(lastMessageContentBase64.String)
if err != nil {
s.logger.Printf("Failed to decrypt last message %d: %v", lastMessageID.Int32, err)
decryptedContent = "[encrypted message]"
s.logger.Printf("Failed to decode content for last message %d: %v", lastMessageID.Int32, err)
decryptedContent = "[decode error: content]"
} else {
decryptedContent = decrypted
encryptedKey, err := base64.StdEncoding.DecodeString(lastMessageEncryptedKeyBase64.String)
if err != nil {
s.logger.Printf("Failed to decode key for last message %d: %v", lastMessageID.Int32, err)
decryptedContent = "[decode error: key]"
} else {
nonce, err := base64.StdEncoding.DecodeString(lastMessageNonceBase64.String)
if err != nil {
s.logger.Printf("Failed to decode nonce for last message %d: %v", lastMessageID.Int32, err)
decryptedContent = "[decode error: nonce]"
} else {
// Расшифровка сообщения
decrypted, err := s.crypto.DecryptMessage(encryptedContent, encryptedKey, nonce)
if err != nil {
s.logger.Printf("Failed to decrypt last message %d: %v", lastMessageID.Int32, err)
decryptedContent = "[encrypted message]"
} else {
decryptedContent = decrypted
s.logger.Printf("Successfully decrypted last message for chat %d", chat.Id)
}
}
}
}
} else {
decryptedContent = "[no message]"
decryptedContent = "[no message content]"
}
chat.LastMessage = &proto.Message{
@ -465,7 +576,7 @@ func (s *server) GetUserChats(ctx context.Context, req *proto.GetUserChatsReques
Status: lastMessageStatus.String,
CreatedAt: timestamppb.New(lastMessageCreatedAt.Time),
}
s.logger.Printf("Found and decrypted last message for chat %d: message_id=%d", chat.Id, lastMessageID.Int32)
s.logger.Printf("Found last message for chat %d: message_id=%d", chat.Id, lastMessageID.Int32)
}
chats = append(chats, &chat)