Skip to content
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@
/ooporthelper
/probe-cli.cov
/tmp-*
/tinyooni
/*.zip
6 changes: 5 additions & 1 deletion cmd/ooniprobe/internal/log/handlers/cli/results.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,11 @@ var summarizers = map[string]func(uint64, uint64, string) []string{
}

func makeSummary(name string, totalCount uint64, anomalyCount uint64, ss string) []string {
return summarizers[name](totalCount, anomalyCount, ss)
summarizer, ok := summarizers[name]
if !ok {
return []string{"", "", ""}
}
return summarizer(totalCount, anomalyCount, ss)
}

func logResultItem(w io.Writer, f log.Fields) error {
Expand Down
69 changes: 69 additions & 0 deletions internal/cmd/tinyooni/database.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package main

import (
"context"
"os"
"path/filepath"
"runtime"

"github.com/ooni/probe-cli/v3/internal/database"
"github.com/ooni/probe-cli/v3/internal/engine"
"github.com/ooni/probe-cli/v3/internal/model"
"github.com/ooni/probe-cli/v3/internal/runtimex"
)

// initDatabase initializes a database and returns the corresponding database properties.
func initDatabase(ctx context.Context, sess *engine.Session, globalOptions *GlobalOptions) *model.DatabaseProps {
ooniHome := maybeGetOONIDir(globalOptions.HomeDir)

db, err := database.Open(databasePath(ooniHome))
runtimex.PanicOnError(err, "database.Open failed")

networkDB, err := db.CreateNetwork(sess)
runtimex.PanicOnError(err, "db.Create failed")

dbResult, err := db.CreateResult(ooniHome, "custom", networkDB.ID)
runtimex.PanicOnError(err, "db.CreateResult failed")

return &model.DatabaseProps{
Database: db,
DatabaseNetwork: networkDB,
DatabaseResult: dbResult,
}
}

// getHomeDir returns the $HOME directory.
func getHomeDir() (string, string) {
// See https://gist.github.com/miguelmota/f30a04a6d64bd52d7ab59ea8d95e54da
if runtime.GOOS == "windows" {
home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
if home == "" {
home = os.Getenv("USERPROFILE")
}
return home, "ooniprobe"
}
if runtime.GOOS == "linux" {
home := os.Getenv("XDG_CONFIG_HOME")
if home != "" {
return home, "ooniprobe"
}
// fallthrough
}
return os.Getenv("HOME"), ".ooniprobe"
}

// maybeGetOONIDir returns the $HOME/.ooniprobe equivalent unless optionsHome
// is already set, in which case it just returns optionsHome.
func maybeGetOONIDir(optionsHome string) string {
if optionsHome != "" {
return optionsHome
}
homeDir, dirName := getHomeDir()
runtimex.Assert(homeDir != "", "homeDir is empty")
return filepath.Join(homeDir, dirName)
}

// databasePath returns the database path given the OONI_HOME.
func databasePath(ooniHome string) string {
return filepath.Join(ooniHome, "db", "main.sqlite3")
}
68 changes: 68 additions & 0 deletions internal/cmd/tinyooni/groups.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
{
"websites": {
"name": "Websites",
"description": "",
"author": "OONI",
"nettests": [{
"test_name": "web_connectivity"
}]
},
"performance": {
"name": "Performance",
"description": "",
"author": "OONI",
"nettests": [{
"test_name": "dash"
}, {
"test_name": "ndt"
}]
},
"middlebox": {
"name": "Middlebox",
"description": "",
"author": "OONI",
"nettests": [{
"test_name": "hirl"
}, {
"test_name": "hhfm"
}]
},
"im": {
"name": "Instant Messaging",
"description": "Runs the instant messaging experiments",
"author": "OONI",
"nettests": [{
"test_name": "facebook_messenger"
}, {
"test_name": "signal"
}, {
"test_name": "telegram"
}, {
"test_name": "whatsapp"
}]
},
"circumvention": {
"name": "Circumvention",
"description": "",
"author": "OONI",
"nettests": [{
"test_name": "psiphon"
}, {
"test_name": "tor"
}]
},
"experimental": {
"name": "Experimental",
"description": "Experimental nettests",
"author": "OONI",
"nettests": [{
"test_name": "dnscheck"
}, {
"test_name": "stun_reachability"
}, {
"test_name": "torsf"
}, {
"test_name": "vanilla_tor"
}]
}
}
151 changes: 151 additions & 0 deletions internal/cmd/tinyooni/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package main

import (
"os"

"github.com/ooni/probe-cli/v3/internal/version"
"github.com/spf13/cobra"
)

// GlobalOptions contains the global options.
type GlobalOptions struct {
Emoji bool
HomeDir string
NoJSON bool
NoCollector bool
ProbeServicesURL string
Proxy string
RepeatEvery int64
ReportFile string
SnowflakeRendezvous string
TorArgs []string
TorBinary string
Tunnel string
Verbose bool
Yes bool
}

func main() {
var globalOptions GlobalOptions
rootCmd := &cobra.Command{
Use: "tinyooni",
Short: "tinyooni is like miniooni but more experimental",
Args: cobra.NoArgs,
Version: version.Version,
}
rootCmd.SetVersionTemplate("{{ .Version }}\n")
flags := rootCmd.PersistentFlags()

flags.BoolVar(
&globalOptions.Emoji,
"emoji",
false,
"whether to use emojis when logging",
)

flags.StringVar(
&globalOptions.HomeDir,
"home",
"",
"force specific home directory",
)

flags.BoolVarP(
&globalOptions.NoJSON,
"no-json",
"N",
false,
"disable writing to disk",
)

flags.BoolVarP(
&globalOptions.NoCollector,
"no-collector",
"n",
false,
"do not submit measurements to the OONI collector",
)

flags.StringVar(
&globalOptions.ProbeServicesURL,
"probe-services",
"",
"URL of the OONI backend instance you want to use",
)

flags.StringVar(
&globalOptions.Proxy,
"proxy",
"",
"set proxy URL to communicate with the OONI backend (mutually exclusive with --tunnel)",
)

flags.Int64Var(
&globalOptions.RepeatEvery,
"repeat-every",
0,
"wait the given number of seconds and then repeat the same measurement",
)

flags.StringVarP(
&globalOptions.ReportFile,
"reportfile",
"o",
"",
"set the output report file path (default: \"report.jsonl\")",
)

flags.StringVar(
&globalOptions.SnowflakeRendezvous,
"snowflake-rendezvous",
"domain_fronting",
"rendezvous method for --tunnel=torsf (one of: \"domain_fronting\" and \"amp\")",
)

flags.StringSliceVar(
&globalOptions.TorArgs,
"tor-args",
[]string{},
"extra arguments for the tor binary (may be specified multiple times)",
)

flags.StringVar(
&globalOptions.TorBinary,
"tor-binary",
"",
"execute a specific tor binary",
)

flags.StringVar(
&globalOptions.Tunnel,
"tunnel",
"",
"tunnel to use to communicate with the OONI backend (one of: psiphon, tor, torsf)",
)

flags.BoolVarP(
&globalOptions.Verbose,
"verbose",
"v",
false,
"increase verbosity level",
)

flags.BoolVarP(
&globalOptions.Yes,
"yes",
"y",
false,
"assume yes as the answer to all questions",
)

rootCmd.MarkFlagsMutuallyExclusive("proxy", "tunnel")

registerRunExperiment(rootCmd, &globalOptions)
registerRunGroup(rootCmd, &globalOptions)
registerOoniRun(rootCmd, &globalOptions)

if err := rootCmd.Execute(); err != nil {
os.Exit(1)
}
}
Loading