154 lines
4.7 KiB
Go
154 lines
4.7 KiB
Go
|
|
package storage
|
||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"errors"
|
||
|
|
"fmt"
|
||
|
|
"log"
|
||
|
|
"strings"
|
||
|
|
|
||
|
|
storeRepo "gadrid/internal/repo/storage"
|
||
|
|
service "gadrid/internal/service/storage"
|
||
|
|
|
||
|
|
"github.com/ProtonMail/go-crypto/openpgp"
|
||
|
|
hkp "github.com/emersion/go-openpgp-hkp"
|
||
|
|
)
|
||
|
|
|
||
|
|
type StorageService struct {
|
||
|
|
hkp.Adder
|
||
|
|
hkp.Lookuper
|
||
|
|
// mailService interface{}
|
||
|
|
storage storeRepo.StorageRepositotyInterface
|
||
|
|
}
|
||
|
|
|
||
|
|
func New(storageRepository storeRepo.StorageRepositotyInterface) StorageService {
|
||
|
|
return StorageService{
|
||
|
|
storage: storageRepository,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
func (s StorageService) Add(el openpgp.EntityList) error {
|
||
|
|
fmt.Println(el)
|
||
|
|
pgpKeys, err := service.ConverterPgpToService(el) // Assuming ConverterPgpToService might return an error now.
|
||
|
|
if err != nil {
|
||
|
|
return fmt.Errorf("service error: Add: failed to convert PGP entities: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(pgpKeys) == 0 {
|
||
|
|
return nil // No keys to add, nothing to do.
|
||
|
|
}
|
||
|
|
|
||
|
|
// 2. Pass the context from this service method down to the storage layer.
|
||
|
|
// 3. ALWAYS check the error returned by the storage layer.
|
||
|
|
err = s.storage.AddKey(context.Background(), pgpKeys) // Pass context here
|
||
|
|
if err != nil {
|
||
|
|
return fmt.Errorf("service error: Add: failed to add keys to storage: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
return nil // Successfully processed
|
||
|
|
}
|
||
|
|
|
||
|
|
// Get key by fingerprint
|
||
|
|
// In Specification "op=get" fingerprint and uid
|
||
|
|
// FUTUE TE IPSUM specification! Only fingerprint search!
|
||
|
|
|
||
|
|
func (s StorageService) Get(req *hkp.LookupRequest) (openpgp.EntityList, error) {
|
||
|
|
|
||
|
|
req.Search = strings.Trim(req.Search, "0x")
|
||
|
|
|
||
|
|
if len(req.Search) <= 15 {
|
||
|
|
return nil, fmt.Errorf("service error: Get: Low entropy string for search")
|
||
|
|
}
|
||
|
|
|
||
|
|
dbKeys, err := s.storage.GetKey(context.Background(), req.Search)
|
||
|
|
if err != nil {
|
||
|
|
if errors.Is(err, storeRepo.ErrKeyNotFound) {
|
||
|
|
return nil, fmt.Errorf("service error: Get: key %s not found: %w", req.Search, err)
|
||
|
|
}
|
||
|
|
return nil, fmt.Errorf("service error: Get: db request failed for key %s: %w", req.Search, err)
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(dbKeys) == 0 {
|
||
|
|
return nil, fmt.Errorf("service error: Get: key %s not found (repository returned empty list): %w", req.Search, storeRepo.ErrKeyNotFound)
|
||
|
|
}
|
||
|
|
|
||
|
|
dbKey := dbKeys[0]
|
||
|
|
|
||
|
|
filteredEntity, err := s.sanitizeAndFilterKey(dbKey)
|
||
|
|
if err != nil {
|
||
|
|
return nil, fmt.Errorf("service error: Get: failed to sanitize and filter key %s: %w", dbKey.Fingerprint, err)
|
||
|
|
}
|
||
|
|
|
||
|
|
return filteredEntity, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (s StorageService) Index(req *hkp.LookupRequest) ([]hkp.IndexKey, error) {
|
||
|
|
|
||
|
|
if len(req.Search) < 5 {
|
||
|
|
return nil, fmt.Errorf("service error: Index: short string for search")
|
||
|
|
}
|
||
|
|
|
||
|
|
dbKeys, err := s.storage.Index(context.Background(), req.Search) // Pass ctx here
|
||
|
|
if err != nil {
|
||
|
|
return nil, fmt.Errorf("service error: Index: db index request for '%s': %w", req.Search, err) // Include original error
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(dbKeys) == 0 {
|
||
|
|
return nil, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
var respIndex []hkp.IndexKey
|
||
|
|
for _, dbKey := range dbKeys {
|
||
|
|
filteredEntity, err := s.sanitizeAndFilterKey(dbKey)
|
||
|
|
if err != nil {
|
||
|
|
log.Printf("Warning: service error: Index: failed to sanitize and filter key %s: %v, skipping.", dbKey.Fingerprint, err)
|
||
|
|
continue // Skip this problematic key
|
||
|
|
}
|
||
|
|
|
||
|
|
for _, fpk := range filteredEntity {
|
||
|
|
idxKey, err := hkp.IndexKeyFromEntity(fpk)
|
||
|
|
if err != nil {
|
||
|
|
log.Printf("Warning: service error: Index: failed to convert entity %s to IndexKey: %v, skipping.", dbKey.Fingerprint, err)
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
respIndex = append(respIndex, *idxKey)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(respIndex) == 0 {
|
||
|
|
return nil, fmt.Errorf("service error: Index: no valid index keys found after processing for '%s': %w", req.Search, storeRepo.ErrKeyNotFound)
|
||
|
|
}
|
||
|
|
|
||
|
|
return respIndex, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (s StorageService) sanitizeAndFilterKey(dbKey *service.PGPkey) (openpgp.EntityList, error) {
|
||
|
|
|
||
|
|
parsedEntities, err := openpgp.ReadArmoredKeyRing(strings.NewReader(dbKey.Packet))
|
||
|
|
if err != nil {
|
||
|
|
return nil, fmt.Errorf("failed to parse key packet for %s: %w", dbKey.Fingerprint, err)
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(parsedEntities) == 0 {
|
||
|
|
return nil, fmt.Errorf("parsed key packet for %s yielded no entities", dbKey.Fingerprint)
|
||
|
|
}
|
||
|
|
var respEntities openpgp.EntityList
|
||
|
|
for _, e := range parsedEntities {
|
||
|
|
if e == nil {
|
||
|
|
return nil, fmt.Errorf("no entity with matching fingerprint %s found in parsed packet from DB", dbKey.Fingerprint)
|
||
|
|
}
|
||
|
|
verifiedUIDStringsFromDB := make(map[string]struct{})
|
||
|
|
for _, dbUID := range dbKey.Uids {
|
||
|
|
verifiedUIDStringsFromDB[dbUID.UIDString] = struct{}{}
|
||
|
|
}
|
||
|
|
filteredIdentities := make(map[string]*openpgp.Identity)
|
||
|
|
for identityKey, identity := range e.Identities {
|
||
|
|
if _, isVerified := verifiedUIDStringsFromDB[identity.Name]; isVerified {
|
||
|
|
filteredIdentities[identityKey] = identity // Keep this identity
|
||
|
|
}
|
||
|
|
}
|
||
|
|
e.Identities = filteredIdentities
|
||
|
|
respEntities = append(respEntities, e)
|
||
|
|
}
|
||
|
|
return respEntities, nil
|
||
|
|
}
|