2026-08-09 10:43:45 +08:00
|
|
|
package verify
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"context"
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"fmt"
|
|
|
|
|
"io"
|
|
|
|
|
"net/http"
|
|
|
|
|
"strings"
|
|
|
|
|
"time"
|
|
|
|
|
|
2026-08-09 12:41:08 +08:00
|
|
|
"bsm/full/module/base/passport/internal/config"
|
|
|
|
|
"bsm/full/module/base/passport/internal/impl"
|
|
|
|
|
"bsm/full/module/base/passport/internal/logic/common"
|
|
|
|
|
"bsm/full/module/base/passport/internal/models"
|
|
|
|
|
pb "bsm/full/module/base/passport/pb"
|
2026-08-09 10:43:45 +08:00
|
|
|
"git.apinb.com/bsm-sdk/core/errcode"
|
|
|
|
|
"git.apinb.com/bsm-sdk/core/printer"
|
|
|
|
|
"git.apinb.com/bsm-sdk/core/service"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type JumioInitRequest struct {
|
|
|
|
|
CustomerInternalReference string `json:"customerInternalReference"`
|
|
|
|
|
UserReference string `json:"userReference"`
|
|
|
|
|
SuccessURL string `json:"successUrl"`
|
|
|
|
|
ErrorURL string `json:"errorUrl"`
|
|
|
|
|
CallbackURL string `json:"callbackUrl"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type JumioInitResponse struct {
|
|
|
|
|
Timestamp string `json:"timestamp"`
|
|
|
|
|
ScanReference string `json:"scanReference"`
|
|
|
|
|
ClientRedirectURL string `json:"clientRedirectUrl"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Request(ctx context.Context, in *pb.VerifyRequest) (reply *pb.StatusReply, err error) {
|
|
|
|
|
auth, err := service.ParseMetaCtx(ctx, nil)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var data string
|
|
|
|
|
switch strings.ToLower(in.Provider) {
|
|
|
|
|
case "jumio":
|
|
|
|
|
id := fmt.Sprintf("ID_%d", auth.ID)
|
|
|
|
|
resp, err := InitiateJumioScan(id, auth.Identity)
|
|
|
|
|
if err != nil {
|
|
|
|
|
printer.Error(err.Error())
|
|
|
|
|
return nil, errcode.ErrInternal
|
|
|
|
|
}
|
|
|
|
|
data = resp.ClientRedirectURL
|
|
|
|
|
case "local":
|
|
|
|
|
if !common.VerifyMapKeys(in.Args, []string{"type", "name", "number", "front", "back"}) {
|
|
|
|
|
return nil, errcode.ErrInvalidArgument
|
|
|
|
|
}
|
|
|
|
|
err = LocalVerify(auth.ID, in.Args)
|
|
|
|
|
if err != nil {
|
|
|
|
|
printer.Error(err.Error())
|
|
|
|
|
return nil, errcode.ErrDB
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
return nil, errcode.ErrNotFound(404, "provider")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &pb.StatusReply{
|
|
|
|
|
Details: data,
|
|
|
|
|
Timeseq: time.Now().UnixMilli(),
|
|
|
|
|
}, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func LocalVerify(authID uint, args map[string]string) error {
|
|
|
|
|
err := impl.DBService.Model(&models.PassportData{}).Where("passport_id = ?", authID).Update("document_verify", 1).Error
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = impl.DBService.Model(&models.PassportVerify{}).Where("passport_id = ?", authID).Updates(map[string]any{
|
|
|
|
|
"document_verify_at": time.Now(),
|
|
|
|
|
"document_type": args["type"],
|
|
|
|
|
"document_name": args["name"],
|
|
|
|
|
"document_number": args["number"],
|
|
|
|
|
"document_front": args["front"],
|
|
|
|
|
"document_back": args["back"],
|
|
|
|
|
}).Error
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func InitiateJumioScan(internalRef, userRef string) (*JumioInitResponse, error) {
|
|
|
|
|
if config.Spec.Kyc == nil {
|
|
|
|
|
return nil, fmt.Errorf("kyc config is missing")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
reqBody := JumioInitRequest{
|
|
|
|
|
CustomerInternalReference: internalRef,
|
|
|
|
|
UserReference: userRef,
|
|
|
|
|
CallbackURL: config.Spec.Kyc.ApiArgs,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
jsonBody, err := json.Marshal(reqBody)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
client := &http.Client{Timeout: 10 * time.Second}
|
|
|
|
|
req, err := http.NewRequest(http.MethodPost, config.Spec.Kyc.BaseUrl, bytes.NewBuffer(jsonBody))
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
req.SetBasicAuth(config.Spec.Kyc.ApiToken, config.Spec.Kyc.ApiSecret)
|
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
|
req.Header.Set("User-Agent", "BSM-Passport/1.0")
|
|
|
|
|
|
|
|
|
|
resp, err := client.Do(req)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
|
|
body, err := io.ReadAll(resp.Body)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
|
return nil, fmt.Errorf("jumio api error: status=%d body=%s", resp.StatusCode, string(body))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var jumioResp JumioInitResponse
|
|
|
|
|
err = json.Unmarshal(body, &jumioResp)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &jumioResp, nil
|
|
|
|
|
}
|