CLI tests for 'ntfy user'
This commit is contained in:
		
							parent
							
								
									1c9766b8fd
								
							
						
					
					
						commit
						29c2fc5472
					
				
					 4 changed files with 160 additions and 20 deletions
				
			
		
							
								
								
									
										60
									
								
								cmd/user.go
									
										
									
									
									
								
							
							
						
						
									
										60
									
								
								cmd/user.go
									
										
									
									
									
								
							|  | @ -23,8 +23,9 @@ var cmdUser = &cli.Command{ | ||||||
| 		{ | 		{ | ||||||
| 			Name:      "add", | 			Name:      "add", | ||||||
| 			Aliases:   []string{"a"}, | 			Aliases:   []string{"a"}, | ||||||
| 			Usage:     "add user", | 			Usage:     "Adds a new user", | ||||||
| 			UsageText: "ntfy user add [--role=admin|user] USERNAME", | 			UsageText: "ntfy user add [--role=admin|user] USERNAME", | ||||||
|  | 			Before:    inheritRootReaderFunc, | ||||||
| 			Action:    execUserAdd, | 			Action:    execUserAdd, | ||||||
| 			Flags: []cli.Flag{ | 			Flags: []cli.Flag{ | ||||||
| 				&cli.StringFlag{Name: "role", Aliases: []string{"r"}, Value: string(auth.RoleUser), Usage: "user role"}, | 				&cli.StringFlag{Name: "role", Aliases: []string{"r"}, Value: string(auth.RoleUser), Usage: "user role"}, | ||||||
|  | @ -43,8 +44,9 @@ Examples: | ||||||
| 		{ | 		{ | ||||||
| 			Name:      "remove", | 			Name:      "remove", | ||||||
| 			Aliases:   []string{"del", "rm"}, | 			Aliases:   []string{"del", "rm"}, | ||||||
| 			Usage:     "remove user", | 			Usage:     "Removes a user", | ||||||
| 			UsageText: "ntfy user remove USERNAME", | 			UsageText: "ntfy user remove USERNAME", | ||||||
|  | 			Before:    inheritRootReaderFunc, | ||||||
| 			Action:    execUserDel, | 			Action:    execUserDel, | ||||||
| 			Description: `Remove a user from the ntfy user database. | 			Description: `Remove a user from the ntfy user database. | ||||||
| 
 | 
 | ||||||
|  | @ -55,8 +57,9 @@ Example: | ||||||
| 		{ | 		{ | ||||||
| 			Name:      "change-pass", | 			Name:      "change-pass", | ||||||
| 			Aliases:   []string{"chp"}, | 			Aliases:   []string{"chp"}, | ||||||
| 			Usage:     "change user password", | 			Usage:     "Changes a user's password", | ||||||
| 			UsageText: "ntfy user change-pass USERNAME", | 			UsageText: "ntfy user change-pass USERNAME", | ||||||
|  | 			Before:    inheritRootReaderFunc, | ||||||
| 			Action:    execUserChangePass, | 			Action:    execUserChangePass, | ||||||
| 			Description: `Change the password for the given user. | 			Description: `Change the password for the given user. | ||||||
| 
 | 
 | ||||||
|  | @ -70,8 +73,9 @@ Example: | ||||||
| 		{ | 		{ | ||||||
| 			Name:      "change-role", | 			Name:      "change-role", | ||||||
| 			Aliases:   []string{"chr"}, | 			Aliases:   []string{"chr"}, | ||||||
| 			Usage:     "change user role", | 			Usage:     "Changes the role of a user", | ||||||
| 			UsageText: "ntfy user change-role USERNAME ROLE", | 			UsageText: "ntfy user change-role USERNAME ROLE", | ||||||
|  | 			Before:    inheritRootReaderFunc, | ||||||
| 			Action:    execUserChangeRole, | 			Action:    execUserChangeRole, | ||||||
| 			Description: `Change the role for the given user to admin or user. | 			Description: `Change the role for the given user to admin or user. | ||||||
| 
 | 
 | ||||||
|  | @ -92,7 +96,8 @@ Example: | ||||||
| 		{ | 		{ | ||||||
| 			Name:    "list", | 			Name:    "list", | ||||||
| 			Aliases: []string{"l"}, | 			Aliases: []string{"l"}, | ||||||
| 			Usage:   "list users", | 			Usage:   "Shows a list of users", | ||||||
|  | 			Before:  inheritRootReaderFunc, | ||||||
| 			Action:  execUserList, | 			Action:  execUserList, | ||||||
| 		}, | 		}, | ||||||
| 	}, | 	}, | ||||||
|  | @ -125,18 +130,21 @@ func execUserAdd(c *cli.Context) error { | ||||||
| 	} else if !auth.AllowedRole(role) { | 	} else if !auth.AllowedRole(role) { | ||||||
| 		return errors.New("role must be either 'user' or 'admin'") | 		return errors.New("role must be either 'user' or 'admin'") | ||||||
| 	} | 	} | ||||||
| 	password, err := readPassword(c) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	manager, err := createAuthManager(c) | 	manager, err := createAuthManager(c) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	if err := manager.AddUser(username, password, auth.Role(role)); err != nil { | 	if user, _ := manager.User(username); user != nil { | ||||||
|  | 		return fmt.Errorf("user %s already exists", username) | ||||||
|  | 	} | ||||||
|  | 	password, err := readPassword(c) | ||||||
|  | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	fmt.Fprintf(c.App.ErrWriter, "User %s added with role %s\n", username, role) | 	if err := manager.AddUser(username, password, role); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	fmt.Fprintf(c.App.ErrWriter, "user %s added with role %s\n", username, role) | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -151,10 +159,13 @@ func execUserDel(c *cli.Context) error { | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  | 	if _, err := manager.User(username); err == auth.ErrNotFound { | ||||||
|  | 		return fmt.Errorf("user %s does not exist", username) | ||||||
|  | 	} | ||||||
| 	if err := manager.RemoveUser(username); err != nil { | 	if err := manager.RemoveUser(username); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	fmt.Fprintf(c.App.ErrWriter, "User %s removed\n", username) | 	fmt.Fprintf(c.App.ErrWriter, "user %s removed\n", username) | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -165,18 +176,21 @@ func execUserChangePass(c *cli.Context) error { | ||||||
| 	} else if username == userEveryone { | 	} else if username == userEveryone { | ||||||
| 		return errors.New("username not allowed") | 		return errors.New("username not allowed") | ||||||
| 	} | 	} | ||||||
| 	password, err := readPassword(c) | 	manager, err := createAuthManager(c) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	manager, err := createAuthManager(c) | 	if _, err := manager.User(username); err == auth.ErrNotFound { | ||||||
|  | 		return fmt.Errorf("user %s does not exist", username) | ||||||
|  | 	} | ||||||
|  | 	password, err := readPassword(c) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	if err := manager.ChangePassword(username, password); err != nil { | 	if err := manager.ChangePassword(username, password); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	fmt.Fprintf(c.App.ErrWriter, "Changed password for user %s\n", username) | 	fmt.Fprintf(c.App.ErrWriter, "changed password for user %s\n", username) | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -192,10 +206,13 @@ func execUserChangeRole(c *cli.Context) error { | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  | 	if _, err := manager.User(username); err == auth.ErrNotFound { | ||||||
|  | 		return fmt.Errorf("user %s does not exist", username) | ||||||
|  | 	} | ||||||
| 	if err := manager.ChangeRole(username, role); err != nil { | 	if err := manager.ChangeRole(username, role); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	fmt.Fprintf(c.App.ErrWriter, "Changed role for user %s to %s\n", username, role) | 	fmt.Fprintf(c.App.ErrWriter, "changed role for user %s to %s\n", username, role) | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -251,3 +268,14 @@ func userCommandFlags() []cli.Flag { | ||||||
| 		altsrc.NewStringFlag(&cli.StringFlag{Name: "auth-default-access", Aliases: []string{"p"}, EnvVars: []string{"NTFY_AUTH_DEFAULT_ACCESS"}, Value: "read-write", Usage: "default permissions if no matching entries in the auth database are found"}), | 		altsrc.NewStringFlag(&cli.StringFlag{Name: "auth-default-access", Aliases: []string{"p"}, EnvVars: []string{"NTFY_AUTH_DEFAULT_ACCESS"}, Value: "read-write", Usage: "default permissions if no matching entries in the auth database are found"}), | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | // inheritRootReaderFunc is a workaround for a urfave/cli bug that makes subcommands not inherit the App.Reader. | ||||||
|  | // This bug was fixed in master, but not in v2.3.0. | ||||||
|  | func inheritRootReaderFunc(ctx *cli.Context) error { | ||||||
|  | 	for _, c := range ctx.Lineage() { | ||||||
|  | 		if c.App != nil && c.App.Reader != nil { | ||||||
|  | 			ctx.App.Reader = c.App.Reader | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										103
									
								
								cmd/user_test.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								cmd/user_test.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,103 @@ | ||||||
|  | package cmd | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"github.com/stretchr/testify/require" | ||||||
|  | 	"github.com/urfave/cli/v2" | ||||||
|  | 	"heckel.io/ntfy/server" | ||||||
|  | 	"heckel.io/ntfy/test" | ||||||
|  | 	"path/filepath" | ||||||
|  | 	"testing" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func TestCLI_User_Add(t *testing.T) { | ||||||
|  | 	s, conf, port := newTestServerWithAuth(t) | ||||||
|  | 	defer test.StopServer(t, s, port) | ||||||
|  | 
 | ||||||
|  | 	app, stdin, _, stderr := newTestApp() | ||||||
|  | 	stdin.WriteString("mypass\nmypass") | ||||||
|  | 	require.Nil(t, runUserCommand(app, conf, "add", "phil")) | ||||||
|  | 	require.Contains(t, stderr.String(), "user phil added with role user") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestCLI_User_Add_Exists(t *testing.T) { | ||||||
|  | 	s, conf, port := newTestServerWithAuth(t) | ||||||
|  | 	defer test.StopServer(t, s, port) | ||||||
|  | 
 | ||||||
|  | 	app, stdin, _, stderr := newTestApp() | ||||||
|  | 	stdin.WriteString("mypass\nmypass") | ||||||
|  | 	require.Nil(t, runUserCommand(app, conf, "add", "phil")) | ||||||
|  | 	require.Contains(t, stderr.String(), "user phil added with role user") | ||||||
|  | 
 | ||||||
|  | 	app, stdin, _, stderr = newTestApp() | ||||||
|  | 	stdin.WriteString("mypass\nmypass") | ||||||
|  | 	err := runUserCommand(app, conf, "add", "phil") | ||||||
|  | 	require.Error(t, err) | ||||||
|  | 	require.Contains(t, err.Error(), "user phil already exists") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestCLI_User_Add_Admin(t *testing.T) { | ||||||
|  | 	s, conf, port := newTestServerWithAuth(t) | ||||||
|  | 	defer test.StopServer(t, s, port) | ||||||
|  | 
 | ||||||
|  | 	app, stdin, _, stderr := newTestApp() | ||||||
|  | 	stdin.WriteString("mypass\nmypass") | ||||||
|  | 	require.Nil(t, runUserCommand(app, conf, "add", "--role=admin", "phil")) | ||||||
|  | 	require.Contains(t, stderr.String(), "user phil added with role admin") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestCLI_User_Add_Password_Mismatch(t *testing.T) { | ||||||
|  | 	s, conf, port := newTestServerWithAuth(t) | ||||||
|  | 	defer test.StopServer(t, s, port) | ||||||
|  | 
 | ||||||
|  | 	app, stdin, _, _ := newTestApp() | ||||||
|  | 	stdin.WriteString("mypass\nNOTMATCH") | ||||||
|  | 	err := runUserCommand(app, conf, "add", "phil") | ||||||
|  | 	require.Error(t, err) | ||||||
|  | 	require.Contains(t, err.Error(), "passwords do not match: try it again, but this time type slooowwwlly") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestCLI_User_ChangePass(t *testing.T) { | ||||||
|  | 	s, conf, port := newTestServerWithAuth(t) | ||||||
|  | 	defer test.StopServer(t, s, port) | ||||||
|  | 
 | ||||||
|  | 	// Add user | ||||||
|  | 	app, stdin, _, stderr := newTestApp() | ||||||
|  | 	stdin.WriteString("mypass\nmypass") | ||||||
|  | 	require.Nil(t, runUserCommand(app, conf, "add", "phil")) | ||||||
|  | 	require.Contains(t, stderr.String(), "user phil added with role user") | ||||||
|  | 
 | ||||||
|  | 	// Change pass | ||||||
|  | 	app, stdin, _, stderr = newTestApp() | ||||||
|  | 	stdin.WriteString("newpass\nnewpass") | ||||||
|  | 	require.Nil(t, runUserCommand(app, conf, "change-pass", "phil")) | ||||||
|  | 	require.Contains(t, stderr.String(), "changed password for user phil") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func newTestServerWithAuth(t *testing.T) (s *server.Server, conf *server.Config, port int) { | ||||||
|  | 	conf = server.NewConfig() | ||||||
|  | 	conf.AuthFile = filepath.Join(t.TempDir(), "user.db") | ||||||
|  | 	conf.AuthDefaultRead = false | ||||||
|  | 	conf.AuthDefaultWrite = false | ||||||
|  | 	s, port = test.StartServerWithConfig(t, conf) | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func runUserCommand(app *cli.App, conf *server.Config, args ...string) error { | ||||||
|  | 	var defaultAccess string | ||||||
|  | 	if conf.AuthDefaultRead && conf.AuthDefaultWrite { | ||||||
|  | 		defaultAccess = "read-write" | ||||||
|  | 	} else if conf.AuthDefaultRead && !conf.AuthDefaultWrite { | ||||||
|  | 		defaultAccess = "read-only" | ||||||
|  | 	} else if !conf.AuthDefaultRead && conf.AuthDefaultWrite { | ||||||
|  | 		defaultAccess = "write-only" | ||||||
|  | 	} else if !conf.AuthDefaultRead && !conf.AuthDefaultWrite { | ||||||
|  | 		defaultAccess = "deny-all" | ||||||
|  | 	} | ||||||
|  | 	userArgs := []string{ | ||||||
|  | 		"ntfy", | ||||||
|  | 		"user", | ||||||
|  | 		"--auth-file=" + conf.AuthFile, | ||||||
|  | 		"--auth-default-access=" + defaultAccess, | ||||||
|  | 	} | ||||||
|  | 	return app.Run(append(userArgs, args...)) | ||||||
|  | } | ||||||
							
								
								
									
										8
									
								
								go.mod
									
										
									
									
									
								
							
							
						
						
									
										8
									
								
								go.mod
									
										
									
									
									
								
							|  | @ -20,13 +20,13 @@ require ( | ||||||
| 	golang.org/x/sync v0.0.0-20210220032951-036812b2e83c | 	golang.org/x/sync v0.0.0-20210220032951-036812b2e83c | ||||||
| 	golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 | 	golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 | ||||||
| 	golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 | 	golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 | ||||||
| 	google.golang.org/api v0.66.0 | 	google.golang.org/api v0.67.0 | ||||||
| 	gopkg.in/yaml.v2 v2.4.0 | 	gopkg.in/yaml.v2 v2.4.0 | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| require ( | require ( | ||||||
| 	cloud.google.com/go v0.100.2 // indirect | 	cloud.google.com/go v0.100.2 // indirect | ||||||
| 	cloud.google.com/go/compute v1.1.0 // indirect | 	cloud.google.com/go/compute v1.2.0 // indirect | ||||||
| 	cloud.google.com/go/iam v0.1.1 // indirect | 	cloud.google.com/go/iam v0.1.1 // indirect | ||||||
| 	github.com/AlekSi/pointer v1.0.0 // indirect | 	github.com/AlekSi/pointer v1.0.0 // indirect | ||||||
| 	github.com/census-instrumentation/opencensus-proto v0.3.0 // indirect | 	github.com/census-instrumentation/opencensus-proto v0.3.0 // indirect | ||||||
|  | @ -46,11 +46,11 @@ require ( | ||||||
| 	github.com/russross/blackfriday/v2 v2.1.0 // indirect | 	github.com/russross/blackfriday/v2 v2.1.0 // indirect | ||||||
| 	go.opencensus.io v0.23.0 // indirect | 	go.opencensus.io v0.23.0 // indirect | ||||||
| 	golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d // indirect | 	golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d // indirect | ||||||
| 	golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect | 	golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 // indirect | ||||||
| 	golang.org/x/text v0.3.7 // indirect | 	golang.org/x/text v0.3.7 // indirect | ||||||
| 	golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect | 	golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect | ||||||
| 	google.golang.org/appengine v1.6.7 // indirect | 	google.golang.org/appengine v1.6.7 // indirect | ||||||
| 	google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350 // indirect | 	google.golang.org/genproto v0.0.0-20220203182621-f4ae394cde3f // indirect | ||||||
| 	google.golang.org/grpc v1.44.0 // indirect | 	google.golang.org/grpc v1.44.0 // indirect | ||||||
| 	google.golang.org/protobuf v1.27.1 // indirect | 	google.golang.org/protobuf v1.27.1 // indirect | ||||||
| 	gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect | 	gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect | ||||||
|  |  | ||||||
							
								
								
									
										9
									
								
								go.sum
									
										
									
									
									
								
							
							
						
						
									
										9
									
								
								go.sum
									
										
									
									
									
								
							|  | @ -39,6 +39,8 @@ cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM7 | ||||||
| cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= | cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= | ||||||
| cloud.google.com/go/compute v1.1.0 h1:pyPhehLfZ6pVzRgJmXGYvCY4K7WSWRhVw0AwhgVvS84= | cloud.google.com/go/compute v1.1.0 h1:pyPhehLfZ6pVzRgJmXGYvCY4K7WSWRhVw0AwhgVvS84= | ||||||
| cloud.google.com/go/compute v1.1.0/go.mod h1:2NIffxgWfORSI7EOYMFatGTfjMLnqrOKBEyYb6NoRgA= | cloud.google.com/go/compute v1.1.0/go.mod h1:2NIffxgWfORSI7EOYMFatGTfjMLnqrOKBEyYb6NoRgA= | ||||||
|  | cloud.google.com/go/compute v1.2.0 h1:EKki8sSdvDU0OO9mAXGwPXOTOgPz2l08R0/IutDH11I= | ||||||
|  | cloud.google.com/go/compute v1.2.0/go.mod h1:xlogom/6gr8RJGBe7nT2eGsQYAFUbbv8dbC29qE3Xmw= | ||||||
| cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= | ||||||
| cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= | cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= | ||||||
| cloud.google.com/go/firestore v1.6.1 h1:8rBq3zRjnHx8UtBvaOWqBB1xq9jH6/wltfQLlTMh2Fw= | cloud.google.com/go/firestore v1.6.1 h1:8rBq3zRjnHx8UtBvaOWqBB1xq9jH6/wltfQLlTMh2Fw= | ||||||
|  | @ -440,6 +442,8 @@ golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBc | ||||||
| golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||||
| golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0= | golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0= | ||||||
| golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||||
|  | golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 h1:XDXtA5hveEEV8JB2l7nhMTp3t3cHp9ZpwcdjqyEWLlo= | ||||||
|  | golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||||
| golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= | ||||||
| golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= | ||||||
| golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= | ||||||
|  | @ -553,6 +557,8 @@ google.golang.org/api v0.64.0/go.mod h1:931CdxA8Rm4t6zqTFGSsgwbAEZ2+GMYurbndwSim | ||||||
| google.golang.org/api v0.65.0/go.mod h1:ArYhxgGadlWmqO1IqVujw6Cs8IdD33bTmzKo2Sh+cbg= | google.golang.org/api v0.65.0/go.mod h1:ArYhxgGadlWmqO1IqVujw6Cs8IdD33bTmzKo2Sh+cbg= | ||||||
| google.golang.org/api v0.66.0 h1:CbGy4LEiXCVCiNEDFgGpWOVwsDT7E2Qej1ZvN1P7KPg= | google.golang.org/api v0.66.0 h1:CbGy4LEiXCVCiNEDFgGpWOVwsDT7E2Qej1ZvN1P7KPg= | ||||||
| google.golang.org/api v0.66.0/go.mod h1:I1dmXYpX7HGwz/ejRxwQp2qj5bFAz93HiCU1C1oYd9M= | google.golang.org/api v0.66.0/go.mod h1:I1dmXYpX7HGwz/ejRxwQp2qj5bFAz93HiCU1C1oYd9M= | ||||||
|  | google.golang.org/api v0.67.0 h1:lYaaLa+x3VVUhtosaK9xihwQ9H9KRa557REHwwZ2orM= | ||||||
|  | google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= | ||||||
| google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= | ||||||
| google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= | ||||||
| google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= | ||||||
|  | @ -633,6 +639,9 @@ google.golang.org/genproto v0.0.0-20220114231437-d2e6a121cae0/go.mod h1:5CzLGKJ6 | ||||||
| google.golang.org/genproto v0.0.0-20220118154757-00ab72f36ad5/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= | google.golang.org/genproto v0.0.0-20220118154757-00ab72f36ad5/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= | ||||||
| google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350 h1:YxHp5zqIcAShDEvRr5/0rVESVS+njYF68PSdazrNLJo= | google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350 h1:YxHp5zqIcAShDEvRr5/0rVESVS+njYF68PSdazrNLJo= | ||||||
| google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= | google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= | ||||||
|  | google.golang.org/genproto v0.0.0-20220201184016-50beb8ab5c44/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= | ||||||
|  | google.golang.org/genproto v0.0.0-20220203182621-f4ae394cde3f h1:w9Sx4FBkwsN0jMZz8E42tMdmhZ5b2Z/vFx2LKAxxI9o= | ||||||
|  | google.golang.org/genproto v0.0.0-20220203182621-f4ae394cde3f/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= | ||||||
| google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= | ||||||
| google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= | ||||||
| google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue