213 lines
6.7 KiB
Go
213 lines
6.7 KiB
Go
package client
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"ips-lacpass-backend/pkg/errors"
|
|
"ips-lacpass-backend/pkg/utils"
|
|
"net/http"
|
|
"net/url"
|
|
)
|
|
|
|
type VhlClient struct {
|
|
Client *http.Client
|
|
BaseURL string
|
|
ICVPValidatorUrl string
|
|
}
|
|
|
|
func NewClient(baseURL string, icvpValidatorUrl string) VhlClient {
|
|
return VhlClient{
|
|
Client: &http.Client{},
|
|
BaseURL: baseURL,
|
|
ICVPValidatorUrl: icvpValidatorUrl,
|
|
}
|
|
}
|
|
|
|
func (c *VhlClient) CreateQr(ctx context.Context, body CreateQrRequest) (*QrData, error) {
|
|
// TODO: To be implemented by the participant
|
|
resp, err := c.Client.Post(fmt.Sprintf("%s/v2/vshcIssuance", c.BaseURL), "application/json", bytes.NewBuffer(body))
|
|
if resp.StatusCode != http.StatusOK {
|
|
return nil, &errors.HttpError{
|
|
StatusCode: 500,
|
|
Body: []map[string]interface{}{{"error": "Not implemented error", "message": "this method is not implemented yet"}},
|
|
Err: fmt.Errorf("failed to get document reference"),
|
|
}
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
func (c *VhlClient) Validate(ctx context.Context, qrData string) (*QRValidationResponse, error) {
|
|
body, err := json.Marshal(QrValidationRequest{QRCodeContent: qrData})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to marshal validation payload: %w", err)
|
|
}
|
|
resp, err := c.Client.Post(fmt.Sprintf("%s/v2/vshcValidation", c.BaseURL), "application/json", bytes.NewBuffer(body))
|
|
if err != nil {
|
|
return nil, &errors.HttpError{
|
|
StatusCode: http.StatusBadGateway,
|
|
Body: []map[string]interface{}{{"error": "service_unavailable", "message": "Failed to connect to VHL service"}},
|
|
Err: err,
|
|
}
|
|
}
|
|
defer utils.CloseBody(resp.Body)
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
bodyBytes, readErr := io.ReadAll(resp.Body)
|
|
if readErr != nil {
|
|
return nil, &errors.HttpError{
|
|
StatusCode: resp.StatusCode,
|
|
Body: []map[string]interface{}{{"error": "internal_error", "message": "Failed to read response body"}},
|
|
Err: readErr,
|
|
}
|
|
}
|
|
return nil, &errors.HttpError{
|
|
StatusCode: resp.StatusCode,
|
|
Body: []map[string]interface{}{{"error": "service_error", "message": string(bodyBytes)}},
|
|
Err: fmt.Errorf("unexpected status code %d: %s", resp.StatusCode, string(bodyBytes)),
|
|
}
|
|
}
|
|
|
|
var valResp QRValidationResponse
|
|
if err := json.NewDecoder(resp.Body).Decode(&valResp); err != nil {
|
|
return nil, &errors.HttpError{
|
|
StatusCode: http.StatusInternalServerError,
|
|
Body: []map[string]interface{}{{"error": "internal_error", "message": "Failed to decode response"}},
|
|
Err: err,
|
|
}
|
|
}
|
|
return &valResp, nil
|
|
}
|
|
|
|
func (c *VhlClient) GetIpsUrl(ctx context.Context, shLink string, passCode string) (*VhlManifestResponse, error) {
|
|
u, err := url.Parse(fmt.Sprintf("%s/ips-url", c.BaseURL))
|
|
if err != nil {
|
|
return nil, &errors.HttpError{
|
|
StatusCode: http.StatusInternalServerError,
|
|
Body: []map[string]interface{}{{"error": "internal_error", "message": "Failed to create request"}},
|
|
Err: err,
|
|
}
|
|
}
|
|
|
|
q := u.Query()
|
|
q.Set("shLink", shLink)
|
|
q.Set("passCode", passCode)
|
|
u.RawQuery = q.Encode()
|
|
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)
|
|
if err != nil {
|
|
return nil, &errors.HttpError{
|
|
StatusCode: http.StatusInternalServerError,
|
|
Body: []map[string]interface{}{{"error": "internal_error", "message": "Failed to create request"}},
|
|
Err: err,
|
|
}
|
|
}
|
|
req.Header.Set("Accept", "application/json")
|
|
|
|
resp, err := c.Client.Do(req)
|
|
if err != nil {
|
|
return nil, &errors.HttpError{
|
|
StatusCode: http.StatusBadGateway,
|
|
Body: []map[string]interface{}{{"error": "service_unavailable", "message": "Failed to connect to VHL service"}},
|
|
Err: err,
|
|
}
|
|
}
|
|
defer utils.CloseBody(resp.Body)
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
bodyBytes, readErr := io.ReadAll(resp.Body)
|
|
if readErr != nil {
|
|
return nil, &errors.HttpError{
|
|
StatusCode: resp.StatusCode,
|
|
Body: []map[string]interface{}{{"error": "internal_error", "message": "Failed to read response body"}},
|
|
Err: readErr,
|
|
}
|
|
}
|
|
return nil, &errors.HttpError{
|
|
StatusCode: resp.StatusCode,
|
|
Body: []map[string]interface{}{{"error": "service_error", "message": string(bodyBytes)}},
|
|
Err: fmt.Errorf("unexpected status code %d: %s", resp.StatusCode, string(bodyBytes)),
|
|
}
|
|
}
|
|
|
|
var manifest VhlManifestResponse
|
|
if err := json.NewDecoder(resp.Body).Decode(&manifest); err != nil {
|
|
return nil, &errors.HttpError{
|
|
StatusCode: http.StatusInternalServerError,
|
|
Body: []map[string]interface{}{{"error": "internal_error", "message": "Failed to decode manifest response"}},
|
|
Err: err,
|
|
}
|
|
}
|
|
return &manifest, nil
|
|
}
|
|
|
|
func (c *VhlClient) ICVPValidate(ctx context.Context, qrData string) (*ICVPQRValidationResponse, error) {
|
|
r := ICVPQrValidationRequest{
|
|
IncludeRaw: true,
|
|
QRData: qrData,
|
|
}
|
|
body, err := json.Marshal(r)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to marshal user payload: %w", err)
|
|
}
|
|
|
|
vu := fmt.Sprintf("%s/decode/hcert", c.ICVPValidatorUrl)
|
|
req, err := http.NewRequest("POST", vu, bytes.NewBuffer(body))
|
|
if err != nil {
|
|
return nil, &errors.HttpError{
|
|
StatusCode: 500,
|
|
Body: []map[string]interface{}{{"error": "internal_error", "message": "Failed to create request"}},
|
|
Err: err,
|
|
}
|
|
}
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
resp, err := c.Client.Do(req)
|
|
|
|
if err != nil {
|
|
return nil, &errors.HttpError{
|
|
StatusCode: 502,
|
|
Body: []map[string]interface{}{{"error": "service_unavailable", "message": "Failed to connect to VHL service"}},
|
|
Err: err,
|
|
}
|
|
}
|
|
defer utils.CloseBody(resp.Body)
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
bodyBytes, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return nil, &errors.HttpError{
|
|
StatusCode: resp.StatusCode,
|
|
Body: []map[string]interface{}{{"error": "internal_error", "message": "Failed to read response body"}},
|
|
Err: err,
|
|
}
|
|
}
|
|
return nil, &errors.HttpError{
|
|
StatusCode: resp.StatusCode,
|
|
Body: []map[string]interface{}{{"error": "service_error", "message": string(bodyBytes)}},
|
|
Err: fmt.Errorf("unexpected status code %d: %s", resp.StatusCode, string(bodyBytes)),
|
|
}
|
|
}
|
|
|
|
bb, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return nil, &errors.HttpError{
|
|
StatusCode: 500,
|
|
Body: []map[string]interface{}{{"error": "internal_error", "message": "Failed to read response body"}},
|
|
Err: err,
|
|
}
|
|
}
|
|
var valResp ICVPQRValidationResponse
|
|
err = json.Unmarshal(bb, &valResp)
|
|
if err != nil {
|
|
return nil, &errors.HttpError{
|
|
StatusCode: 500,
|
|
Body: []map[string]interface{}{{"error": "internal_error", "message": "Failed to read parse response body"}},
|
|
Err: err,
|
|
}
|
|
}
|
|
return &valResp, nil
|
|
}
|