diff --git a/.envrc b/.envrc index a31c62bc496..466281410e1 100644 --- a/.envrc +++ b/.envrc @@ -50,6 +50,8 @@ export AWS_VAULT_KEYCHAIN_NAME=login # The AWS_PROFILE setting is in the project configuration section # because now we're working with multiple accounts. +export AWS_PROFILE=transcom-ppp + ############################# # Load Secrets from Chamber # ############################# @@ -180,11 +182,11 @@ export TZ="UTC" # Setting region and profile conditionally while we migrate from com to govcloud. if [ "$STORAGE_BACKEND" == "s3" ]; then export AWS_S3_BUCKET_NAME="transcom-gov-dev-app-devlocal-us-gov-west-1" - export AWS_PROFILE=transcom-gov-dev export AWS_S3_REGION="us-gov-west-1" + export AWS_DEFAULT_REGION="us-gov-west-1" + export AWS_PROFILE=transcom-gov-dev fi -export AWS_DEFAULT_REGION="us-gov-west-1" export AWS_S3_KEY_NAMESPACE=$USER export AWS_SES_DOMAIN="devlocal.dp3.us" export AWS_SES_REGION="us-gov-west-1" diff --git a/cmd/milmove/migrate.go b/cmd/milmove/migrate.go index 3030cb9b4d0..e8f213e602b 100644 --- a/cmd/milmove/migrate.go +++ b/cmd/milmove/migrate.go @@ -10,6 +10,7 @@ import ( "strings" "time" + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/credentials/stscreds" awssession "github.com/aws/aws-sdk-go/aws/session" @@ -192,10 +193,8 @@ func migrateFunction(cmd *cobra.Command, args []string) error { var session *awssession.Session if v.GetBool(cli.DbIamFlag) || s3Migrations { - verbose := cli.LogLevelIsDebug(v) - c, errorConfig := cli.GetAWSConfig(v, verbose) - if errorConfig != nil { - return errors.Wrap(errorConfig, "error creating aws config") + c := &aws.Config{ + Region: aws.String(v.GetString(cli.AWSRegionFlag)), } s, errorSession := awssession.NewSession(c) if errorSession != nil { diff --git a/go.mod b/go.mod index 40e7cbf40f4..0d440d832b7 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/99designs/keyring v1.1.6 github.com/alexedwards/scs/redisstore v0.0.0-20200225172727-3308e1066830 github.com/alexedwards/scs/v2 v2.4.0 - github.com/aws/aws-sdk-go v1.37.6 + github.com/aws/aws-sdk-go v1.37.8 github.com/benbjohnson/clock v1.1.0 github.com/codegangsta/envy v0.0.0-20141216192214-4b78388c8ce4 // indirect github.com/codegangsta/gin v0.0.0-20171026143024-cafe2ce98974 diff --git a/go.sum b/go.sum index 7bda4d93f93..d06a3b5b5f3 100644 --- a/go.sum +++ b/go.sum @@ -73,8 +73,8 @@ github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:o github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef h1:46PFijGLmAjMPwCCCo7Jf0W6f9slllCkkv7vyc1yOSg= github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48= -github.com/aws/aws-sdk-go v1.37.6 h1:SWYjRvyZw6DJc3pkZfRWVRD/5wiTDuwOkyb89AAkEBY= -github.com/aws/aws-sdk-go v1.37.6/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.37.8 h1:9kywcbuz6vQuTf+FD+U7FshafrHzmqUCjgAEiLuIJ8U= +github.com/aws/aws-sdk-go v1.37.8/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= diff --git a/pkg/gen/adminapi/adminoperations/mymove_api.go b/pkg/gen/adminapi/adminoperations/mymove_api.go index 1c5424dce1e..216dedb43e2 100644 --- a/pkg/gen/adminapi/adminoperations/mymove_api.go +++ b/pkg/gen/adminapi/adminoperations/mymove_api.go @@ -81,6 +81,9 @@ func NewMymoveAPI(spec *loads.Document) *MymoveAPI { UsersGetUserHandler: users.GetUserHandlerFunc(func(params users.GetUserParams) middleware.Responder { return middleware.NotImplemented("operation users.GetUser has not yet been implemented") }), + WebhookSubscriptionsGetWebhookSubscriptionHandler: webhook_subscriptions.GetWebhookSubscriptionHandlerFunc(func(params webhook_subscriptions.GetWebhookSubscriptionParams) middleware.Responder { + return middleware.NotImplemented("operation webhook_subscriptions.GetWebhookSubscription has not yet been implemented") + }), AccessCodesIndexAccessCodesHandler: access_codes.IndexAccessCodesHandlerFunc(func(params access_codes.IndexAccessCodesParams) middleware.Responder { return middleware.NotImplemented("operation access_codes.IndexAccessCodes has not yet been implemented") }), @@ -177,6 +180,8 @@ type MymoveAPI struct { UploadGetUploadHandler upload.GetUploadHandler // UsersGetUserHandler sets the operation handler for the get user operation UsersGetUserHandler users.GetUserHandler + // WebhookSubscriptionsGetWebhookSubscriptionHandler sets the operation handler for the get webhook subscription operation + WebhookSubscriptionsGetWebhookSubscriptionHandler webhook_subscriptions.GetWebhookSubscriptionHandler // AccessCodesIndexAccessCodesHandler sets the operation handler for the index access codes operation AccessCodesIndexAccessCodesHandler access_codes.IndexAccessCodesHandler // AdminUsersIndexAdminUsersHandler sets the operation handler for the index admin users operation @@ -300,6 +305,9 @@ func (o *MymoveAPI) Validate() error { if o.UsersGetUserHandler == nil { unregistered = append(unregistered, "users.GetUserHandler") } + if o.WebhookSubscriptionsGetWebhookSubscriptionHandler == nil { + unregistered = append(unregistered, "webhook_subscriptions.GetWebhookSubscriptionHandler") + } if o.AccessCodesIndexAccessCodesHandler == nil { unregistered = append(unregistered, "access_codes.IndexAccessCodesHandler") } @@ -472,6 +480,10 @@ func (o *MymoveAPI) initHandlerCache() { if o.handlers["GET"] == nil { o.handlers["GET"] = make(map[string]http.Handler) } + o.handlers["GET"]["/webhook_subscriptions/{webhookSubscriptionId}"] = webhook_subscriptions.NewGetWebhookSubscription(o.context, o.WebhookSubscriptionsGetWebhookSubscriptionHandler) + if o.handlers["GET"] == nil { + o.handlers["GET"] = make(map[string]http.Handler) + } o.handlers["GET"]["/access_codes"] = access_codes.NewIndexAccessCodes(o.context, o.AccessCodesIndexAccessCodesHandler) if o.handlers["GET"] == nil { o.handlers["GET"] = make(map[string]http.Handler) diff --git a/pkg/gen/adminapi/adminoperations/webhook_subscriptions/get_webhook_subscription.go b/pkg/gen/adminapi/adminoperations/webhook_subscriptions/get_webhook_subscription.go new file mode 100644 index 00000000000..4b89731a843 --- /dev/null +++ b/pkg/gen/adminapi/adminoperations/webhook_subscriptions/get_webhook_subscription.go @@ -0,0 +1,60 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package webhook_subscriptions + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the generate command + +import ( + "net/http" + + "github.com/go-openapi/runtime/middleware" +) + +// GetWebhookSubscriptionHandlerFunc turns a function with the right signature into a get webhook subscription handler +type GetWebhookSubscriptionHandlerFunc func(GetWebhookSubscriptionParams) middleware.Responder + +// Handle executing the request and returning a response +func (fn GetWebhookSubscriptionHandlerFunc) Handle(params GetWebhookSubscriptionParams) middleware.Responder { + return fn(params) +} + +// GetWebhookSubscriptionHandler interface for that can handle valid get webhook subscription params +type GetWebhookSubscriptionHandler interface { + Handle(GetWebhookSubscriptionParams) middleware.Responder +} + +// NewGetWebhookSubscription creates a new http.Handler for the get webhook subscription operation +func NewGetWebhookSubscription(ctx *middleware.Context, handler GetWebhookSubscriptionHandler) *GetWebhookSubscription { + return &GetWebhookSubscription{Context: ctx, Handler: handler} +} + +/*GetWebhookSubscription swagger:route GET /webhook_subscriptions/{webhookSubscriptionId} webhook_subscriptions getWebhookSubscription + +Get information about a webhook subscription + +Returns the given webhook subscription and its details + +*/ +type GetWebhookSubscription struct { + Context *middleware.Context + Handler GetWebhookSubscriptionHandler +} + +func (o *GetWebhookSubscription) ServeHTTP(rw http.ResponseWriter, r *http.Request) { + route, rCtx, _ := o.Context.RouteInfo(r) + if rCtx != nil { + r = rCtx + } + var Params = NewGetWebhookSubscriptionParams() + + if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params + o.Context.Respond(rw, r, route.Produces, route, err) + return + } + + res := o.Handler.Handle(Params) // actually handle the request + + o.Context.Respond(rw, r, route.Produces, route, res) + +} diff --git a/pkg/gen/adminapi/adminoperations/webhook_subscriptions/get_webhook_subscription_parameters.go b/pkg/gen/adminapi/adminoperations/webhook_subscriptions/get_webhook_subscription_parameters.go new file mode 100644 index 00000000000..554f2bda389 --- /dev/null +++ b/pkg/gen/adminapi/adminoperations/webhook_subscriptions/get_webhook_subscription_parameters.go @@ -0,0 +1,91 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package webhook_subscriptions + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "net/http" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime/middleware" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/validate" +) + +// NewGetWebhookSubscriptionParams creates a new GetWebhookSubscriptionParams object +// no default values defined in spec. +func NewGetWebhookSubscriptionParams() GetWebhookSubscriptionParams { + + return GetWebhookSubscriptionParams{} +} + +// GetWebhookSubscriptionParams contains all the bound params for the get webhook subscription operation +// typically these are obtained from a http.Request +// +// swagger:parameters getWebhookSubscription +type GetWebhookSubscriptionParams struct { + + // HTTP Request Object + HTTPRequest *http.Request `json:"-"` + + /* + Required: true + In: path + */ + WebhookSubscriptionID strfmt.UUID +} + +// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface +// for simple values it will use straight method calls. +// +// To ensure default values, the struct must have been initialized with NewGetWebhookSubscriptionParams() beforehand. +func (o *GetWebhookSubscriptionParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error { + var res []error + + o.HTTPRequest = r + + rWebhookSubscriptionID, rhkWebhookSubscriptionID, _ := route.Params.GetOK("webhookSubscriptionId") + if err := o.bindWebhookSubscriptionID(rWebhookSubscriptionID, rhkWebhookSubscriptionID, route.Formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +// bindWebhookSubscriptionID binds and validates parameter WebhookSubscriptionID from path. +func (o *GetWebhookSubscriptionParams) bindWebhookSubscriptionID(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: true + // Parameter is provided by construction from the route + + // Format: uuid + value, err := formats.Parse("uuid", raw) + if err != nil { + return errors.InvalidType("webhookSubscriptionId", "path", "strfmt.UUID", raw) + } + o.WebhookSubscriptionID = *(value.(*strfmt.UUID)) + + if err := o.validateWebhookSubscriptionID(formats); err != nil { + return err + } + + return nil +} + +// validateWebhookSubscriptionID carries on validations for parameter WebhookSubscriptionID +func (o *GetWebhookSubscriptionParams) validateWebhookSubscriptionID(formats strfmt.Registry) error { + + if err := validate.FormatOf("webhookSubscriptionId", "path", "uuid", o.WebhookSubscriptionID.String(), formats); err != nil { + return err + } + return nil +} diff --git a/pkg/gen/adminapi/adminoperations/webhook_subscriptions/get_webhook_subscription_responses.go b/pkg/gen/adminapi/adminoperations/webhook_subscriptions/get_webhook_subscription_responses.go new file mode 100644 index 00000000000..e37b72b7a5f --- /dev/null +++ b/pkg/gen/adminapi/adminoperations/webhook_subscriptions/get_webhook_subscription_responses.go @@ -0,0 +1,154 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package webhook_subscriptions + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "net/http" + + "github.com/go-openapi/runtime" + + "github.com/transcom/mymove/pkg/gen/adminmessages" +) + +// GetWebhookSubscriptionOKCode is the HTTP code returned for type GetWebhookSubscriptionOK +const GetWebhookSubscriptionOKCode int = 200 + +/*GetWebhookSubscriptionOK success + +swagger:response getWebhookSubscriptionOK +*/ +type GetWebhookSubscriptionOK struct { + + /* + In: Body + */ + Payload *adminmessages.WebhookSubscription `json:"body,omitempty"` +} + +// NewGetWebhookSubscriptionOK creates GetWebhookSubscriptionOK with default headers values +func NewGetWebhookSubscriptionOK() *GetWebhookSubscriptionOK { + + return &GetWebhookSubscriptionOK{} +} + +// WithPayload adds the payload to the get webhook subscription o k response +func (o *GetWebhookSubscriptionOK) WithPayload(payload *adminmessages.WebhookSubscription) *GetWebhookSubscriptionOK { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the get webhook subscription o k response +func (o *GetWebhookSubscriptionOK) SetPayload(payload *adminmessages.WebhookSubscription) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *GetWebhookSubscriptionOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(200) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} + +// GetWebhookSubscriptionBadRequestCode is the HTTP code returned for type GetWebhookSubscriptionBadRequest +const GetWebhookSubscriptionBadRequestCode int = 400 + +/*GetWebhookSubscriptionBadRequest invalid request + +swagger:response getWebhookSubscriptionBadRequest +*/ +type GetWebhookSubscriptionBadRequest struct { +} + +// NewGetWebhookSubscriptionBadRequest creates GetWebhookSubscriptionBadRequest with default headers values +func NewGetWebhookSubscriptionBadRequest() *GetWebhookSubscriptionBadRequest { + + return &GetWebhookSubscriptionBadRequest{} +} + +// WriteResponse to the client +func (o *GetWebhookSubscriptionBadRequest) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.Header().Del(runtime.HeaderContentType) //Remove Content-Type on empty responses + + rw.WriteHeader(400) +} + +// GetWebhookSubscriptionUnauthorizedCode is the HTTP code returned for type GetWebhookSubscriptionUnauthorized +const GetWebhookSubscriptionUnauthorizedCode int = 401 + +/*GetWebhookSubscriptionUnauthorized request requires user authentication + +swagger:response getWebhookSubscriptionUnauthorized +*/ +type GetWebhookSubscriptionUnauthorized struct { +} + +// NewGetWebhookSubscriptionUnauthorized creates GetWebhookSubscriptionUnauthorized with default headers values +func NewGetWebhookSubscriptionUnauthorized() *GetWebhookSubscriptionUnauthorized { + + return &GetWebhookSubscriptionUnauthorized{} +} + +// WriteResponse to the client +func (o *GetWebhookSubscriptionUnauthorized) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.Header().Del(runtime.HeaderContentType) //Remove Content-Type on empty responses + + rw.WriteHeader(401) +} + +// GetWebhookSubscriptionNotFoundCode is the HTTP code returned for type GetWebhookSubscriptionNotFound +const GetWebhookSubscriptionNotFoundCode int = 404 + +/*GetWebhookSubscriptionNotFound subscription not found + +swagger:response getWebhookSubscriptionNotFound +*/ +type GetWebhookSubscriptionNotFound struct { +} + +// NewGetWebhookSubscriptionNotFound creates GetWebhookSubscriptionNotFound with default headers values +func NewGetWebhookSubscriptionNotFound() *GetWebhookSubscriptionNotFound { + + return &GetWebhookSubscriptionNotFound{} +} + +// WriteResponse to the client +func (o *GetWebhookSubscriptionNotFound) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.Header().Del(runtime.HeaderContentType) //Remove Content-Type on empty responses + + rw.WriteHeader(404) +} + +// GetWebhookSubscriptionInternalServerErrorCode is the HTTP code returned for type GetWebhookSubscriptionInternalServerError +const GetWebhookSubscriptionInternalServerErrorCode int = 500 + +/*GetWebhookSubscriptionInternalServerError server error + +swagger:response getWebhookSubscriptionInternalServerError +*/ +type GetWebhookSubscriptionInternalServerError struct { +} + +// NewGetWebhookSubscriptionInternalServerError creates GetWebhookSubscriptionInternalServerError with default headers values +func NewGetWebhookSubscriptionInternalServerError() *GetWebhookSubscriptionInternalServerError { + + return &GetWebhookSubscriptionInternalServerError{} +} + +// WriteResponse to the client +func (o *GetWebhookSubscriptionInternalServerError) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.Header().Del(runtime.HeaderContentType) //Remove Content-Type on empty responses + + rw.WriteHeader(500) +} diff --git a/pkg/gen/adminapi/adminoperations/webhook_subscriptions/get_webhook_subscription_urlbuilder.go b/pkg/gen/adminapi/adminoperations/webhook_subscriptions/get_webhook_subscription_urlbuilder.go new file mode 100644 index 00000000000..a5497e36407 --- /dev/null +++ b/pkg/gen/adminapi/adminoperations/webhook_subscriptions/get_webhook_subscription_urlbuilder.go @@ -0,0 +1,101 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package webhook_subscriptions + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the generate command + +import ( + "errors" + "net/url" + golangswaggerpaths "path" + "strings" + + "github.com/go-openapi/strfmt" +) + +// GetWebhookSubscriptionURL generates an URL for the get webhook subscription operation +type GetWebhookSubscriptionURL struct { + WebhookSubscriptionID strfmt.UUID + + _basePath string + // avoid unkeyed usage + _ struct{} +} + +// WithBasePath sets the base path for this url builder, only required when it's different from the +// base path specified in the swagger spec. +// When the value of the base path is an empty string +func (o *GetWebhookSubscriptionURL) WithBasePath(bp string) *GetWebhookSubscriptionURL { + o.SetBasePath(bp) + return o +} + +// SetBasePath sets the base path for this url builder, only required when it's different from the +// base path specified in the swagger spec. +// When the value of the base path is an empty string +func (o *GetWebhookSubscriptionURL) SetBasePath(bp string) { + o._basePath = bp +} + +// Build a url path and query string +func (o *GetWebhookSubscriptionURL) Build() (*url.URL, error) { + var _result url.URL + + var _path = "/webhook_subscriptions/{webhookSubscriptionId}" + + webhookSubscriptionID := o.WebhookSubscriptionID.String() + if webhookSubscriptionID != "" { + _path = strings.Replace(_path, "{webhookSubscriptionId}", webhookSubscriptionID, -1) + } else { + return nil, errors.New("webhookSubscriptionId is required on GetWebhookSubscriptionURL") + } + + _basePath := o._basePath + if _basePath == "" { + _basePath = "/admin/v1" + } + _result.Path = golangswaggerpaths.Join(_basePath, _path) + + return &_result, nil +} + +// Must is a helper function to panic when the url builder returns an error +func (o *GetWebhookSubscriptionURL) Must(u *url.URL, err error) *url.URL { + if err != nil { + panic(err) + } + if u == nil { + panic("url can't be nil") + } + return u +} + +// String returns the string representation of the path with query string +func (o *GetWebhookSubscriptionURL) String() string { + return o.Must(o.Build()).String() +} + +// BuildFull builds a full url with scheme, host, path and query string +func (o *GetWebhookSubscriptionURL) BuildFull(scheme, host string) (*url.URL, error) { + if scheme == "" { + return nil, errors.New("scheme is required for a full url on GetWebhookSubscriptionURL") + } + if host == "" { + return nil, errors.New("host is required for a full url on GetWebhookSubscriptionURL") + } + + base, err := o.Build() + if err != nil { + return nil, err + } + + base.Scheme = scheme + base.Host = host + return base, nil +} + +// StringFull returns the string representation of a complete url +func (o *GetWebhookSubscriptionURL) StringFull(scheme, host string) string { + return o.Must(o.BuildFull(scheme, host)).String() +} diff --git a/pkg/gen/adminapi/configure_mymove.go b/pkg/gen/adminapi/configure_mymove.go index a683375c365..2e456b1e0ae 100644 --- a/pkg/gen/adminapi/configure_mymove.go +++ b/pkg/gen/adminapi/configure_mymove.go @@ -90,6 +90,11 @@ func configureAPI(api *adminoperations.MymoveAPI) http.Handler { return middleware.NotImplemented("operation users.GetUser has not yet been implemented") }) } + if api.WebhookSubscriptionsGetWebhookSubscriptionHandler == nil { + api.WebhookSubscriptionsGetWebhookSubscriptionHandler = webhook_subscriptions.GetWebhookSubscriptionHandlerFunc(func(params webhook_subscriptions.GetWebhookSubscriptionParams) middleware.Responder { + return middleware.NotImplemented("operation webhook_subscriptions.GetWebhookSubscription has not yet been implemented") + }) + } if api.AccessCodesIndexAccessCodesHandler == nil { api.AccessCodesIndexAccessCodesHandler = access_codes.IndexAccessCodesHandlerFunc(func(params access_codes.IndexAccessCodesParams) middleware.Responder { return middleware.NotImplemented("operation access_codes.IndexAccessCodes has not yet been implemented") diff --git a/pkg/gen/adminapi/embedded_spec.go b/pkg/gen/adminapi/embedded_spec.go index 51c9a5ee177..51afc973394 100644 --- a/pkg/gen/adminapi/embedded_spec.go +++ b/pkg/gen/adminapi/embedded_spec.go @@ -1291,6 +1291,45 @@ func init() { } } } + }, + "/webhook_subscriptions/{webhookSubscriptionId}": { + "get": { + "description": "Returns the given webhook subscription and its details", + "tags": [ + "webhook_subscriptions" + ], + "summary": "Get information about a webhook subscription", + "operationId": "getWebhookSubscription", + "parameters": [ + { + "type": "string", + "format": "uuid", + "name": "webhookSubscriptionId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "success", + "schema": { + "$ref": "#/definitions/WebhookSubscription" + } + }, + "400": { + "description": "invalid request" + }, + "401": { + "description": "request requires user authentication" + }, + "404": { + "description": "subscription not found" + }, + "500": { + "description": "server error" + } + } + } } }, "definitions": { @@ -2419,6 +2458,12 @@ func init() { "status": { "$ref": "#/definitions/WebhookSubscriptionStatus" }, + "subscriberId": { + "description": "Unique identifier for the subscriber", + "type": "string", + "format": "uuid", + "example": "d494f114-05a2-4b39-840c-3d33243b7e29" + }, "updatedAt": { "type": "string", "format": "date-time" @@ -3722,6 +3767,45 @@ func init() { } } } + }, + "/webhook_subscriptions/{webhookSubscriptionId}": { + "get": { + "description": "Returns the given webhook subscription and its details", + "tags": [ + "webhook_subscriptions" + ], + "summary": "Get information about a webhook subscription", + "operationId": "getWebhookSubscription", + "parameters": [ + { + "type": "string", + "format": "uuid", + "name": "webhookSubscriptionId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "success", + "schema": { + "$ref": "#/definitions/WebhookSubscription" + } + }, + "400": { + "description": "invalid request" + }, + "401": { + "description": "request requires user authentication" + }, + "404": { + "description": "subscription not found" + }, + "500": { + "description": "server error" + } + } + } } }, "definitions": { @@ -4855,6 +4939,12 @@ func init() { "status": { "$ref": "#/definitions/WebhookSubscriptionStatus" }, + "subscriberId": { + "description": "Unique identifier for the subscriber", + "type": "string", + "format": "uuid", + "example": "d494f114-05a2-4b39-840c-3d33243b7e29" + }, "updatedAt": { "type": "string", "format": "date-time" diff --git a/pkg/gen/adminmessages/webhook_subscription.go b/pkg/gen/adminmessages/webhook_subscription.go index ffb76c6a3f4..df427c8ab32 100644 --- a/pkg/gen/adminmessages/webhook_subscription.go +++ b/pkg/gen/adminmessages/webhook_subscription.go @@ -39,6 +39,10 @@ type WebhookSubscription struct { // status Status WebhookSubscriptionStatus `json:"status,omitempty"` + // Unique identifier for the subscriber + // Format: uuid + SubscriberID strfmt.UUID `json:"subscriberId,omitempty"` + // updated at // Format: date-time UpdatedAt strfmt.DateTime `json:"updatedAt,omitempty"` @@ -64,6 +68,10 @@ func (m *WebhookSubscription) Validate(formats strfmt.Registry) error { res = append(res, err) } + if err := m.validateSubscriberID(formats); err != nil { + res = append(res, err) + } + if err := m.validateUpdatedAt(formats); err != nil { res = append(res, err) } @@ -129,6 +137,19 @@ func (m *WebhookSubscription) validateStatus(formats strfmt.Registry) error { return nil } +func (m *WebhookSubscription) validateSubscriberID(formats strfmt.Registry) error { + + if swag.IsZero(m.SubscriberID) { // not required + return nil + } + + if err := validate.FormatOf("subscriberId", "body", "uuid", m.SubscriberID.String(), formats); err != nil { + return err + } + + return nil +} + func (m *WebhookSubscription) validateUpdatedAt(formats strfmt.Registry) error { if swag.IsZero(m.UpdatedAt) { // not required diff --git a/pkg/handlers/adminapi/api.go b/pkg/handlers/adminapi/api.go index d6fd484a272..aef865521af 100644 --- a/pkg/handlers/adminapi/api.go +++ b/pkg/handlers/adminapi/api.go @@ -23,12 +23,12 @@ import ( move "github.com/transcom/mymove/pkg/services/move" "github.com/transcom/mymove/pkg/services/office" officeuser "github.com/transcom/mymove/pkg/services/office_user" - tspop "github.com/transcom/mymove/pkg/services/tsp" - user "github.com/transcom/mymove/pkg/services/user" - "github.com/transcom/mymove/pkg/services/pagination" "github.com/transcom/mymove/pkg/services/query" + tspop "github.com/transcom/mymove/pkg/services/tsp" "github.com/transcom/mymove/pkg/services/upload" + user "github.com/transcom/mymove/pkg/services/user" + webhooksubscription "github.com/transcom/mymove/pkg/services/webhook_subscription" ) // NewAdminAPIHandler returns a handler for the admin API @@ -198,5 +198,11 @@ func NewAdminAPIHandler(context handlers.HandlerContext) http.Handler { pagination.NewPagination, } + adminAPI.WebhookSubscriptionsGetWebhookSubscriptionHandler = GetWebhookSubscriptionHandler{ + context, + webhooksubscription.NewWebhookSubscriptionFetcher(queryBuilder), + query.NewQueryFilter, + } + return adminAPI.Serve(nil) } diff --git a/pkg/handlers/adminapi/webhook_subscriptions.go b/pkg/handlers/adminapi/webhook_subscriptions.go index 4c685c3779d..4d574468d27 100644 --- a/pkg/handlers/adminapi/webhook_subscriptions.go +++ b/pkg/handlers/adminapi/webhook_subscriptions.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/go-openapi/runtime/middleware" + "github.com/gofrs/uuid" webhooksubscriptionop "github.com/transcom/mymove/pkg/gen/adminapi/adminoperations/webhook_subscriptions" "github.com/transcom/mymove/pkg/gen/adminmessages" @@ -17,13 +18,14 @@ func payloadForWebhookSubscriptionModel(subscription models.WebhookSubscription) severity := int64(subscription.Severity) return &adminmessages.WebhookSubscription{ - ID: *handlers.FmtUUID(subscription.ID), - CallbackURL: subscription.CallbackURL, - Severity: &severity, - EventKey: subscription.EventKey, - Status: adminmessages.WebhookSubscriptionStatus(subscription.Status), - CreatedAt: *handlers.FmtDateTime(subscription.CreatedAt), - UpdatedAt: *handlers.FmtDateTime(subscription.UpdatedAt), + ID: *handlers.FmtUUID(subscription.ID), + SubscriberID: *handlers.FmtUUID(subscription.SubscriberID), + CallbackURL: subscription.CallbackURL, + Severity: &severity, + EventKey: subscription.EventKey, + Status: adminmessages.WebhookSubscriptionStatus(subscription.Status), + CreatedAt: *handlers.FmtDateTime(subscription.CreatedAt), + UpdatedAt: *handlers.FmtDateTime(subscription.UpdatedAt), } } @@ -66,3 +68,26 @@ func (h IndexWebhookSubscriptionsHandler) Handle(params webhooksubscriptionop.In return webhooksubscriptionop.NewIndexWebhookSubscriptionsOK().WithContentRange(fmt.Sprintf("webhookSubscriptions %d-%d/%d", pagination.Offset(), pagination.Offset()+queriedWebhookSubscriptionsCount, totalWebhookSubscriptionsCount)).WithPayload(payload) } + +// GetWebhookSubscriptionHandler returns one webhookSubscription via GET /webhook_subscriptions/:ID +type GetWebhookSubscriptionHandler struct { + handlers.HandlerContext + services.WebhookSubscriptionFetcher + services.NewQueryFilter +} + +// Handle retrieves a webhook subscription +func (h GetWebhookSubscriptionHandler) Handle(params webhooksubscriptionop.GetWebhookSubscriptionParams) middleware.Responder { + logger := h.LoggerFromRequest(params.HTTPRequest) + webhookSubscriptionID := uuid.FromStringOrNil(params.WebhookSubscriptionID.String()) + queryFilters := []services.QueryFilter{query.NewQueryFilter("id", "=", webhookSubscriptionID)} + + webhookSubscription, err := h.WebhookSubscriptionFetcher.FetchWebhookSubscription(queryFilters) + + if err != nil { + return handlers.ResponseForError(logger, err) + } + + payload := payloadForWebhookSubscriptionModel(webhookSubscription) + return webhooksubscriptionop.NewGetWebhookSubscriptionOK().WithPayload(payload) +} diff --git a/pkg/handlers/adminapi/webhook_subscriptions_test.go b/pkg/handlers/adminapi/webhook_subscriptions_test.go index b429b720c3f..3bbbb2f8d95 100644 --- a/pkg/handlers/adminapi/webhook_subscriptions_test.go +++ b/pkg/handlers/adminapi/webhook_subscriptions_test.go @@ -1,10 +1,13 @@ package adminapi import ( + "fmt" "net/http" "net/http/httptest" "testing" + "github.com/go-openapi/strfmt" + "github.com/gofrs/uuid" "github.com/stretchr/testify/mock" webhooksubscriptionop "github.com/transcom/mymove/pkg/gen/adminapi/adminoperations/webhook_subscriptions" @@ -14,6 +17,7 @@ import ( "github.com/transcom/mymove/pkg/services/mocks" "github.com/transcom/mymove/pkg/services/pagination" "github.com/transcom/mymove/pkg/services/query" + webhooksubscriptionservice "github.com/transcom/mymove/pkg/services/webhook_subscription" "github.com/transcom/mymove/pkg/testdatagen" ) @@ -83,3 +87,70 @@ func (suite *HandlerSuite) TestIndexWebhookSubscriptionsHandler() { suite.CheckErrorResponse(response, http.StatusNotFound, expectedError.Error()) }) } + +func (suite *HandlerSuite) TestGetWebhookSubscriptionHandler() { + // Setup: Create a default webhook subscription and request + webhookSubscription := testdatagen.MakeDefaultWebhookSubscription(suite.DB()) + req := httptest.NewRequest("GET", fmt.Sprintf("/webhook_subscriptions/%s", webhookSubscription.ID), nil) + + suite.T().Run("200 - OK, Successfuly get webhook subscription", func(t *testing.T) { + // Under test: GetWebhookSubscriptionHandler, Fetcher + // Set up: Provide a valid request with the id of a webhook_subscription + // to the getWebhookSubscription endpoint. + // Expected Outcome: The webhookSubscription is returned and we + // review a 200 OK. + params := webhooksubscriptionop.GetWebhookSubscriptionParams{ + HTTPRequest: req, + WebhookSubscriptionID: strfmt.UUID(webhookSubscription.ID.String()), + } + + queryBuilder := query.NewQueryBuilder(suite.DB()) + handler := GetWebhookSubscriptionHandler{ + handlers.NewHandlerContext(suite.DB(), suite.TestLogger()), + webhooksubscriptionservice.NewWebhookSubscriptionFetcher(queryBuilder), + query.NewQueryFilter, + } + + response := handler.Handle(params) + + suite.IsType(&webhooksubscriptionop.GetWebhookSubscriptionOK{}, response) + okResponse := response.(*webhooksubscriptionop.GetWebhookSubscriptionOK) + suite.Equal(webhookSubscription.ID.String(), okResponse.Payload.ID.String()) + }) + + suite.T().Run("404 - Not Found", func(t *testing.T) { + // Under test: GetWebhookSubscriptionHandler + // Mocks: WebhookSubscriptionFetcher + // Set up: Provide an invalid uuid to the getWebhookSubscription + // endpoint and mock Fetcher to return an error. + // Expected Outcome: The handler returns a 404. + + webhookSubscriptionFetcher := &mocks.WebhookSubscriptionFetcher{} + fakeID, err := uuid.NewV4() + suite.NoError(err) + + expectedError := models.ErrFetchNotFound + params := webhooksubscriptionop.GetWebhookSubscriptionParams{ + HTTPRequest: req, + WebhookSubscriptionID: strfmt.UUID(fakeID.String()), + } + + webhookSubscriptionFetcher.On("FetchWebhookSubscription", + mock.Anything, + ).Return(models.WebhookSubscription{}, expectedError).Once() + + handler := GetWebhookSubscriptionHandler{ + handlers.NewHandlerContext(suite.DB(), suite.TestLogger()), + webhookSubscriptionFetcher, + query.NewQueryFilter, + } + + response := handler.Handle(params) + + expectedResponse := &handlers.ErrResponse{ + Code: http.StatusNotFound, + Err: expectedError, + } + suite.Equal(expectedResponse, response) + }) +} diff --git a/pkg/services/mocks/WebhookSubscriptionFetcher.go b/pkg/services/mocks/WebhookSubscriptionFetcher.go new file mode 100644 index 00000000000..3f099967bf1 --- /dev/null +++ b/pkg/services/mocks/WebhookSubscriptionFetcher.go @@ -0,0 +1,36 @@ +// Code generated by mockery v1.0.0. DO NOT EDIT. + +package mocks + +import ( + mock "github.com/stretchr/testify/mock" + models "github.com/transcom/mymove/pkg/models" + + services "github.com/transcom/mymove/pkg/services" +) + +// WebhookSubscriptionFetcher is an autogenerated mock type for the WebhookSubscriptionFetcher type +type WebhookSubscriptionFetcher struct { + mock.Mock +} + +// FetchWebhookSubscription provides a mock function with given fields: filters +func (_m *WebhookSubscriptionFetcher) FetchWebhookSubscription(filters []services.QueryFilter) (models.WebhookSubscription, error) { + ret := _m.Called(filters) + + var r0 models.WebhookSubscription + if rf, ok := ret.Get(0).(func([]services.QueryFilter) models.WebhookSubscription); ok { + r0 = rf(filters) + } else { + r0 = ret.Get(0).(models.WebhookSubscription) + } + + var r1 error + if rf, ok := ret.Get(1).(func([]services.QueryFilter) error); ok { + r1 = rf(filters) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} diff --git a/pkg/services/webhook_subscription.go b/pkg/services/webhook_subscription.go new file mode 100644 index 00000000000..bcab970c29d --- /dev/null +++ b/pkg/services/webhook_subscription.go @@ -0,0 +1,11 @@ +package services + +import ( + "github.com/transcom/mymove/pkg/models" +) + +// WebhookSubscriptionFetcher is the service object interface for FetchWebhookSubscription +//go:generate mockery -name WebhookSubscriptionFetcher +type WebhookSubscriptionFetcher interface { + FetchWebhookSubscription(filters []QueryFilter) (models.WebhookSubscription, error) +} diff --git a/pkg/services/webhook_subscription/logger.go b/pkg/services/webhook_subscription/logger.go new file mode 100644 index 00000000000..a12dc633482 --- /dev/null +++ b/pkg/services/webhook_subscription/logger.go @@ -0,0 +1,15 @@ +package webhooksubscription + +import ( + "go.uber.org/zap" +) + +// Logger is an interface that describes the logging requirements of this package. +type Logger interface { + Debug(msg string, fields ...zap.Field) + Info(msg string, fields ...zap.Field) + Warn(msg string, fields ...zap.Field) + Error(msg string, fields ...zap.Field) + Fatal(msg string, fields ...zap.Field) + WithOptions(opts ...zap.Option) *zap.Logger +} diff --git a/pkg/services/webhook_subscription/webhook_subscription_fetcher.go b/pkg/services/webhook_subscription/webhook_subscription_fetcher.go new file mode 100644 index 00000000000..74eeca77a03 --- /dev/null +++ b/pkg/services/webhook_subscription/webhook_subscription_fetcher.go @@ -0,0 +1,26 @@ +package webhooksubscription + +import ( + "github.com/transcom/mymove/pkg/models" + "github.com/transcom/mymove/pkg/services" +) + +type webhookSubscriptionQueryBuilder interface { + FetchOne(model interface{}, filters []services.QueryFilter) error +} + +type webhookSubscriptionFetcher struct { + builder webhookSubscriptionQueryBuilder +} + +// FetchWebhookSubscription fetches a webhookSubscription given a slice of filters +func (o *webhookSubscriptionFetcher) FetchWebhookSubscription(filters []services.QueryFilter) (models.WebhookSubscription, error) { + var webhookSubscription models.WebhookSubscription + error := o.builder.FetchOne(&webhookSubscription, filters) + return webhookSubscription, error +} + +// NewWebhookSubscriptionFetcher return an implementation of the WebhookSubscriptionFetcher interface +func NewWebhookSubscriptionFetcher(builder webhookSubscriptionQueryBuilder) services.WebhookSubscriptionFetcher { + return &webhookSubscriptionFetcher{builder} +} diff --git a/pkg/services/webhook_subscription/webhook_subscription_fetcher_test.go b/pkg/services/webhook_subscription/webhook_subscription_fetcher_test.go new file mode 100644 index 00000000000..193ad9220bf --- /dev/null +++ b/pkg/services/webhook_subscription/webhook_subscription_fetcher_test.go @@ -0,0 +1,42 @@ +package webhooksubscription + +import ( + "testing" + + "github.com/gofrs/uuid" + + "github.com/transcom/mymove/pkg/models" + "github.com/transcom/mymove/pkg/services" + "github.com/transcom/mymove/pkg/services/query" + "github.com/transcom/mymove/pkg/testdatagen" +) + +func (suite *WebhookSubscriptionServiceSuite) TestWebhookSubscriptionFetcher() { + builder := query.NewQueryBuilder(suite.DB()) + fetcher := NewWebhookSubscriptionFetcher(builder) + + webhookSubscription := testdatagen.MakeDefaultWebhookSubscription(suite.DB()) + webhookSubscriptionID := webhookSubscription.ID + + suite.T().Run("Get a webhook subscription successfully", func(t *testing.T) { + filters := []services.QueryFilter{query.NewQueryFilter("id", "=", webhookSubscription.ID.String())} + + webhookSubscription, err := fetcher.FetchWebhookSubscription(filters) + + suite.NoError(err) + suite.Equal(webhookSubscriptionID, webhookSubscription.ID) + }) + + suite.T().Run("Failure to fetch - return empty webhookSubscription and error", func(t *testing.T) { + fakeID, err := uuid.NewV4() + suite.NoError(err) + + filters := []services.QueryFilter{query.NewQueryFilter("id", "=", fakeID.String())} + + fakeWebhookSubscription, err := fetcher.FetchWebhookSubscription(filters) + + suite.Error(err) + suite.Equal(models.WebhookSubscription{}, fakeWebhookSubscription) + }) + +} diff --git a/pkg/services/webhook_subscription/webhook_subscription_test.go b/pkg/services/webhook_subscription/webhook_subscription_test.go new file mode 100644 index 00000000000..eb78e424b1c --- /dev/null +++ b/pkg/services/webhook_subscription/webhook_subscription_test.go @@ -0,0 +1,25 @@ +package webhooksubscription + +import ( + "testing" + + "github.com/stretchr/testify/suite" + "go.uber.org/zap" + + "github.com/transcom/mymove/pkg/testingsuite" +) + +type WebhookSubscriptionServiceSuite struct { + testingsuite.PopTestSuite + logger Logger +} + +func TestWebhookSubscriptionSuite(t *testing.T) { + + ts := &WebhookSubscriptionServiceSuite{ + PopTestSuite: testingsuite.NewPopTestSuite(testingsuite.CurrentPackage()), + logger: zap.NewNop(), // Use a no-op logger during testing + } + suite.Run(t, ts) + ts.PopTestSuite.TearDown() +} diff --git a/pkg/storage/storage.go b/pkg/storage/storage.go index 7fe81430b4c..07ee69f05e1 100644 --- a/pkg/storage/storage.go +++ b/pkg/storage/storage.go @@ -1,12 +1,16 @@ package storage import ( - /* - #nosec - we use md5 because it's required by the S3 API for - validating data integrity. - https://aws.amazon.com/premiumsupport/knowledge-center/data-integrity-s3/ - */ - "crypto/md5" + //RA Summary: gosec - G401 - Weak cryptographic hash + //RA: This line was flagged because of the use of MD5 hashing + //RA: This line of code hashes the AWS object to be able to verify data integrity + //RA: Purpose of this hash is to protect against environmental risks, it does not + //RA: hash any sensitive user provided information such as passwords. + //RA: AWS S3 API requires use of MD5 to validate data integrity. + //RA Developer Status: Mitigated + //RA Validator Status: Mitigated + //RA Modified Severity: CAT III + "crypto/md5" // #nosec G501 "encoding/base64" "io" "net/http" @@ -37,16 +41,21 @@ type FileStorer interface { Tags(string) (map[string]string, error) } -// ComputeChecksum calculates the MD% checksum for the provided data. It expects that +// ComputeChecksum calculates the MD5 checksum for the provided data. It expects that // the passed io object will be seeked to its beginning and will seek back to the // beginning after reading its content. func ComputeChecksum(data io.ReadSeeker) (string, error) { - /* - #nosec - we use md5 because it's required by the S3 API for - validating data integrity. - https://aws.amazon.com/premiumsupport/knowledge-center/data-integrity-s3/ - */ - hash := md5.New() + //RA Summary: gosec - G401 - Weak cryptographic hash + //RA: This line was flagged because of the use of MD5 hashing + //RA: This line of code hashes the AWS object to be able to verify data integrity + //RA: Purpose of this hash is to protect against environmental risks, it does not + //RA: hash any sensitive user provided information such as passwords + //RA: AWS S3 API requires use of MD5 to validate data integrity. + //RA Developer Status: Mitigated + //RA Validator Status: Mitigated + //RA Validator: jneuner@mitre.org + //RA Modified Severity: CAT III + hash := md5.New() // #nosec G401 if _, err := io.Copy(hash, data); err != nil { return "", errors.Wrap(err, "could not read file") } diff --git a/swagger/admin.yaml b/swagger/admin.yaml index f6d5c300bf1..cc70e48adc8 100644 --- a/swagger/admin.yaml +++ b/swagger/admin.yaml @@ -890,6 +890,11 @@ definitions: format: uuid example: c56a4180-65aa-42ec-a945-5fd21dec0538 readOnly: true + subscriberId: + type: string + format: uuid + example: d494f114-05a2-4b39-840c-3d33243b7e29 + description: Unique identifier for the subscriber status: $ref: '#/definitions/WebhookSubscriptionStatus' callbackUrl: @@ -1726,4 +1731,30 @@ paths: 404: description: Webhook subscriptions not found 500: - description: Server error \ No newline at end of file + description: Server error + /webhook_subscriptions/{webhookSubscriptionId}: + get: + summary: Get information about a webhook subscription + description: Returns the given webhook subscription and its details + operationId: getWebhookSubscription + tags: + - webhook_subscriptions + parameters: + - in: path + name: webhookSubscriptionId + type: string + format: uuid + required: true + responses: + 200: + description: success + schema: + $ref: '#/definitions/WebhookSubscription' + 400: + description: invalid request + 401: + description: request requires user authentication + 404: + description: subscription not found + 500: + description: server error diff --git a/yarn.lock b/yarn.lock index 808631ad8b2..37613d4d622 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8835,6 +8835,11 @@ filter-console@^0.1.1: resolved "https://registry.yarnpkg.com/filter-console/-/filter-console-0.1.1.tgz#6242be28982bba7415bcc6db74a79f4a294fa67c" integrity sha512-zrXoV1Uaz52DqPs+qEwNJWJFAWZpYJ47UNmpN9q4j+/EYsz85uV0DC9k8tRND5kYmoVzL0W+Y75q4Rg8sRJCdg== +filter-obj@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-1.1.0.tgz#9b311112bc6c6127a16e016c6c5d7f19e0805c5b" + integrity sha1-mzERErxsYSehbgFsbF1/GeCAXFs= + final-form-arrays@^3.0.1: version "3.0.2" resolved "https://registry.yarnpkg.com/final-form-arrays/-/final-form-arrays-3.0.2.tgz#9f3bef778dec61432357744eb6f3abef7e7f3847" @@ -15522,11 +15527,12 @@ qs@~6.5.2: integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== query-string@6, query-string@^6.1.0, query-string@^6.8.2: - version "6.13.8" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.13.8.tgz#8cf231759c85484da3cf05a851810d8e825c1159" - integrity sha512-jxJzQI2edQPE/NPUOusNjO/ZOGqr1o2OBa/3M00fU76FsLXDVbJDv/p7ng5OdQyorKrkRz1oqfwmbe5MAMePQg== + version "6.14.0" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.14.0.tgz#0b7b7ca326f5facf10dd2d45d26645cd287f8c92" + integrity sha512-In3o+lUxlgejoVJgwEdYtdxrmlL0cQWJXj0+kkI7RWVo7hg5AhFtybeKlC9Dpgbr8eOC4ydpEh8017WwyfzqVQ== dependencies: decode-uri-component "^0.2.0" + filter-obj "^1.1.0" split-on-first "^1.0.0" strict-uri-encode "^2.0.0"