diff --git a/config/dukcapil.go b/config/dukcapil.go index 767434b..9d99954 100644 --- a/config/dukcapil.go +++ b/config/dukcapil.go @@ -9,7 +9,6 @@ type Dukcapil struct { Methode string `mapstructure:"methode"` UserID string `mapstructure:"user_id"` Password string `mapstructure:"password"` - PublicKeyPath string `mapstructure:"public_key_path"` DefaultIP string `mapstructure:"default_ip"` TimeoutSecond int `mapstructure:"timeout_second"` } diff --git a/infra/development.yaml b/infra/development.yaml index 3857fc8..0dcec26 100644 --- a/infra/development.yaml +++ b/infra/development.yaml @@ -33,6 +33,5 @@ dukcapil: methode: "CALL_FN" user_id: "281020241202039900305241000011252" password: "Fjskdhv35$%" - public_key_path: "infra/dukcapil_public.pem" default_ip: "10.160.86.53" timeout_second: 30 diff --git a/internal/client/dukcapil_client.go b/internal/client/dukcapil_client.go index 263dcfa..1dadbdd 100644 --- a/internal/client/dukcapil_client.go +++ b/internal/client/dukcapil_client.go @@ -3,19 +3,12 @@ package client import ( "bytes" "context" - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "encoding/base64" "encoding/json" - "encoding/pem" "errors" "fmt" "io" "net/http" - "os" "strings" - "sync" "time" "go-backend-template/config" @@ -23,14 +16,10 @@ import ( "go-backend-template/internal/logger" ) -// DukcapilClient performs HTTPS calls to the Dukcapil 1:N face recognition -// endpoint (CALL_FN). It loads and caches the configured RSA public key used -// to encrypt sensitive credentials. +// DukcapilClient performs HTTPS calls to the Dukcapil 1:N face recognition endpoint (CALL_FN). type DukcapilClient struct { - cfg config.Dukcapil - http *http.Client - pubKey *rsa.PublicKey - keyMu sync.Mutex + cfg config.Dukcapil + http *http.Client } func NewDukcapilClient(cfg config.Dukcapil) *DukcapilClient { @@ -42,42 +31,26 @@ func NewDukcapilClient(cfg config.Dukcapil) *DukcapilClient { } } -// FaceMatch performs a 1:N face match call. user_id/password are encrypted -// with the configured public key (RSA PKCS1v15 -> base64). The image must -// already be base64 encoded. +// FaceMatch performs a 1:N face match call. The image must already be base64 encoded. func (c *DukcapilClient) FaceMatch(ctx context.Context, req *contract.FaceMatchRequest) (*contract.DukcapilFaceResponse, error) { if c.cfg.BaseURL == "" || c.cfg.CustomerID == "" || c.cfg.Methode == "" { return nil, errors.New("dukcapil: incomplete configuration") } - pub, err := c.loadPublicKey() - if err != nil { - return nil, fmt.Errorf("dukcapil: load public key: %w", err) - } + ip := req.IP + if strings.TrimSpace(ip) == "" { + ip = c.cfg.DefaultIP + } - encUserID, err := encryptAndEncode(pub, []byte(c.cfg.UserID)) - if err != nil { - return nil, fmt.Errorf("dukcapil: encrypt user_id: %w", err) - } - encPassword, err := encryptAndEncode(pub, []byte(c.cfg.Password)) - if err != nil { - return nil, fmt.Errorf("dukcapil: encrypt password: %w", err) - } - - ip := req.IP - if strings.TrimSpace(ip) == "" { - ip = c.cfg.DefaultIP - } - - body := contract.DukcapilFaceRequest{ - TransactionID: req.TransactionID, - TransactionSource: req.TransactionSource, - Threshold: req.Threshold, - Image: req.Image, - UserID: encUserID, - Password: encPassword, - IP: ip, - } + body := contract.DukcapilFaceRequest{ + TransactionID: req.TransactionID, + TransactionSource: req.TransactionSource, + Threshold: req.Threshold, + Image: req.Image, + UserID: c.cfg.UserID, + Password: c.cfg.Password, + IP: ip, + } payload, err := json.Marshal(body) if err != nil { @@ -122,47 +95,5 @@ func (c *DukcapilClient) FaceMatch(ctx context.Context, req *contract.FaceMatchR return &out, nil } -func (c *DukcapilClient) loadPublicKey() (*rsa.PublicKey, error) { - c.keyMu.Lock() - defer c.keyMu.Unlock() - if c.pubKey != nil { - return c.pubKey, nil - } - if c.cfg.PublicKeyPath == "" { - return nil, errors.New("public key path not configured") - } - raw, err := os.ReadFile(c.cfg.PublicKeyPath) - if err != nil { - return nil, err - } - block, _ := pem.Decode(raw) - if block == nil { - return nil, errors.New("invalid PEM file") - } - // Try PKIX first (BEGIN PUBLIC KEY) then PKCS1 (BEGIN RSA PUBLIC KEY). - if pub, err := x509.ParsePKIXPublicKey(block.Bytes); err == nil { - rsaPub, ok := pub.(*rsa.PublicKey) - if !ok { - return nil, errors.New("public key is not RSA") - } - c.pubKey = rsaPub - return rsaPub, nil - } - rsaPub, err := x509.ParsePKCS1PublicKey(block.Bytes) - if err != nil { - return nil, fmt.Errorf("parse rsa public key: %w", err) - } - c.pubKey = rsaPub - return rsaPub, nil -} -// encryptAndEncode mimics PHP openssl_public_encrypt (default padding = -// PKCS1v15) and base64-encodes the ciphertext. -func encryptAndEncode(pub *rsa.PublicKey, plaintext []byte) (string, error) { - cipherBytes, err := rsa.EncryptPKCS1v15(rand.Reader, pub, plaintext) - if err != nil { - return "", err - } - return base64.StdEncoding.EncodeToString(cipherBytes), nil -}