Skip to content

Commit

Permalink
feat: Added 'accept list' management command to orb-cli
Browse files Browse the repository at this point in the history
Added an 'acceptlist' command to orb-cli that manages accept lists that are used by the 'Follow' and 'Invite' witness authorization handlers. The command has three sub-commands:

- add - Adds one or more actor URIs to the accept list of a given type (follow or invite-witness)
- remove - Removes one or more actor URIs from the accept list of a given type (follow or invite-witness)
- get - Retrieves all accept lists or an accept list of a specified type (follow or invite-witness)

closes #865

Signed-off-by: Bob Stasyszyn <Bob.Stasyszyn@securekey.com>
  • Loading branch information
bstasyszyn committed Nov 10, 2021
1 parent ecebebb commit 90084f7
Show file tree
Hide file tree
Showing 15 changed files with 663 additions and 21 deletions.
50 changes: 50 additions & 0 deletions cmd/orb-cli/acceptlistcmd/acceptlist.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
Copyright SecureKey Technologies Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package acceptlistcmd

import (
"errors"

"github.com/spf13/cobra"
)

const (
urlFlagName = "url"
urlFlagUsage = "The URL of the accept list REST endpoint." +
" Alternatively, this can be set with the following environment variable: " + urlEnvKey
urlEnvKey = "ORB_CLI_URL"

actorFlagName = "actor"
actorFlagUsage = "A comma-separated list of service URIs to add to/remove from the accept list." +
" Alternatively, this can be set with the following environment variable: " + actorEnvKey
actorEnvKey = "ORB_CLI_ACTOR"

typeFlagName = "type"
typeFlagUsage = "Accept list type (follow or invite-witness)." +
" Alternatively, this can be set with the following environment variable: " + typeEnvKey
typeEnvKey = "ORB_CLI_ACCEPT_TYPE"
)

// GetCmd returns the Cobra acceptlist command.
func GetCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "acceptlist",
Short: "Manages accept lists.",
Long: "Manages accept lists for 'Follow' and 'Invite' witness authorization handlers.",
RunE: func(cmd *cobra.Command, args []string) error {
return errors.New("expecting subcommand add, remove, or get")
},
}

cmd.AddCommand(
newAddCmd(),
newRemoveCmd(),
newGetCmd(),
)

return cmd
}
21 changes: 21 additions & 0 deletions cmd/orb-cli/acceptlistcmd/acceptlist_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
Copyright SecureKey Technologies Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package acceptlistcmd

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestAcceptListCmd(t *testing.T) {
t.Run("test missing subcommand", func(t *testing.T) {
err := GetCmd().Execute()
require.Error(t, err)
require.Contains(t, err.Error(), "expecting subcommand add, remove, or get")
})
}
66 changes: 66 additions & 0 deletions cmd/orb-cli/acceptlistcmd/getcmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
Copyright SecureKey Technologies Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package acceptlistcmd

import (
"fmt"
"net/http"
"net/url"

"github.com/spf13/cobra"
cmdutils "github.com/trustbloc/edge-core/pkg/utils/cmd"

"github.com/trustbloc/orb/cmd/orb-cli/common"
)

func newGetCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "get",
Short: "Retrieves accept lists.",
Long: "Retrieves accept lists used by the 'Follow' and 'Invite' witness authorization handlers.",
RunE: func(cmd *cobra.Command, args []string) error {
return executeGet(cmd)
},
}

common.AddCommonFlags(cmd)

cmd.Flags().StringP(urlFlagName, "", "", urlFlagUsage)
cmd.Flags().StringP(typeFlagName, "", "", typeFlagUsage)

return cmd
}

func executeGet(cmd *cobra.Command) error {
u, err := cmdutils.GetUserSetVarFromString(cmd, urlFlagName, urlEnvKey, false)
if err != nil {
return err
}

_, err = url.Parse(u)
if err != nil {
return fmt.Errorf("invalid URL %s: %w", u, err)
}

acceptType, err := cmdutils.GetUserSetVarFromString(cmd, typeFlagName, typeEnvKey, true)
if err != nil {
return err
}

if acceptType != "" {
u = fmt.Sprintf("%s?type=%s", u, acceptType)
}

resp, err := common.SendHTTPRequest(cmd, nil, http.MethodGet, u)
if err != nil {
return err
}

fmt.Println(string(resp))

return nil
}
62 changes: 62 additions & 0 deletions cmd/orb-cli/acceptlistcmd/getcmd_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
Copyright SecureKey Technologies Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package acceptlistcmd

