// GETLayersVulnerabilities returns the complete list of vulnerabilities that // a layer has if it exists. func GETLayersVulnerabilities(w http.ResponseWriter, r *http.Request, p httprouter.Params) { // Get minumum priority parameter. minimumPriority := types.Priority(r.URL.Query().Get("minimumPriority")) if minimumPriority == "" { minimumPriority = "High" // Set default priority to High } else if !minimumPriority.IsValid() { httputils.WriteHTTPError(w, 0, cerrors.NewBadRequestError("invalid priority")) return } // Find layer layer, err := database.FindOneLayerByID(p.ByName("id"), []string{database.FieldLayerParent, database.FieldLayerPackages}) if err != nil { httputils.WriteHTTPError(w, 0, err) return } // Find layer's packages. packagesNodes, err := layer.AllPackages() if err != nil { httputils.WriteHTTPError(w, 0, err) return } // Find vulnerabilities. vulnerabilities, err := getVulnerabilitiesFromLayerPackagesNodes(packagesNodes, minimumPriority, []string{database.FieldVulnerabilityID, database.FieldVulnerabilityLink, database.FieldVulnerabilityPriority, database.FieldVulnerabilityDescription, database.FieldVulnerabilityCausedByPackage}) if err != nil { httputils.WriteHTTPError(w, 0, err) return } httputils.WriteHTTP(w, http.StatusOK, struct{ Vulnerabilities []*database.Vulnerability }{Vulnerabilities: vulnerabilities}) }
// GETLayersPackages returns the complete list of packages that a layer has // if it exists. func GETLayersPackages(w http.ResponseWriter, r *http.Request, p httprouter.Params) { // Find layer layer, err := database.FindOneLayerByID(p.ByName("id"), []string{database.FieldLayerParent, database.FieldLayerPackages}) if err != nil { httputils.WriteHTTPError(w, 0, err) return } // Find layer's packages. packagesNodes, err := layer.AllPackages() if err != nil { httputils.WriteHTTPError(w, 0, err) return } packages := []*database.Package{} if len(packagesNodes) > 0 { packages, err = database.FindAllPackagesByNodes(packagesNodes, []string{database.FieldPackageOS, database.FieldPackageName, database.FieldPackageVersion}) if err != nil { httputils.WriteHTTPError(w, 0, err) return } } httputils.WriteHTTP(w, http.StatusOK, struct{ Packages []*database.Package }{Packages: packages}) }
// GETLayersPackagesDiff returns the list of packages that a layer installs and // removes if it exists. func GETLayersPackagesDiff(w http.ResponseWriter, r *http.Request, p httprouter.Params) { // Find layer. layer, err := database.FindOneLayerByID(p.ByName("id"), []string{database.FieldLayerPackages}) if err != nil { httputils.WriteHTTPError(w, 0, err) return } // Find layer's packages. installedPackages, removedPackages := make([]*database.Package, 0), make([]*database.Package, 0) if len(layer.InstalledPackagesNodes) > 0 { installedPackages, err = database.FindAllPackagesByNodes(layer.InstalledPackagesNodes, []string{database.FieldPackageOS, database.FieldPackageName, database.FieldPackageVersion}) if err != nil { httputils.WriteHTTPError(w, 0, err) return } } if len(layer.RemovedPackagesNodes) > 0 { removedPackages, err = database.FindAllPackagesByNodes(layer.RemovedPackagesNodes, []string{database.FieldPackageOS, database.FieldPackageName, database.FieldPackageVersion}) if err != nil { httputils.WriteHTTPError(w, 0, err) return } } httputils.WriteHTTP(w, http.StatusOK, struct{ InstalledPackages, RemovedPackages []*database.Package }{InstalledPackages: installedPackages, RemovedPackages: removedPackages}) }
// POSTLayers analyzes a layer and returns the engine version that has been used // for the analysis. func POSTLayers(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { var parameters POSTLayersParameters if s, err := httputils.ParseHTTPBody(r, ¶meters); err != nil { httputils.WriteHTTPError(w, s, err) return } // Process data. if err := worker.Process(parameters.ID, parameters.ParentID, parameters.Path); err != nil { httputils.WriteHTTPError(w, 0, err) return } // Get engine version and return. httputils.WriteHTTP(w, http.StatusCreated, struct{ Version string }{Version: strconv.Itoa(worker.Version)}) }
// TimeOut wraps a http.HandlerFunc and ensure that a response is given under // the specified duration. // // If the handler takes longer than the time limit, the wrapper responds with // a Service Unavailable error, an error message and the handler response which // may come later is ignored. // // After a timeout, any write the handler to its ResponseWriter will return // ErrHandlerTimeout. // // If the duration is 0, the wrapper does nothing. func TimeOut(d time.Duration, fn httprouter.Handle) httprouter.Handle { if d == 0 { return fn } return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { done := make(chan bool) tw := &timeoutWriter{ResponseWriter: w} go func() { fn(tw, r, p) done <- true }() select { case <-done: return case <-time.After(d): tw.mu.Lock() defer tw.mu.Unlock() if !tw.wroteHeader { httputils.WriteHTTPError(tw.ResponseWriter, http.StatusServiceUnavailable, ErrHandlerTimeout) } tw.timedOut = true } } }
// GETVulnerabilities returns a vulnerability identified by an ID if it exists. func GETVulnerabilities(w http.ResponseWriter, r *http.Request, p httprouter.Params) { // Find vulnerability. vulnerability, err := database.FindOneVulnerability(p.ByName("id"), []string{database.FieldVulnerabilityID, database.FieldVulnerabilityLink, database.FieldVulnerabilityPriority, database.FieldVulnerabilityDescription, database.FieldVulnerabilityFixedIn}) if err != nil { httputils.WriteHTTPError(w, 0, err) return } abstractVulnerability, err := vulnerability.ToAbstractVulnerability() if err != nil { httputils.WriteHTTPError(w, 0, err) return } httputils.WriteHTTP(w, http.StatusOK, abstractVulnerability) }
// GETLayersOS returns the operating system of a layer if it exists. // It uses not only the specified layer but also its parent layers if necessary. // An empty OS string is returned if no OS has been detected. func GETLayersOS(w http.ResponseWriter, r *http.Request, p httprouter.Params) { // Find layer. layer, err := database.FindOneLayerByID(p.ByName("id"), []string{database.FieldLayerParent, database.FieldLayerOS}) if err != nil { httputils.WriteHTTPError(w, 0, err) return } // Get OS. os, err := layer.OperatingSystem() if err != nil { httputils.WriteHTTPError(w, 0, err) return } httputils.WriteHTTP(w, http.StatusOK, struct{ OS string }{OS: os}) }
// GETLayersVulnerabilitiesDiff returns the list of vulnerabilities that a layer // adds and removes if it exists. func GETLayersVulnerabilitiesDiff(w http.ResponseWriter, r *http.Request, p httprouter.Params) { // Get minumum priority parameter. minimumPriority := types.Priority(r.URL.Query().Get("minimumPriority")) if minimumPriority == "" { minimumPriority = "High" // Set default priority to High } else if !minimumPriority.IsValid() { httputils.WriteHTTPError(w, 0, cerrors.NewBadRequestError("invalid priority")) return } // Find layer. layer, err := database.FindOneLayerByID(p.ByName("id"), []string{database.FieldLayerPackages}) if err != nil { httputils.WriteHTTPError(w, 0, err) return } // Selected fields for vulnerabilities. selectedFields := []string{database.FieldVulnerabilityID, database.FieldVulnerabilityLink, database.FieldVulnerabilityPriority, database.FieldVulnerabilityDescription, database.FieldVulnerabilityCausedByPackage} // Find vulnerabilities for installed packages. addedVulnerabilities, err := getVulnerabilitiesFromLayerPackagesNodes(layer.InstalledPackagesNodes, minimumPriority, selectedFields) if err != nil { httputils.WriteHTTPError(w, 0, err) return } // Find vulnerabilities for removed packages. removedVulnerabilities, err := getVulnerabilitiesFromLayerPackagesNodes(layer.RemovedPackagesNodes, minimumPriority, selectedFields) if err != nil { httputils.WriteHTTPError(w, 0, err) return } // Remove vulnerabilities which appears both in added and removed lists (eg. case of updated packages but still vulnerable). for ia, a := range addedVulnerabilities { for ir, r := range removedVulnerabilities { if a.ID == r.ID { addedVulnerabilities = append(addedVulnerabilities[:ia], addedVulnerabilities[ia+1:]...) removedVulnerabilities = append(removedVulnerabilities[:ir], removedVulnerabilities[ir+1:]...) } } } httputils.WriteHTTP(w, http.StatusOK, struct{ Adds, Removes []*database.Vulnerability }{Adds: addedVulnerabilities, Removes: removedVulnerabilities}) }
// DELETELayers deletes the specified layer and any child layers that are // dependent on the specified layer. func DELETELayers(w http.ResponseWriter, r *http.Request, p httprouter.Params) { err := database.DeleteLayer(p.ByName("id")) if err != nil { httputils.WriteHTTPError(w, 0, err) return } httputils.WriteHTTP(w, http.StatusNoContent, nil) }
// PUTVulnerabilities updates a vulnerability if it exists. func PUTVulnerabilities(w http.ResponseWriter, r *http.Request, p httprouter.Params) { var parameters *database.AbstractVulnerability if s, err := httputils.ParseHTTPBody(r, ¶meters); err != nil { httputils.WriteHTTPError(w, s, err) return } parameters.ID = p.ByName("id") // Ensure that the vulnerability exists. _, err := database.FindOneVulnerability(parameters.ID, []string{}) if err != nil { httputils.WriteHTTPError(w, 0, err) return } // Insert packages. packages := database.AbstractPackagesToPackages(parameters.AffectedPackages) err = database.InsertPackages(packages) if err != nil { httputils.WriteHTTPError(w, 0, err) return } var pkgNodes []string for _, p := range packages { pkgNodes = append(pkgNodes, p.Node) } // Insert vulnerability. notifications, err := database.InsertVulnerabilities([]*database.Vulnerability{parameters.ToVulnerability(pkgNodes)}) if err != nil { httputils.WriteHTTPError(w, 0, err) return } // Insert notifications. err = database.InsertNotifications(notifications, database.GetDefaultNotificationWrapper()) if err != nil { httputils.WriteHTTPError(w, 0, err) return } httputils.WriteHTTP(w, http.StatusCreated, nil) }
// GETLayersParent returns the parent ID of a layer if it exists. // An empty ID string is returned if the layer has no parent. func GETLayersParent(w http.ResponseWriter, r *http.Request, p httprouter.Params) { // Find layer layer, err := database.FindOneLayerByID(p.ByName("id"), []string{database.FieldLayerParent}) if err != nil { httputils.WriteHTTPError(w, 0, err) return } // Get layer's parent. parent, err := layer.Parent([]string{database.FieldLayerID}) if err != nil { httputils.WriteHTTPError(w, 0, err) return } ID := "" if parent != nil { ID = parent.ID } httputils.WriteHTTP(w, http.StatusOK, struct{ ID string }{ID: ID}) }
// GETVulnerabilitiesIntroducingLayers returns the list of layers that // introduces a given vulnerability, if it exists. // To clarify, it does not return the list of every layers that have // the vulnerability. func GETVulnerabilitiesIntroducingLayers(w http.ResponseWriter, r *http.Request, p httprouter.Params) { // Find vulnerability to verify that it exists. _, err := database.FindOneVulnerability(p.ByName("id"), []string{}) if err != nil { httputils.WriteHTTPError(w, 0, err) return } layers, err := database.FindAllLayersIntroducingVulnerability(p.ByName("id"), []string{database.FieldLayerID}) if err != nil { httputils.WriteHTTPError(w, 0, err) return } layersIDs := []string{} for _, l := range layers { layersIDs = append(layersIDs, l.ID) } httputils.WriteHTTP(w, http.StatusOK, struct{ IntroducingLayersIDs []string }{IntroducingLayersIDs: layersIDs}) }
// POSTBatchLayersVulnerabilities returns the complete list of vulnerabilities // that the provided layers have, if they all exist. func POSTBatchLayersVulnerabilities(w http.ResponseWriter, r *http.Request, p httprouter.Params) { // Parse body var parameters POSTBatchLayersVulnerabilitiesParameters if s, err := httputils.ParseHTTPBody(r, ¶meters); err != nil { httputils.WriteHTTPError(w, s, err) return } if len(parameters.LayersIDs) == 0 { httputils.WriteHTTPError(w, http.StatusBadRequest, errors.New("at least one LayerID query parameter must be provided")) return } // Get minumum priority parameter. minimumPriority := types.Priority(r.URL.Query().Get("minimumPriority")) if minimumPriority == "" { minimumPriority = "High" // Set default priority to High } else if !minimumPriority.IsValid() { httputils.WriteHTTPError(w, 0, cerrors.NewBadRequestError("invalid priority")) return } response := make(map[string]interface{}) // For each LayerID parameter for _, layerID := range parameters.LayersIDs { // Find layer layer, err := database.FindOneLayerByID(layerID, []string{database.FieldLayerParent, database.FieldLayerPackages}) if err != nil { httputils.WriteHTTPError(w, 0, err) return } // Find layer's packages. packagesNodes, err := layer.AllPackages() if err != nil { httputils.WriteHTTPError(w, 0, err) return } // Find vulnerabilities. vulnerabilities, err := getVulnerabilitiesFromLayerPackagesNodes(packagesNodes, minimumPriority, []string{database.FieldVulnerabilityID, database.FieldVulnerabilityLink, database.FieldVulnerabilityPriority, database.FieldVulnerabilityDescription, database.FieldVulnerabilityCausedByPackage}) if err != nil { httputils.WriteHTTPError(w, 0, err) return } response[layerID] = struct{ Vulnerabilities []*database.Vulnerability }{Vulnerabilities: vulnerabilities} } httputils.WriteHTTP(w, http.StatusOK, response) }
// POSTVulnerabilitiesAffectedLayers returns whether the specified layers // (by their IDs) are vulnerable to the given Vulnerability or not. func POSTVulnerabilitiesAffectedLayers(w http.ResponseWriter, r *http.Request, p httprouter.Params) { // Parse body. var parameters POSTBatchLayersVulnerabilitiesParameters if s, err := httputils.ParseHTTPBody(r, ¶meters); err != nil { httputils.WriteHTTPError(w, s, err) return } if len(parameters.LayersIDs) == 0 { httputils.WriteHTTPError(w, http.StatusBadRequest, errors.New("getting the entire list of affected layers is not supported yet: at least one LayerID query parameter must be provided")) return } // Find vulnerability. vulnerability, err := database.FindOneVulnerability(p.ByName("id"), []string{database.FieldVulnerabilityFixedIn}) if err != nil { httputils.WriteHTTPError(w, 0, err) return } // Save the fixed in nodes into a map for fast check. fixedInPackagesMap := make(map[string]struct{}) for _, fixedInNode := range vulnerability.FixedInNodes { fixedInPackagesMap[fixedInNode] = struct{}{} } response := make(map[string]interface{}) // For each LayerID parameter. for _, layerID := range parameters.LayersIDs { // Find layer layer, err := database.FindOneLayerByID(layerID, []string{database.FieldLayerParent, database.FieldLayerPackages, database.FieldLayerPackages}) if err != nil { httputils.WriteHTTPError(w, 0, err) return } // Find layer's packages. packagesNodes, err := layer.AllPackages() if err != nil { httputils.WriteHTTPError(w, 0, err) return } // Get successors packages of layer' packages. successors, err := getSuccessorsFromPackagesNodes(packagesNodes) if err != nil { httputils.WriteHTTPError(w, 0, err) return } // Determine if the layer is vulnerable by verifying if one of the successors // of its packages are fixed by the vulnerability. vulnerable := false for _, p := range successors { if _, fixed := fixedInPackagesMap[p]; fixed { vulnerable = true break } } response[layerID] = struct{ Vulnerable bool }{Vulnerable: vulnerable} } httputils.WriteHTTP(w, http.StatusOK, response) }