refactor: config is now a private package (#164)
We are working on ooniprobe for Debian. Before starting to apply changes to the codebase, I'd like to apply some refactoring steps that I've been thinking about for quite some time. The general concept here is that the purpose of this repository changed since it was designed and now there is probe-engine which is a library, therefore, this repo can be mostly private.
This commit is contained in:
@@ -7,8 +7,8 @@ import (
|
||||
"github.com/apex/log"
|
||||
"github.com/fatih/color"
|
||||
ooni "github.com/ooni/probe-cli"
|
||||
"github.com/ooni/probe-cli/config"
|
||||
"github.com/ooni/probe-cli/internal/cli/root"
|
||||
"github.com/ooni/probe-cli/internal/config"
|
||||
"github.com/ooni/probe-cli/internal/output"
|
||||
"github.com/pkg/errors"
|
||||
"gopkg.in/AlecAivazis/survey.v1"
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"sync"
|
||||
|
||||
"github.com/apex/log"
|
||||
"github.com/ooni/probe-cli/internal/crashreport"
|
||||
"github.com/ooni/probe-cli/utils"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// ConfigVersion is the current version of the config
|
||||
const ConfigVersion = 1
|
||||
|
||||
// ReadConfig reads the configuration from the path
|
||||
func ReadConfig(path string) (*Config, error) {
|
||||
b, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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) {
|
||||
var c Config
|
||||
|
||||
if err := json.Unmarshal(b, &c); err != nil {
|
||||
return nil, errors.Wrap(err, "parsing json")
|
||||
}
|
||||
|
||||
home, err := utils.GetOONIHome()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.path = utils.ConfigPath(home)
|
||||
|
||||
if c.Advanced.SendCrashReports == false {
|
||||
log.Info("Disabling crash reporting.")
|
||||
crashreport.Disabled = true
|
||||
}
|
||||
|
||||
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"`
|
||||
|
||||
Sharing Sharing `json:"sharing"`
|
||||
Nettests Nettests `json:"nettests"`
|
||||
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()
|
||||
defer c.Unlock()
|
||||
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")
|
||||
}
|
||||
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()
|
||||
}
|
||||
|
||||
// MaybeMigrate checks the current config version and the config file on disk
|
||||
// and if necessary performs and upgrade of the configuration file.
|
||||
func (c *Config) MaybeMigrate() error {
|
||||
if c.Version < ConfigVersion {
|
||||
return c.Write()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func getShasum(path string) (string, error) {
|
||||
hasher := sha256.New()
|
||||
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer f.Close()
|
||||
if _, err := io.Copy(hasher, f); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return hex.EncodeToString(hasher.Sum(nil)), nil
|
||||
}
|
||||
|
||||
func TestParseConfig(t *testing.T) {
|
||||
config, err := ReadConfig("testdata/valid-config.json")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if config.Sharing.IncludeASN == false {
|
||||
t.Error("network should be included")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateConfig(t *testing.T) {
|
||||
tmpFile, err := ioutil.TempFile(os.TempDir(), "ooniconfig-")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
configPath := tmpFile.Name()
|
||||
defer os.Remove(configPath)
|
||||
|
||||
data, err := ioutil.ReadFile("testdata/config-v0.json")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
err = ioutil.WriteFile(configPath, data, 0644)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
origShasum, err := getShasum(configPath)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
config, err := ReadConfig(configPath)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
origIncludeIP := config.Sharing.IncludeIP
|
||||
origIncludeASN := config.Sharing.IncludeASN
|
||||
origUploadResults := config.Sharing.UploadResults
|
||||
origInformedConsent := config.InformedConsent
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
config.MaybeMigrate()
|
||||
migratedShasum, err := getShasum(configPath)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if migratedShasum == origShasum {
|
||||
t.Fatal("the config was not migrated")
|
||||
}
|
||||
|
||||
newConfig, err := ReadConfig(configPath)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if newConfig.Sharing.IncludeIP != origIncludeIP {
|
||||
t.Error("includeIP differs")
|
||||
}
|
||||
if newConfig.Sharing.IncludeASN != origIncludeASN {
|
||||
t.Error("includeASN differs")
|
||||
}
|
||||
if newConfig.Sharing.UploadResults != origUploadResults {
|
||||
t.Error("UploadResults differs")
|
||||
}
|
||||
if newConfig.InformedConsent != origInformedConsent {
|
||||
t.Error("InformedConsent differs")
|
||||
}
|
||||
|
||||
// Check that the config file stays the same if it's already the most up to
|
||||
// date version
|
||||
config.MaybeMigrate()
|
||||
finalShasum, err := getShasum(configPath)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if migratedShasum != finalShasum {
|
||||
t.Fatal("the config was migrated again")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package config
|
||||
|
||||
var websiteCategories = []string{
|
||||
"ALDR",
|
||||
"ANON",
|
||||
"COMM",
|
||||
"COMT",
|
||||
"CTRL",
|
||||
"CULTR",
|
||||
"DATE",
|
||||
"ECON",
|
||||
"ENV",
|
||||
"FILE",
|
||||
"GAME",
|
||||
"GMB",
|
||||
"GOVT",
|
||||
"GRP",
|
||||
"HACK",
|
||||
"HATE",
|
||||
"HOST",
|
||||
"HUMR",
|
||||
"IGO",
|
||||
"LGBT",
|
||||
"MILX",
|
||||
"MMED",
|
||||
"NEWS",
|
||||
"POLR",
|
||||
"PORN",
|
||||
"PROV",
|
||||
"PUBH",
|
||||
"REL",
|
||||
"SRCH",
|
||||
"XED",
|
||||
}
|
||||
|
||||
// Sharing settings
|
||||
type Sharing struct {
|
||||
IncludeIP bool `json:"include_ip"`
|
||||
IncludeASN bool `json:"include_asn"`
|
||||
UploadResults bool `json:"upload_results"`
|
||||
}
|
||||
|
||||
// Advanced settings
|
||||
type Advanced struct {
|
||||
SendCrashReports bool `json:"send_crash_reports"`
|
||||
}
|
||||
|
||||
// Nettests related settings
|
||||
type Nettests struct {
|
||||
WebsitesURLLimit int64 `json:"websites_url_limit"`
|
||||
WebsitesEnabledCategoryCodes []string `json:"websites_enabled_category_codes"`
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
{
|
||||
"_version": 0,
|
||||
"_informed_consent": true,
|
||||
"_is_beta": true,
|
||||
"auto_update": true,
|
||||
"sharing": {
|
||||
"include_ip": false,
|
||||
"include_asn": true,
|
||||
"include_country": true,
|
||||
"include_gps": true,
|
||||
"upload_results": true
|
||||
},
|
||||
"notifications": {
|
||||
"enabled": true,
|
||||
"notify_on_test_completion": true,
|
||||
"notify_on_news": false
|
||||
},
|
||||
"automated_testing": {
|
||||
"enabled": false,
|
||||
"enabled_tests": [
|
||||
"web-connectivity",
|
||||
"facebook-messenger",
|
||||
"whatsapp",
|
||||
"telegram",
|
||||
"dash",
|
||||
"ndt",
|
||||
"http-invalid-request-line",
|
||||
"http-header-field-manipulation"
|
||||
],
|
||||
"monthly_allowance": "300MB"
|
||||
},
|
||||
"test_settings": {
|
||||
"websites": {
|
||||
"enabled_categories": []
|
||||
},
|
||||
"instant_messaging": {
|
||||
"enabled_tests": [
|
||||
"facebook-messenger",
|
||||
"whatsapp",
|
||||
"telegram"
|
||||
]
|
||||
},
|
||||
"performance": {
|
||||
"ndt_server": "auto",
|
||||
"ndt_server_port": "auto",
|
||||
"dash_server": "auto",
|
||||
"dash_server_port": "auto"
|
||||
},
|
||||
"middlebox": {
|
||||
"enabled_tests": [
|
||||
"http-invalid-request-line",
|
||||
"http-header-field-manipulation"
|
||||
]
|
||||
}
|
||||
},
|
||||
"advanced": {
|
||||
"use_domain_fronting": false,
|
||||
"send_crash_reports": true,
|
||||
"collector_url": "",
|
||||
"bouncer_url": "https://bouncer.ooni.io"
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"_version": 1,
|
||||
"_informed_consent": false,
|
||||
"sharing": {
|
||||
"include_ip": false,
|
||||
"include_asn": true,
|
||||
"include_country": true,
|
||||
"upload_results": true
|
||||
},
|
||||
"nettests": {
|
||||
"websites_url_limit": 0
|
||||
},
|
||||
"advanced": {
|
||||
"use_domain_fronting": false,
|
||||
"send_crash_reports": true,
|
||||
"collector_url": "",
|
||||
"bouncer_url": "https://bouncer.ooni.io"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user