From a2b6355fb593aef968599964d1dc3ffe15aa1ec8 Mon Sep 17 00:00:00 2001 From: Wenkai Yin Date: Tue, 28 Jun 2016 17:33:39 +0800 Subject: [PATCH] audit deleting repository --- api/repository.go | 10 ---- service/notification.go | 107 +++++++++++++++++++++++++++------------- 2 files changed, 72 insertions(+), 45 deletions(-) diff --git a/api/repository.go b/api/repository.go index b4b36c090..57564e61f 100644 --- a/api/repository.go +++ b/api/repository.go @@ -154,17 +154,7 @@ func (ra *RepositoryAPI) Delete() { ra.CustomAbort(http.StatusInternalServerError, "internal error") } log.Infof("delete tag: %s %s", repoName, t) - go TriggerReplicationByRepository(repoName, []string{t}, models.RepOpDelete) - } - - go func() { - log.Debug("refreshing catalog cache") - if err := cache.RefreshCatalogCache(); err != nil { - log.Errorf("error occurred while refresh catalog cache: %v", err) - } - }() - } type tag struct { diff --git a/service/notification.go b/service/notification.go index 2bd391924..e72b13419 100644 --- a/service/notification.go +++ b/service/notification.go @@ -39,55 +39,92 @@ const manifestPattern = `^application/vnd.docker.distribution.manifest.v\d\+json // Post handles POST request, and records audit log or refreshes cache based on event. func (n *NotificationHandler) Post() { var notification models.Notification - //log.Info("Notification Handler triggered!\n") - // log.Infof("request body in string: %s", string(n.Ctx.Input.CopyBody())) + log.Infof("request body in string: %s", string(n.Ctx.Input.CopyBody(1<<32))) err := json.Unmarshal(n.Ctx.Input.CopyBody(1<<32), ¬ification) if err != nil { - log.Errorf("error while decoding json: %v", err) + log.Errorf("failed to decode notification: %v", err) return } - var username, action, repo, project, repoTag string - var matched bool - for _, e := range notification.Events { - matched, err = regexp.MatchString(manifestPattern, e.Target.MediaType) - if err != nil { - log.Errorf("Failed to match the media type against pattern, error: %v", err) - matched = false + + events, err := filterEvents(¬ification) + if err != nil { + log.Errorf("failed to filter events: %v", err) + return + } + + for _, event := range events { + repository := event.Target.Repository + + project := "" + if strings.Contains(repository, "/") { + project = repository[0:strings.LastIndex(repository, "/")] } - if matched && (strings.HasPrefix(e.Request.UserAgent, "docker") || - strings.ToLower(strings.TrimSpace(e.Request.UserAgent)) == "harbor-registry-client") { - username = e.Actor.Name - action = e.Action - repo = e.Target.Repository - repoTag = e.Target.Tag - log.Debugf("repo tag is : %v ", repoTag) - if strings.Contains(repo, "/") { - project = repo[0:strings.LastIndex(repo, "/")] - } - if username == "" { - username = "anonymous" - } + tag := event.Target.Tag + action := event.Action - if action == "pull" && username == "job-service-user" { - return - } + user := event.Actor.Name + if len(user) == 0 { + user = "anonymous" + } - go dao.AccessLog(username, project, repo, repoTag, action) + go dao.AccessLog(user, project, repository, tag, action) + if action == "push" || action == "delete" { + go func() { + if err := cache.RefreshCatalogCache(); err != nil { + log.Errorf("failed to refresh cache: %v", err) + } + }() + + operation := "" if action == "push" { - go func() { - err2 := cache.RefreshCatalogCache() - if err2 != nil { - log.Errorf("Error happens when refreshing cache: %v", err2) - } - }() - - go api.TriggerReplicationByRepository(repo, []string{repoTag}, models.RepOpTransfer) + operation = models.RepOpTransfer + } else { + operation = models.RepOpDelete } + + go api.TriggerReplicationByRepository(repository, []string{tag}, operation) + } + } +} + +func filterEvents(notification *models.Notification) ([]*models.Event, error) { + events := []*models.Event{} + + for _, event := range notification.Events { + + //delete + // TODO add tag field + if event.Action == "delete" { + events = append(events, &event) + continue + } + + isManifest, err := regexp.MatchString(manifestPattern, event.Target.MediaType) + if err != nil { + log.Errorf("failed to match the media type against pattern: %v", err) + continue + } + + if !isManifest { + continue + } + + //pull and push manifest by docker-client + if strings.HasPrefix(event.Request.UserAgent, "docker") && (event.Action == "pull" || event.Action == "push") { + events = append(events, &event) + continue + } + + //push manifest by docker-client or job-service + if strings.ToLower(strings.TrimSpace(event.Request.UserAgent)) == "harbor-registry-client" && event.Action == "push" { + events = append(events, &event) + continue } } + return events, nil } // Render returns nil as it won't render any template.