import (
"fmt"
"net/http"
"net/http/httptest"
"testing"

"github.com/stretchr/testify/require"
)

func TestGetCmd(t *testing.T) {
t.Run("test missing url arg", func(t *testing.T) {
cmd := GetCmd()
cmd.SetArgs([]string{"get"})

err := cmd.Execute()

require.Error(t, err)
require.Equal(t,
"Neither url (command line flag) nor ORB_CLI_URL (environment variable) have been set.",
err.Error())
})

t.Run("test invalid url arg", func(t *testing.T) {
cmd := GetCmd()

args := []string{"get"}
args = append(args, urlArg(":invalid")...)
cmd.SetArgs(args)

err := cmd.Execute()

require.Error(t, err)
require.Contains(t, err.Error(), "invalid URL")
})

t.Run("success", func(t *testing.T) {
serv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_, err := fmt.Fprint(w, "d1")
require.NoError(t, err)
}))

cmd := GetCmd()

args := []string{"get"}
args = append(args, urlArg(serv.URL)...)
args = append(args, typeArg("follow")...)
cmd.SetArgs(args)

cmd.SetArgs(args)
err := cmd.Execute()

require.NoError(t, err)
})
}
125 changes: 125 additions & 0 deletions cmd/orb-cli/acceptlistcmd/updatecmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
Copyright SecureKey Technologies Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package acceptlistcmd

import (
"encoding/json"
"fmt"
"net/http"
"net/url"

"github.com/spf13/cobra"
cmdutils "github.com/trustbloc/edge-core/pkg/utils/cmd"

"github.com/trustbloc/orb/cmd/orb-cli/common"
)

func newAddCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "add",
Short: "Adds actors to an accept list.",
Long: "Adds actors to an accept list used by the 'Follow' and 'Invite' witness authorization handlers.",
RunE: func(cmd *cobra.Command, args []string) error {
return executeUpdate(cmd, true)
},
}

addUpdateFlags(cmd)

return cmd
}

func newRemoveCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "remove",
Short: "Removes actors from an accept list.",
Long: "Removes actors from an accept list used by the 'Follow' and 'Invite' witness authorization handlers.",
RunE: func(cmd *cobra.Command, args []string) error {
return executeUpdate(cmd, false)
},
}

addUpdateFlags(cmd)

return cmd
}

func executeUpdate(cmd *cobra.Command, isAdd bool) error {
u, acceptType, actors, err := getUpdateArgs(cmd)
if err != nil {
return err
}

req := acceptListRequest{
Type: acceptType,
}

if isAdd {
req.Add = actors
} else {
req.Remove = actors
}

reqBytes, err := json.Marshal([]acceptListRequest{req})
if err != nil {
return err
}

_, err = common.SendHTTPRequest(cmd, reqBytes, http.MethodPost, u)
if err != nil {
return err
}

fmt.Println("Accept list has successfully been updated.")

return nil
}

func addUpdateFlags(cmd *cobra.Command) {
common.AddCommonFlags(cmd)

cmd.Flags().StringP(urlFlagName, "", "", urlFlagUsage)
cmd.Flags().StringArrayP(actorFlagName, "", nil, actorFlagUsage)
cmd.Flags().StringP(typeFlagName, "", "", typeFlagUsage)
}

func getUpdateArgs(cmd *cobra.Command) (u, acceptType string, actors []string, err error) {
u, err = cmdutils.GetUserSetVarFromString(cmd, urlFlagName, urlEnvKey, false)
if err != nil {
return "", "", nil, err
}

_, err = url.Parse(u)
if err != nil {
return "", "", nil, fmt.Errorf("invalid URL %s: %w", u, err)
}

acceptType, err = cmdutils.GetUserSetVarFromString(cmd, typeFlagName, typeEnvKey, false)
if err != nil {
return "", "", nil, err
}

actors, err = cmdutils.GetUserSetVarFromArrayString(cmd, actorFlagName, actorEnvKey, false)
if err != nil {
return "", "", nil, err
}

for _, actor := range actors {
_, err = url.Parse(actor)
if err != nil {
return "", "", nil, fmt.Errorf("invalid actor URL %s: %w", u, err)
}
}

return u, acceptType, actors, nil
}

type acceptListRequest struct {
Type string `json:"type"`
Add []string `json:"add,omitempty"`
Remove []string `json:"remove,omitempty"`
}
Loading

0 comments on commit 90084f7

Please sign in to comment.