1package gosec
2
3import (
4	"bytes"
5	"encoding/json"
6	"fmt"
7	"io"
8	"io/ioutil"
9)
10
11const (
12	// Globals are applicable to all rules and used for general
13	// configuration settings for gosec.
14	Globals = "global"
15)
16
17// GlobalOption defines the name of the global options
18type GlobalOption string
19
20const (
21	// Nosec global option for #nosec directive
22	Nosec GlobalOption = "nosec"
23	// Audit global option which indicates that gosec runs in audit mode
24	Audit GlobalOption = "audit"
25	// NoSecAlternative global option alternative for #nosec directive
26	NoSecAlternative GlobalOption = "#nosec"
27)
28
29// Config is used to provide configuration and customization to each of the rules.
30type Config map[string]interface{}
31
32// NewConfig initializes a new configuration instance. The configuration data then
33// needs to be loaded via c.ReadFrom(strings.NewReader("config data"))
34// or from a *os.File.
35func NewConfig() Config {
36	cfg := make(Config)
37	cfg[Globals] = make(map[GlobalOption]string)
38	return cfg
39}
40
41func (c Config) keyToGlobalOptions(key string) GlobalOption {
42	return GlobalOption(key)
43}
44
45func (c Config) convertGlobals() {
46	if globals, ok := c[Globals]; ok {
47		if settings, ok := globals.(map[string]interface{}); ok {
48			validGlobals := map[GlobalOption]string{}
49			for k, v := range settings {
50				validGlobals[c.keyToGlobalOptions(k)] = fmt.Sprintf("%v", v)
51			}
52			c[Globals] = validGlobals
53		}
54	}
55}
56
57// ReadFrom implements the io.ReaderFrom interface. This
58// should be used with io.Reader to load configuration from
59//file or from string etc.
60func (c Config) ReadFrom(r io.Reader) (int64, error) {
61	data, err := ioutil.ReadAll(r)
62	if err != nil {
63		return int64(len(data)), err
64	}
65	if err = json.Unmarshal(data, &c); err != nil {
66		return int64(len(data)), err
67	}
68	c.convertGlobals()
69	return int64(len(data)), nil
70}
71
72// WriteTo implements the io.WriteTo interface. This should
73// be used to save or print out the configuration information.
74func (c Config) WriteTo(w io.Writer) (int64, error) {
75	data, err := json.Marshal(c)
76	if err != nil {
77		return int64(len(data)), err
78	}
79	return io.Copy(w, bytes.NewReader(data))
80}
81
82// Get returns the configuration section for the supplied key
83func (c Config) Get(section string) (interface{}, error) {
84	settings, found := c[section]
85	if !found {
86		return nil, fmt.Errorf("Section %s not in configuration", section)
87	}
88	return settings, nil
89}
90
91// Set section in the configuration to specified value
92func (c Config) Set(section string, value interface{}) {
93	c[section] = value
94}
95
96// GetGlobal returns value associated with global configuration option
97func (c Config) GetGlobal(option GlobalOption) (string, error) {
98	if globals, ok := c[Globals]; ok {
99		if settings, ok := globals.(map[GlobalOption]string); ok {
100			if value, ok := settings[option]; ok {
101				return value, nil
102			}
103			return "", fmt.Errorf("global setting for %s not found", option)
104		}
105	}
106	return "", fmt.Errorf("no global config options found")
107}
108
109// SetGlobal associates a value with a global configuration option
110func (c Config) SetGlobal(option GlobalOption, value string) {
111	if globals, ok := c[Globals]; ok {
112		if settings, ok := globals.(map[GlobalOption]string); ok {
113			settings[option] = value
114		}
115	}
116}
117
118// IsGlobalEnabled checks if a global option is enabled
119func (c Config) IsGlobalEnabled(option GlobalOption) (bool, error) {
120	value, err := c.GetGlobal(option)
121	if err != nil {
122		return false, err
123	}
124	return (value == "true" || value == "enabled"), nil
125}
126