use encrypt page in listVuln api

Signed-off-by: liangchenye <liangchenye@huawei.com>
This commit is contained in:
liangchenye 2016-02-29 16:29:40 +08:00
parent a541e964e0
commit 48ffb2687a
6 changed files with 59 additions and 28 deletions

View File

@ -213,7 +213,7 @@ The GET route for the Vulnerabilities resource displays the vulnerabilities data
###### Example Request ###### Example Request
```json ```json
GET http://localhost:6060/v1/namespaces/debian%3A8/vulnerabilities?page=0&limit=2 HTTP/1.1 GET http://localhost:6060/v1/namespaces/debian%3A8/vulnerabilities?limit=2 HTTP/1.1
``` ```
###### Example Response ###### Example Response
@ -247,7 +247,8 @@ Server: clair
} }
} }
} }
] ],
"NextPage":"gAAAAABW1ABiOlm6KMDKYFE022bEy_IFJdm4ExxTNuJZMN0Eycn0Sut2tOH9bDB4EWGy5s6xwATUHiG-6JXXaU5U32sBs6_DmA=="
} }
``` ```

View File

@ -19,6 +19,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"strconv"
"time" "time"
"github.com/coreos/clair/database" "github.com/coreos/clair/database"
@ -276,6 +277,7 @@ type NamespaceEnvelope struct {
type VulnerabilityEnvelope struct { type VulnerabilityEnvelope struct {
Vulnerability *Vulnerability `json:"Vulnerability,omitempty"` Vulnerability *Vulnerability `json:"Vulnerability,omitempty"`
Vulnerabilities *[]Vulnerability `json:"Vulnerabilities,omitempty"` Vulnerabilities *[]Vulnerability `json:"Vulnerabilities,omitempty"`
NextPage *string `json:"NextPage,omitempty"`
Error *Error `json:"Error,omitempty"` Error *Error `json:"Error,omitempty"`
} }
@ -317,3 +319,24 @@ func pageNumberToToken(page database.VulnerabilityNotificationPageNumber, key st
return string(tokenBytes) return string(tokenBytes)
} }
func tokenToNumber(token, key string) (int, error) {
k, _ := fernet.DecodeKey(key)
msg := fernet.VerifyAndDecrypt([]byte(token), time.Hour, []*fernet.Key{k})
if msg == nil {
return -1, errors.New("invalid or expired pagination token")
}
page, err := strconv.Atoi(string(msg))
return page, err
}
func numberToToken(page int, key string) string {
k, _ := fernet.DecodeKey(key)
tokenBytes, err := fernet.EncryptAndSign([]byte(strconv.Itoa(page)), k)
if err != nil {
log.Fatal("failed to encrypt number")
}
return string(tokenBytes)
}

View File

@ -202,21 +202,17 @@ func getVulnerabilities(w http.ResponseWriter, r *http.Request, p httprouter.Par
return getVulnerabilitiesRoute, http.StatusBadRequest return getVulnerabilitiesRoute, http.StatusBadRequest
} }
page := 0
pageStrs, pageExists := query["page"] pageStrs, pageExists := query["page"]
if !pageExists { if pageExists {
writeResponse(w, r, http.StatusBadRequest, VulnerabilityEnvelope{Error: &Error{"must provide page query parameter"}}) page, err = tokenToNumber(pageStrs[0], ctx.Config.PaginationKey)
return getVulnerabilitiesRoute, http.StatusBadRequest if err != nil {
} writeResponse(w, r, http.StatusBadRequest, VulnerabilityEnvelope{Error: &Error{"invalid page format: " + err.Error()}})
page, err := strconv.Atoi(pageStrs[0]) return getNotificationRoute, http.StatusBadRequest
if err != nil { }
writeResponse(w, r, http.StatusBadRequest, VulnerabilityEnvelope{Error: &Error{"invalid page format: " + err.Error()}})
return getVulnerabilitiesRoute, http.StatusBadRequest
} else if page < 0 {
writeResponse(w, r, http.StatusBadRequest, VulnerabilityEnvelope{Error: &Error{"page value should not be less than zero"}})
return getVulnerabilitiesRoute, http.StatusBadRequest
} }
dbVulns, err := ctx.Store.ListVulnerabilities(p.ByName("namespaceName"), limit, page) dbVulns, nextPage, err := ctx.Store.ListVulnerabilities(p.ByName("namespaceName"), limit, page)
if err != nil { if err != nil {
writeResponse(w, r, http.StatusInternalServerError, VulnerabilityEnvelope{Error: &Error{err.Error()}}) writeResponse(w, r, http.StatusInternalServerError, VulnerabilityEnvelope{Error: &Error{err.Error()}})
return getVulnerabilitiesRoute, http.StatusInternalServerError return getVulnerabilitiesRoute, http.StatusInternalServerError
@ -228,7 +224,12 @@ func getVulnerabilities(w http.ResponseWriter, r *http.Request, p httprouter.Par
vulns = append(vulns, vuln) vulns = append(vulns, vuln)
} }
writeResponse(w, r, http.StatusOK, VulnerabilityEnvelope{Vulnerabilities: &vulns}) var nextPageStr string
if nextPage != -1 {
nextPageStr = numberToToken(nextPage, ctx.Config.PaginationKey)
}
writeResponse(w, r, http.StatusOK, VulnerabilityEnvelope{Vulnerabilities: &vulns, NextPage: &nextPageStr})
return getVulnerabilitiesRoute, http.StatusOK return getVulnerabilitiesRoute, http.StatusOK
} }

