diff --git a/config/advanced.go b/config/advanced.go deleted file mode 100644 index 2add03c..0000000 --- a/config/advanced.go +++ /dev/null @@ -1,7 +0,0 @@ -package config - -// Advanced settings -type Advanced struct { - IncludeCountry bool `json:"include_country"` - UseDomainFronting bool `json:"use_domain_fronting"` -} diff --git a/config/automated_testing.go b/config/automated_testing.go deleted file mode 100644 index 56dc660..0000000 --- a/config/automated_testing.go +++ /dev/null @@ -1,8 +0,0 @@ -package config - -// AutomatedTesting settings -type AutomatedTesting struct { - Enabled bool `json:"enabled"` - EnabledTests []string `json:"enabled_tests"` - MonthlyAllowance string `json:"monthly_allowance"` -} diff --git a/config/notifications.go b/config/notifications.go deleted file mode 100644 index 7341ac3..0000000 --- a/config/notifications.go +++ /dev/null @@ -1,8 +0,0 @@ -package config - -// Notifications settings -type Notifications struct { - Enabled bool `json:"enabled"` - NotifyOnTestCompletion bool `json:"notify_on_test_completion"` - NotifyOnNews bool `json:"notify_on_news"` -} diff --git a/config/parser.go b/config/parser.go new file mode 100644 index 0000000..f013900 --- /dev/null +++ b/config/parser.go @@ -0,0 +1,119 @@ +package config + +import ( + "encoding/json" + "io/ioutil" + "os" + "path/filepath" + "sync" + + "github.com/ooni/probe-cli/utils" + "github.com/pkg/errors" +) + +// ReadConfig reads the configuration from the path +func ReadConfig(path string) (*Config, error) { + b, err := ioutil.ReadFile(path) + + if os.IsNotExist(err) { + c := &Config{} + + if err = c.Default(); err != nil { + return nil, errors.Wrap(err, "defaulting") + } + + if err = c.Validate(); err != nil { + return nil, errors.Wrap(err, "validating") + } + + return c, nil + } + + if err != nil { + return nil, errors.Wrap(err, "reading file") + } + + c, err := ParseConfig(b) + if err != nil { + return nil, errors.Wrap(err, "parsing config") + } + c.path = path + return c, err +} + +// ParseConfig returns config from JSON bytes. +func ParseConfig(b []byte) (*Config, error) { + c := &Config{} + + if err := json.Unmarshal(b, c); err != nil { + return nil, errors.Wrap(err, "parsing json") + } + + if err := c.Default(); err != nil { + return nil, errors.Wrap(err, "defaulting") + } + + if err := c.Validate(); err != nil { + return nil, errors.Wrap(err, "validating") + } + + return c, nil +} + +// Config for the OONI Probe installation +type Config struct { + // Private settings + Comment string `json:"_"` + Version int64 `json:"_version"` + InformedConsent bool `json:"_informed_consent"` + + AutoUpdate bool `json:"auto_update"` + Sharing Sharing `json:"sharing"` + Notifications Notifications `json:"notifications"` + AutomatedTesting AutomatedTesting `json:"automated_testing"` + NettestGroups NettestGroups `json:"test_settings"` + Advanced Advanced `json:"advanced"` + + mutex sync.Mutex + path string +} + +// Write the config file in json to the path +func (c *Config) Write() error { + c.Lock() + configJSON, _ := json.MarshalIndent(c, "", " ") + if c.path == "" { + return errors.New("config file path is empty") + } + if err := ioutil.WriteFile(c.path, configJSON, 0644); err != nil { + return errors.Wrap(err, "writing config JSON") + } + c.Unlock() + return nil +} + +// Lock acquires the write mutex +func (c *Config) Lock() { + c.mutex.Lock() +} + +// Unlock releases the write mutex +func (c *Config) Unlock() { + c.mutex.Unlock() +} + +// Default config settings +func (c *Config) Default() error { + home, err := utils.GetOONIHome() + if err != nil { + return err + } + + c.path = filepath.Join(home, "config.json") + return nil +} + +// Validate the config file +func (c *Config) Validate() error { + return nil +} diff --git a/config/nettest_groups.go b/config/settings.go similarity index 65% rename from config/nettest_groups.go rename to config/settings.go index 9be7a6c..0935772 100644 --- a/config/nettest_groups.go +++ b/config/settings.go @@ -82,11 +82,10 @@ func (s *InstantMessaging) NettestConfigs() []NettestConfig { // Performance nettest group type Performance struct { - EnabledTests []string `json:"enabled_tests"` - NDTServer string `json:"ndt_server"` - NDTServerPort string `json:"ndt_server_port"` - DashServer string `json:"dash_server"` - DashServerPort string `json:"dash_server_port"` + NDTServer string `json:"ndt_server"` + NDTServerPort string `json:"ndt_server_port"` + DashServer string `json:"dash_server"` + DashServerPort string `json:"dash_server_port"` } // Middlebox nettest group @@ -101,3 +100,32 @@ type NettestGroups struct { Performance Performance `json:"performance"` Middlebox Middlebox `json:"middlebox"` } + +// Notifications settings +type Notifications struct { + Enabled bool `json:"enabled"` + NotifyOnTestCompletion bool `json:"notify_on_test_completion"` + NotifyOnNews bool `json:"notify_on_news"` +} + +// Sharing settings +type Sharing struct { + IncludeIP bool `json:"include_ip"` + IncludeASN bool `json:"include_asn"` + IncludeGPS bool `json:"include_gps"` + UploadResults bool `json:"upload_results"` + SendCrashReports bool `json:"send_crash_reports"` +} + +// Advanced settings +type Advanced struct { + IncludeCountry bool `json:"include_country"` + UseDomainFronting bool `json:"use_domain_fronting"` +} + +// AutomatedTesting settings +type AutomatedTesting struct { + Enabled bool `json:"enabled"` + EnabledTests []string `json:"enabled_tests"` + MonthlyAllowance string `json:"monthly_allowance"` +} diff --git a/config/sharing.go b/config/sharing.go deleted file mode 100644 index 6aebf8d..0000000 --- a/config/sharing.go +++ /dev/null @@ -1,10 +0,0 @@ -package config - -// Sharing settings -type Sharing struct { - IncludeIP bool `json:"include_ip"` - IncludeASN bool `json:"include_asn"` - IncludeGPS bool `json:"include_gps"` - UploadResults bool `json:"upload_results"` - SendCrashReports bool `json:"send_crash_reports"` -} diff --git a/data/default-config.json b/data/default-config.json index 1068d91..79438b1 100644 --- a/data/default-config.json +++ b/data/default-config.json @@ -1,5 +1,7 @@ { - "_": "This is your OONI Probe config file. See https://ooni.io/help/ooniprobe-cli for help", + "_": "This is your OONI Probe config file. See https://ooni.io/help/probe-cli for help", + "_version": 0, + "_informed_consent": false, "auto_update": true, "sharing": { "include_ip": false, @@ -56,8 +58,6 @@ }, "advanced": { "include_country": true, - "use_domain_fronting": true + "use_domain_fronting": false }, - "_config_version": "0.0.1", - "_informed_consent": true } diff --git a/ooni.go b/ooni.go index 051e051..1c794e9 100644 --- a/ooni.go +++ b/ooni.go @@ -1,11 +1,9 @@ package ooni import ( - "encoding/json" "io/ioutil" "os" "path/filepath" - "sync" "github.com/apex/log" "github.com/jmoiron/sqlx" @@ -17,7 +15,7 @@ import ( ) // Onboarding process -func Onboarding(c *Config) error { +func Onboarding(c *config.Config) error { log.Info("Onboarding starting") // To prevent races we always must acquire the config file lock before @@ -35,7 +33,7 @@ func Onboarding(c *Config) error { // Context for OONI Probe type Context struct { - Config *Config + Config *config.Config DB *sqlx.DB Location *utils.LocationInfo @@ -82,7 +80,7 @@ func (c *Context) Init() error { if c.configPath != "" { log.Debugf("Reading config file from %s", c.configPath) - c.Config, err = ReadConfig(c.configPath) + c.Config, err = config.ReadConfig(c.configPath) } else { log.Debug("Reading default config file") c.Config, err = ReadDefaultConfigPaths(c.Home) @@ -118,88 +116,11 @@ func (c *Context) Init() error { func NewContext(configPath string, homePath string) *Context { return &Context{ Home: homePath, - Config: &Config{}, + Config: &config.Config{}, configPath: configPath, } } -// Config for the OONI Probe installation -type Config struct { - // Private settings - Comment string `json:"_"` - ConfigVersion string `json:"_config_version"` - InformedConsent bool `json:"_informed_consent"` - - AutoUpdate bool `json:"auto_update"` - Sharing config.Sharing `json:"sharing"` - Notifications config.Notifications `json:"notifications"` - AutomatedTesting config.AutomatedTesting `json:"automated_testing"` - NettestGroups config.NettestGroups `json:"test_settings"` - Advanced config.Advanced `json:"advanced"` - - mutex sync.Mutex - path string -} - -// Write the config file in json to the path -func (c *Config) Write() error { - c.Lock() - configJSON, _ := json.MarshalIndent(c, "", " ") - if c.path == "" { - return errors.New("config file path is empty") - } - if err := ioutil.WriteFile(c.path, configJSON, 0644); err != nil { - return errors.Wrap(err, "writing config JSON") - } - c.Unlock() - return nil -} - -// Lock acquires the write mutex -func (c *Config) Lock() { - c.mutex.Lock() -} - -// Unlock releases the write mutex -func (c *Config) Unlock() { - c.mutex.Unlock() -} - -// Default config settings -func (c *Config) Default() error { - home, err := utils.GetOONIHome() - if err != nil { - return err - } - - c.path = filepath.Join(home, "config.json") - return nil -} - -// Validate the config file -func (c *Config) Validate() error { - return nil -} - -// ParseConfig returns config from JSON bytes. -func ParseConfig(b []byte) (*Config, error) { - c := &Config{} - - if err := json.Unmarshal(b, c); err != nil { - return nil, errors.Wrap(err, "parsing json") - } - - if err := c.Default(); err != nil { - return nil, errors.Wrap(err, "defaulting") - } - - if err := c.Validate(); err != nil { - return nil, errors.Wrap(err, "validating") - } - - return c, nil -} - // MaybeInitializeHome does the setup for a new OONI Home func MaybeInitializeHome(home string) error { firstRun := false @@ -214,9 +135,11 @@ func MaybeInitializeHome(home string) error { if firstRun == true { log.Info("This is the first time you are running OONI Probe. Downloading some files.") geoipDir := utils.GeoIPDir(home) + log.Debugf("Downloading GeoIP database files") if err := utils.DownloadGeoIPDatabaseFiles(geoipDir); err != nil { return err } + log.Debugf("Downloading legacy GeoIP database Files") if err := utils.DownloadLegacyGeoIPDatabaseFiles(geoipDir); err != nil { return err } @@ -225,44 +148,14 @@ func MaybeInitializeHome(home string) error { return nil } -// ReadConfig reads the configuration from the path -func ReadConfig(path string) (*Config, error) { - b, err := ioutil.ReadFile(path) - - if os.IsNotExist(err) { - c := &Config{} - - if err = c.Default(); err != nil { - return nil, errors.Wrap(err, "defaulting") - } - - if err = c.Validate(); err != nil { - return nil, errors.Wrap(err, "validating") - } - - return c, nil - } - - if err != nil { - return nil, errors.Wrap(err, "reading file") - } - - c, err := ParseConfig(b) - if err != nil { - return nil, errors.Wrap(err, "parsing config") - } - c.path = path - return c, err -} - // ReadDefaultConfigPaths from common locations. -func ReadDefaultConfigPaths(home string) (*Config, error) { +func ReadDefaultConfigPaths(home string) (*config.Config, error) { var paths = []string{ filepath.Join(home, "config.json"), } for _, path := range paths { if _, err := os.Stat(path); err == nil { - c, err := ReadConfig(path) + c, err := config.ReadConfig(path) if err != nil { return nil, err } @@ -271,5 +164,5 @@ func ReadDefaultConfigPaths(home string) (*Config, error) { } // Run from the default config - return ReadConfig(paths[0]) + return config.ReadConfig(paths[0]) }