vulndb/snooze.go (154 lines of code) (raw):
// Copyright (c) Facebook, Inc. and its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package vulndb
import (
"context"
"database/sql"
"encoding/csv"
"io"
"time"
"github.com/pkg/errors"
"github.com/facebookincubator/flog"
"github.com/facebookincubator/nvdtools/vulndb/debug"
"github.com/facebookincubator/nvdtools/vulndb/sqlutil"
)
// SnoozeRecord represents a database record of the `snooze` table.
type SnoozeRecord struct {
Owner string `sql:"owner"`
Collector string `sql:"collector"`
Provider string `sql:"provider"`
CVE string `sql:"cve_id"`
Deadline sqlutil.NullTime `sql:"deadline"`
Metadata []byte `sql:"metadata"`
}
// SnoozeCreator is a helper for creating snoozes.
type SnoozeCreator struct {
DB *sql.DB
Owner string
Collector string
Provider string
Deadline time.Time
Metadata []byte
}
// Create creates a snooze.
func (s SnoozeCreator) Create(ctx context.Context, cve ...string) error {
records := make([]SnoozeRecord, len(cve))
for i := 0; i < len(records); i++ {
records[i] = SnoozeRecord{
Owner: s.Owner,
Collector: s.Collector,
Provider: s.Provider,
CVE: cve[i],
Deadline: sqlutil.NullTime{
Valid: !s.Deadline.IsZero(),
Time: s.Deadline,
},
Metadata: s.Metadata,
}
}
r := sqlutil.NewRecords(records)
q := sqlutil.Replace().
Into("snooze").
Fields(r.Fields()...).
Values(r...)
query, args := q.String(), q.QueryArgs()
if debug.V(1) {
flog.Infof("running: %q / %#v", query, args)
}
_, err := s.DB.ExecContext(ctx, query, args...)
if err != nil {
return errors.Wrap(err, "cannot create snooze")
}
return nil
}
// SnoozeGetter gets data from the database.
type SnoozeGetter struct {
DB *sql.DB
Collector string
Provider string
FilterCVEs []string
}
// CSV writes snooze records to w.
func (s SnoozeGetter) CSV(ctx context.Context, w io.Writer, header bool) error {
r := sqlutil.NewRecordType(SnoozeRecord{})
q := sqlutil.Select(
r.Fields()...,
).From(
"snooze",
)
var cond *sqlutil.QueryConditionSet
if s.Collector != "" {
cond = sqlutil.Cond().Equal("collector", s.Collector)
}
if s.Provider != "" {
if cond == nil {
cond = sqlutil.Cond()
} else {
cond = cond.And()
}
cond = cond.Equal("provider", s.Provider)
}
if len(s.FilterCVEs) > 0 {
if cond == nil {
cond = sqlutil.Cond()
} else {
cond = cond.And()
}
cond = cond.In("cve_id", s.FilterCVEs)
}
if cond != nil {
q = q.Where(cond)
}
query, args := q.String(), q.QueryArgs()
if debug.V(1) {
flog.Infof("running: %q / %#v", query, args)
}
rows, err := s.DB.QueryContext(ctx, query, args...)
if err != nil {
return errors.Wrap(err, "cannot query snooze")
}
defer rows.Close()
cw := csv.NewWriter(w)
defer cw.Flush()
if header {
cw.Write(r.Fields())
}
for rows.Next() {
var sr SnoozeRecord
err = rows.Scan(sqlutil.NewRecordType(&sr).Values()...)
if err != nil {
return errors.Wrap(err, "cannot scan snooze data")
}
var deadline string
if sr.Deadline.Valid {
deadline = sr.Deadline.Time.Format(TimeLayout)
}
cw.Write([]string{
sr.Owner,
sr.Collector,
sr.Provider,
sr.CVE,
deadline,
string(sr.Metadata),
})
}
return nil
}
// SnoozeDeleter deletes snoozes from the database.
type SnoozeDeleter struct {
DB *sql.DB
Collector string
Provider string
FilterCVEs []string
}
// Delete deletes snooze data from the database.
func (s SnoozeDeleter) Delete(ctx context.Context) error {
cond := sqlutil.Cond().
Equal("collector", s.Provider).
And().
Equal("provider", s.Provider)
if len(s.FilterCVEs) > 0 {
cond = cond.And().In("cve_id", s.FilterCVEs)
}
q := sqlutil.Delete().From("snooze").Where(cond)
query, args := q.String(), q.QueryArgs()
if debug.V(1) {
flog.Infof("running: %q / %#v", query, args)
}
_, err := s.DB.ExecContext(ctx, query, args...)
if err != nil {
return errors.Wrap(err, "cannot delete snooze data")
}
return nil
}