From 9dd49b10e93bcdccbcc2a211a6d68a9ba1818711 Mon Sep 17 00:00:00 2001 From: Atomys Date: Tue, 20 Feb 2024 22:36:25 +0100 Subject: [PATCH] fix: webhooks processor unamrshal empty interface (#582) **Describe the pull request** An issue when webhooks are unmarshalled into an interface and not a struct. **Checklist** - [x] I have made the modifications or added tests related to my PR - [x] I have run the tests and linters locally and they pass - [x] I have added/updated the documentation for my RP --- internal/webhooks/campus_user.go | 8 ++++++++ internal/webhooks/location.go | 8 ++++++++ internal/webhooks/serve.go | 29 +++++++++++++++++------------ internal/webhooks/user.go | 8 ++++++++ 4 files changed, 41 insertions(+), 12 deletions(-) diff --git a/internal/webhooks/campus_user.go b/internal/webhooks/campus_user.go index f10d8344..668c6868 100644 --- a/internal/webhooks/campus_user.go +++ b/internal/webhooks/campus_user.go @@ -12,6 +12,14 @@ type campusUserProcessor struct { duoapi.CampusUserWebhookProcessor } +func unmarshalAndProcessCampusUser(data []byte, metadata duoapi.WebhookMetadata, p *processor) error { + webhookCampusUser, err := unmarshalWebhook[duoapi.WebhookMetadata, duoapi.CampusUser](data) + if err != nil { + return err + } + return webhookCampusUser.Payload.ProcessWebhook(p.ctx, &metadata, &campusUserProcessor{processor: p}) +} + func (p *campusUserProcessor) Create(cu *duoapi.CampusUser, metadata *duoapi.WebhookMetadata) error { // Do nothing if the primary campus is not true. Due to the fact of when an // User switch of campus : the current campus is set to false and the new diff --git a/internal/webhooks/location.go b/internal/webhooks/location.go index 6b5fa7b4..a1b49b68 100644 --- a/internal/webhooks/location.go +++ b/internal/webhooks/location.go @@ -19,6 +19,14 @@ type locationProcessor struct { duoapi.LocationWebhookProcessor[duoapi.LocationUser] } +func unmarshalAndProcessLocation(data []byte, metadata duoapi.WebhookMetadata, p *processor) error { + webhookLocation, err := unmarshalWebhook[duoapi.WebhookMetadata, duoapi.Location[duoapi.LocationUser]](data) + if err != nil { + return err + } + return webhookLocation.Payload.ProcessWebhook(p.ctx, &metadata, &locationProcessor{processor: p}) +} + func (p *locationProcessor) Create(loc *duoapi.Location[duoapi.LocationUser], metadata *duoapi.WebhookMetadata) error { campus, err := p.db.Campus.Query().Where(campus.DuoID(loc.CampusID)).Only(p.ctx) if err != nil { diff --git a/internal/webhooks/serve.go b/internal/webhooks/serve.go index 09cc9064..0cc989c7 100644 --- a/internal/webhooks/serve.go +++ b/internal/webhooks/serve.go @@ -128,12 +128,14 @@ func (p *processor) handler(data []byte) error { handler := strings.Split(webhook.Metadata.SpecName, "-")[0] - log.Debug().Msgf("Received a message(%s): %+v", webhook.Metadata.SpecName, webhook.Payload) + log.Debug().Msgf("Received a message[%s](%s): %+v", handler, webhook.Metadata.SpecName, webhook.Payload) switch handler { case "github": return p.githubHandler(data) case "duo": return p.duoHandler(data) + default: + log.Error().Str("handler", handler).Msg("Unknown handler") } return nil @@ -193,24 +195,27 @@ func (p *processor) githubHandler(data []byte) error { // duoHandler is the processor for the duo webhooks. func (p *processor) duoHandler(data []byte) error { - webhook, err := unmarshalWebhook[*duoapi.WebhookMetadata, any](data) + webhook, err := unmarshalWebhook[duoapi.WebhookMetadata, any](data) if err != nil { return err } - payload, ok := webhook.Payload.(duoapi.IWebhookPayload) - if !ok { - return errors.New("invalid duo webhook payload. Cannot cast to IWebhookPayload interface") + var modelToFunction = map[string]func([]byte, duoapi.WebhookMetadata, *processor) error{ + "campus_user": unmarshalAndProcessCampusUser, + "location": unmarshalAndProcessLocation, + "user": unmarshalAndProcessUser, } - switch webhook.Metadata.Model { - case "campus_user": - err = payload.ProcessWebhook(p.ctx, webhook.Metadata, &campusUserProcessor{processor: p}) - case "location": - err = payload.ProcessWebhook(p.ctx, webhook.Metadata, &locationProcessor{processor: p}) - case "user": - err = payload.ProcessWebhook(p.ctx, webhook.Metadata, &userProcessor{processor: p}) + if function, exists := modelToFunction[webhook.Metadata.Model]; exists { + err = function(data, webhook.Metadata, p) + if err != nil { + log.Error().Err(err).Str("model", webhook.Metadata.Model).Str("event", webhook.Metadata.Event).Msg("Failed to process webhook") + return err + } + } else { + log.Error().Str("model", webhook.Metadata.Model).Msg("Unknown model") } + if err != nil { log.Error().Err(err).Str("model", webhook.Metadata.Model).Str("event", webhook.Metadata.Event).Msg("Failed to process webhook") return err diff --git a/internal/webhooks/user.go b/internal/webhooks/user.go index 4810cdef..4ea55b5d 100644 --- a/internal/webhooks/user.go +++ b/internal/webhooks/user.go @@ -13,6 +13,14 @@ type userProcessor struct { duoapi.UserWebhookProcessor } +func unmarshalAndProcessUser(data []byte, metadata duoapi.WebhookMetadata, p *processor) error { + webhookUser, err := unmarshalWebhook[duoapi.WebhookMetadata, duoapi.User](data) + if err != nil { + return err + } + return webhookUser.Payload.ProcessWebhook(p.ctx, &metadata, &userProcessor{processor: p}) +} + func (p *userProcessor) Create(u *duoapi.User, metadata *duoapi.WebhookMetadata) error { ok, err := p.db.User.Query().Where(user.DuoID(u.ID)).Exist(p.ctx) if err != nil && !modelgen.IsNotFound(err) {