From 92f9f4d22593252018dd7aaeb1089d5fd0f09d5c Mon Sep 17 00:00:00 2001 From: masv3971 Date: Thu, 11 Apr 2024 15:39:03 +0200 Subject: [PATCH 1/9] Add target to makefile to generate openapi v3 documentation, and deps. --- Makefile | 13 +++++++++++-- go.mod | 1 + go.sum | 5 ++--- vendor/modules.txt | 2 ++ 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 4c06a750..d6b6dcba 100755 --- a/Makefile +++ b/Makefile @@ -147,7 +147,7 @@ docker-push-apigw: $(info Pushing docker images) docker push $(DOCKER_TAG_APIGW) -docker-push: docker-push-gobuild docker-push-datastore docker-push-datastore docker-push-verifier docker-push-registry docker-push-cache docker-push-persistent docker-push-apigw +docker-push: docker-push-datastore docker-push-datastore docker-push-verifier docker-push-registry docker-push-cache docker-push-persistent docker-push-apigw $(info Pushing docker images) docker-pull: @@ -213,6 +213,14 @@ swagger-verifier: swagger-apigw: swag init -d internal/apigw/apiv1/ -g client.go --output docs/apigw --parseDependency --packageName docs +openapi3-apigw: swagger-apigw + docker run --rm -v ./docs/apigw:/work openapitools/openapi-generator-cli:latest-release generate -i /work/swagger.yaml -o ./work/v3 -g openapi-yaml --minimal-update + docker run --rm -v ./docs/apigw:/work openapitools/openapi-generator-cli:latest-release generate -i /work/swagger.json -o ./work/v3 -g openapi --minimal-update + sudo mv ./docs/apigw/v3/openapi/openapi.yaml ./internal/apigw/httpserver/openapiv3/openapi.yaml + sudo mv ./docs/apigw/v3/openapi.json ./internal/apigw/httpserver/openapiv3/openapi.json + sudo rm -rf ./docs/apigw/v3 + sudo chown -R $(shell id -u):$(shell id -g) ./internal/apigw/httpserver/openapiv3/ + install-tools: $(info Install from apt) apt-get update && apt-get install -y \ @@ -239,4 +247,5 @@ vscode: go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest && \ go install golang.org/x/tools/cmd/deadcode@latest && \ go install github.com/securego/gosec/v2/cmd/gosec@latest && \ - go install honnef.co/go/tools/cmd/staticcheck@latest \ No newline at end of file + go install honnef.co/go/tools/cmd/staticcheck@latest && \ + go install github.com/deepmap/oapi-codegen/cmd/oapi-codegen@latest \ No newline at end of file diff --git a/go.mod b/go.mod index 8d8bf795..98f28be8 100644 --- a/go.mod +++ b/go.mod @@ -55,6 +55,7 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-sqlite3 v1.14.22 // indirect + github.com/rogpeppe/go-internal v1.12.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 // indirect go.opentelemetry.io/otel/metric v1.24.0 // indirect go.opentelemetry.io/proto/otlp v1.1.0 // indirect diff --git a/go.sum b/go.sum index aab64fac..2914f274 100644 --- a/go.sum +++ b/go.sum @@ -55,7 +55,6 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator v9.31.0+incompatible h1:UA72EPEogEnq76ehGdEDp4Mit+3FDh548oRqwVgNsHA= github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4= github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/go-redis/redismock/v9 v9.2.0 h1:ZrMYQeKPECZPjOj5u9eyOjg8Nnb0BS9lkVIZ6IpsKLw= @@ -120,8 +119,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/redis/go-redis/v9 v9.5.1 h1:H1X4D3yHPaYrkL5X06Wh6xNVM/pX0Ft4RV0vMGvLBh8= github.com/redis/go-redis/v9 v9.5.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 h1:unQFBIznI+VYD1/1fApl1A+9VcBk+9dcqGfnePY87LY= diff --git a/vendor/modules.txt b/vendor/modules.txt index 0945db49..ff032797 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -213,6 +213,8 @@ github.com/redis/go-redis/v9/internal/pool github.com/redis/go-redis/v9/internal/proto github.com/redis/go-redis/v9/internal/rand github.com/redis/go-redis/v9/internal/util +# github.com/rogpeppe/go-internal v1.12.0 +## explicit; go 1.20 # github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e ## explicit; go 1.13 github.com/skip2/go-qrcode From dea74dd186d519242a0b7ae9206cf1ed9911f2bd Mon Sep 17 00:00:00 2001 From: masv3971 Date: Thu, 11 Apr 2024 15:46:14 +0200 Subject: [PATCH 2/9] Clean up. --- cmd/apigw/main.go | 3 --- internal/apigw/apiv1/client.go | 4 ---- 2 files changed, 7 deletions(-) diff --git a/cmd/apigw/main.go b/cmd/apigw/main.go index d8d8ec7b..7a4208eb 100644 --- a/cmd/apigw/main.go +++ b/cmd/apigw/main.go @@ -20,8 +20,6 @@ type service interface { Close(ctx context.Context) error } -var GitCommit string - func main() { var wg sync.WaitGroup ctx := context.Background() @@ -37,7 +35,6 @@ func main() { if err != nil { panic(err) } - log.Info("compile variable", "git commit", GitCommit) tracer, err := trace.New(ctx, cfg, log, "vc", "apigw") if err != nil { panic(err) diff --git a/internal/apigw/apiv1/client.go b/internal/apigw/apiv1/client.go index 11e75cb9..ffa9ca3e 100644 --- a/internal/apigw/apiv1/client.go +++ b/internal/apigw/apiv1/client.go @@ -10,10 +10,6 @@ import ( "vc/pkg/trace" ) -var ( - BuildVarGitCommit string -) - // @title Datastore API // @version 0.1.0 // @BasePath /api/v1 From 6d7230dd9f3dbd39b033e222c3b867fb11f23216 Mon Sep 17 00:00:00 2001 From: masv3971 Date: Thu, 11 Apr 2024 15:49:06 +0200 Subject: [PATCH 3/9] Add tracing. --- cmd/cache/main.go | 2 +- cmd/persistent/main.go | 2 +- internal/apigw/apiv1/handlers_misc.go | 3 +++ internal/apigw/apiv1/handlers_vc.go | 36 +++++++++++++++++++++++++++ pkg/helpers/validate.go | 4 ++- pkg/kvclient/client.go | 3 +++ pkg/trace/otel.go | 10 +++++--- 7 files changed, 54 insertions(+), 6 deletions(-) diff --git a/cmd/cache/main.go b/cmd/cache/main.go index 1b62968e..9f642cbe 100644 --- a/cmd/cache/main.go +++ b/cmd/cache/main.go @@ -34,7 +34,7 @@ func main() { if err != nil { panic(err) } - tracer, err := trace.New(ctx, cfg, log, "vc_cache", "cache") + tracer, err := trace.New(ctx, cfg, log, "vc", "cache") if err != nil { panic(err) } diff --git a/cmd/persistent/main.go b/cmd/persistent/main.go index 4fe69969..a145aab4 100644 --- a/cmd/persistent/main.go +++ b/cmd/persistent/main.go @@ -35,7 +35,7 @@ func main() { if err != nil { panic(err) } - tracer, err := trace.New(ctx, cfg, log, "vc_persistent", "cache") + tracer, err := trace.New(ctx, cfg, log, "vc", "persistent") if err != nil { panic(err) } diff --git a/internal/apigw/apiv1/handlers_misc.go b/internal/apigw/apiv1/handlers_misc.go index e7faa2c2..29d57470 100644 --- a/internal/apigw/apiv1/handlers_misc.go +++ b/internal/apigw/apiv1/handlers_misc.go @@ -8,6 +8,9 @@ import ( // Health return health for this service and dependencies func (c *Client) Health(ctx context.Context, req *apiv1_status.StatusRequest) (*apiv1_status.StatusReply, error) { + ctx, span := c.tp.Start(ctx, "apiv1:Health") + defer span.End() + c.log.Info("health handler") probes := model.Probes{} probes = append(probes, c.kv.Status(ctx)) diff --git a/internal/apigw/apiv1/handlers_vc.go b/internal/apigw/apiv1/handlers_vc.go index a473b6e1..d8fd24f6 100644 --- a/internal/apigw/apiv1/handlers_vc.go +++ b/internal/apigw/apiv1/handlers_vc.go @@ -6,6 +6,8 @@ import ( "vc/internal/apigw/db" "vc/pkg/helpers" "vc/pkg/model" + + "go.opentelemetry.io/otel/codes" ) // UploadReply is the reply for a generic upload @@ -28,11 +30,16 @@ type UploadReply struct { // @Param req body model.Upload true " " // @Router /upload [post] func (c *Client) Upload(ctx context.Context, req *model.Upload) error { + ctx, span := c.tp.Start(ctx, "apiv1:Upload") + defer span.End() + if err := helpers.Check(ctx, c.cfg, req, c.log); err != nil { + span.SetStatus(codes.Error, err.Error()) return err } if err := req.QRGenerator(ctx, c.cfg.Common.QR.BaseURL, c.cfg.Common.QR.RecoveryLevel, c.cfg.Common.QR.Size); err != nil { + span.SetStatus(codes.Error, err.Error()) return err } @@ -40,6 +47,7 @@ func (c *Client) Upload(ctx context.Context, req *model.Upload) error { _, err := c.simpleQueue.VCPersistentSave.Enqueue(ctx, req) if err != nil { + span.SetStatus(codes.Error, err.Error()) return err } return nil @@ -70,12 +78,16 @@ type NotificationReply struct { // @Param req body NotificationRequest true " " // @Router /notification [post] func (c *Client) Notification(ctx context.Context, req *NotificationRequest) (*NotificationReply, error) { + ctx, span := c.tp.Start(ctx, "apiv1:Notification") + defer span.End() + qrCode, err := c.db.VCDatastoreColl.GetQR(ctx, &model.MetaData{ AuthenticSource: req.AuthenticSource, DocumentType: req.DocumentType, DocumentID: req.DocumentID, }) if err != nil { + span.SetStatus(codes.Error, err.Error()) return nil, err } @@ -111,7 +123,11 @@ type IDMappingReply struct { // @Param req body model.MetaData true " " // @Router /id_mapping [post] func (c *Client) IDMapping(ctx context.Context, reg *IDMappingRequest) (*IDMappingReply, error) { + ctx, span := c.tp.Start(ctx, "apiv1:IDMapping") + defer span.End() + if err := helpers.Check(ctx, c.cfg, reg, c.log); err != nil { + span.SetStatus(codes.Error, err.Error()) return nil, err } authenticSourcePersonID, err := c.db.VCDatastoreColl.IDMapping(ctx, &db.IDMappingQuery{ @@ -119,6 +135,7 @@ func (c *Client) IDMapping(ctx context.Context, reg *IDMappingRequest) (*IDMappi Identity: reg.Identity, }) if err != nil { + span.SetStatus(codes.Error, err.Error()) return nil, err } reply := &IDMappingReply{ @@ -157,6 +174,9 @@ type GetDocumentReply struct { // @Param req body GetDocumentRequest true " " // @Router /document [post] func (c *Client) GetDocument(ctx context.Context, req *GetDocumentRequest) (*GetDocumentReply, error) { + ctx, span := c.tp.Start(ctx, "apiv1:GetDocument") + defer span.End() + query := &model.MetaData{ DocumentID: req.DocumentID, DocumentType: req.DocumentType, @@ -164,6 +184,7 @@ func (c *Client) GetDocument(ctx context.Context, req *GetDocumentRequest) (*Get } doc, err := c.db.VCDatastoreColl.GetDocument(ctx, query) if err != nil { + span.SetStatus(codes.Error, err.Error()) return nil, err } reply := &GetDocumentReply{ @@ -196,12 +217,17 @@ type DeleteDocumentRequest struct { // @Param req body DeleteDocumentRequest true " " // @Router /document [delete] func (c *Client) DeleteDocument(ctx context.Context, req *DeleteDocumentRequest) error { + ctx, span := c.tp.Start(ctx, "apiv1:DeleteDocument") + defer span.End() + if err := helpers.Check(ctx, c.cfg, req, c.log); err != nil { + span.SetStatus(codes.Error, err.Error()) return err } _, err := c.simpleQueue.VCPersistentDelete.Enqueue(ctx, req) if err != nil { + span.SetStatus(codes.Error, err.Error()) return err } @@ -232,7 +258,11 @@ type GetDocumentAttestationReply struct { // @Param req body model.MetaData true " " // @Router /document/collection_code [post] func (c *Client) GetDocumentAttestation(ctx context.Context, req *GetDocumentAttestationRequest) (*GetDocumentAttestationReply, error) { + ctx, span := c.tp.Start(ctx, "apiv1:GetDocumentAttestation") + defer span.End() + if err := helpers.Check(ctx, c.cfg, req, c.log); err != nil { + span.SetStatus(codes.Error, err.Error()) return nil, err } @@ -243,6 +273,7 @@ func (c *Client) GetDocumentAttestation(ctx context.Context, req *GetDocumentAtt doc, err := c.db.VCDatastoreColl.GetDocumentAttestation(ctx, query) if err != nil { + span.SetStatus(codes.Error, err.Error()) return nil, err } @@ -278,7 +309,11 @@ type PortalReply struct { // @Param req body PortalRequest true " " // @Router /portal [post] func (c *Client) Portal(ctx context.Context, req *PortalRequest) (*PortalReply, error) { + ctx, span := c.tp.Start(ctx, "apiv1:Portal") + defer span.End() + if err := helpers.Check(ctx, c.cfg, req, c.log); err != nil { + span.SetStatus(codes.Error, err.Error()) return nil, err } @@ -290,6 +325,7 @@ func (c *Client) Portal(ctx context.Context, req *PortalRequest) (*PortalReply, } portalData, err := c.db.VCDatastoreColl.PortalData(ctx, query) if err != nil { + span.SetStatus(codes.Error, err.Error()) return nil, err } diff --git a/pkg/helpers/validate.go b/pkg/helpers/validate.go index 74aeef0c..26bad902 100644 --- a/pkg/helpers/validate.go +++ b/pkg/helpers/validate.go @@ -9,11 +9,12 @@ import ( "vc/pkg/trace" "github.com/go-playground/validator/v10" + "go.opentelemetry.io/otel/codes" ) // Check checks for validation error func Check(ctx context.Context, cfg *model.Cfg, s any, log *logger.Log) error { - tp, err := trace.New(ctx, cfg, log, "vc", "vc") + tp, err := trace.New(ctx, cfg, log, "vc", "helpers:check") if err != nil { return err } @@ -33,6 +34,7 @@ func Check(ctx context.Context, cfg *model.Cfg, s any, log *logger.Log) error { }) if err := validate.Struct(s); err != nil { + span.SetStatus(codes.Error, err.Error()) return NewErrorFromError(err) } diff --git a/pkg/kvclient/client.go b/pkg/kvclient/client.go index f6fe65af..9c799c83 100644 --- a/pkg/kvclient/client.go +++ b/pkg/kvclient/client.go @@ -52,6 +52,9 @@ func New(ctx context.Context, cfg *model.Cfg, tracer *trace.Tracer, log *logger. // Status returns the status of the database func (c *Client) Status(ctx context.Context) *apiv1_status.StatusProbe { + ctx, span := c.tp.Start(ctx, "kvclient:Status") + defer span.End() + if time.Now().Before(c.probeStore.NextCheck.AsTime()) { return c.probeStore.PreviousResult } diff --git a/pkg/trace/otel.go b/pkg/trace/otel.go index 16990235..ee30b33e 100644 --- a/pkg/trace/otel.go +++ b/pkg/trace/otel.go @@ -48,14 +48,14 @@ func New(ctx context.Context, cfg *model.Cfg, log *logger.Log, projectName, serv } tracer := &Tracer{ - TP: newTraceProvider(exp, projectName), + TP: newTraceProvider(exp, serviceName), log: log, } otel.SetTracerProvider(tracer.TP) otel.SetTextMapPropagator(jaegerPropagator.Jaeger{}) - tracer.Tracer = otel.Tracer("") + tracer.Tracer = otel.Tracer(projectName) return tracer, nil } @@ -63,5 +63,9 @@ func New(ctx context.Context, cfg *model.Cfg, log *logger.Log, projectName, serv // Shutdown shuts down the tracer func (t *Tracer) Shutdown(ctx context.Context) error { t.log.Info("Shutting down tracer") - return t.TP.Shutdown(ctx) + if err := t.TP.Shutdown(ctx); err != nil { + return err + } + ctx.Done() + return nil } From b94ccc6617eeae45e3d64570a5810e85016b0051 Mon Sep 17 00:00:00 2001 From: masv3971 Date: Thu, 11 Apr 2024 15:49:55 +0200 Subject: [PATCH 4/9] Integrate mockas to apigw and new api spec. --- internal/mockas/apiv1/datastore_request.go | 4 ++ internal/mockas/apiv1/handlers.go | 12 ++---- internal/mockas/apiv1/utils.go | 43 +++++++++++++++++++++- 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/internal/mockas/apiv1/datastore_request.go b/internal/mockas/apiv1/datastore_request.go index 74717841..8d19e62c 100644 --- a/internal/mockas/apiv1/datastore_request.go +++ b/internal/mockas/apiv1/datastore_request.go @@ -29,6 +29,7 @@ func (c *Client) uploader(ctx context.Context, upload *model.Upload) (*uploaderR reply, ) if err != nil { + c.log.Debug("uploader", "error", err) return nil, resp, err } @@ -90,6 +91,7 @@ func (c *Client) do(ctx context.Context, req *http.Request, value any) (*http.Re c.log.Debug("json unmarshal", "error", err) return nil, err } + c.log.Debug("checkResponse", "error", err) return nil, caError } @@ -121,11 +123,13 @@ func (c *Client) call(ctx context.Context, method, path string, body, reply any) body, ) if err != nil { + c.log.Debug("call", "error", err) return nil, err } resp, err := c.do(ctx, request, reply) if err != nil { + c.log.Debug("do", "error", err) return resp, err } diff --git a/internal/mockas/apiv1/handlers.go b/internal/mockas/apiv1/handlers.go index 47adc736..3cc029df 100644 --- a/internal/mockas/apiv1/handlers.go +++ b/internal/mockas/apiv1/handlers.go @@ -22,16 +22,15 @@ func (c *Client) MockNext(ctx context.Context, inData *MockNextRequest) (*MockNe // send to datastore mockUpload, err := c.mockOne(ctx, inData.AuthenticSource, inData.DocumentType) if err != nil { + c.log.Debug("mocknext", "mockone", err) return nil, err } - restReply, _, err := c.uploader(ctx, mockUpload) + _, _, err = c.uploader(ctx, mockUpload) if err != nil { + c.log.Debug("uploader", "error", err) return nil, err } - if restReply.Data.Status != "OK" { - return nil, errors.New("upload failed") - } reply := &MockNextReply{ Upload: mockUpload, @@ -67,13 +66,10 @@ func (c *Client) MockBulk(ctx context.Context, inData *MockBulkRequest) (*MockBu } documentIDS = append(documentIDS, mockUpload.Meta.DocumentID) - restReply, _, err := c.uploader(ctx, mockUpload) + _, _, err = c.uploader(ctx, mockUpload) if err != nil { return nil, err } - if restReply.Data.Status != "OK" { - return nil, errors.New("upload failed") - } } return &MockBulkReply{ diff --git a/internal/mockas/apiv1/utils.go b/internal/mockas/apiv1/utils.go index 4a261712..5ee12370 100644 --- a/internal/mockas/apiv1/utils.go +++ b/internal/mockas/apiv1/utils.go @@ -13,6 +13,7 @@ func (c *Client) mockOne(ctx context.Context, authenticSource, documentType stri meta := &model.MetaData{ AuthenticSource: authenticSource, AuthenticSourcePersonID: gofakeit.UUID(), + DocumentVersion: 1, DocumentType: documentType, DocumentID: gofakeit.UUID(), FirstName: person.FirstName, @@ -21,9 +22,49 @@ func (c *Client) mockOne(ctx context.Context, authenticSource, documentType stri UID: gofakeit.UUID(), RevocationID: gofakeit.UUID(), CollectID: gofakeit.UUID(), + MemberState: "SE", + ValidFrom: gofakeit.Date().String(), + ValidTo: gofakeit.Date().String(), } + + attestation := &model.Attestation{ + Version: 1, + Type: documentType, + DescriptionShort: "a short description", + DescriptionLong: "a longer description", + } + + identity := &model.Identity{ + Version: "1", + FamilyName: gofakeit.LastName(), + GivenName: gofakeit.FirstName(), + BirthDate: gofakeit.Date().String(), + UID: gofakeit.UUID(), + FamilyNameAtBirth: gofakeit.LastName(), + GivenNameAtBirth: gofakeit.FirstName(), + BirthPlace: gofakeit.City(), + Gender: gofakeit.RandomString([]string{"M", "F", "X"}), + AgeOver18: "", + AgeOverNN: "", + AgeInYears: "", + AgeBirthYear: "", + BirthCountry: "", + BirthState: "", + BirthCity: "", + ResidentAddress: "", + ResidentCountry: "", + ResidentState: "", + ResidentCity: "", + ResidentPostalCode: "", + ResidentStreet: "", + ResidentHouseNumber: "", + Nationality: "", + } + mockUpload := &model.Upload{ - Meta: meta, + Meta: meta, + Attestation: attestation, + Identity: identity, } switch documentType { From fcf3b0c96a184134ee2ffaee9046f65d4bcf4999 Mon Sep 17 00:00:00 2001 From: masv3971 Date: Thu, 11 Apr 2024 15:50:35 +0200 Subject: [PATCH 5/9] Remove tracing from middleware, it does not work as intended. --- internal/apigw/httpserver/middleware.go | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/internal/apigw/httpserver/middleware.go b/internal/apigw/httpserver/middleware.go index ae77b99b..619e7b41 100755 --- a/internal/apigw/httpserver/middleware.go +++ b/internal/apigw/httpserver/middleware.go @@ -16,6 +16,7 @@ func (s *Service) middlewareDuration(ctx context.Context) gin.HandlerFunc { c.Next() duration := time.Since(t) c.Set("duration", duration) + c.Header("duration", duration.String()) } } @@ -36,9 +37,6 @@ func (s *Service) middlewareLogger(ctx context.Context) gin.HandlerFunc { } func (s *Service) middlewareAuthLog(ctx context.Context) gin.HandlerFunc { - ctx, span := s.tp.Start(ctx, "httpserver:middlewareAuthLog") - defer span.End() - log := s.logger.New("http") return func(c *gin.Context) { u, _ := c.Get("user") @@ -48,9 +46,6 @@ func (s *Service) middlewareAuthLog(ctx context.Context) gin.HandlerFunc { } func (s *Service) middlewareValidationCert(ctx context.Context) gin.HandlerFunc { - ctx, span := s.tp.Start(ctx, "httpserver:middlewareValidationCert") - defer span.End() - log := s.logger.New("http") return func(c *gin.Context) { s.server.TLSConfig = s.tlsConfig @@ -67,7 +62,7 @@ func (s *Service) middlewareCrash(ctx context.Context) gin.HandlerFunc { if r := recover(); r != nil { status := c.Writer.Status() log.Trace("crash", "error", r, "status", status, "url", c.Request.URL.Path, "method", c.Request.Method) - renderContent(c, 500, gin.H{"data": nil, "error": helpers.NewError("internal_server_error")}) + s.renderContent(ctx, c, 500, gin.H{"data": nil, "error": helpers.NewError("internal_server_error")}) } }() c.Next() @@ -75,9 +70,6 @@ func (s *Service) middlewareCrash(ctx context.Context) gin.HandlerFunc { } func (s *Service) middlewareClientCertAuth(ctx context.Context) gin.HandlerFunc { - ctx, span := s.tp.Start(ctx, "httpserver:middlewareClientCertAuth") - defer span.End() - log := s.logger.New("http") return func(c *gin.Context) { clientCertSHA1 := c.Request.Header.Get("X-SSL-Client-SHA1") From 570a8d99061111b1801c2634a011646535a434b8 Mon Sep 17 00:00:00 2001 From: masv3971 Date: Thu, 11 Apr 2024 15:52:13 +0200 Subject: [PATCH 6/9] Add openapi v3 staticfile endpoint as well as building of the spec from swagger. --- docs/apigw/swagger.json | 279 +++- docs/apigw/swagger.yaml | 289 +++- .../apigw/httpserver/openapiv3/openapi.json | 1020 +++++++++++++++ .../apigw/httpserver/openapiv3/openapi.yaml | 1164 +++++++++++++++++ internal/apigw/httpserver/service.go | 40 +- 5 files changed, 2737 insertions(+), 55 deletions(-) create mode 100644 internal/apigw/httpserver/openapiv3/openapi.json create mode 100644 internal/apigw/httpserver/openapiv3/openapi.yaml diff --git a/docs/apigw/swagger.json b/docs/apigw/swagger.json index 8a7598ca..da9299b7 100644 --- a/docs/apigw/swagger.json +++ b/docs/apigw/swagger.json @@ -46,6 +46,42 @@ } } } + }, + "delete": { + "description": "delete one document endpoint", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "dc4eu" + ], + "summary": "DeleteDocument", + "operationId": "delete-document", + "parameters": [ + { + "description": " ", + "name": "req", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/apiv1.DeleteDocumentRequest" + } + } + ], + "responses": { + "200": { + "description": "Success" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/helpers.ErrorResponse" + } + } + } } }, "/document/collection_code": { @@ -290,9 +326,9 @@ } } }, - "/metadata": { + "/notification": { "post": { - "description": "List metadata endpoint", + "description": "notification endpoint", "consumes": [ "application/json" ], @@ -302,8 +338,8 @@ "tags": [ "dc4eu" ], - "summary": "ListMetadata", - "operationId": "list-metadata", + "summary": "Notification", + "operationId": "generic-notification", "parameters": [ { "description": " ", @@ -311,7 +347,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/apiv1.ListMetadataRequest" + "$ref": "#/definitions/apiv1.NotificationRequest" } } ], @@ -319,7 +355,7 @@ "200": { "description": "Success", "schema": { - "$ref": "#/definitions/apiv1.ListMetadataReply" + "$ref": "#/definitions/apiv1.NotificationReply" } }, "400": { @@ -456,6 +492,19 @@ } }, "definitions": { + "apiv1.DeleteDocumentRequest": { + "type": "object", + "properties": { + "authentic_source": { + "description": "required: true\nexample: skatteverket", + "type": "string" + }, + "document_id": { + "description": "required: true\nexample: 5e7a981c-c03f-11ee-b116-9b12c59362b9", + "type": "string" + } + } + }, "apiv1.GetDocumentReply": { "type": "object", "properties": { @@ -491,24 +540,24 @@ } } }, - "apiv1.ListMetadataReply": { + "apiv1.NotificationReply": { "type": "object", "properties": { "data": { - "type": "array", - "items": { - "$ref": "#/definitions/model.MetaData" - } + "$ref": "#/definitions/model.QR" } } }, - "apiv1.ListMetadataRequest": { + "apiv1.NotificationRequest": { "type": "object", "properties": { "authentic_source": { "type": "string" }, - "authentic_source_person_id": { + "document_id": { + "type": "string" + }, + "document_type": { "type": "string" } } @@ -591,19 +640,29 @@ "data": { "type": "array", "items": { - "$ref": "#/definitions/model.MetaData" + "$ref": "#/definitions/model.Upload" } } } }, "apiv1.PortalRequest": { "type": "object", + "required": [ + "authentic_source", + "authentic_source_person_id" + ], "properties": { "authentic_source": { "type": "string" }, "authentic_source_person_id": { "type": "string" + }, + "validity_from": { + "type": "string" + }, + "validity_to": { + "type": "string" } } }, @@ -667,6 +726,141 @@ } } }, + "model.Attestation": { + "type": "object", + "required": [ + "description_long", + "description_short", + "type", + "version" + ], + "properties": { + "description_long": { + "description": "TODO(masv): change TextLong to DescriptionLong\nrequired: true\nexample: European Health Insurance Card", + "type": "string" + }, + "description_short": { + "description": "TODO(masv): ShortText to DescriptionShort, more descriptive, pun intended\nrequired: true\nexample: EHIC", + "type": "string" + }, + "type": { + "description": "required: true\nexample: secure", + "type": "string" + }, + "version": { + "description": "TODO(masv): change AttestationDataVersion to AttestationVersion, data seems redundant\nrequired: true\nexample: 1.0.0", + "type": "integer" + } + } + }, + "model.Identity": { + "type": "object", + "required": [ + "birth_date", + "family_name", + "given_name", + "uid", + "version" + ], + "properties": { + "age_birth_year": { + "description": "TODO(masv): int instead of string?\nrequired: false\nexample: 1970", + "type": "string" + }, + "age_in_years": { + "description": "TODO(masv): int instead of string?\nrequired: false\nexample: 19", + "type": "string" + }, + "age_over_18": { + "description": "TODO(masv): int instead of string?\nrequired: false\nexample: 19", + "type": "string" + }, + "age_over_nn": { + "description": "TODO(masv): int instead of string? How is supposed to work, query NN?\nrequired: false\nexample: 19", + "type": "string" + }, + "birth_city": { + "description": "required: false\nexample: Stockholm", + "type": "string" + }, + "birth_country": { + "description": "TODO(masv): full name or just country code?\nrequired: false\nexample: sweden", + "type": "string" + }, + "birth_date": { + "description": "required: true\nexample: 1970-01-01", + "type": "string" + }, + "birth_place": { + "description": "required: false\nexample: Stockholm", + "type": "string" + }, + "birth_state": { + "description": "required: false\nexample: Stockholm", + "type": "string" + }, + "family_name": { + "description": "required: true\nexample: Svensson", + "type": "string" + }, + "family_name_at_birth": { + "description": "required: false\nexample: Karlsson", + "type": "string" + }, + "gender": { + "description": "required: false\nexample: male", + "type": "string" + }, + "given_name": { + "description": "required: true\nexample: Magnus", + "type": "string" + }, + "given_name_at_birth": { + "description": "required: false\nexample: Magnus", + "type": "string" + }, + "nationality": { + "description": "required: false\nexample: swedish", + "type": "string" + }, + "resident_address": { + "description": "required: false\nexample: 221b baker street", + "type": "string" + }, + "resident_city": { + "description": "required: false\nexample: london", + "type": "string" + }, + "resident_country": { + "description": "required: false\nexample: england", + "type": "string" + }, + "resident_house_number": { + "description": "required: false\nexample: 221b", + "type": "string" + }, + "resident_postal_code": { + "description": "required: false\nexample: W1U 6SG", + "type": "string" + }, + "resident_state": { + "description": "required: false\nexample: england", + "type": "string" + }, + "resident_street": { + "description": "required: false\nexample: baker street", + "type": "string" + }, + "uid": { + "description": "required: true\nexample: 85f90d4c-c03f-11ee-9386-ef1b105c4f3e", + "type": "string" + }, + "version": { + "description": "required: true\nexample: 1.0.0", + "type": "string" + } + } + }, "model.MetaData": { "type": "object", "required": [ @@ -676,14 +870,18 @@ "date_of_birth", "document_id", "document_type", + "document_version", "first_name", "last_name", + "member_state", "revocation_id", - "uid" + "uid", + "valid_from", + "valid_to" ], "properties": { "authentic_source": { - "description": "required: true\nexample: Sunet", + "description": "required: true\nexample: SUNET", "type": "string" }, "authentic_source_person_id": { @@ -691,7 +889,11 @@ "type": "string" }, "collect_id": { - "description": "required: true\nexample: 98fe67fc-c03f-11ee-bbee-4345224d414f", + "description": "required: false\nexample: 98fe67fc-c03f-11ee-bbee-4345224d414f", + "type": "string" + }, + "created_at": { + "description": "required: false\nexample: 2024-03-15T10:00:00Z+01:00", "type": "string" }, "date_of_birth": { @@ -710,6 +912,11 @@ "EHIC" ] }, + "document_version": { + "description": "required: true\nexample: 1", + "type": "integer", + "minimum": 1 + }, "first_name": { "description": "required: true\nexample: John", "type": "string" @@ -718,44 +925,64 @@ "description": "required: true\nexample: Doe", "type": "string" }, - "qr": { - "description": "required: false", - "allOf": [ - { - "$ref": "#/definitions/model.QR" - } - ] + "member_state": { + "description": "required: true\nexample: \"DE\"", + "type": "string" }, "revocation_id": { - "description": "required: true\nexample: 8dbd2680-c03f-11ee-a21b-034aafe41222", + "description": "required: false\nexample: 8dbd2680-c03f-11ee-a21b-034aafe41222", "type": "string" }, "uid": { "description": "required: true\nexample: 85f90d4c-c03f-11ee-9386-ef1b105c4f3e", "type": "string" + }, + "valid_from": { + "description": "TODO(masv): ISO8601?\nrequired: true\nexample: 2024-01-01", + "type": "string" + }, + "valid_to": { + "description": "TODO(masv): ISO8601?\nrequired: true\nexample: 2024-12-31", + "type": "string" } } }, "model.QR": { "type": "object", "required": [ - "base64_image" + "base64_image", + "deep_link" ], "properties": { "base64_image": { "type": "string" + }, + "deep_link": { + "type": "string" } } }, "model.Upload": { "type": "object", "required": [ + "attestation", + "document_data", + "identity", "meta" ], "properties": { + "attestation": { + "$ref": "#/definitions/model.Attestation" + }, "document_data": {}, + "identity": { + "$ref": "#/definitions/model.Identity" + }, "meta": { "$ref": "#/definitions/model.MetaData" + }, + "qr": { + "$ref": "#/definitions/model.QR" } } }, diff --git a/docs/apigw/swagger.yaml b/docs/apigw/swagger.yaml index 149ceeb8..9f671527 100644 --- a/docs/apigw/swagger.yaml +++ b/docs/apigw/swagger.yaml @@ -1,5 +1,18 @@ basePath: /api/v1 definitions: + apiv1.DeleteDocumentRequest: + properties: + authentic_source: + description: |- + required: true + example: skatteverket + type: string + document_id: + description: |- + required: true + example: 5e7a981c-c03f-11ee-b116-9b12c59362b9 + type: string + type: object apiv1.GetDocumentReply: properties: data: @@ -22,18 +35,18 @@ definitions: type: string type: object type: object - apiv1.ListMetadataReply: + apiv1.NotificationReply: properties: data: - items: - $ref: '#/definitions/model.MetaData' - type: array + $ref: '#/definitions/model.QR' type: object - apiv1.ListMetadataRequest: + apiv1.NotificationRequest: properties: authentic_source: type: string - authentic_source_person_id: + document_id: + type: string + document_type: type: string type: object apiv1.PDFGetSignedReply: @@ -85,7 +98,7 @@ definitions: properties: data: items: - $ref: '#/definitions/model.MetaData' + $ref: '#/definitions/model.Upload' type: array type: object apiv1.PortalRequest: @@ -94,6 +107,13 @@ definitions: type: string authentic_source_person_id: type: string + validity_from: + type: string + validity_to: + type: string + required: + - authentic_source + - authentic_source_person_id type: object apiv1.RevokeReply: properties: @@ -133,12 +153,177 @@ definitions: error: $ref: '#/definitions/helpers.Error' type: object + model.Attestation: + properties: + description_long: + description: |- + TODO(masv): change TextLong to DescriptionLong + required: true + example: European Health Insurance Card + type: string + description_short: + description: |- + TODO(masv): ShortText to DescriptionShort, more descriptive, pun intended + required: true + example: EHIC + type: string + type: + description: |- + required: true + example: secure + type: string + version: + description: |- + TODO(masv): change AttestationDataVersion to AttestationVersion, data seems redundant + required: true + example: 1.0.0 + type: integer + required: + - description_long + - description_short + - type + - version + type: object + model.Identity: + properties: + age_birth_year: + description: |- + TODO(masv): int instead of string? + required: false + example: 1970 + type: string + age_in_years: + description: |- + TODO(masv): int instead of string? + required: false + example: 19 + type: string + age_over_18: + description: |- + TODO(masv): int instead of string? + required: false + example: 19 + type: string + age_over_nn: + description: |- + TODO(masv): int instead of string? How is supposed to work, query NN? + required: false + example: 19 + type: string + birth_city: + description: |- + required: false + example: Stockholm + type: string + birth_country: + description: |- + TODO(masv): full name or just country code? + required: false + example: sweden + type: string + birth_date: + description: |- + required: true + example: 1970-01-01 + type: string + birth_place: + description: |- + required: false + example: Stockholm + type: string + birth_state: + description: |- + required: false + example: Stockholm + type: string + family_name: + description: |- + required: true + example: Svensson + type: string + family_name_at_birth: + description: |- + required: false + example: Karlsson + type: string + gender: + description: |- + required: false + example: male + type: string + given_name: + description: |- + required: true + example: Magnus + type: string + given_name_at_birth: + description: |- + required: false + example: Magnus + type: string + nationality: + description: |- + required: false + example: swedish + type: string + resident_address: + description: |- + required: false + example: 221b baker street + type: string + resident_city: + description: |- + required: false + example: london + type: string + resident_country: + description: |- + required: false + example: england + type: string + resident_house_number: + description: |- + required: false + example: 221b + type: string + resident_postal_code: + description: |- + required: false + example: W1U 6SG + type: string + resident_state: + description: |- + required: false + example: england + type: string + resident_street: + description: |- + required: false + example: baker street + type: string + uid: + description: |- + required: true + example: 85f90d4c-c03f-11ee-9386-ef1b105c4f3e + type: string + version: + description: |- + required: true + example: 1.0.0 + type: string + required: + - birth_date + - family_name + - given_name + - uid + - version + type: object model.MetaData: properties: authentic_source: description: |- required: true - example: Sunet + example: SUNET type: string authentic_source_person_id: description: |- @@ -147,9 +332,14 @@ definitions: type: string collect_id: description: |- - required: true + required: false example: 98fe67fc-c03f-11ee-bbee-4345224d414f type: string + created_at: + description: |- + required: false + example: 2024-03-15T10:00:00Z+01:00 + type: string date_of_birth: description: |- required: true @@ -168,6 +358,12 @@ definitions: - PDA1 - EHIC type: string + document_version: + description: |- + required: true + example: 1 + minimum: 1 + type: integer first_name: description: |- required: true @@ -178,13 +374,14 @@ definitions: required: true example: Doe type: string - qr: - allOf: - - $ref: '#/definitions/model.QR' - description: 'required: false' - revocation_id: + member_state: description: |- required: true + example: "DE" + type: string + revocation_id: + description: |- + required: false example: 8dbd2680-c03f-11ee-a21b-034aafe41222 type: string uid: @@ -192,6 +389,18 @@ definitions: required: true example: 85f90d4c-c03f-11ee-9386-ef1b105c4f3e type: string + valid_from: + description: |- + TODO(masv): ISO8601? + required: true + example: 2024-01-01 + type: string + valid_to: + description: |- + TODO(masv): ISO8601? + required: true + example: 2024-12-31 + type: string required: - authentic_source - authentic_source_person_id @@ -199,24 +408,40 @@ definitions: - date_of_birth - document_id - document_type + - document_version - first_name - last_name + - member_state - revocation_id - uid + - valid_from + - valid_to type: object model.QR: properties: base64_image: type: string + deep_link: + type: string required: - base64_image + - deep_link type: object model.Upload: properties: + attestation: + $ref: '#/definitions/model.Attestation' document_data: {} + identity: + $ref: '#/definitions/model.Identity' meta: $ref: '#/definitions/model.MetaData' + qr: + $ref: '#/definitions/model.QR' required: + - attestation + - document_data + - identity - meta type: object types.Document: @@ -263,6 +488,30 @@ info: version: 0.1.0 paths: /document: + delete: + consumes: + - application/json + description: delete one document endpoint + operationId: delete-document + parameters: + - description: ' ' + in: body + name: req + required: true + schema: + $ref: '#/definitions/apiv1.DeleteDocumentRequest' + produces: + - application/json + responses: + "200": + description: Success + "400": + description: Bad Request + schema: + $ref: '#/definitions/helpers.ErrorResponse' + summary: DeleteDocument + tags: + - dc4eu post: consumes: - application/json @@ -449,31 +698,31 @@ paths: summary: Validate pdf tags: - ladok - /metadata: + /notification: post: consumes: - application/json - description: List metadata endpoint - operationId: list-metadata + description: notification endpoint + operationId: generic-notification parameters: - description: ' ' in: body name: req required: true schema: - $ref: '#/definitions/apiv1.ListMetadataRequest' + $ref: '#/definitions/apiv1.NotificationRequest' produces: - application/json responses: "200": description: Success schema: - $ref: '#/definitions/apiv1.ListMetadataReply' + $ref: '#/definitions/apiv1.NotificationReply' "400": description: Bad Request schema: $ref: '#/definitions/helpers.ErrorResponse' - summary: ListMetadata + summary: Notification tags: - dc4eu /portal: diff --git a/internal/apigw/httpserver/openapiv3/openapi.json b/internal/apigw/httpserver/openapiv3/openapi.json new file mode 100644 index 00000000..856eaea1 --- /dev/null +++ b/internal/apigw/httpserver/openapiv3/openapi.json @@ -0,0 +1,1020 @@ +{ + "openapi" : "3.0.1", + "info" : { + "contact" : { }, + "title" : "Datastore API", + "version" : "0.1.0" + }, + "servers" : [ { + "url" : "/api/v1" + } ], + "paths" : { + "/document" : { + "delete" : { + "description" : "delete one document endpoint", + "operationId" : "delete-document", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/apiv1.DeleteDocumentRequest" + } + } + }, + "required" : true + }, + "responses" : { + "200" : { + "content" : { }, + "description" : "Success" + }, + "400" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/helpers.ErrorResponse" + } + } + }, + "description" : "Bad Request" + } + }, + "summary" : "DeleteDocument", + "tags" : [ "dc4eu" ], + "x-codegen-request-body-name" : "req" + }, + "post" : { + "description" : "Get document endpoint", + "operationId" : "get-document", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/apiv1.GetDocumentRequest" + } + } + }, + "required" : true + }, + "responses" : { + "200" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/apiv1.GetDocumentReply" + } + } + }, + "description" : "Success" + }, + "400" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/helpers.ErrorResponse" + } + } + }, + "description" : "Bad Request" + } + }, + "summary" : "GetDocument", + "tags" : [ "dc4eu" ], + "x-codegen-request-body-name" : "req" + } + }, + "/document/collection_code" : { + "post" : { + "description" : "Get document by collect code endpoint", + "operationId" : "get-document-collect-code", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/model.MetaData" + } + } + }, + "required" : true + }, + "responses" : { + "200" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/apiv1.GetDocumentReply" + } + } + }, + "description" : "Success" + }, + "400" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/helpers.ErrorResponse" + } + } + }, + "description" : "Bad Request" + } + }, + "summary" : "GetDocumentByCollectCode", + "tags" : [ "dc4eu" ], + "x-codegen-request-body-name" : "req" + } + }, + "/id_mapping" : { + "post" : { + "description" : "ID mapping endpoint", + "operationId" : "id-mapping", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/model.MetaData" + } + } + }, + "required" : true + }, + "responses" : { + "200" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/apiv1.IDMappingReply" + } + } + }, + "description" : "Success" + }, + "400" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/helpers.ErrorResponse" + } + } + }, + "description" : "Bad Request" + } + }, + "summary" : "IDMapping", + "tags" : [ "dc4eu" ], + "x-codegen-request-body-name" : "req" + } + }, + "/ladok/pdf/revoke/{transaction_id}" : { + "put" : { + "description" : "revoke a singed pdf", + "operationId" : "ladok-pdf-revoke", + "parameters" : [ { + "description" : "transaction_id", + "in" : "path", + "name" : "transaction_id", + "required" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/apiv1.PDFRevokeReply" + } + } + }, + "description" : "Success" + }, + "400" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/helpers.ErrorResponse" + } + } + }, + "description" : "Bad Request" + } + }, + "summary" : "revoke signed pdf", + "tags" : [ "ladok" ] + } + }, + "/ladok/pdf/sign" : { + "post" : { + "description" : "sign base64 encoded PDF", + "operationId" : "ladok-pdf-sign", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/apiv1.PDFSignRequest" + } + } + }, + "required" : true + }, + "responses" : { + "200" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/apiv1.PDFSignReply" + } + } + }, + "description" : "Success" + }, + "400" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/helpers.ErrorResponse" + } + } + }, + "description" : "Bad Request" + } + }, + "summary" : "Sign pdf", + "tags" : [ "ladok" ], + "x-codegen-request-body-name" : "req" + } + }, + "/ladok/pdf/validate" : { + "post" : { + "description" : "validate a signed base64 encoded PDF", + "operationId" : "ladok-pdf-validate", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/apiv1.PDFValidateRequest" + } + } + }, + "required" : true + }, + "responses" : { + "200" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/apiv1.PDFValidateReply" + } + } + }, + "description" : "Success" + }, + "400" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/helpers.ErrorResponse" + } + } + }, + "description" : "Bad Request" + } + }, + "summary" : "Validate pdf", + "tags" : [ "ladok" ], + "x-codegen-request-body-name" : "req" + } + }, + "/ladok/pdf/{transaction_id}" : { + "get" : { + "description" : "fetch a singed pdf", + "operationId" : "ladok-pdf-fetch", + "parameters" : [ { + "description" : "transaction_id", + "in" : "path", + "name" : "transaction_id", + "required" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/apiv1.PDFGetSignedReply" + } + } + }, + "description" : "Success" + }, + "400" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/helpers.ErrorResponse" + } + } + }, + "description" : "Bad Request" + } + }, + "summary" : "fetch singed pdf", + "tags" : [ "ladok" ] + } + }, + "/notification" : { + "post" : { + "description" : "notification endpoint", + "operationId" : "generic-notification", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/apiv1.NotificationRequest" + } + } + }, + "required" : true + }, + "responses" : { + "200" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/apiv1.NotificationReply" + } + } + }, + "description" : "Success" + }, + "400" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/helpers.ErrorResponse" + } + } + }, + "description" : "Bad Request" + } + }, + "summary" : "Notification", + "tags" : [ "dc4eu" ], + "x-codegen-request-body-name" : "req" + } + }, + "/portal" : { + "post" : { + "description" : "Get portal data endpoint", + "operationId" : "portal", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/apiv1.PortalRequest" + } + } + }, + "required" : true + }, + "responses" : { + "200" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/apiv1.PortalReply" + } + } + }, + "description" : "Success" + }, + "400" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/helpers.ErrorResponse" + } + } + }, + "description" : "Bad Request" + } + }, + "summary" : "Portal", + "tags" : [ "dc4eu" ], + "x-codegen-request-body-name" : "req" + } + }, + "/revoke" : { + "post" : { + "description" : "Revoke endpoint", + "operationId" : "generic-revoke", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/apiv1.RevokeRequest" + } + } + }, + "required" : true + }, + "responses" : { + "200" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/apiv1.RevokeReply" + } + } + }, + "description" : "Success" + }, + "400" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/helpers.ErrorResponse" + } + } + }, + "description" : "Bad Request" + } + }, + "summary" : "Revoke", + "tags" : [ "dc4eu" ], + "x-codegen-request-body-name" : "req" + } + }, + "/upload" : { + "post" : { + "description" : "Upload endpoint", + "operationId" : "generic-upload", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/model.Upload" + } + } + }, + "required" : true + }, + "responses" : { + "200" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/apiv1.UploadReply" + } + } + }, + "description" : "Success" + }, + "400" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/helpers.ErrorResponse" + } + } + }, + "description" : "Bad Request" + } + }, + "summary" : "Upload", + "tags" : [ "dc4eu" ], + "x-codegen-request-body-name" : "req" + } + } + }, + "components" : { + "schemas" : { + "apiv1.DeleteDocumentRequest" : { + "properties" : { + "authentic_source" : { + "description" : "required: true\nexample: skatteverket", + "type" : "string" + }, + "document_id" : { + "description" : "required: true\nexample: 5e7a981c-c03f-11ee-b116-9b12c59362b9", + "type" : "string" + } + }, + "type" : "object" + }, + "apiv1.GetDocumentReply" : { + "properties" : { + "data" : { + "$ref" : "#/components/schemas/model.Upload" + } + }, + "type" : "object" + }, + "apiv1.GetDocumentRequest" : { + "properties" : { + "authentic_source" : { + "type" : "string" + }, + "document_id" : { + "type" : "string" + }, + "document_type" : { + "type" : "string" + } + }, + "type" : "object" + }, + "apiv1.IDMappingReply" : { + "properties" : { + "data" : { + "$ref" : "#/components/schemas/apiv1_IDMappingReply_data" + } + }, + "type" : "object" + }, + "apiv1.NotificationReply" : { + "properties" : { + "data" : { + "$ref" : "#/components/schemas/model.QR" + } + }, + "type" : "object" + }, + "apiv1.NotificationRequest" : { + "properties" : { + "authentic_source" : { + "type" : "string" + }, + "document_id" : { + "type" : "string" + }, + "document_type" : { + "type" : "string" + } + }, + "type" : "object" + }, + "apiv1.PDFGetSignedReply" : { + "properties" : { + "data" : { + "$ref" : "#/components/schemas/apiv1_PDFGetSignedReply_data" + } + }, + "type" : "object" + }, + "apiv1.PDFRevokeReply" : { + "properties" : { + "data" : { + "$ref" : "#/components/schemas/apiv1_PDFRevokeReply_data" + } + }, + "type" : "object" + }, + "apiv1.PDFSignReply" : { + "properties" : { + "data" : { + "$ref" : "#/components/schemas/apiv1_PDFSignReply_data" + } + }, + "type" : "object" + }, + "apiv1.PDFSignRequest" : { + "properties" : { + "pdf" : { + "type" : "string" + } + }, + "required" : [ "pdf" ], + "type" : "object" + }, + "apiv1.PDFValidateReply" : { + "properties" : { + "data" : { + "$ref" : "#/components/schemas/types.Validation" + } + }, + "type" : "object" + }, + "apiv1.PDFValidateRequest" : { + "properties" : { + "pdf" : { + "type" : "string" + } + }, + "type" : "object" + }, + "apiv1.PortalReply" : { + "properties" : { + "data" : { + "items" : { + "$ref" : "#/components/schemas/model.Upload" + }, + "type" : "array" + } + }, + "type" : "object" + }, + "apiv1.PortalRequest" : { + "properties" : { + "authentic_source" : { + "type" : "string" + }, + "authentic_source_person_id" : { + "type" : "string" + }, + "validity_from" : { + "type" : "string" + }, + "validity_to" : { + "type" : "string" + } + }, + "required" : [ "authentic_source", "authentic_source_person_id" ], + "type" : "object" + }, + "apiv1.RevokeReply" : { + "properties" : { + "data" : { + "$ref" : "#/components/schemas/apiv1_PDFRevokeReply_data" + } + }, + "type" : "object" + }, + "apiv1.RevokeRequest" : { + "properties" : { + "authentic_source" : { + "type" : "string" + }, + "document_id" : { + "type" : "string" + }, + "document_type" : { + "type" : "string" + }, + "revocation_id" : { + "type" : "string" + } + }, + "type" : "object" + }, + "apiv1.UploadReply" : { + "properties" : { + "data" : { + "$ref" : "#/components/schemas/apiv1_UploadReply_data" + } + }, + "type" : "object" + }, + "helpers.Error" : { + "properties" : { + "details" : { + "type" : "object" + }, + "title" : { + "type" : "string" + } + }, + "type" : "object" + }, + "helpers.ErrorResponse" : { + "properties" : { + "error" : { + "$ref" : "#/components/schemas/helpers.Error" + } + }, + "type" : "object" + }, + "model.Attestation" : { + "properties" : { + "description_long" : { + "description" : "TODO(masv): change TextLong to DescriptionLong\nrequired: true\nexample: European Health Insurance Card", + "type" : "string" + }, + "description_short" : { + "description" : "TODO(masv): ShortText to DescriptionShort, more descriptive, pun intended\nrequired: true\nexample: EHIC", + "type" : "string" + }, + "type" : { + "description" : "required: true\nexample: secure", + "type" : "string" + }, + "version" : { + "description" : "TODO(masv): change AttestationDataVersion to AttestationVersion, data seems redundant\nrequired: true\nexample: 1.0.0", + "type" : "integer" + } + }, + "required" : [ "description_long", "description_short", "type", "version" ], + "type" : "object" + }, + "model.Identity" : { + "properties" : { + "age_birth_year" : { + "description" : "TODO(masv): int instead of string?\nrequired: false\nexample: 1970", + "type" : "string" + }, + "age_in_years" : { + "description" : "TODO(masv): int instead of string?\nrequired: false\nexample: 19", + "type" : "string" + }, + "age_over_18" : { + "description" : "TODO(masv): int instead of string?\nrequired: false\nexample: 19", + "type" : "string" + }, + "age_over_nn" : { + "description" : "TODO(masv): int instead of string? How is supposed to work, query NN?\nrequired: false\nexample: 19", + "type" : "string" + }, + "birth_city" : { + "description" : "required: false\nexample: Stockholm", + "type" : "string" + }, + "birth_country" : { + "description" : "TODO(masv): full name or just country code?\nrequired: false\nexample: sweden", + "type" : "string" + }, + "birth_date" : { + "description" : "required: true\nexample: 1970-01-01", + "type" : "string" + }, + "birth_place" : { + "description" : "required: false\nexample: Stockholm", + "type" : "string" + }, + "birth_state" : { + "description" : "required: false\nexample: Stockholm", + "type" : "string" + }, + "family_name" : { + "description" : "required: true\nexample: Svensson", + "type" : "string" + }, + "family_name_at_birth" : { + "description" : "required: false\nexample: Karlsson", + "type" : "string" + }, + "gender" : { + "description" : "required: false\nexample: male", + "type" : "string" + }, + "given_name" : { + "description" : "required: true\nexample: Magnus", + "type" : "string" + }, + "given_name_at_birth" : { + "description" : "required: false\nexample: Magnus", + "type" : "string" + }, + "nationality" : { + "description" : "required: false\nexample: swedish", + "type" : "string" + }, + "resident_address" : { + "description" : "required: false\nexample: 221b baker street", + "type" : "string" + }, + "resident_city" : { + "description" : "required: false\nexample: london", + "type" : "string" + }, + "resident_country" : { + "description" : "required: false\nexample: england", + "type" : "string" + }, + "resident_house_number" : { + "description" : "required: false\nexample: 221b", + "type" : "string" + }, + "resident_postal_code" : { + "description" : "required: false\nexample: W1U 6SG", + "type" : "string" + }, + "resident_state" : { + "description" : "required: false\nexample: england", + "type" : "string" + }, + "resident_street" : { + "description" : "required: false\nexample: baker street", + "type" : "string" + }, + "uid" : { + "description" : "required: true\nexample: 85f90d4c-c03f-11ee-9386-ef1b105c4f3e", + "type" : "string" + }, + "version" : { + "description" : "required: true\nexample: 1.0.0", + "type" : "string" + } + }, + "required" : [ "birth_date", "family_name", "given_name", "uid", "version" ], + "type" : "object" + }, + "model.MetaData" : { + "properties" : { + "authentic_source" : { + "description" : "required: true\nexample: SUNET", + "type" : "string" + }, + "authentic_source_person_id" : { + "description" : "required: true\nexample: 65636cbc-c03f-11ee-8dc4-67135cc9bd8a", + "type" : "string" + }, + "collect_id" : { + "description" : "required: false\nexample: 98fe67fc-c03f-11ee-bbee-4345224d414f", + "type" : "string" + }, + "created_at" : { + "description" : "required: false\nexample: 2024-03-15T10:00:00Z+01:00", + "type" : "string" + }, + "date_of_birth" : { + "description" : "required: true\nexample: 1970-01-01", + "type" : "string" + }, + "document_id" : { + "description" : "required: true\nexample: 5e7a981c-c03f-11ee-b116-9b12c59362b9", + "type" : "string" + }, + "document_type" : { + "description" : "required: true\nexample: PDA1", + "enum" : [ "PDA1", "EHIC" ], + "type" : "string" + }, + "document_version" : { + "description" : "required: true\nexample: 1", + "minimum" : 1, + "type" : "integer" + }, + "first_name" : { + "description" : "required: true\nexample: John", + "type" : "string" + }, + "last_name" : { + "description" : "required: true\nexample: Doe", + "type" : "string" + }, + "member_state" : { + "description" : "required: true\nexample: \"DE\"", + "type" : "string" + }, + "revocation_id" : { + "description" : "required: false\nexample: 8dbd2680-c03f-11ee-a21b-034aafe41222", + "type" : "string" + }, + "uid" : { + "description" : "required: true\nexample: 85f90d4c-c03f-11ee-9386-ef1b105c4f3e", + "type" : "string" + }, + "valid_from" : { + "description" : "TODO(masv): ISO8601?\nrequired: true\nexample: 2024-01-01", + "type" : "string" + }, + "valid_to" : { + "description" : "TODO(masv): ISO8601?\nrequired: true\nexample: 2024-12-31", + "type" : "string" + } + }, + "required" : [ "authentic_source", "authentic_source_person_id", "collect_id", "date_of_birth", "document_id", "document_type", "document_version", "first_name", "last_name", "member_state", "revocation_id", "uid", "valid_from", "valid_to" ], + "type" : "object" + }, + "model.QR" : { + "properties" : { + "base64_image" : { + "type" : "string" + }, + "deep_link" : { + "type" : "string" + } + }, + "required" : [ "base64_image", "deep_link" ], + "type" : "object" + }, + "model.Upload" : { + "properties" : { + "attestation" : { + "$ref" : "#/components/schemas/model.Attestation" + }, + "document_data" : { + "type" : "object" + }, + "identity" : { + "$ref" : "#/components/schemas/model.Identity" + }, + "meta" : { + "$ref" : "#/components/schemas/model.MetaData" + }, + "qr" : { + "$ref" : "#/components/schemas/model.QR" + } + }, + "required" : [ "attestation", "document_data", "identity", "meta" ], + "type" : "object" + }, + "types.Document" : { + "properties" : { + "base64_data" : { + "type" : "string" + }, + "contact_info" : { + "type" : "string" + }, + "create_ts" : { + "type" : "integer" + }, + "error" : { + "type" : "string" + }, + "location" : { + "type" : "string" + }, + "message" : { + "type" : "string" + }, + "modify_ts" : { + "type" : "integer" + }, + "name" : { + "type" : "string" + }, + "reason" : { + "type" : "string" + }, + "revoked_ts" : { + "type" : "integer" + }, + "transaction_id" : { + "type" : "string" + } + }, + "type" : "object" + }, + "types.Validation" : { + "properties" : { + "error" : { + "type" : "string" + }, + "is_revoked" : { + "type" : "boolean" + }, + "message" : { + "type" : "string" + }, + "transaction_id" : { + "type" : "string" + }, + "valid_signature" : { + "type" : "boolean" + } + }, + "type" : "object" + }, + "apiv1_IDMappingReply_data" : { + "properties" : { + "authentic_source_person_id" : { + "type" : "string" + } + }, + "type" : "object" + }, + "apiv1_PDFGetSignedReply_data" : { + "properties" : { + "document" : { + "$ref" : "#/components/schemas/types.Document" + }, + "message" : { + "type" : "string" + } + }, + "type" : "object" + }, + "apiv1_PDFRevokeReply_data" : { + "properties" : { + "status" : { + "type" : "boolean" + } + }, + "type" : "object" + }, + "apiv1_PDFSignReply_data" : { + "properties" : { + "transaction_id" : { + "type" : "string" + } + }, + "required" : [ "transaction_id" ], + "type" : "object" + }, + "apiv1_UploadReply_data" : { + "properties" : { + "status" : { + "type" : "string" + } + }, + "type" : "object" + } + } + }, + "x-original-swagger-version" : "2.0" +} \ No newline at end of file diff --git a/internal/apigw/httpserver/openapiv3/openapi.yaml b/internal/apigw/httpserver/openapiv3/openapi.yaml new file mode 100644 index 00000000..6f74051b --- /dev/null +++ b/internal/apigw/httpserver/openapiv3/openapi.yaml @@ -0,0 +1,1164 @@ +openapi: 3.0.1 +info: + contact: {} + title: Datastore API + version: 0.1.0 +servers: +- url: /api/v1 +paths: + /document: + delete: + description: delete one document endpoint + operationId: delete-document + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/apiv1.DeleteDocumentRequest' + required: true + responses: + "200": + content: {} + description: Success + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/helpers.ErrorResponse' + description: Bad Request + summary: DeleteDocument + tags: + - dc4eu + x-codegen-request-body-name: req + post: + description: Get document endpoint + operationId: get-document + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/apiv1.GetDocumentRequest' + required: true + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/apiv1.GetDocumentReply' + description: Success + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/helpers.ErrorResponse' + description: Bad Request + summary: GetDocument + tags: + - dc4eu + x-codegen-request-body-name: req + /document/collection_code: + post: + description: Get document by collect code endpoint + operationId: get-document-collect-code + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/model.MetaData' + required: true + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/apiv1.GetDocumentReply' + description: Success + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/helpers.ErrorResponse' + description: Bad Request + summary: GetDocumentByCollectCode + tags: + - dc4eu + x-codegen-request-body-name: req + /id_mapping: + post: + description: ID mapping endpoint + operationId: id-mapping + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/model.MetaData' + required: true + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/apiv1.IDMappingReply' + description: Success + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/helpers.ErrorResponse' + description: Bad Request + summary: IDMapping + tags: + - dc4eu + x-codegen-request-body-name: req + /ladok/pdf/{transaction_id}: + get: + description: fetch a singed pdf + operationId: ladok-pdf-fetch + parameters: + - description: transaction_id + in: path + name: transaction_id + required: true + schema: + type: string + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/apiv1.PDFGetSignedReply' + description: Success + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/helpers.ErrorResponse' + description: Bad Request + summary: fetch singed pdf + tags: + - ladok + /ladok/pdf/revoke/{transaction_id}: + put: + description: revoke a singed pdf + operationId: ladok-pdf-revoke + parameters: + - description: transaction_id + in: path + name: transaction_id + required: true + schema: + type: string + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/apiv1.PDFRevokeReply' + description: Success + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/helpers.ErrorResponse' + description: Bad Request + summary: revoke signed pdf + tags: + - ladok + /ladok/pdf/sign: + post: + description: sign base64 encoded PDF + operationId: ladok-pdf-sign + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/apiv1.PDFSignRequest' + required: true + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/apiv1.PDFSignReply' + description: Success + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/helpers.ErrorResponse' + description: Bad Request + summary: Sign pdf + tags: + - ladok + x-codegen-request-body-name: req + /ladok/pdf/validate: + post: + description: validate a signed base64 encoded PDF + operationId: ladok-pdf-validate + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/apiv1.PDFValidateRequest' + required: true + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/apiv1.PDFValidateReply' + description: Success + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/helpers.ErrorResponse' + description: Bad Request + summary: Validate pdf + tags: + - ladok + x-codegen-request-body-name: req + /notification: + post: + description: notification endpoint + operationId: generic-notification + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/apiv1.NotificationRequest' + required: true + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/apiv1.NotificationReply' + description: Success + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/helpers.ErrorResponse' + description: Bad Request + summary: Notification + tags: + - dc4eu + x-codegen-request-body-name: req + /portal: + post: + description: Get portal data endpoint + operationId: portal + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/apiv1.PortalRequest' + required: true + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/apiv1.PortalReply' + description: Success + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/helpers.ErrorResponse' + description: Bad Request + summary: Portal + tags: + - dc4eu + x-codegen-request-body-name: req + /revoke: + post: + description: Revoke endpoint + operationId: generic-revoke + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/apiv1.RevokeRequest' + required: true + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/apiv1.RevokeReply' + description: Success + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/helpers.ErrorResponse' + description: Bad Request + summary: Revoke + tags: + - dc4eu + x-codegen-request-body-name: req + /upload: + post: + description: Upload endpoint + operationId: generic-upload + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/model.Upload' + required: true + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/apiv1.UploadReply' + description: Success + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/helpers.ErrorResponse' + description: Bad Request + summary: Upload + tags: + - dc4eu + x-codegen-request-body-name: req +components: + schemas: + apiv1.DeleteDocumentRequest: + properties: + authentic_source: + description: |- + required: true + example: skatteverket + type: string + document_id: + description: |- + required: true + example: 5e7a981c-c03f-11ee-b116-9b12c59362b9 + type: string + type: object + apiv1.GetDocumentReply: + example: + data: + qr: + base64_image: base64_image + deep_link: deep_link + attestation: + description_short: description_short + description_long: description_long + type: type + version: 0 + document_data: "{}" + identity: + given_name_at_birth: given_name_at_birth + resident_street: resident_street + birth_city: birth_city + gender: gender + age_over_18: age_over_18 + birth_date: birth_date + birth_place: birth_place + age_in_years: age_in_years + given_name: given_name + birth_state: birth_state + resident_postal_code: resident_postal_code + version: version + birth_country: birth_country + resident_house_number: resident_house_number + uid: uid + nationality: nationality + age_birth_year: age_birth_year + resident_address: resident_address + resident_state: resident_state + age_over_nn: age_over_nn + resident_country: resident_country + family_name: family_name + family_name_at_birth: family_name_at_birth + resident_city: resident_city + meta: + collect_id: collect_id + date_of_birth: date_of_birth + created_at: created_at + last_name: last_name + valid_from: valid_from + document_id: document_id + document_version: 1 + uid: uid + authentic_source: authentic_source + authentic_source_person_id: authentic_source_person_id + member_state: member_state + revocation_id: revocation_id + valid_to: valid_to + first_name: first_name + document_type: PDA1 + properties: + data: + $ref: '#/components/schemas/model.Upload' + type: object + apiv1.GetDocumentRequest: + properties: + authentic_source: + type: string + document_id: + type: string + document_type: + type: string + type: object + apiv1.IDMappingReply: + example: + data: + authentic_source_person_id: authentic_source_person_id + properties: + data: + $ref: '#/components/schemas/apiv1_IDMappingReply_data' + type: object + apiv1.NotificationReply: + example: + data: + base64_image: base64_image + deep_link: deep_link + properties: + data: + $ref: '#/components/schemas/model.QR' + type: object + apiv1.NotificationRequest: + properties: + authentic_source: + type: string + document_id: + type: string + document_type: + type: string + type: object + apiv1.PDFGetSignedReply: + example: + data: + document: + transaction_id: transaction_id + base64_data: base64_data + reason: reason + modify_ts: 6 + revoked_ts: 1 + create_ts: 0 + name: name + location: location + contact_info: contact_info + error: error + message: message + message: message + properties: + data: + $ref: '#/components/schemas/apiv1_PDFGetSignedReply_data' + type: object + apiv1.PDFRevokeReply: + example: + data: + status: true + properties: + data: + $ref: '#/components/schemas/apiv1_PDFRevokeReply_data' + type: object + apiv1.PDFSignReply: + example: + data: + transaction_id: transaction_id + properties: + data: + $ref: '#/components/schemas/apiv1_PDFSignReply_data' + type: object + apiv1.PDFSignRequest: + properties: + pdf: + type: string + required: + - pdf + type: object + apiv1.PDFValidateReply: + example: + data: + transaction_id: transaction_id + valid_signature: true + is_revoked: true + error: error + message: message + properties: + data: + $ref: '#/components/schemas/types.Validation' + type: object + apiv1.PDFValidateRequest: + properties: + pdf: + type: string + type: object + apiv1.PortalReply: + example: + data: + - qr: + base64_image: base64_image + deep_link: deep_link + attestation: + description_short: description_short + description_long: description_long + type: type + version: 0 + document_data: "{}" + identity: + given_name_at_birth: given_name_at_birth + resident_street: resident_street + birth_city: birth_city + gender: gender + age_over_18: age_over_18 + birth_date: birth_date + birth_place: birth_place + age_in_years: age_in_years + given_name: given_name + birth_state: birth_state + resident_postal_code: resident_postal_code + version: version + birth_country: birth_country + resident_house_number: resident_house_number + uid: uid + nationality: nationality + age_birth_year: age_birth_year + resident_address: resident_address + resident_state: resident_state + age_over_nn: age_over_nn + resident_country: resident_country + family_name: family_name + family_name_at_birth: family_name_at_birth + resident_city: resident_city + meta: + collect_id: collect_id + date_of_birth: date_of_birth + created_at: created_at + last_name: last_name + valid_from: valid_from + document_id: document_id + document_version: 1 + uid: uid + authentic_source: authentic_source + authentic_source_person_id: authentic_source_person_id + member_state: member_state + revocation_id: revocation_id + valid_to: valid_to + first_name: first_name + document_type: PDA1 + - qr: + base64_image: base64_image + deep_link: deep_link + attestation: + description_short: description_short + description_long: description_long + type: type + version: 0 + document_data: "{}" + identity: + given_name_at_birth: given_name_at_birth + resident_street: resident_street + birth_city: birth_city + gender: gender + age_over_18: age_over_18 + birth_date: birth_date + birth_place: birth_place + age_in_years: age_in_years + given_name: given_name + birth_state: birth_state + resident_postal_code: resident_postal_code + version: version + birth_country: birth_country + resident_house_number: resident_house_number + uid: uid + nationality: nationality + age_birth_year: age_birth_year + resident_address: resident_address + resident_state: resident_state + age_over_nn: age_over_nn + resident_country: resident_country + family_name: family_name + family_name_at_birth: family_name_at_birth + resident_city: resident_city + meta: + collect_id: collect_id + date_of_birth: date_of_birth + created_at: created_at + last_name: last_name + valid_from: valid_from + document_id: document_id + document_version: 1 + uid: uid + authentic_source: authentic_source + authentic_source_person_id: authentic_source_person_id + member_state: member_state + revocation_id: revocation_id + valid_to: valid_to + first_name: first_name + document_type: PDA1 + properties: + data: + items: + $ref: '#/components/schemas/model.Upload' + type: array + type: object + apiv1.PortalRequest: + properties: + authentic_source: + type: string + authentic_source_person_id: + type: string + validity_from: + type: string + validity_to: + type: string + required: + - authentic_source + - authentic_source_person_id + type: object + apiv1.RevokeReply: + example: + data: + status: true + properties: + data: + $ref: '#/components/schemas/apiv1_PDFRevokeReply_data' + type: object + apiv1.RevokeRequest: + properties: + authentic_source: + type: string + document_id: + type: string + document_type: + type: string + revocation_id: + type: string + type: object + apiv1.UploadReply: + example: + data: + status: status + properties: + data: + $ref: '#/components/schemas/apiv1_UploadReply_data' + type: object + helpers.Error: + example: + details: "{}" + title: title + properties: + details: + type: object + title: + type: string + type: object + helpers.ErrorResponse: + example: + error: + details: "{}" + title: title + properties: + error: + $ref: '#/components/schemas/helpers.Error' + type: object + model.Attestation: + example: + description_short: description_short + description_long: description_long + type: type + version: 0 + properties: + description_long: + description: |- + TODO(masv): change TextLong to DescriptionLong + required: true + example: European Health Insurance Card + type: string + description_short: + description: |- + TODO(masv): ShortText to DescriptionShort, more descriptive, pun intended + required: true + example: EHIC + type: string + type: + description: |- + required: true + example: secure + type: string + version: + description: |- + TODO(masv): change AttestationDataVersion to AttestationVersion, data seems redundant + required: true + example: 1.0.0 + type: integer + required: + - description_long + - description_short + - type + - version + type: object + model.Identity: + example: + given_name_at_birth: given_name_at_birth + resident_street: resident_street + birth_city: birth_city + gender: gender + age_over_18: age_over_18 + birth_date: birth_date + birth_place: birth_place + age_in_years: age_in_years + given_name: given_name + birth_state: birth_state + resident_postal_code: resident_postal_code + version: version + birth_country: birth_country + resident_house_number: resident_house_number + uid: uid + nationality: nationality + age_birth_year: age_birth_year + resident_address: resident_address + resident_state: resident_state + age_over_nn: age_over_nn + resident_country: resident_country + family_name: family_name + family_name_at_birth: family_name_at_birth + resident_city: resident_city + properties: + age_birth_year: + description: |- + TODO(masv): int instead of string? + required: false + example: 1970 + type: string + age_in_years: + description: |- + TODO(masv): int instead of string? + required: false + example: 19 + type: string + age_over_18: + description: |- + TODO(masv): int instead of string? + required: false + example: 19 + type: string + age_over_nn: + description: |- + TODO(masv): int instead of string? How is supposed to work, query NN? + required: false + example: 19 + type: string + birth_city: + description: |- + required: false + example: Stockholm + type: string + birth_country: + description: |- + TODO(masv): full name or just country code? + required: false + example: sweden + type: string + birth_date: + description: |- + required: true + example: 1970-01-01 + type: string + birth_place: + description: |- + required: false + example: Stockholm + type: string + birth_state: + description: |- + required: false + example: Stockholm + type: string + family_name: + description: |- + required: true + example: Svensson + type: string + family_name_at_birth: + description: |- + required: false + example: Karlsson + type: string + gender: + description: |- + required: false + example: male + type: string + given_name: + description: |- + required: true + example: Magnus + type: string + given_name_at_birth: + description: |- + required: false + example: Magnus + type: string + nationality: + description: |- + required: false + example: swedish + type: string + resident_address: + description: |- + required: false + example: 221b baker street + type: string + resident_city: + description: |- + required: false + example: london + type: string + resident_country: + description: |- + required: false + example: england + type: string + resident_house_number: + description: |- + required: false + example: 221b + type: string + resident_postal_code: + description: |- + required: false + example: W1U 6SG + type: string + resident_state: + description: |- + required: false + example: england + type: string + resident_street: + description: |- + required: false + example: baker street + type: string + uid: + description: |- + required: true + example: 85f90d4c-c03f-11ee-9386-ef1b105c4f3e + type: string + version: + description: |- + required: true + example: 1.0.0 + type: string + required: + - birth_date + - family_name + - given_name + - uid + - version + type: object + model.MetaData: + example: + collect_id: collect_id + date_of_birth: date_of_birth + created_at: created_at + last_name: last_name + valid_from: valid_from + document_id: document_id + document_version: 1 + uid: uid + authentic_source: authentic_source + authentic_source_person_id: authentic_source_person_id + member_state: member_state + revocation_id: revocation_id + valid_to: valid_to + first_name: first_name + document_type: PDA1 + properties: + authentic_source: + description: |- + required: true + example: SUNET + type: string + authentic_source_person_id: + description: |- + required: true + example: 65636cbc-c03f-11ee-8dc4-67135cc9bd8a + type: string + collect_id: + description: |- + required: false + example: 98fe67fc-c03f-11ee-bbee-4345224d414f + type: string + created_at: + description: |- + required: false + example: 2024-03-15T10:00:00Z+01:00 + type: string + date_of_birth: + description: |- + required: true + example: 1970-01-01 + type: string + document_id: + description: |- + required: true + example: 5e7a981c-c03f-11ee-b116-9b12c59362b9 + type: string + document_type: + description: |- + required: true + example: PDA1 + enum: + - PDA1 + - EHIC + type: string + document_version: + description: |- + required: true + example: 1 + minimum: 1 + type: integer + first_name: + description: |- + required: true + example: John + type: string + last_name: + description: |- + required: true + example: Doe + type: string + member_state: + description: |- + required: true + example: "DE" + type: string + revocation_id: + description: |- + required: false + example: 8dbd2680-c03f-11ee-a21b-034aafe41222 + type: string + uid: + description: |- + required: true + example: 85f90d4c-c03f-11ee-9386-ef1b105c4f3e + type: string + valid_from: + description: |- + TODO(masv): ISO8601? + required: true + example: 2024-01-01 + type: string + valid_to: + description: |- + TODO(masv): ISO8601? + required: true + example: 2024-12-31 + type: string + required: + - authentic_source + - authentic_source_person_id + - collect_id + - date_of_birth + - document_id + - document_type + - document_version + - first_name + - last_name + - member_state + - revocation_id + - uid + - valid_from + - valid_to + type: object + model.QR: + example: + base64_image: base64_image + deep_link: deep_link + properties: + base64_image: + type: string + deep_link: + type: string + required: + - base64_image + - deep_link + type: object + model.Upload: + example: + qr: + base64_image: base64_image + deep_link: deep_link + attestation: + description_short: description_short + description_long: description_long + type: type + version: 0 + document_data: "{}" + identity: + given_name_at_birth: given_name_at_birth + resident_street: resident_street + birth_city: birth_city + gender: gender + age_over_18: age_over_18 + birth_date: birth_date + birth_place: birth_place + age_in_years: age_in_years + given_name: given_name + birth_state: birth_state + resident_postal_code: resident_postal_code + version: version + birth_country: birth_country + resident_house_number: resident_house_number + uid: uid + nationality: nationality + age_birth_year: age_birth_year + resident_address: resident_address + resident_state: resident_state + age_over_nn: age_over_nn + resident_country: resident_country + family_name: family_name + family_name_at_birth: family_name_at_birth + resident_city: resident_city + meta: + collect_id: collect_id + date_of_birth: date_of_birth + created_at: created_at + last_name: last_name + valid_from: valid_from + document_id: document_id + document_version: 1 + uid: uid + authentic_source: authentic_source + authentic_source_person_id: authentic_source_person_id + member_state: member_state + revocation_id: revocation_id + valid_to: valid_to + first_name: first_name + document_type: PDA1 + properties: + attestation: + $ref: '#/components/schemas/model.Attestation' + document_data: + type: object + identity: + $ref: '#/components/schemas/model.Identity' + meta: + $ref: '#/components/schemas/model.MetaData' + qr: + $ref: '#/components/schemas/model.QR' + required: + - attestation + - document_data + - identity + - meta + type: object + types.Document: + example: + transaction_id: transaction_id + base64_data: base64_data + reason: reason + modify_ts: 6 + revoked_ts: 1 + create_ts: 0 + name: name + location: location + contact_info: contact_info + error: error + message: message + properties: + base64_data: + type: string + contact_info: + type: string + create_ts: + type: integer + error: + type: string + location: + type: string + message: + type: string + modify_ts: + type: integer + name: + type: string + reason: + type: string + revoked_ts: + type: integer + transaction_id: + type: string + type: object + types.Validation: + example: + transaction_id: transaction_id + valid_signature: true + is_revoked: true + error: error + message: message + properties: + error: + type: string + is_revoked: + type: boolean + message: + type: string + transaction_id: + type: string + valid_signature: + type: boolean + type: object + apiv1_IDMappingReply_data: + example: + authentic_source_person_id: authentic_source_person_id + properties: + authentic_source_person_id: + type: string + type: object + apiv1_PDFGetSignedReply_data: + example: + document: + transaction_id: transaction_id + base64_data: base64_data + reason: reason + modify_ts: 6 + revoked_ts: 1 + create_ts: 0 + name: name + location: location + contact_info: contact_info + error: error + message: message + message: message + properties: + document: + $ref: '#/components/schemas/types.Document' + message: + type: string + type: object + apiv1_PDFRevokeReply_data: + example: + status: true + properties: + status: + type: boolean + type: object + apiv1_PDFSignReply_data: + example: + transaction_id: transaction_id + properties: + transaction_id: + type: string + required: + - transaction_id + type: object + apiv1_UploadReply_data: + example: + status: status + properties: + status: + type: string + type: object +x-original-swagger-version: "2.0" diff --git a/internal/apigw/httpserver/service.go b/internal/apigw/httpserver/service.go index 40b17024..50e44a3a 100644 --- a/internal/apigw/httpserver/service.go +++ b/internal/apigw/httpserver/service.go @@ -3,6 +3,8 @@ package httpserver import ( "context" "crypto/tls" + "embed" + "io/fs" "net/http" "reflect" "strings" @@ -23,6 +25,9 @@ import ( ginSwagger "github.com/swaggo/gin-swagger" ) +//go:embed openapiv3 +var openAPIV3Folder embed.FS + // Service is the service object for httpserver type Service struct { config *model.Cfg @@ -87,9 +92,16 @@ func New(ctx context.Context, config *model.Cfg, api *apiv1.Client, tp *trace.Tr rgRoot := s.gin.Group("/") s.regEndpoint(ctx, rgRoot, http.MethodGet, "health", s.endpointHealth) - rgDocs := rgRoot.Group("/swagger") + rgDocs := rgRoot.Group("swagger") rgDocs.GET("/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) + rgOpenAPIV3 := rgRoot.Group("openapi/v3") + openAPIV3Files, err := fs.Sub(openAPIV3Folder, "openapiv3") + if err != nil { + return nil, err + } + rgOpenAPIV3.StaticFS("/", http.FS(openAPIV3Files)) + rgAPIv1 := rgRoot.Group("api/v1") s.regEndpoint(ctx, rgAPIv1, http.MethodPost, "/upload", s.endpointUpload) @@ -113,15 +125,16 @@ func New(ctx context.Context, config *model.Cfg, api *apiv1.Client, tp *trace.Tr // Run http server go func() { if s.config.APIGW.APIServer.TLS.Enabled { + s.logger.Debug("TLS enabled") s.applyTLSConfig(ctx) - err := s.server.ListenAndServeTLS(s.config.APIGW.APIServer.TLS.CertFilePath, s.config.APIGW.APIServer.TLS.KeyFilePath) - if err != nil { + if err := s.server.ListenAndServeTLS(s.config.APIGW.APIServer.TLS.CertFilePath, s.config.APIGW.APIServer.TLS.KeyFilePath); err != nil { s.logger.Error(err, "listen_and_server_tls") } + } else { - err = s.server.ListenAndServe() - if err != nil { + s.logger.Debug("TLS disabled") + if err := s.server.ListenAndServe(); err != nil { s.logger.Error(err, "listen_and_server") } } @@ -132,19 +145,27 @@ func New(ctx context.Context, config *model.Cfg, api *apiv1.Client, tp *trace.Tr return s, nil } -func (s *Service) regEndpoint(ctx context.Context, rg *gin.RouterGroup, method, path string, handler func(context.Context, *gin.Context) (interface{}, error)) { +func (s *Service) regEndpoint(ctx context.Context, rg *gin.RouterGroup, method, path string, handler func(context.Context, *gin.Context) (any, error)) { + // Should not have tracing since it will keep the span open for each endpoint, it will just make it harder to find the current trace in jaeger. rg.Handle(method, path, func(c *gin.Context) { + ctx, span := s.tp.Start(ctx, "httpserver:regEndpoint") + defer span.End() + span.SetName(c.Request.URL.String()) + res, err := handler(ctx, c) if err != nil { - renderContent(c, 400, gin.H{"error": helpers.NewErrorFromError(err)}) + s.renderContent(ctx, c, 400, gin.H{"error": helpers.NewErrorFromError(err)}) return } - renderContent(c, 200, res) + s.renderContent(ctx, c, 200, res) }) } -func renderContent(c *gin.Context, code int, data interface{}) { +func (s *Service) renderContent(ctx context.Context, c *gin.Context, code int, data interface{}) { + ctx, span := s.tp.Start(ctx, "httpserver:renderContent") + defer span.End() + switch c.NegotiateFormat(gin.MIMEJSON, "*/*") { case gin.MIMEJSON: c.JSON(code, data) @@ -158,5 +179,6 @@ func renderContent(c *gin.Context, code int, data interface{}) { // Close closing httpserver func (s *Service) Close(ctx context.Context) error { s.logger.Info("Quit") + ctx.Done() return nil } From 061421a37bbb491af7bfda1ed8065268e34ace56 Mon Sep 17 00:00:00 2001 From: masv3971 Date: Thu, 11 Apr 2024 15:52:44 +0200 Subject: [PATCH 7/9] New swagger golang def. --- docs/apigw/docs.go | 279 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 253 insertions(+), 26 deletions(-) diff --git a/docs/apigw/docs.go b/docs/apigw/docs.go index 5f026dfe..c7eed2f5 100644 --- a/docs/apigw/docs.go +++ b/docs/apigw/docs.go @@ -54,6 +54,42 @@ const docTemplate = `{ } } } + }, + "delete": { + "description": "delete one document endpoint", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "dc4eu" + ], + "summary": "DeleteDocument", + "operationId": "delete-document", + "parameters": [ + { + "description": " ", + "name": "req", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/apiv1.DeleteDocumentRequest" + } + } + ], + "responses": { + "200": { + "description": "Success" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/helpers.ErrorResponse" + } + } + } } }, "/document/collection_code": { @@ -298,9 +334,9 @@ const docTemplate = `{ } } }, - "/metadata": { + "/notification": { "post": { - "description": "List metadata endpoint", + "description": "notification endpoint", "consumes": [ "application/json" ], @@ -310,8 +346,8 @@ const docTemplate = `{ "tags": [ "dc4eu" ], - "summary": "ListMetadata", - "operationId": "list-metadata", + "summary": "Notification", + "operationId": "generic-notification", "parameters": [ { "description": " ", @@ -319,7 +355,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/apiv1.ListMetadataRequest" + "$ref": "#/definitions/apiv1.NotificationRequest" } } ], @@ -327,7 +363,7 @@ const docTemplate = `{ "200": { "description": "Success", "schema": { - "$ref": "#/definitions/apiv1.ListMetadataReply" + "$ref": "#/definitions/apiv1.NotificationReply" } }, "400": { @@ -464,6 +500,19 @@ const docTemplate = `{ } }, "definitions": { + "apiv1.DeleteDocumentRequest": { + "type": "object", + "properties": { + "authentic_source": { + "description": "required: true\nexample: skatteverket", + "type": "string" + }, + "document_id": { + "description": "required: true\nexample: 5e7a981c-c03f-11ee-b116-9b12c59362b9", + "type": "string" + } + } + }, "apiv1.GetDocumentReply": { "type": "object", "properties": { @@ -499,24 +548,24 @@ const docTemplate = `{ } } }, - "apiv1.ListMetadataReply": { + "apiv1.NotificationReply": { "type": "object", "properties": { "data": { - "type": "array", - "items": { - "$ref": "#/definitions/model.MetaData" - } + "$ref": "#/definitions/model.QR" } } }, - "apiv1.ListMetadataRequest": { + "apiv1.NotificationRequest": { "type": "object", "properties": { "authentic_source": { "type": "string" }, - "authentic_source_person_id": { + "document_id": { + "type": "string" + }, + "document_type": { "type": "string" } } @@ -599,19 +648,29 @@ const docTemplate = `{ "data": { "type": "array", "items": { - "$ref": "#/definitions/model.MetaData" + "$ref": "#/definitions/model.Upload" } } } }, "apiv1.PortalRequest": { "type": "object", + "required": [ + "authentic_source", + "authentic_source_person_id" + ], "properties": { "authentic_source": { "type": "string" }, "authentic_source_person_id": { "type": "string" + }, + "validity_from": { + "type": "string" + }, + "validity_to": { + "type": "string" } } }, @@ -675,6 +734,141 @@ const docTemplate = `{ } } }, + "model.Attestation": { + "type": "object", + "required": [ + "description_long", + "description_short", + "type", + "version" + ], + "properties": { + "description_long": { + "description": "TODO(masv): change TextLong to DescriptionLong\nrequired: true\nexample: European Health Insurance Card", + "type": "string" + }, + "description_short": { + "description": "TODO(masv): ShortText to DescriptionShort, more descriptive, pun intended\nrequired: true\nexample: EHIC", + "type": "string" + }, + "type": { + "description": "required: true\nexample: secure", + "type": "string" + }, + "version": { + "description": "TODO(masv): change AttestationDataVersion to AttestationVersion, data seems redundant\nrequired: true\nexample: 1.0.0", + "type": "integer" + } + } + }, + "model.Identity": { + "type": "object", + "required": [ + "birth_date", + "family_name", + "given_name", + "uid", + "version" + ], + "properties": { + "age_birth_year": { + "description": "TODO(masv): int instead of string?\nrequired: false\nexample: 1970", + "type": "string" + }, + "age_in_years": { + "description": "TODO(masv): int instead of string?\nrequired: false\nexample: 19", + "type": "string" + }, + "age_over_18": { + "description": "TODO(masv): int instead of string?\nrequired: false\nexample: 19", + "type": "string" + }, + "age_over_nn": { + "description": "TODO(masv): int instead of string? How is supposed to work, query NN?\nrequired: false\nexample: 19", + "type": "string" + }, + "birth_city": { + "description": "required: false\nexample: Stockholm", + "type": "string" + }, + "birth_country": { + "description": "TODO(masv): full name or just country code?\nrequired: false\nexample: sweden", + "type": "string" + }, + "birth_date": { + "description": "required: true\nexample: 1970-01-01", + "type": "string" + }, + "birth_place": { + "description": "required: false\nexample: Stockholm", + "type": "string" + }, + "birth_state": { + "description": "required: false\nexample: Stockholm", + "type": "string" + }, + "family_name": { + "description": "required: true\nexample: Svensson", + "type": "string" + }, + "family_name_at_birth": { + "description": "required: false\nexample: Karlsson", + "type": "string" + }, + "gender": { + "description": "required: false\nexample: male", + "type": "string" + }, + "given_name": { + "description": "required: true\nexample: Magnus", + "type": "string" + }, + "given_name_at_birth": { + "description": "required: false\nexample: Magnus", + "type": "string" + }, + "nationality": { + "description": "required: false\nexample: swedish", + "type": "string" + }, + "resident_address": { + "description": "required: false\nexample: 221b baker street", + "type": "string" + }, + "resident_city": { + "description": "required: false\nexample: london", + "type": "string" + }, + "resident_country": { + "description": "required: false\nexample: england", + "type": "string" + }, + "resident_house_number": { + "description": "required: false\nexample: 221b", + "type": "string" + }, + "resident_postal_code": { + "description": "required: false\nexample: W1U 6SG", + "type": "string" + }, + "resident_state": { + "description": "required: false\nexample: england", + "type": "string" + }, + "resident_street": { + "description": "required: false\nexample: baker street", + "type": "string" + }, + "uid": { + "description": "required: true\nexample: 85f90d4c-c03f-11ee-9386-ef1b105c4f3e", + "type": "string" + }, + "version": { + "description": "required: true\nexample: 1.0.0", + "type": "string" + } + } + }, "model.MetaData": { "type": "object", "required": [ @@ -684,14 +878,18 @@ const docTemplate = `{ "date_of_birth", "document_id", "document_type", + "document_version", "first_name", "last_name", + "member_state", "revocation_id", - "uid" + "uid", + "valid_from", + "valid_to" ], "properties": { "authentic_source": { - "description": "required: true\nexample: Sunet", + "description": "required: true\nexample: SUNET", "type": "string" }, "authentic_source_person_id": { @@ -699,7 +897,11 @@ const docTemplate = `{ "type": "string" }, "collect_id": { - "description": "required: true\nexample: 98fe67fc-c03f-11ee-bbee-4345224d414f", + "description": "required: false\nexample: 98fe67fc-c03f-11ee-bbee-4345224d414f", + "type": "string" + }, + "created_at": { + "description": "required: false\nexample: 2024-03-15T10:00:00Z+01:00", "type": "string" }, "date_of_birth": { @@ -718,6 +920,11 @@ const docTemplate = `{ "EHIC" ] }, + "document_version": { + "description": "required: true\nexample: 1", + "type": "integer", + "minimum": 1 + }, "first_name": { "description": "required: true\nexample: John", "type": "string" @@ -726,44 +933,64 @@ const docTemplate = `{ "description": "required: true\nexample: Doe", "type": "string" }, - "qr": { - "description": "required: false", - "allOf": [ - { - "$ref": "#/definitions/model.QR" - } - ] + "member_state": { + "description": "required: true\nexample: \"DE\"", + "type": "string" }, "revocation_id": { - "description": "required: true\nexample: 8dbd2680-c03f-11ee-a21b-034aafe41222", + "description": "required: false\nexample: 8dbd2680-c03f-11ee-a21b-034aafe41222", "type": "string" }, "uid": { "description": "required: true\nexample: 85f90d4c-c03f-11ee-9386-ef1b105c4f3e", "type": "string" + }, + "valid_from": { + "description": "TODO(masv): ISO8601?\nrequired: true\nexample: 2024-01-01", + "type": "string" + }, + "valid_to": { + "description": "TODO(masv): ISO8601?\nrequired: true\nexample: 2024-12-31", + "type": "string" } } }, "model.QR": { "type": "object", "required": [ - "base64_image" + "base64_image", + "deep_link" ], "properties": { "base64_image": { "type": "string" + }, + "deep_link": { + "type": "string" } } }, "model.Upload": { "type": "object", "required": [ + "attestation", + "document_data", + "identity", "meta" ], "properties": { + "attestation": { + "$ref": "#/definitions/model.Attestation" + }, "document_data": {}, + "identity": { + "$ref": "#/definitions/model.Identity" + }, "meta": { "$ref": "#/definitions/model.MetaData" + }, + "qr": { + "$ref": "#/definitions/model.QR" } } }, From bf2fa65a352d94057eead6f66f9b710b1f0aa53c Mon Sep 17 00:00:00 2001 From: masv3971 Date: Thu, 11 Apr 2024 15:53:10 +0200 Subject: [PATCH 8/9] Rename file. --- .../simplequeue/{queue_vc_save.go => queue_vc_persistent_save.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename internal/persistent/simplequeue/{queue_vc_save.go => queue_vc_persistent_save.go} (100%) diff --git a/internal/persistent/simplequeue/queue_vc_save.go b/internal/persistent/simplequeue/queue_vc_persistent_save.go similarity index 100% rename from internal/persistent/simplequeue/queue_vc_save.go rename to internal/persistent/simplequeue/queue_vc_persistent_save.go From f76b7c6006b69dac518189876280d4963c374e5c Mon Sep 17 00:00:00 2001 From: masv3971 Date: Thu, 11 Apr 2024 15:54:36 +0200 Subject: [PATCH 9/9] Add better tls support. --- dev_config_docker.yaml | 4 ++++ dockerfiles/worker | 4 ++-- internal/apigw/httpserver/tls.go | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/dev_config_docker.yaml b/dev_config_docker.yaml index 0701b070..b409705f 100644 --- a/dev_config_docker.yaml +++ b/dev_config_docker.yaml @@ -78,6 +78,10 @@ persistent: apigw: api_server: addr: :8080 + tls: + enabled: false + cert_file_path: "" + key_file_path: "" py_pdfsigner: sign_queue_name: sign diff --git a/dockerfiles/worker b/dockerfiles/worker index 8f3586d7..9d0ac835 100644 --- a/dockerfiles/worker +++ b/dockerfiles/worker @@ -24,7 +24,7 @@ ARG SERVICE_NAME WORKDIR / -RUN apt-get update && apt-get install -y curl procps iputils-ping less +RUN apt-get update && apt-get install -y curl procps iputils-ping less coreutils file netcat-openbsd RUN rm -rf /var/lib/apt/lists/* COPY --from=builder /go/src/app/bin/vc_${SERVICE_NAME} /vc_service @@ -32,7 +32,7 @@ COPY --from=builder /go/src/app/docs /docs EXPOSE 8080 -HEALTHCHECK --interval=20s --timeout=10s CMD curl --connect-timeout 5 http://localhost:8080/health | grep -q STATUS_OK +HEALTHCHECK --interval=20s --timeout=10s CMD curl --insecure --connect-timeout 5 https://localhost:8080/health | grep -q STATUS_OK # vars in CMD and ENTRYPOINT are evaluated at runtime, that's why we use a static name on the binary. CMD [ "./vc_service" ] \ No newline at end of file diff --git a/internal/apigw/httpserver/tls.go b/internal/apigw/httpserver/tls.go index 5226627b..e7291831 100644 --- a/internal/apigw/httpserver/tls.go +++ b/internal/apigw/httpserver/tls.go @@ -6,9 +6,11 @@ import ( ) func (s *Service) applyTLSConfig(ctx context.Context) { + ctx, span := s.tp.Start(ctx, "httpserver:applyTLSConfig") + defer span.End() + cfg := &tls.Config{ MinVersion: tls.VersionTLS12, - CurvePreferences: []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256}, PreferServerCipherSuites: true, }