180 lines
5.1 KiB
Go
180 lines
5.1 KiB
Go
package storage
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
service "gadrid/internal/service/storage" // Adjust this import path
|
|
)
|
|
|
|
// InMemStorageMock is a mock implementation of PGPKeyStorage for testing purposes.
|
|
// It stores data in memory, mimicking database operations.
|
|
type InMemStorageMock struct {
|
|
keys map[string]*service.PGPkey
|
|
uids map[string]map[string]*service.PGPUid // fingerprint -> uid_string -> UID
|
|
mu sync.RWMutex // Mutex for concurrent access safety
|
|
}
|
|
|
|
// NewInMemStorageMock creates a new in-memory mock storage.
|
|
func NewInMemStorageMock() *InMemStorageMock {
|
|
return &InMemStorageMock{
|
|
keys: make(map[string]*service.PGPkey),
|
|
uids: make(map[string]map[string]*service.PGPUid),
|
|
}
|
|
}
|
|
|
|
// AddKey implements PGPKeyStorage interface for the mock.
|
|
// See PGPKeyStorage interface for documentation.
|
|
func (m *InMemStorageMock) AddKey(ctx context.Context, keys []*service.PGPkey) error {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
|
|
for _, k := range keys {
|
|
// Simulate UPSERT for pgp_keys
|
|
m.keys[k.Fingerprint] = &service.PGPkey{ // Deep copy
|
|
Fingerprint: k.Fingerprint,
|
|
Packet: k.Packet,
|
|
Revoked: k.Revoked,
|
|
// Uids are handled separately, so this slice will be empty here in the key itself
|
|
}
|
|
|
|
// Ensure the inner map exists for UIDs
|
|
if _, ok := m.uids[k.Fingerprint]; !ok {
|
|
m.uids[k.Fingerprint] = make(map[string]*service.PGPUid)
|
|
}
|
|
|
|
// Simulate INSERT (ON CONFLICT DO NOTHING) for pgp_uids
|
|
for _, u := range k.Uids {
|
|
if _, exists := m.uids[k.Fingerprint][u.UIDString]; !exists {
|
|
m.uids[k.Fingerprint][u.UIDString] = &service.PGPUid{ // Deep copy
|
|
UIDString: u.UIDString,
|
|
Email: u.Email,
|
|
Verify: u.Verify,
|
|
Token: u.Token,
|
|
TokenExpires: u.TokenExpires,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// VerifyUID implements PGPKeyStorage interface for the mock.
|
|
// See PGPKeyStorage interface for documentation.
|
|
func (m *InMemStorageMock) VerifyUID(ctx context.Context, fingerprint, email, token string) error {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
|
|
keyUids, ok := m.uids[fingerprint]
|
|
if !ok {
|
|
return fmt.Errorf("invalid verification token or link") // Mimic no matching entry
|
|
}
|
|
|
|
var targetUID *service.PGPUid
|
|
var targetUIDString string // To be used as key in the map for update
|
|
for uidStr, uid := range keyUids {
|
|
if uid.Email == email {
|
|
targetUID = uid
|
|
targetUIDString = uidStr
|
|
break
|
|
}
|
|
}
|
|
|
|
if targetUID == nil {
|
|
return fmt.Errorf("invalid verification token or link") // Mimic no matching entry by email
|
|
}
|
|
|
|
if targetUID.Verify {
|
|
return fmt.Errorf("UID for %s is already verified", email)
|
|
}
|
|
if targetUID.Token == "" || targetUID.Token != token {
|
|
return fmt.Errorf("invalid verification token or link")
|
|
}
|
|
if targetUID.TokenExpires.Before(time.Now()) {
|
|
return fmt.Errorf("verification token has expired")
|
|
}
|
|
|
|
// Simulate update
|
|
targetUID.Verify = true
|
|
targetUID.Token = "" // Simulate setting to null
|
|
targetUID.TokenExpires = time.Time{} // Simulate setting to null
|
|
|
|
// Ensure the updated UID is correctly stored back in the map
|
|
m.uids[fingerprint][targetUIDString] = targetUID
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetKey implements PGPKeyStorage interface for the mock.
|
|
// See PGPKeyStorage interface for documentation.
|
|
func (m *InMemStorageMock) GetKey(ctx context.Context, fingerprint string) ([]*service.PGPkey, error) {
|
|
m.mu.RLock()
|
|
defer m.mu.RUnlock()
|
|
|
|
pgpKey, ok := m.keys[fingerprint]
|
|
if !ok {
|
|
return nil, ErrKeyNotFound // Use the specific error defined in the interface package
|
|
}
|
|
|
|
// Create a deep copy of the key
|
|
resultKey := &service.PGPkey{
|
|
Fingerprint: pgpKey.Fingerprint,
|
|
Packet: pgpKey.Packet,
|
|
Revoked: pgpKey.Revoked,
|
|
Uids: []*service.PGPUid{}, // Only add verified UIDs
|
|
}
|
|
|
|
// Filter UIDs by 'verified = true'
|
|
if keyUids, ok := m.uids[fingerprint]; ok {
|
|
for _, uid := range keyUids {
|
|
if uid.Verify {
|
|
// Deep copy the UID
|
|
resultKey.Uids = append(resultKey.Uids, &service.PGPUid{
|
|
UIDString: uid.UIDString,
|
|
Email: uid.Email,
|
|
Verify: uid.Verify,
|
|
Token: uid.Token,
|
|
TokenExpires: uid.TokenExpires,
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
return []*service.PGPkey{resultKey}, nil
|
|
}
|
|
|
|
// Index implements PGPKeyStorage interface for the mock.
|
|
// See PGPKeyStorage interface for documentation.
|
|
func (m *InMemStorageMock) Index(ctx context.Context, q string) ([]*service.PGPkey, error) {
|
|
m.mu.RLock()
|
|
defer m.mu.RUnlock()
|
|
|
|
matchedFingerprints := make(map[string]bool)
|
|
lowerQ := strings.ToLower(q) // Simulate case-insensitive search
|
|
|
|
for f, uidMap := range m.uids {
|
|
for _, uid := range uidMap {
|
|
// Simulate case-insensitive substring match for regex.
|
|
// For a more accurate mock, you'd use the 'regexp' package here.
|
|
if strings.Contains(strings.ToLower(uid.UIDString), lowerQ) ||
|
|
strings.Contains(strings.ToLower(uid.Email), lowerQ) {
|
|
matchedFingerprints[f] = true
|
|
}
|
|
}
|
|
}
|
|
|
|
var resultKeys []*service.PGPkey
|
|
for f := range matchedFingerprints {
|
|
// Reuse GetKey logic from mock (which filters for verified UIDs)
|
|
keys, err := m.GetKey(ctx, f)
|
|
if err == nil && len(keys) > 0 { // Check error from GetKey (e.g., ErrKeyNotFound)
|
|
resultKeys = append(resultKeys, keys[0])
|
|
}
|
|
}
|
|
|
|
return resultKeys, nil
|
|
}
|