mirror of
https://github.com/gocsaf/csaf.git
synced 2025-12-22 11:55:40 +01:00
Rename opts to cfg
This commit is contained in:
parent
0d17db0c59
commit
12ad7706e3
4 changed files with 62 additions and 64 deletions
|
|
@ -10,10 +10,11 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
type options struct {
|
type config struct {
|
||||||
Output string `short:"o" long:"output" description:"File name of the generated report" value-name:"REPORT-FILE"`
|
Output string `short:"o" long:"output" description:"File name of the generated report" value-name:"REPORT-FILE"`
|
||||||
Format string `short:"f" long:"format" choice:"json" choice:"html" description:"Format of report" default:"json"`
|
Format string `short:"f" long:"format" choice:"json" choice:"html" description:"Format of report" default:"json"`
|
||||||
Insecure bool `long:"insecure" description:"Do not check TLS certificates from provider"`
|
Insecure bool `long:"insecure" description:"Do not check TLS certificates from provider"`
|
||||||
|
|
@ -31,3 +32,28 @@ type options struct {
|
||||||
|
|
||||||
clientCerts []tls.Certificate
|
clientCerts []tls.Certificate
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// protectedAccess returns true if we have client certificates or
|
||||||
|
// extra http headers configured.
|
||||||
|
// This may be a wrong assumption, because the certs are not checked
|
||||||
|
// for their domain and custom headers may have other purposes.
|
||||||
|
func (cfg *config) protectedAccess() bool {
|
||||||
|
return len(cfg.clientCerts) > 0 || len(cfg.ExtraHeader) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg *config) prepare() error {
|
||||||
|
// Load client certs.
|
||||||
|
switch hasCert, hasKey := cfg.ClientCert != nil, cfg.ClientKey != nil; {
|
||||||
|
|
||||||
|
case hasCert && !hasKey || !hasCert && hasKey:
|
||||||
|
return errors.New("both client-key and client-cert options must be set for the authentication")
|
||||||
|
|
||||||
|
case hasCert:
|
||||||
|
cert, err := tls.LoadX509KeyPair(*cfg.ClientCert, *cfg.ClientKey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cfg.clientCerts = []tls.Certificate{cert}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,8 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"crypto/tls"
|
|
||||||
_ "embed" // Used for embedding.
|
_ "embed" // Used for embedding.
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
|
|
@ -37,31 +35,6 @@ func errCheck(err error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *options) prepare() error {
|
|
||||||
// Load client certs.
|
|
||||||
switch hasCert, hasKey := o.ClientCert != nil, o.ClientKey != nil; {
|
|
||||||
|
|
||||||
case hasCert && !hasKey || !hasCert && hasKey:
|
|
||||||
return errors.New("both client-key and client-cert options must be set for the authentication")
|
|
||||||
|
|
||||||
case hasCert:
|
|
||||||
cert, err := tls.LoadX509KeyPair(*o.ClientCert, *o.ClientKey)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
o.clientCerts = []tls.Certificate{cert}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// protectedAccess returns true if we have client certificates or
|
|
||||||
// extra http headers configured.
|
|
||||||
// This may be a wrong assumption, because the certs are not checked
|
|
||||||
// for their domain and custom headers may have other purposes.
|
|
||||||
func (o *options) protectedAccess() bool {
|
|
||||||
return len(o.clientCerts) > 0 || len(o.ExtraHeader) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// writeJSON writes the JSON encoding of the given report to the given stream.
|
// writeJSON writes the JSON encoding of the given report to the given stream.
|
||||||
// It returns nil, otherwise an error.
|
// It returns nil, otherwise an error.
|
||||||
func writeJSON(report *Report, w io.WriteCloser) error {
|
func writeJSON(report *Report, w io.WriteCloser) error {
|
||||||
|
|
@ -102,14 +75,14 @@ func (nc *nopCloser) Close() error { return nil }
|
||||||
|
|
||||||
// writeReport defines where to write the report according to the "output" flag option.
|
// writeReport defines where to write the report according to the "output" flag option.
|
||||||
// It calls also the "writeJSON" or "writeHTML" function according to the "format" flag option.
|
// It calls also the "writeJSON" or "writeHTML" function according to the "format" flag option.
|
||||||
func writeReport(report *Report, opts *options) error {
|
func writeReport(report *Report, cfg *config) error {
|
||||||
|
|
||||||
var w io.WriteCloser
|
var w io.WriteCloser
|
||||||
|
|
||||||
if opts.Output == "" {
|
if cfg.Output == "" {
|
||||||
w = &nopCloser{os.Stdout}
|
w = &nopCloser{os.Stdout}
|
||||||
} else {
|
} else {
|
||||||
f, err := os.Create(opts.Output)
|
f, err := os.Create(cfg.Output)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -118,7 +91,7 @@ func writeReport(report *Report, opts *options) error {
|
||||||
|
|
||||||
var writer func(*Report, io.WriteCloser) error
|
var writer func(*Report, io.WriteCloser) error
|
||||||
|
|
||||||
switch opts.Format {
|
switch cfg.Format {
|
||||||
case "json":
|
case "json":
|
||||||
writer = writeJSON
|
writer = writeJSON
|
||||||
default:
|
default:
|
||||||
|
|
@ -130,8 +103,8 @@ func writeReport(report *Report, opts *options) error {
|
||||||
|
|
||||||
// run uses a processor to check all the given domains or direct urls
|
// run uses a processor to check all the given domains or direct urls
|
||||||
// and generates a report.
|
// and generates a report.
|
||||||
func run(opts *options, domains []string) (*Report, error) {
|
func run(cfg *config, domains []string) (*Report, error) {
|
||||||
p, err := newProcessor(opts)
|
p, err := newProcessor(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -140,27 +113,27 @@ func run(opts *options, domains []string) (*Report, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
opts := new(options)
|
cfg := new(config)
|
||||||
|
|
||||||
parser := flags.NewParser(opts, flags.Default)
|
parser := flags.NewParser(cfg, flags.Default)
|
||||||
parser.Usage = "[OPTIONS] domain..."
|
parser.Usage = "[OPTIONS] domain..."
|
||||||
domains, err := parser.Parse()
|
domains, err := parser.Parse()
|
||||||
errCheck(err)
|
errCheck(err)
|
||||||
|
|
||||||
if opts.Version {
|
if cfg.Version {
|
||||||
fmt.Println(util.SemVersion)
|
fmt.Println(util.SemVersion)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
errCheck(opts.prepare())
|
errCheck(cfg.prepare())
|
||||||
|
|
||||||
if len(domains) == 0 {
|
if len(domains) == 0 {
|
||||||
log.Println("No domain or direct url given.")
|
log.Println("No domain or direct url given.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
report, err := run(opts, domains)
|
report, err := run(cfg, domains)
|
||||||
errCheck(err)
|
errCheck(err)
|
||||||
|
|
||||||
errCheck(writeReport(report, opts))
|
errCheck(writeReport(report, cfg))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ import (
|
||||||
type topicMessages []Message
|
type topicMessages []Message
|
||||||
|
|
||||||
type processor struct {
|
type processor struct {
|
||||||
opts *options
|
cfg *config
|
||||||
validator csaf.RemoteValidator
|
validator csaf.RemoteValidator
|
||||||
client util.Client
|
client util.Client
|
||||||
unauthClient util.Client
|
unauthClient util.Client
|
||||||
|
|
@ -165,17 +165,16 @@ func (m *topicMessages) hasErrors() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// newProcessor returns a processor structure after assigning the given options to the opts attribute
|
// newProcessor returns an initilaized processor.
|
||||||
// and initializing the "alreadyChecked" and "expr" fields.
|
func newProcessor(cfg *config) (*processor, error) {
|
||||||
func newProcessor(opts *options) (*processor, error) {
|
|
||||||
|
|
||||||
var validator csaf.RemoteValidator
|
var validator csaf.RemoteValidator
|
||||||
|
|
||||||
if opts.RemoteValidator != "" {
|
if cfg.RemoteValidator != "" {
|
||||||
validatorOptions := csaf.RemoteValidatorOptions{
|
validatorOptions := csaf.RemoteValidatorOptions{
|
||||||
URL: opts.RemoteValidator,
|
URL: cfg.RemoteValidator,
|
||||||
Presets: opts.RemoteValidatorPresets,
|
Presets: cfg.RemoteValidatorPresets,
|
||||||
Cache: opts.RemoteValidatorCache,
|
Cache: cfg.RemoteValidatorCache,
|
||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
if validator, err = validatorOptions.Open(); err != nil {
|
if validator, err = validatorOptions.Open(); err != nil {
|
||||||
|
|
@ -185,10 +184,10 @@ func newProcessor(opts *options) (*processor, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return &processor{
|
return &processor{
|
||||||
opts: opts,
|
cfg: cfg,
|
||||||
alreadyChecked: map[string]whereType{},
|
alreadyChecked: map[string]whereType{},
|
||||||
expr: util.NewPathEval(),
|
expr: util.NewPathEval(),
|
||||||
ageAccept: ageAccept(opts),
|
ageAccept: ageAccept(cfg),
|
||||||
validator: validator,
|
validator: validator,
|
||||||
labelChecker: labelChecker{
|
labelChecker: labelChecker{
|
||||||
advisories: map[csaf.TLPLabel]util.Set[string]{},
|
advisories: map[csaf.TLPLabel]util.Set[string]{},
|
||||||
|
|
@ -205,11 +204,11 @@ func (p *processor) close() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ageAccept(opts *options) func(time.Time) bool {
|
func ageAccept(cfg *config) func(time.Time) bool {
|
||||||
if opts.Years == nil {
|
if cfg.Years == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
good := time.Now().AddDate(-int(*opts.Years), 0, 0)
|
good := time.Now().AddDate(-int(*cfg.Years), 0, 0)
|
||||||
return func(t time.Time) bool {
|
return func(t time.Time) bool {
|
||||||
return !t.Before(good)
|
return !t.Before(good)
|
||||||
}
|
}
|
||||||
|
|
@ -431,12 +430,12 @@ func (p *processor) fullClient() util.Client {
|
||||||
hClient.CheckRedirect = p.checkRedirect
|
hClient.CheckRedirect = p.checkRedirect
|
||||||
|
|
||||||
var tlsConfig tls.Config
|
var tlsConfig tls.Config
|
||||||
if p.opts.Insecure {
|
if p.cfg.Insecure {
|
||||||
tlsConfig.InsecureSkipVerify = true
|
tlsConfig.InsecureSkipVerify = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(p.opts.clientCerts) != 0 {
|
if len(p.cfg.clientCerts) != 0 {
|
||||||
tlsConfig.Certificates = p.opts.clientCerts
|
tlsConfig.Certificates = p.cfg.clientCerts
|
||||||
}
|
}
|
||||||
|
|
||||||
hClient.Transport = &http.Transport{
|
hClient.Transport = &http.Transport{
|
||||||
|
|
@ -446,23 +445,23 @@ func (p *processor) fullClient() util.Client {
|
||||||
client := util.Client(&hClient)
|
client := util.Client(&hClient)
|
||||||
|
|
||||||
// Add extra headers.
|
// Add extra headers.
|
||||||
if len(p.opts.ExtraHeader) > 0 {
|
if len(p.cfg.ExtraHeader) > 0 {
|
||||||
client = &util.HeaderClient{
|
client = &util.HeaderClient{
|
||||||
Client: client,
|
Client: client,
|
||||||
Header: p.opts.ExtraHeader,
|
Header: p.cfg.ExtraHeader,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add optional URL logging.
|
// Add optional URL logging.
|
||||||
if p.opts.Verbose {
|
if p.cfg.Verbose {
|
||||||
client = &util.LoggingClient{Client: client}
|
client = &util.LoggingClient{Client: client}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add optional rate limiting.
|
// Add optional rate limiting.
|
||||||
if p.opts.Rate != nil {
|
if p.cfg.Rate != nil {
|
||||||
client = &util.LimitingClient{
|
client = &util.LimitingClient{
|
||||||
Client: client,
|
Client: client,
|
||||||
Limiter: rate.NewLimiter(rate.Limit(*p.opts.Rate), 1),
|
Limiter: rate.NewLimiter(rate.Limit(*p.cfg.Rate), 1),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return client
|
return client
|
||||||
|
|
@ -470,7 +469,7 @@ func (p *processor) fullClient() util.Client {
|
||||||
|
|
||||||
// basicClient returns a http Client w/o certs and headers.
|
// basicClient returns a http Client w/o certs and headers.
|
||||||
func (p *processor) basicClient() *http.Client {
|
func (p *processor) basicClient() *http.Client {
|
||||||
if p.opts.Insecure {
|
if p.cfg.Insecure {
|
||||||
tr := &http.Transport{
|
tr := &http.Transport{
|
||||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||||
}
|
}
|
||||||
|
|
@ -500,7 +499,7 @@ func (p *processor) unauthorizedClient() util.Client {
|
||||||
// usedAuthorizedClient tells if an authorized client is used
|
// usedAuthorizedClient tells if an authorized client is used
|
||||||
// for downloading.
|
// for downloading.
|
||||||
func (p *processor) usedAuthorizedClient() bool {
|
func (p *processor) usedAuthorizedClient() bool {
|
||||||
return p.opts.protectedAccess()
|
return p.cfg.protectedAccess()
|
||||||
}
|
}
|
||||||
|
|
||||||
// rolieFeedEntries loads the references to the advisory files for a given feed.
|
// rolieFeedEntries loads the references to the advisory files for a given feed.
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ func (r *validReporter) report(p *processor, domain *Domain) {
|
||||||
case !p.invalidAdvisories.used():
|
case !p.invalidAdvisories.used():
|
||||||
req.message(InfoType, "No validations performed")
|
req.message(InfoType, "No validations performed")
|
||||||
case len(p.invalidAdvisories) == 0:
|
case len(p.invalidAdvisories) == 0:
|
||||||
if p.validator != nil && containsAny(p.opts.RemoteValidatorPresets,
|
if p.validator != nil && containsAny(p.cfg.RemoteValidatorPresets,
|
||||||
"basic", "mandatory", "extended", "full") {
|
"basic", "mandatory", "extended", "full") {
|
||||||
req.message(InfoType, "All advisories validated fine.")
|
req.message(InfoType, "All advisories validated fine.")
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue