v.0.0.4.5 Добавлено шифрование сообщения
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
fe9f706e1b
commit
261f14b451
181
server.go
181
server.go
@ -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)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user