From 93a00a13e2032d962a0c7ac0d332cabc5e5659c2 Mon Sep 17 00:00:00 2001 From: Naoki Kosaka Date: Sat, 22 Dec 2018 23:05:57 +0900 Subject: [PATCH] Use cobra in CLI. (#10) --- Gopkg.lock | 78 +++++++++------- cli/cli.go | 156 +++---------------------------- cli/config.go | 130 +++++++++++++++++++------- cli/config_test.go | 198 +++++++++++++++++++--------------------- cli/domain.go | 86 +++++++++++------ cli/domain_test.go | 194 +++++++++++++++++++++++++++++++++++++++ cli/follow.go | 187 ++++++++++++++++++++++--------------- misc/blankConfig.json | 1 + misc/exampleConfig.json | 1 + 9 files changed, 615 insertions(+), 416 deletions(-) create mode 100644 cli/domain_test.go create mode 100644 misc/blankConfig.json create mode 100644 misc/exampleConfig.json diff --git a/Gopkg.lock b/Gopkg.lock index 369aa49..467f777 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -73,7 +73,7 @@ version = "v1.0.0" [[projects]] - digest = "1:8fc076db6baabdb055f30e929ab3896931587d58fb105c2dadf046611f5f137d" + digest = "1:b05246dbce3abe23afdbb856b31666b5c6f77ecedf014f126ec6ce709e964b1e" name = "github.com/aws/aws-sdk-go" packages = [ "aws", @@ -115,8 +115,8 @@ "service/sts", ] pruneopts = "UT" - revision = "5f1ca23f3ded773a9ba214e6fac36acd9a965a53" - version = "v1.16.6" + revision = "3991042237b45cf58c9d5f34295942d5533c28c6" + version = "v1.16.11" [[projects]] branch = "master" @@ -179,12 +179,23 @@ version = "v1.1.0" [[projects]] - digest = "1:e04cc716992a302cacf6d726409a05aa9546241998b24356d6dd0f01bc5a374e" + digest = "1:cd9864c6366515827a759931746738ede6079faa08df9c584596370d6add135c" name = "github.com/googleapis/gax-go" + packages = [ + ".", + "v2", + ] + pruneopts = "UT" + revision = "c8a15bac9b9fe955bd9f900272f9a306465d28cf" + version = "v2.0.3" + +[[projects]] + digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be" + name = "github.com/inconshreveable/mousetrap" packages = ["."] pruneopts = "UT" - revision = "b001040cd31805261cbd978842099e326dfa857b" - version = "v2.0.2" + revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75" + version = "v1.0" [[projects]] digest = "1:bb81097a5b62634f3e9fec1014657855610c82d19b9a40c17612e32651e35dca" @@ -193,14 +204,6 @@ pruneopts = "UT" revision = "c2b33e84" -[[projects]] - branch = "master" - digest = "1:1f251f2f217a800ef952995dac5fbe0615f4cacd0dc448a0dffd9176a09a3823" - name = "github.com/kami-zh/go-capturer" - packages = ["."] - pruneopts = "UT" - revision = "e492ea43421da7381e5200a2e22753bfc31347c2" - [[projects]] digest = "1:edbef42561faa44c19129b68d1e109fbc1647f63239250391eadc8d0e7c9f669" name = "github.com/kelseyhightower/envconfig" @@ -237,6 +240,22 @@ revision = "f58768cc1a7a7e77a3bd49e98cdd21419399b6a3" version = "v1.2.0" +[[projects]] + digest = "1:645cabccbb4fa8aab25a956cbcbdf6a6845ca736b2c64e197ca7cbb9d210b939" + name = "github.com/spf13/cobra" + packages = ["."] + pruneopts = "UT" + revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385" + version = "v0.0.3" + +[[projects]] + digest = "1:c1b1102241e7f645bc8e0c22ae352e8f0dc6484b6cb4d132fa9f24174e0119e2" + name = "github.com/spf13/pflag" + packages = ["."] + pruneopts = "UT" + revision = "298182f68c66c05229eb03ac171abe6e309ee79a" + version = "v1.0.3" + [[projects]] branch = "master" digest = "1:525ac3364813b4688df380594e562133e07830dfce0722effda64b37634c13d0" @@ -245,14 +264,6 @@ pruneopts = "UT" revision = "a314942b2fd9dde7a3f70ba3f1062848ce6eb392" -[[projects]] - digest = "1:b24d38b282bacf9791408a080f606370efa3d364e4b5fd9ba0f7b87786d3b679" - name = "github.com/urfave/cli" - packages = ["."] - pruneopts = "UT" - revision = "cfb38830724cc34fedffe9a2a29fb54fa9169cd1" - version = "v1.20.0" - [[projects]] digest = "1:bb78bf98bee383e091714423f2363a9a3b31a62e9ebbd887cb4f94e693d4890d" name = "github.com/yukimochi/httpsig" @@ -313,7 +324,7 @@ "trace", ] pruneopts = "UT" - revision = "891ebc4b82d6e74f468c533b06f983c7be918a96" + revision = "927f97764cc334a6575f4b7a1584a147864d5723" [[projects]] branch = "master" @@ -331,25 +342,25 @@ [[projects]] branch = "master" - digest = "1:d6b0cfc5ae30841c4b116ac589629f56f8add0955a39f11d8c0d06ca67f5b3d5" + digest = "1:04a5b0e4138f98eef79ce12a955a420ee358e9f787044cc3a553ac3c3ade997e" name = "golang.org/x/sync" packages = [ "errgroup", "semaphore", ] pruneopts = "UT" - revision = "42b317875d0fa942474b76e1b46a6060d720ae6e" + revision = "37e7f081c4d4c64e13b10787722085407fe5d15f" [[projects]] branch = "master" - digest = "1:9bd2a1332ddcee55c2dad82b983716d41a32635dafab848a12de0e73f29d4c2c" + digest = "1:b9a5b255010eff293ac236a559771a8d6a7464cd341b9c3174bfe334a953d20f" name = "golang.org/x/sys" packages = [ "cpu", "unix", ] pruneopts = "UT" - revision = "4d1cda033e0619309c606fc686de3adcf599539e" + revision = "b4a75ba826a64a70990f11a225237acd6ef35c9f" [[projects]] digest = "1:a2ab62866c75542dd18d2b069fec854577a20211d7c0ea6ae746072a1dccdd18" @@ -390,10 +401,10 @@ "transport/http/internal/propagation", ] pruneopts = "UT" - revision = "874d9dc5b186e361475b082852f136f094555c30" + revision = "65a46cafb132eff435c7d1e0f439cc73c8eebb85" [[projects]] - digest = "1:b13819327be647014031c6a194299da87ca35313bfc01fdc1da7bd3ddf08cbce" + digest = "1:c4eaa5f79d36f76ef4bd0c4f96e36bc1b7b5a359528d1267f0cb7a5d58b7b5bb" name = "google.golang.org/appengine" packages = [ ".", @@ -410,8 +421,8 @@ "urlfetch", ] pruneopts = "UT" - revision = "4a4468ece617fc8205e99368fa2200e9d1fad421" - version = "v1.3.0" + revision = "e9657d882bb81064595ca3b56cbe2546bbabf7b1" + version = "v1.4.0" [[projects]] branch = "master" @@ -425,7 +436,7 @@ "protobuf/field_mask", ] pruneopts = "UT" - revision = "bd91e49a0898e27abb88c339b432fa53d7497ac0" + revision = "bd9b4fb69e2ffd37621a6caa54dcbead29b546f2" [[projects]] digest = "1:3fc54ad826c0183f803bb97e0927dfc05fcb7b7a6ddabed646ee8184d861fa9b" @@ -499,10 +510,9 @@ "github.com/RichardKnop/machinery/v1/tasks", "github.com/Songmu/go-httpdate", "github.com/go-redis/redis", - "github.com/kami-zh/go-capturer", "github.com/patrickmn/go-cache", "github.com/satori/go.uuid", - "github.com/urfave/cli", + "github.com/spf13/cobra", "github.com/yukimochi/httpsig", ] solver-name = "gps-cdcl" diff --git a/cli/cli.go b/cli/cli.go index 6fcaecb..867b735 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -3,14 +3,13 @@ package main import ( "crypto/rsa" "fmt" - "log" "net/url" "os" "github.com/RichardKnop/machinery/v1" "github.com/RichardKnop/machinery/v1/config" "github.com/go-redis/redis" - "github.com/urfave/cli" + "github.com/spf13/cobra" "github.com/yukimochi/Activity-Relay/KeyLoader" "github.com/yukimochi/Activity-Relay/State" ) @@ -21,6 +20,14 @@ var redClient *redis.Client var macServer *machinery.Server var relayState state.RelayState +func buildNewCmd() *cobra.Command { + var app = &cobra.Command{} + app.AddCommand(domainCmdInit()) + app.AddCommand(followCmdInit()) + app.AddCommand(configCmdInit()) + return app +} + func main() { pemPath := os.Getenv("ACTOR_PEM") if pemPath == "" { @@ -59,147 +66,8 @@ func main() { if err != nil { fmt.Fprintln(os.Stderr, err) } - - app := cli.NewApp() - app.Name = "Activity Relay Extarnal CLI" - app.Usage = "Configure Activity-Relay" - app.Version = "0.2.0rc2" - app.Commands = []cli.Command{ - { - Name: "domain", - Usage: "Management domains", - Subcommands: []cli.Command{ - { - Name: "list", - Usage: "List {subscribed,limited,blocked} domains", - Flags: []cli.Flag{ - cli.StringFlag{ - Name: "type, t", - Value: "subscribed", - Usage: "Domain type [subscribed,limited,blocked]", - }, - }, - Action: listDomains, - }, - { - Name: "set", - Usage: "set domain type [limited,blocked]", - Flags: []cli.Flag{ - cli.StringFlag{ - Name: "type, t", - Usage: "Domain type [limited,blocked]", - }, - cli.StringFlag{ - Name: "domain, d", - Usage: "Registrate domain", - }, - cli.BoolFlag{ - Name: "undo, u", - Usage: "Undo registrate", - }, - }, - Action: setDomainType, - }, - }, - }, - { - Name: "config", - Usage: "Management relay config", - Subcommands: []cli.Command{ - { - Name: "show", - Usage: "Show all relay configrations", - Action: listConfigs, - }, - { - Name: "export", - Usage: "Export all relay information (json)", - Action: exportConfigs, - }, - { - Name: "import", - Usage: "Import relay information (json)", - Action: importConfigs, - Flags: []cli.Flag{ - cli.StringFlag{ - Name: "json, j", - Usage: "json file path", - }, - }, - }, - { - Name: "service-block", - Usage: "Enable blocking for service-type actor", - Flags: []cli.Flag{ - cli.BoolFlag{ - Name: "undo, u", - Usage: "Undo block", - }, - }, - Action: serviceBlock, - }, - { - Name: "manually-accept", - Usage: "Enable manually accept follow-request", - Flags: []cli.Flag{ - cli.BoolFlag{ - Name: "undo, u", - Usage: "Undo block", - }, - }, - Action: manuallyAccept, - }, - { - Name: "create-as-announce", - Usage: "Enable announce activity instead of relay create activity (Not recommend)", - Flags: []cli.Flag{ - cli.BoolFlag{ - Name: "undo, u", - Usage: "Undo block", - }, - }, - Action: createAsAnnounce, - }, - }, - }, - { - Name: "follow-request", - Usage: "Management follow-request", - Subcommands: []cli.Command{ - { - Name: "show", - Usage: "Show all follow-request", - Action: listFollows, - }, - { - Name: "reject", - Usage: "Reject follow-request", - Flags: []cli.Flag{ - cli.StringFlag{ - Name: "domain, d", - Usage: "domain name", - }, - }, - Action: rejectFollow, - }, - { - Name: "accept", - Usage: "Accept follow-request", - Flags: []cli.Flag{ - cli.StringFlag{ - Name: "domain, d", - Usage: "domain name", - }, - }, - Action: acceptFollow, - }, - }, - }, - } - relayState = state.NewState(redClient) - err = app.Run(os.Args) - if err != nil { - log.Fatal(err) - } + + var app = buildNewCmd() + app.Execute() } diff --git a/cli/config.go b/cli/config.go index dbdf0cf..61cffdc 100644 --- a/cli/config.go +++ b/cli/config.go @@ -6,7 +6,7 @@ import ( "io/ioutil" "os" - "github.com/urfave/cli" + "github.com/spf13/cobra" "github.com/yukimochi/Activity-Relay/State" ) @@ -16,49 +16,107 @@ const ( CreateAsAnnounce ) -func serviceBlock(c *cli.Context) { - if c.Bool("undo") { - relayState.SetConfig(BlockService, false) - fmt.Println("Blocking for service-type actor is Disabled.") - } else { - relayState.SetConfig(BlockService, true) - fmt.Println("Blocking for service-type actor is Enabled.") +func configCmdInit() *cobra.Command { + var config = &cobra.Command{ + Use: "config", + Short: "Manage configuration for relay", + Long: "Enable/disable relay costomize and import/export relay database.", } -} -func manuallyAccept(c *cli.Context) { - if c.Bool("undo") { - relayState.SetConfig(ManuallyAccept, false) - fmt.Println("Manually accept follow-request is Disabled.") - } else { - relayState.SetConfig(ManuallyAccept, true) - fmt.Println("Manually accept follow-request is Enabled.") + var configList = &cobra.Command{ + Use: "list", + Short: "List all relay configration", + Long: "List all relay configration.", + Run: listConfig, } -} + config.AddCommand(configList) -func createAsAnnounce(c *cli.Context) { - if c.Bool("undo") { - relayState.SetConfig(CreateAsAnnounce, false) - fmt.Println("Announce activity instead of relay create activity is Disabled.") - } else { - relayState.SetConfig(CreateAsAnnounce, true) - fmt.Println("Announce activity instead of relay create activity is Enabled.") + var configExport = &cobra.Command{ + Use: "export", + Short: "Export all relay information", + Long: "Export all relay information by JSON format.", + Run: exportConfig, } + config.AddCommand(configExport) + + var configImport = &cobra.Command{ + Use: "import [flags]", + Short: "Import all relay information", + Long: "Import all relay information from JSON file.", + Run: importConfig, + } + configImport.Flags().String("json", "", "JSON file-path") + configImport.MarkFlagRequired("json") + config.AddCommand(configImport) + + var configEnable = &cobra.Command{ + Use: "enable", + Short: "Enable/disable relay configration", + Long: `Enable or disable relay configration. + - service-block + Blocking feature for service-type actor. + - manually-accept + Enable manually accept follow request. + - create-as-announce + Enable announce activity instead of relay create activity (not recommend)`, + Args: cobra.MinimumNArgs(1), + RunE: configEnable, + } + configEnable.Flags().BoolP("disable", "d", false, "Disable configration instead of Enable") + config.AddCommand(configEnable) + + return config } -func listConfigs(c *cli.Context) { - fmt.Println("Blocking for service-type actor : ", relayState.RelayConfig.BlockService) - fmt.Println("Manually accept follow-request : ", relayState.RelayConfig.ManuallyAccept) - fmt.Println("Announce activity instead of relay create activity : ", relayState.RelayConfig.CreateAsAnnounce) +func configEnable(cmd *cobra.Command, args []string) error { + disable := cmd.Flag("disable").Value.String() == "true" + for _, config := range args { + switch config { + case "service-block": + if disable { + relayState.SetConfig(BlockService, false) + cmd.Println("Blocking for service-type actor is Disabled.") + } else { + relayState.SetConfig(BlockService, true) + cmd.Println("Blocking for service-type actor is Enabled.") + } + case "manually-accept": + if disable { + relayState.SetConfig(ManuallyAccept, false) + cmd.Println("Manually accept follow-request is Disabled.") + } else { + relayState.SetConfig(ManuallyAccept, true) + cmd.Println("Manually accept follow-request is Enabled.") + } + case "create-as-announce": + if disable { + relayState.SetConfig(CreateAsAnnounce, false) + cmd.Println("Announce activity instead of relay create activity is Disabled.") + } else { + relayState.SetConfig(CreateAsAnnounce, true) + cmd.Println("Announce activity instead of relay create activity is Enabled.") + } + default: + cmd.Println("Invalid config given") + } + } + + return nil } -func exportConfigs(c *cli.Context) { +func listConfig(cmd *cobra.Command, args []string) { + cmd.Println("Blocking for service-type actor : ", relayState.RelayConfig.BlockService) + cmd.Println("Manually accept follow-request : ", relayState.RelayConfig.ManuallyAccept) + cmd.Println("Announce activity instead of relay create activity : ", relayState.RelayConfig.CreateAsAnnounce) +} + +func exportConfig(cmd *cobra.Command, args []string) { jsonData, _ := json.Marshal(&relayState) - fmt.Println(string(jsonData)) + cmd.Println(string(jsonData)) } -func importConfigs(c *cli.Context) { - file, err := os.Open(c.String("json")) +func importConfig(cmd *cobra.Command, args []string) { + file, err := os.Open(cmd.Flag("json").Value.String()) if err != nil { fmt.Fprintln(os.Stderr, err) return @@ -77,18 +135,23 @@ func importConfigs(c *cli.Context) { if data.RelayConfig.BlockService { relayState.SetConfig(BlockService, true) + cmd.Println("Blocking for service-type actor is Enabled.") } if data.RelayConfig.ManuallyAccept { relayState.SetConfig(ManuallyAccept, true) + cmd.Println("Manually accept follow-request is Enabled.") } if data.RelayConfig.CreateAsAnnounce { relayState.SetConfig(CreateAsAnnounce, true) + cmd.Println("Announce activity instead of relay create activity is Enabled.") } for _, LimitedDomain := range data.LimitedDomains { relayState.SetLimitedDomain(LimitedDomain, true) + cmd.Println("Set [" + LimitedDomain + "] as limited domain") } for _, BlockedDomain := range data.BlockedDomains { - relayState.SetLimitedDomain(BlockedDomain, true) + relayState.SetBlockedDomain(BlockedDomain, true) + cmd.Println("Set [" + BlockedDomain + "] as blocked domain") } for _, Subscription := range data.Subscriptions { relayState.AddSubscription(state.Subscription{ @@ -97,5 +160,6 @@ func importConfigs(c *cli.Context) { ActivityID: Subscription.ActivityID, ActorID: Subscription.ActorID, }) + cmd.Println("Regist [" + Subscription.Domain + "] as subscriber") } } diff --git a/cli/config_test.go b/cli/config_test.go index 12907ce..66210fa 100644 --- a/cli/config_test.go +++ b/cli/config_test.go @@ -1,156 +1,142 @@ package main import ( + "bytes" + "io/ioutil" + "os" "strings" "testing" - - "github.com/kami-zh/go-capturer" - "github.com/urfave/cli" ) func TestServiceBlock(t *testing.T) { - app := cli.NewApp() - fooCmd := cli.Command{ - Name: "service-block", - Usage: "Enable blocking for service-type actor", - Flags: []cli.Flag{ - cli.BoolFlag{ - Name: "undo, u", - Usage: "Undo block", - }, - }, - Action: serviceBlock, - } - app.Commands = []cli.Command{ - fooCmd, - } + app := buildNewCmd() relayState.SetConfig(BlockService, false) - app.Run([]string{"", "service-block"}) + app.SetArgs([]string{"config", "enable", "service-block"}) + app.Execute() if !relayState.RelayConfig.BlockService { - t.Fatalf("Not Enabled ServiceBlock feature,") + t.Fatalf("Not Enabled Blocking feature for service-type actor") } - app.Run([]string{"", "service-block", "-u"}) + app.SetArgs([]string{"config", "enable", "-d", "service-block"}) + app.Execute() if relayState.RelayConfig.BlockService { - t.Fatalf("Not Disabled ServiceBlock feature,") + t.Fatalf("Not Disabled Blocking feature for service-type actor") } } - func TestManuallyAccept(t *testing.T) { - app := cli.NewApp() - fooCmd := cli.Command{ - Name: "manually-accept", - Usage: "Enable Manually accept follow-request", - Flags: []cli.Flag{ - cli.BoolFlag{ - Name: "undo, u", - Usage: "Undo block", - }, - }, - Action: manuallyAccept, - } - app.Commands = []cli.Command{ - fooCmd, - } + app := buildNewCmd() relayState.SetConfig(ManuallyAccept, false) - app.Run([]string{"", "manually-accept"}) + app.SetArgs([]string{"config", "enable", "manually-accept"}) + app.Execute() if !relayState.RelayConfig.ManuallyAccept { - t.Fatalf("Not Enabled Manually accept follow-request feature,") + t.Fatalf("Not Enabled Manually accept follow-request feature") } - app.Run([]string{"", "manually-accept", "-u"}) + app.SetArgs([]string{"config", "enable", "-d", "manually-accept"}) + app.Execute() if relayState.RelayConfig.ManuallyAccept { - t.Fatalf("Not Disabled Manually accept follow-request feature,") + t.Fatalf("Not Disabled Manually accept follow-request feature") } } - func TestCreateAsAnnounce(t *testing.T) { - app := cli.NewApp() - fooCmd := cli.Command{ - Name: "create-as-announce", - Usage: "Enable Announce activity instead of relay create activity (Not recommended)", - Flags: []cli.Flag{ - cli.BoolFlag{ - Name: "undo, u", - Usage: "Undo block", - }, - }, - Action: createAsAnnounce, - } - app.Commands = []cli.Command{ - fooCmd, - } + app := buildNewCmd() relayState.SetConfig(CreateAsAnnounce, false) - app.Run([]string{"", "create-as-announce"}) + app.SetArgs([]string{"config", "enable", "create-as-announce"}) + app.Execute() if !relayState.RelayConfig.CreateAsAnnounce { - t.Fatalf("Not Enabled Announce activity instead of relay create activity feature,") + t.Fatalf("Enable announce activity instead of relay create activity") } - app.Run([]string{"", "create-as-announce", "-u"}) + app.SetArgs([]string{"config", "enable", "-d", "create-as-announce"}) + app.Execute() if relayState.RelayConfig.CreateAsAnnounce { - t.Fatalf("Not Disabled Announce activity instead of relay create activity feature,") + t.Fatalf("Enable announce activity instead of relay create activity") + } +} +func TestInvalidConfig(t *testing.T) { + app := buildNewCmd() + buffer := new(bytes.Buffer) + app.SetOutput(buffer) + + app.SetArgs([]string{"config", "enable", "hoge"}) + app.Execute() + + output := buffer.String() + if strings.Split(output, "\n")[0] != "Invalid config given" { + t.Fatalf("Invalid Responce.") } } -func TestListConfigs(t *testing.T) { - app := cli.NewApp() - fooCmd := cli.Command{ - Name: "show", - Usage: "Show all relay configrations", - Action: listConfigs, - } - app.Commands = []cli.Command{ - fooCmd, - } +func TestListConfig(t *testing.T) { + app := buildNewCmd() + buffer := new(bytes.Buffer) + app.SetOutput(buffer) - relayState.SetConfig(BlockService, true) - relayState.SetConfig(ManuallyAccept, true) - relayState.SetConfig(CreateAsAnnounce, true) - out := capturer.CaptureStdout(func() { - app.Run([]string{"", "show"}) - }) + app.SetArgs([]string{"config", "list"}) + app.Execute() - for _, row := range strings.Split(out, "\n") { + output := buffer.String() + for _, row := range strings.Split(output, "\n") { switch strings.Split(row, ":")[0] { case "Blocking for service-type actor ": - if !(strings.Split(row, ":")[1] == " true") { - t.Fatalf(strings.Split(row, ":")[1]) - } - case "Manually accept follow-request ": - if !(strings.Split(row, ":")[1] == " true") { - t.Fatalf("Invalid Responce.") - } - case "Announce activity instead of relay create activity ": - if !(strings.Split(row, ":")[1] == " true") { - t.Fatalf("Invalid Responce.") - } - } - } - - relayState.SetConfig(BlockService, false) - relayState.SetConfig(ManuallyAccept, false) - relayState.SetConfig(CreateAsAnnounce, false) - out = capturer.CaptureStdout(func() { - app.Run([]string{"", "show"}) - }) - - for _, row := range strings.Split(out, "\n") { - switch strings.Split(row, ":")[0] { - case "Blocking for service-type actor ": - if !(strings.Split(row, ":")[1] == " false") { + if strings.Split(row, ":")[1] == " true" { t.Fatalf("Invalid Responce.") } case "Manually accept follow-request ": - if !(strings.Split(row, ":")[1] == " false") { + if strings.Split(row, ":")[1] == " true" { t.Fatalf("Invalid Responce.") } case "Announce activity instead of relay create activity ": - if !(strings.Split(row, ":")[1] == " false") { + if strings.Split(row, ":")[1] == " true" { t.Fatalf("Invalid Responce.") } } } } + +func TestExportConfig(t *testing.T) { + app := buildNewCmd() + buffer := new(bytes.Buffer) + app.SetOutput(buffer) + + app.SetArgs([]string{"config", "export"}) + app.Execute() + + file, err := os.Open("../misc/blankConfig.json") + if err != nil { + t.Fatalf("Test resource fetch error.") + } + jsonData, err := ioutil.ReadAll(file) + output := buffer.String() + if strings.Split(output, "\n")[0] != string(jsonData) { + t.Fatalf("Invalid Responce.") + } +} +func TestImportConfig(t *testing.T) { + app := buildNewCmd() + + app.SetArgs([]string{"config", "import", "--json", "../misc/exampleConfig.json"}) + app.Execute() + + buffer := new(bytes.Buffer) + app.SetOutput(buffer) + + app.SetArgs([]string{"config", "export"}) + app.Execute() + + file, err := os.Open("../misc/exampleConfig.json") + if err != nil { + t.Fatalf("Test resource fetch error.") + } + jsonData, err := ioutil.ReadAll(file) + output := buffer.String() + if strings.Split(output, "\n")[0] != string(jsonData) { + t.Fatalf("Invalid Responce.") + } + + relayState.RedisClient.FlushAll().Result() + relayState.Load() +} diff --git a/cli/domain.go b/cli/domain.go index f3515d4..e5acff7 100644 --- a/cli/domain.go +++ b/cli/domain.go @@ -3,56 +3,88 @@ package main import ( "fmt" - "github.com/urfave/cli" + "github.com/spf13/cobra" ) -func listDomains(c *cli.Context) error { +func domainCmdInit() *cobra.Command { + var domain = &cobra.Command{ + Use: "domain", + Short: "Manage subscriber domain", + Long: "List all subscriber, set/unset domain as limited or blocked and undo subscribe domain.", + } + + var domainList = &cobra.Command{ + Use: "list [flags]", + Short: "List domain", + Long: "List domain which filtered given type.", + RunE: listDomains, + } + domainList.Flags().StringP("type", "t", "subscriber", "domain type [subscriber,limited,blocked]") + domain.AddCommand(domainList) + + var domainSet = &cobra.Command{ + Use: "set [flags]", + Short: "Set or unset domain as limited or blocked", + Long: "Set or unset domain as limited or blocked.", + Args: cobra.MinimumNArgs(1), + RunE: setDomainType, + } + domainSet.Flags().StringP("type", "t", "", "Apply domain type [limited,blocked]") + domainSet.MarkFlagRequired("type") + domainSet.Flags().BoolP("undo", "u", false, "Unset domain as limited or blocked") + domain.AddCommand(domainSet) + + return domain +} + +func listDomains(cmd *cobra.Command, args []string) error { var domains []string - switch c.String("type") { + switch cmd.Flag("type").Value.String() { case "limited": - fmt.Println(" - Limited domain :") + cmd.Println(" - Limited domain :") domains = relayState.LimitedDomains case "blocked": - fmt.Println(" - Blocked domain :") + cmd.Println(" - Blocked domain :") domains = relayState.BlockedDomains default: - fmt.Println(" - Subscribed domain :") + cmd.Println(" - Subscriber domain :") temp := relayState.Subscriptions for _, domain := range temp { domains = append(domains, domain.Domain) } } for _, domain := range domains { - fmt.Println(domain) + cmd.Println(domain) } - fmt.Println(fmt.Sprintf("Total : %d", len(domains))) + cmd.Println(fmt.Sprintf("Total : %d", len(domains))) + return nil } -func setDomainType(c *cli.Context) error { - if c.String("domain") == "" { - fmt.Println("No domain given.") - return nil - } - switch c.String("type") { +func setDomainType(cmd *cobra.Command, args []string) error { + undo := cmd.Flag("undo").Value.String() == "true" + switch cmd.Flag("type").Value.String() { case "limited": - if c.Bool("undo") { - relayState.SetLimitedDomain(c.String("domain"), false) - fmt.Println("Unset [" + c.String("domain") + "] as Limited domain.") - } else { - relayState.SetLimitedDomain(c.String("domain"), true) - fmt.Println("Set [" + c.String("domain") + "] as Limited domain.") + for _, domain := range args { + relayState.SetLimitedDomain(domain, !undo) + if undo { + cmd.Println("Unset [" + domain + "] as limited domain") + } else { + cmd.Println("Set [" + domain + "] as limited domain") + } } case "blocked": - if c.Bool("undo") { - relayState.SetBlockedDomain(c.String("domain"), false) - fmt.Println("Unset [" + c.String("domain") + "] as Blocked domain.") - } else { - relayState.SetBlockedDomain(c.String("domain"), true) - fmt.Println("Set [" + c.String("domain") + "] as Blocked domain.") + for _, domain := range args { + relayState.SetBlockedDomain(domain, !undo) + if undo { + cmd.Println("Unset [" + domain + "] as blocked domain") + } else { + cmd.Println("Set [" + domain + "] as blocked domain") + } } default: - fmt.Println("No type given.") + cmd.Println("Invalid type given") } + return nil } diff --git a/cli/domain_test.go b/cli/domain_test.go new file mode 100644 index 0000000..bd2ceb5 --- /dev/null +++ b/cli/domain_test.go @@ -0,0 +1,194 @@ +package main + +import ( + "bytes" + "strings" + "testing" +) + +func TestListDomainSubscriber(t *testing.T) { + app := buildNewCmd() + + app.SetArgs([]string{"config", "import", "--json", "../misc/exampleConfig.json"}) + app.Execute() + + buffer := new(bytes.Buffer) + app.SetOutput(buffer) + + app.SetArgs([]string{"domain", "list"}) + app.Execute() + + output := buffer.String() + valid := ` - Subscriber domain : +subscription.example.jp +subscription.example.com +Total : 2 +` + if output != valid { + t.Fatalf("Invalid Responce.") + } + + relayState.RedisClient.FlushAll().Result() + relayState.Load() +} + +func TestListDomainLimited(t *testing.T) { + app := buildNewCmd() + + app.SetArgs([]string{"config", "import", "--json", "../misc/exampleConfig.json"}) + app.Execute() + + buffer := new(bytes.Buffer) + app.SetOutput(buffer) + + app.SetArgs([]string{"domain", "list", "-t", "limited"}) + app.Execute() + + output := buffer.String() + valid := ` - Limited domain : +limitedDomain.example.jp +Total : 1 +` + if output != valid { + t.Fatalf("Invalid Responce.") + } + + relayState.RedisClient.FlushAll().Result() + relayState.Load() +} + +func TestListDomainBlocked(t *testing.T) { + app := buildNewCmd() + + app.SetArgs([]string{"config", "import", "--json", "../misc/exampleConfig.json"}) + app.Execute() + + buffer := new(bytes.Buffer) + app.SetOutput(buffer) + + app.SetArgs([]string{"domain", "list", "-t", "blocked"}) + app.Execute() + + output := buffer.String() + valid := ` - Blocked domain : +blockedDomain.example.jp +Total : 1 +` + if output != valid { + t.Fatalf("Invalid Responce.") + } + + relayState.RedisClient.FlushAll().Result() + relayState.Load() +} + +func TestSetDomainBlocked(t *testing.T) { + app := buildNewCmd() + + app.SetArgs([]string{"domain", "set", "-t", "blocked", "testdomain.example.jp"}) + app.Execute() + + valid := false + for _, domain := range relayState.BlockedDomains { + if domain == "testdomain.example.jp" { + valid = true + } + } + + if !valid { + t.Fatalf("Not set blocked domain") + } + + relayState.RedisClient.FlushAll().Result() + relayState.Load() +} + +func TestSetDomainLimited(t *testing.T) { + app := buildNewCmd() + + app.SetArgs([]string{"domain", "set", "-t", "limited", "testdomain.example.jp"}) + app.Execute() + + valid := false + for _, domain := range relayState.LimitedDomains { + if domain == "testdomain.example.jp" { + valid = true + } + } + + if !valid { + t.Fatalf("Not set limited domain") + } + + relayState.RedisClient.FlushAll().Result() + relayState.Load() +} + +func TestUnsetDomainBlocked(t *testing.T) { + app := buildNewCmd() + + app.SetArgs([]string{"config", "import", "--json", "../misc/exampleConfig.json"}) + app.Execute() + + app.SetArgs([]string{"domain", "set", "-t", "blocked", "-u", "blockedDomain.example.jp"}) + app.Execute() + + valid := true + for _, domain := range relayState.BlockedDomains { + if domain == "blockedDomain.example.jp" { + valid = false + } + } + + if !valid { + t.Fatalf("Not unset blocked domain") + } + + relayState.RedisClient.FlushAll().Result() + relayState.Load() +} + +func TestUnsetDomainLimited(t *testing.T) { + app := buildNewCmd() + + app.SetArgs([]string{"config", "import", "--json", "../misc/exampleConfig.json"}) + app.Execute() + + app.SetArgs([]string{"domain", "set", "-t", "limited", "-u", "limitedDomain.example.jp"}) + app.Execute() + + valid := true + for _, domain := range relayState.LimitedDomains { + if domain == "limitedDomain.example.jp" { + valid = false + } + } + + if !valid { + t.Fatalf("Not unset blocked domain") + } + + relayState.RedisClient.FlushAll().Result() + relayState.Load() +} + +func TestSetDomainInvalid(t *testing.T) { + app := buildNewCmd() + + app.SetArgs([]string{"config", "import", "--json", "../misc/exampleConfig.json"}) + app.Execute() + + buffer := new(bytes.Buffer) + app.SetOutput(buffer) + + app.SetArgs([]string{"domain", "set", "-t", "hoge", "hoge.example.jp"}) + app.Execute() + + output := buffer.String() + if strings.Split(output, "\n")[0] != "Invalid type given" { + t.Fatalf("Invalid Responce.") + } + + relayState.RedisClient.FlushAll().Result() + relayState.Load() +} diff --git a/cli/follow.go b/cli/follow.go index 09c7b23..8410355 100644 --- a/cli/follow.go +++ b/cli/follow.go @@ -7,10 +7,47 @@ import ( "strings" "github.com/RichardKnop/machinery/v1/tasks" - "github.com/urfave/cli" + "github.com/spf13/cobra" "github.com/yukimochi/Activity-Relay/ActivityPub" + "github.com/yukimochi/Activity-Relay/State" ) +func followCmdInit() *cobra.Command { + var follow = &cobra.Command{ + Use: "follow", + Short: "Manage follow request for relay", + Long: "List all follow request and accept/reject follow requests.", + } + + var followList = &cobra.Command{ + Use: "list", + Short: "List follow request", + Long: "List follow request.", + RunE: listFollowsC, + } + follow.AddCommand(followList) + + var followAccept = &cobra.Command{ + Use: "accept", + Short: "Accept follow request", + Long: "Accept follow request by domain.", + Args: cobra.MinimumNArgs(1), + RunE: acceptFollowC, + } + follow.AddCommand(followAccept) + + var followReject = &cobra.Command{ + Use: "reject", + Short: "Reject follow request", + Long: "Reject follow request by domain.", + Args: cobra.MinimumNArgs(1), + RunE: rejectFollowC, + } + follow.AddCommand(followReject) + + return follow +} + func pushRegistorJob(inboxURL string, body []byte) { job := &tasks.Signature{ Name: "registor", @@ -34,12 +71,10 @@ func pushRegistorJob(inboxURL string, body []byte) { } } -func listFollows(c *cli.Context) error { - var err error +func listFollowsC(cmd *cobra.Command, args []string) error { var domains []string - - fmt.Println(" - Follow request :") - follows, err := redClient.Keys("relay:pending:*").Result() + cmd.Println(" - Follow request :") + follows, err := relayState.RedisClient.Keys("relay:pending:*").Result() if err != nil { return err } @@ -47,80 +82,88 @@ func listFollows(c *cli.Context) error { domains = append(domains, strings.Replace(follow, "relay:pending:", "", 1)) } for _, domain := range domains { - fmt.Println(domain) + cmd.Println(domain) } + cmd.Println(fmt.Sprintf("Total : %d", len(domains))) + return nil } -func acceptFollow(c *cli.Context) error { - domain := c.String("domain") - if domain != "" { - num, err := redClient.Exists("relay:pending:" + domain).Result() - if err != nil { - return err - } - if num == 0 { - fmt.Println("Given domain not found.") - return nil - } - - fmt.Println("Accept Follow request : " + domain) - data, err := redClient.HGetAll("relay:pending:" + domain).Result() - if err != nil { - return err - } - activity := activitypub.Activity{ - Context: []string{"https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1"}, - ID: data["activity_id"], - Actor: data["actor"], - Type: data["type"], - Object: data["object"], - } - - resp := activity.GenerateResponse(hostname, "Accept") - jsonData, _ := json.Marshal(&resp) - - pushRegistorJob(data["inbox_url"], jsonData) - redClient.HSet("relay:subscription:"+domain, "inbox_url", data["inbox_url"]) - redClient.Del("relay:pending:" + domain) - } else { - fmt.Println("No domain given.") +func createFollowRequestResponse(domain string, response string) error { + data, err := relayState.RedisClient.HGetAll("relay:pending:" + domain).Result() + if err != nil { + return err } + activity := activitypub.Activity{ + Context: []string{"https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1"}, + ID: data["activity_id"], + Actor: data["actor"], + Type: data["type"], + Object: data["object"], + } + + resp := activity.GenerateResponse(hostname, response) + jsonData, _ := json.Marshal(&resp) + pushRegistorJob(data["inbox_url"], jsonData) + relayState.RedisClient.Del("relay:pending:" + domain) + if response == "Accept" { + relayState.AddSubscription(state.Subscription{ + Domain: domain, + InboxURL: data["inbox_url"], + ActivityID: data["activity_id"], + ActorID: data["actor"], + }) + } + return nil } -func rejectFollow(c *cli.Context) error { - domain := c.String("domain") - if domain != "" { - num, err := redClient.Exists("relay:pending:" + domain).Result() - if err != nil { - return err - } - if num == 0 { - fmt.Println("Given domain not found.") - return nil - } - - fmt.Println("Reject Follow request : " + domain) - data, err := redClient.HGetAll("relay:pending:" + domain).Result() - if err != nil { - return err - } - activity := activitypub.Activity{ - Context: []string{"https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1"}, - ID: data["activity_id"], - Actor: data["actor"], - Type: data["type"], - Object: data["object"], - } - - resp := activity.GenerateResponse(hostname, "Reject") - jsonData, _ := json.Marshal(&resp) - - pushRegistorJob(data["inbox_url"], jsonData) - redClient.Del("relay:pending:" + domain) - } else { - fmt.Println("No domain given.") +func acceptFollowC(cmd *cobra.Command, args []string) error { + var err error + var domains []string + follows, err := relayState.RedisClient.Keys("relay:pending:*").Result() + if err != nil { + return err } + for _, follow := range follows { + domains = append(domains, strings.Replace(follow, "relay:pending:", "", 1)) + } + + for _, domain := range args { + for _, request := range domains { + if domain == request { + cmd.Println("Accept [" + domain + "] follow request") + createFollowRequestResponse(domain, "Accept") + break + } + } + cmd.Println("Invalid domain given") + } + + return nil +} + +func rejectFollowC(cmd *cobra.Command, args []string) error { + var err error + var domains []string + follows, err := redClient.Keys("relay:pending:*").Result() + if err != nil { + return err + } + for _, follow := range follows { + domains = append(domains, strings.Replace(follow, "relay:pending:", "", 1)) + } + + for _, domain := range args { + for _, request := range domains { + if domain == request { + cmd.Println("Reject [" + domain + "] follow request") + createFollowRequestResponse(domain, "Reject") + break + } + } + cmd.Println("Invalid domain given") + } + return nil } diff --git a/misc/blankConfig.json b/misc/blankConfig.json new file mode 100644 index 0000000..6a834b2 --- /dev/null +++ b/misc/blankConfig.json @@ -0,0 +1 @@ +{"RedisClient":{},"relayConfig":{"blockService":false,"manuallyAccept":false,"createAsAnnounce":false},"limitedDomains":null,"blockedDomains":null,"subscriptions":null} \ No newline at end of file diff --git a/misc/exampleConfig.json b/misc/exampleConfig.json new file mode 100644 index 0000000..7a28a9d --- /dev/null +++ b/misc/exampleConfig.json @@ -0,0 +1 @@ +{"RedisClient":{},"relayConfig":{"blockService":true,"manuallyAccept":true,"createAsAnnounce":true},"limitedDomains":["limitedDomain.example.jp"],"blockedDomains":["blockedDomain.example.jp"],"subscriptions":[{"domain":"subscription.example.jp","inbox_url":"https://subscription.example.jp/inbox","activity_id":"https://subscription.example.jp/UUID","actor_id":"https://subscription.example.jp/users/example"},{"domain":"subscription.example.com","inbox_url":"https://subscription.example.com/inbox","activity_id":"","actor_id":""}]} \ No newline at end of file