View File

@ -62,7 +62,9 @@ type Datastore interface {
// # Vulnerability // # Vulnerability
// ListVulnerabilities returns the list of vulnerabilies of a certain Namespace. // ListVulnerabilities returns the list of vulnerabilies of a certain Namespace.
// The Limit and page parameters are used to paginate the return list. // The Limit and page parameters are used to paginate the return list.
ListVulnerabilities(namespaceName string, limit int, page int) ([]Vulnerability, error) // The first given page should be 0. The function will then return the next available page.
// If there is no more page, -1 has to be returned.
ListVulnerabilities(namespaceName string, limit int, page int) ([]Vulnerability, int, error)
// InsertVulnerabilities stores the given Vulnerabilities in the database, updating them if // InsertVulnerabilities stores the given Vulnerabilities in the database, updating them if
// necessary. A vulnerability is uniquely identified by its Namespace and its Name. // necessary. A vulnerability is uniquely identified by its Namespace and its Name.

View File

@ -145,8 +145,9 @@ const (
searchVulnerabilityByNamespaceAndName = ` WHERE n.name = $1 AND v.name = $2 AND v.deleted_at IS NULL` searchVulnerabilityByNamespaceAndName = ` WHERE n.name = $1 AND v.name = $2 AND v.deleted_at IS NULL`
searchVulnerabilityByID = ` WHERE v.id = $1` searchVulnerabilityByID = ` WHERE v.id = $1`
searchVulnerabilityByNamespace = ` WHERE n.name = $1 AND v.deleted_at IS NULL searchVulnerabilityByNamespace = ` WHERE n.name = $1 AND v.deleted_at IS NULL
ORDER BY v.name AND v.id >= $2
LIMIT $2 offset $3` ORDER BY v.id
LIMIT $3`
searchVulnerabilityFixedIn = ` searchVulnerabilityFixedIn = `
SELECT vfif.version, f.id, f.Name SELECT vfif.version, f.id, f.Name

View File

@ -28,22 +28,20 @@ import (
"github.com/guregu/null/zero" "github.com/guregu/null/zero"
) )
func (pgSQL *pgSQL) ListVulnerabilities(namespaceName string, limit int, page int) ([]database.Vulnerability, error) { func (pgSQL *pgSQL) ListVulnerabilities(namespaceName string, limit int, startID int) ([]database.Vulnerability, int, error) {
return listVulnerabilities(pgSQL, namespaceName, limit, page)
}
func listVulnerabilities(queryer Queryer, namespaceName string, limit int, page int) ([]database.Vulnerability, error) {
defer observeQueryTime("listVulnerabilities", "all", time.Now()) defer observeQueryTime("listVulnerabilities", "all", time.Now())
// Query. // Query.
query := searchVulnerabilityBase + searchVulnerabilityByNamespace query := searchVulnerabilityBase + searchVulnerabilityByNamespace
rows, err := queryer.Query(query, namespaceName, limit, page*limit) rows, err := pgSQL.Query(query, namespaceName, startID, limit+1)
if err != nil { if err != nil {
return nil, handleError("searchVulnerabilityByNamespace", err) return nil, -1, handleError("searchVulnerabilityByNamespace", err)
} }
defer rows.Close() defer rows.Close()
var vulns []database.Vulnerability var vulns []database.Vulnerability
nextID := -1
size := 0
// Scan query. // Scan query.
for rows.Next() { for rows.Next() {
var vulnerability database.Vulnerability var vulnerability database.Vulnerability
@ -59,17 +57,22 @@ func listVulnerabilities(queryer Queryer, namespaceName string, limit int, page
&vulnerability.Metadata, &vulnerability.Metadata,
) )
if err != nil { if err != nil {
return nil, handleError("searchVulnerabilityByNamespace.Scan()", err) return nil, -1, handleError("searchVulnerabilityByNamespace.Scan()", err)
}
size++
if size > limit {
nextID = vulnerability.ID
} else { } else {
vulns = append(vulns, vulnerability) vulns = append(vulns, vulnerability)
} }
} }
if err := rows.Err(); err != nil { if err := rows.Err(); err != nil {
return nil, handleError("searchVulnerabilityByNamespace.Rows()", err) return nil, -1, handleError("searchVulnerabilityByNamespace.Rows()", err)
} }
return vulns, nil fmt.Println(nextID)
return vulns, nextID, nil
} }
func (pgSQL *pgSQL) FindVulnerability(namespaceName, name string) (database.Vulnerability, error) { func (pgSQL *pgSQL) FindVulnerability(namespaceName, name string) (database.Vulnerability, error) {