From 0edd3ae92596aa5b00dbff9504fc1895723c8f83 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Wed, 18 Dec 2024 10:39:25 +0100 Subject: [PATCH] add ability to set display and email to cli Signed-off-by: Kristoffer Dalby --- cmd/headscale/cli/routes.go | 6 +++--- cmd/headscale/cli/users.go | 26 ++++++++++++++++++++++++++ hscontrol/db/db_test.go | 8 ++++---- hscontrol/db/node_test.go | 24 ++++++++++++------------ hscontrol/db/preauth_keys_test.go | 18 +++++++++--------- hscontrol/db/routes_test.go | 8 ++++---- hscontrol/db/users.go | 11 ++++------- hscontrol/db/users_test.go | 14 +++++++------- hscontrol/grpcv1.go | 8 +++++++- 9 files changed, 76 insertions(+), 47 deletions(-) diff --git a/cmd/headscale/cli/routes.go b/cmd/headscale/cli/routes.go index dfbcb8fa8c..e39b407fb1 100644 --- a/cmd/headscale/cli/routes.go +++ b/cmd/headscale/cli/routes.go @@ -25,21 +25,21 @@ func init() { enableRouteCmd.Flags().Uint64P("route", "r", 0, "Route identifier (ID)") err := enableRouteCmd.MarkFlagRequired("route") if err != nil { - log.Fatalf(err.Error()) + log.Fatal(err.Error()) } routesCmd.AddCommand(enableRouteCmd) disableRouteCmd.Flags().Uint64P("route", "r", 0, "Route identifier (ID)") err = disableRouteCmd.MarkFlagRequired("route") if err != nil { - log.Fatalf(err.Error()) + log.Fatal(err.Error()) } routesCmd.AddCommand(disableRouteCmd) deleteRouteCmd.Flags().Uint64P("route", "r", 0, "Route identifier (ID)") err = deleteRouteCmd.MarkFlagRequired("route") if err != nil { - log.Fatalf(err.Error()) + log.Fatal(err.Error()) } routesCmd.AddCommand(deleteRouteCmd) } diff --git a/cmd/headscale/cli/users.go b/cmd/headscale/cli/users.go index 4032b82d4f..b65b890910 100644 --- a/cmd/headscale/cli/users.go +++ b/cmd/headscale/cli/users.go @@ -3,6 +3,7 @@ package cli import ( "errors" "fmt" + "net/url" survey "github.com/AlecAivazis/survey/v2" v1 "github.com/juanfont/headscale/gen/go/headscale/v1" @@ -40,6 +41,9 @@ func usernameAndIDFromFlag(cmd *cobra.Command) (uint64, string) { func init() { rootCmd.AddCommand(userCmd) userCmd.AddCommand(createUserCmd) + userCmd.Flags().StringP("display-name", "d", "", "Display name") + userCmd.Flags().StringP("email", "e", "", "Email") + userCmd.Flags().StringP("picture-url", "p", "", "Profile picture URL") userCmd.AddCommand(listUsersCmd) usernameAndIDFlag(listUsersCmd) listUsersCmd.Flags().StringP("email", "e", "", "Email") @@ -83,6 +87,28 @@ var createUserCmd = &cobra.Command{ request := &v1.CreateUserRequest{Name: userName} + if displayName, _ := cmd.Flags().GetString("display-name"); displayName != "" { + request.DisplayName = displayName + } + + if email, _ := cmd.Flags().GetString("email"); email != "" { + request.Email = email + } + + if pictureURL, _ := cmd.Flags().GetString("picture-url"); pictureURL != "" { + if _, err := url.Parse(pictureURL); err != nil { + ErrorOutput( + err, + fmt.Sprintf( + "Invalid Picture URL: %s", + err, + ), + output, + ) + } + request.PictureUrl = pictureURL + } + log.Trace().Interface("request", request).Msg("Sending CreateUser request") response, err := client.CreateUser(ctx, request) if err != nil { diff --git a/hscontrol/db/db_test.go b/hscontrol/db/db_test.go index 95c82160b7..c3d9a83568 100644 --- a/hscontrol/db/db_test.go +++ b/hscontrol/db/db_test.go @@ -278,9 +278,9 @@ func TestConstraints(t *testing.T) { { name: "no-duplicate-username-if-no-oidc", run: func(t *testing.T, db *gorm.DB) { - _, err := CreateUser(db, "user1") + _, err := CreateUser(db, types.User{Name: "user1"}) require.NoError(t, err) - _, err = CreateUser(db, "user1") + _, err = CreateUser(db, types.User{Name: "user1"}) requireConstraintFailed(t, err) }, }, @@ -331,7 +331,7 @@ func TestConstraints(t *testing.T) { { name: "allow-duplicate-username-cli-then-oidc", run: func(t *testing.T, db *gorm.DB) { - _, err := CreateUser(db, "user1") // Create CLI username + _, err := CreateUser(db, types.User{Name: "user1"}) // Create CLI username require.NoError(t, err) user := types.User{ @@ -354,7 +354,7 @@ func TestConstraints(t *testing.T) { err := db.Save(&user).Error require.NoError(t, err) - _, err = CreateUser(db, "user1") // Create CLI username + _, err = CreateUser(db, types.User{Name: "user1"}) // Create CLI username require.NoError(t, err) }, }, diff --git a/hscontrol/db/node_test.go b/hscontrol/db/node_test.go index 7c83c1be42..270fd91b2e 100644 --- a/hscontrol/db/node_test.go +++ b/hscontrol/db/node_test.go @@ -27,7 +27,7 @@ import ( ) func (s *Suite) TestGetNode(c *check.C) { - user, err := db.CreateUser("test") + user, err := db.CreateUser(types.User{Name: "test"}) c.Assert(err, check.IsNil) pak, err := db.CreatePreAuthKey(types.UserID(user.ID), false, false, nil, nil) @@ -56,7 +56,7 @@ func (s *Suite) TestGetNode(c *check.C) { } func (s *Suite) TestGetNodeByID(c *check.C) { - user, err := db.CreateUser("test") + user, err := db.CreateUser(types.User{Name: "test"}) c.Assert(err, check.IsNil) pak, err := db.CreatePreAuthKey(types.UserID(user.ID), false, false, nil, nil) @@ -85,7 +85,7 @@ func (s *Suite) TestGetNodeByID(c *check.C) { } func (s *Suite) TestGetNodeByAnyNodeKey(c *check.C) { - user, err := db.CreateUser("test") + user, err := db.CreateUser(types.User{Name: "test"}) c.Assert(err, check.IsNil) pak, err := db.CreatePreAuthKey(types.UserID(user.ID), false, false, nil, nil) @@ -116,7 +116,7 @@ func (s *Suite) TestGetNodeByAnyNodeKey(c *check.C) { } func (s *Suite) TestHardDeleteNode(c *check.C) { - user, err := db.CreateUser("test") + user, err := db.CreateUser(types.User{Name: "test"}) c.Assert(err, check.IsNil) nodeKey := key.NewNode() @@ -141,7 +141,7 @@ func (s *Suite) TestHardDeleteNode(c *check.C) { } func (s *Suite) TestListPeers(c *check.C) { - user, err := db.CreateUser("test") + user, err := db.CreateUser(types.User{Name: "test"}) c.Assert(err, check.IsNil) pak, err := db.CreatePreAuthKey(types.UserID(user.ID), false, false, nil, nil) @@ -188,7 +188,7 @@ func (s *Suite) TestGetACLFilteredPeers(c *check.C) { stor := make([]base, 0) for _, name := range []string{"test", "admin"} { - user, err := db.CreateUser(name) + user, err := db.CreateUser(types.User{Name: name}) c.Assert(err, check.IsNil) pak, err := db.CreatePreAuthKey(types.UserID(user.ID), false, false, nil, nil) c.Assert(err, check.IsNil) @@ -279,7 +279,7 @@ func (s *Suite) TestGetACLFilteredPeers(c *check.C) { } func (s *Suite) TestExpireNode(c *check.C) { - user, err := db.CreateUser("test") + user, err := db.CreateUser(types.User{Name: "test"}) c.Assert(err, check.IsNil) pak, err := db.CreatePreAuthKey(types.UserID(user.ID), false, false, nil, nil) @@ -320,7 +320,7 @@ func (s *Suite) TestExpireNode(c *check.C) { } func (s *Suite) TestSetTags(c *check.C) { - user, err := db.CreateUser("test") + user, err := db.CreateUser(types.User{Name: "test"}) c.Assert(err, check.IsNil) pak, err := db.CreatePreAuthKey(types.UserID(user.ID), false, false, nil, nil) @@ -565,7 +565,7 @@ func TestAutoApproveRoutes(t *testing.T) { require.NoError(t, err) require.NotNil(t, pol) - user, err := adb.CreateUser("test") + user, err := adb.CreateUser(types.User{Name: "test"}) require.NoError(t, err) pak, err := adb.CreatePreAuthKey(types.UserID(user.ID), false, false, nil, nil) @@ -706,7 +706,7 @@ func TestListEphemeralNodes(t *testing.T) { t.Fatalf("creating db: %s", err) } - user, err := db.CreateUser("test") + user, err := db.CreateUser(types.User{Name: "test"}) require.NoError(t, err) pak, err := db.CreatePreAuthKey(types.UserID(user.ID), false, false, nil, nil) @@ -762,10 +762,10 @@ func TestRenameNode(t *testing.T) { t.Fatalf("creating db: %s", err) } - user, err := db.CreateUser("test") + user, err := db.CreateUser(types.User{Name: "test"}) require.NoError(t, err) - user2, err := db.CreateUser("test2") + user2, err := db.CreateUser(types.User{Name: "user2"}) require.NoError(t, err) node := types.Node{ diff --git a/hscontrol/db/preauth_keys_test.go b/hscontrol/db/preauth_keys_test.go index 3c56a35e8c..a3a24ac72d 100644 --- a/hscontrol/db/preauth_keys_test.go +++ b/hscontrol/db/preauth_keys_test.go @@ -15,7 +15,7 @@ func (*Suite) TestCreatePreAuthKey(c *check.C) { _, err := db.CreatePreAuthKey(12345, true, false, nil, nil) c.Assert(err, check.NotNil) - user, err := db.CreateUser("test") + user, err := db.CreateUser(types.User{Name: "test"}) c.Assert(err, check.IsNil) key, err := db.CreatePreAuthKey(types.UserID(user.ID), true, false, nil, nil) @@ -41,7 +41,7 @@ func (*Suite) TestCreatePreAuthKey(c *check.C) { } func (*Suite) TestExpiredPreAuthKey(c *check.C) { - user, err := db.CreateUser("test2") + user, err := db.CreateUser(types.User{Name: "test2"}) c.Assert(err, check.IsNil) now := time.Now().Add(-5 * time.Second) @@ -60,7 +60,7 @@ func (*Suite) TestPreAuthKeyDoesNotExist(c *check.C) { } func (*Suite) TestValidateKeyOk(c *check.C) { - user, err := db.CreateUser("test3") + user, err := db.CreateUser(types.User{Name: "test3"}) c.Assert(err, check.IsNil) pak, err := db.CreatePreAuthKey(types.UserID(user.ID), true, false, nil, nil) @@ -72,7 +72,7 @@ func (*Suite) TestValidateKeyOk(c *check.C) { } func (*Suite) TestAlreadyUsedKey(c *check.C) { - user, err := db.CreateUser("test4") + user, err := db.CreateUser(types.User{Name: "test4"}) c.Assert(err, check.IsNil) pak, err := db.CreatePreAuthKey(types.UserID(user.ID), false, false, nil, nil) @@ -94,7 +94,7 @@ func (*Suite) TestAlreadyUsedKey(c *check.C) { } func (*Suite) TestReusableBeingUsedKey(c *check.C) { - user, err := db.CreateUser("test5") + user, err := db.CreateUser(types.User{Name: "test5"}) c.Assert(err, check.IsNil) pak, err := db.CreatePreAuthKey(types.UserID(user.ID), true, false, nil, nil) @@ -116,7 +116,7 @@ func (*Suite) TestReusableBeingUsedKey(c *check.C) { } func (*Suite) TestNotReusableNotBeingUsedKey(c *check.C) { - user, err := db.CreateUser("test6") + user, err := db.CreateUser(types.User{Name: "test6"}) c.Assert(err, check.IsNil) pak, err := db.CreatePreAuthKey(types.UserID(user.ID), false, false, nil, nil) @@ -128,7 +128,7 @@ func (*Suite) TestNotReusableNotBeingUsedKey(c *check.C) { } func (*Suite) TestExpirePreauthKey(c *check.C) { - user, err := db.CreateUser("test3") + user, err := db.CreateUser(types.User{Name: "test3"}) c.Assert(err, check.IsNil) pak, err := db.CreatePreAuthKey(types.UserID(user.ID), true, false, nil, nil) @@ -145,7 +145,7 @@ func (*Suite) TestExpirePreauthKey(c *check.C) { } func (*Suite) TestNotReusableMarkedAsUsed(c *check.C) { - user, err := db.CreateUser("test6") + user, err := db.CreateUser(types.User{Name: "test6"}) c.Assert(err, check.IsNil) pak, err := db.CreatePreAuthKey(types.UserID(user.ID), false, false, nil, nil) @@ -158,7 +158,7 @@ func (*Suite) TestNotReusableMarkedAsUsed(c *check.C) { } func (*Suite) TestPreAuthKeyACLTags(c *check.C) { - user, err := db.CreateUser("test8") + user, err := db.CreateUser(types.User{Name: "test8"}) c.Assert(err, check.IsNil) _, err = db.CreatePreAuthKey(types.UserID(user.ID), false, false, nil, []string{"badtag"}) diff --git a/hscontrol/db/routes_test.go b/hscontrol/db/routes_test.go index ed9d4c042e..909024fc80 100644 --- a/hscontrol/db/routes_test.go +++ b/hscontrol/db/routes_test.go @@ -32,7 +32,7 @@ var mp = func(p string) netip.Prefix { } func (s *Suite) TestGetRoutes(c *check.C) { - user, err := db.CreateUser("test") + user, err := db.CreateUser(types.User{Name: "test"}) c.Assert(err, check.IsNil) pak, err := db.CreatePreAuthKey(types.UserID(user.ID), false, false, nil, nil) @@ -76,7 +76,7 @@ func (s *Suite) TestGetRoutes(c *check.C) { } func (s *Suite) TestGetEnableRoutes(c *check.C) { - user, err := db.CreateUser("test") + user, err := db.CreateUser(types.User{Name: "test"}) c.Assert(err, check.IsNil) pak, err := db.CreatePreAuthKey(types.UserID(user.ID), false, false, nil, nil) @@ -150,7 +150,7 @@ func (s *Suite) TestGetEnableRoutes(c *check.C) { } func (s *Suite) TestIsUniquePrefix(c *check.C) { - user, err := db.CreateUser("test") + user, err := db.CreateUser(types.User{Name: "test"}) c.Assert(err, check.IsNil) pak, err := db.CreatePreAuthKey(types.UserID(user.ID), false, false, nil, nil) @@ -231,7 +231,7 @@ func (s *Suite) TestIsUniquePrefix(c *check.C) { } func (s *Suite) TestDeleteRoutes(c *check.C) { - user, err := db.CreateUser("test") + user, err := db.CreateUser(types.User{Name: "test"}) c.Assert(err, check.IsNil) pak, err := db.CreatePreAuthKey(types.UserID(user.ID), false, false, nil, nil) diff --git a/hscontrol/db/users.go b/hscontrol/db/users.go index 0eaa9ea348..3fdc14a0bb 100644 --- a/hscontrol/db/users.go +++ b/hscontrol/db/users.go @@ -15,22 +15,19 @@ var ( ErrUserStillHasNodes = errors.New("user not empty: node(s) found") ) -func (hsdb *HSDatabase) CreateUser(name string) (*types.User, error) { +func (hsdb *HSDatabase) CreateUser(user types.User) (*types.User, error) { return Write(hsdb.DB, func(tx *gorm.DB) (*types.User, error) { - return CreateUser(tx, name) + return CreateUser(tx, user) }) } // CreateUser creates a new User. Returns error if could not be created // or another user already exists. -func CreateUser(tx *gorm.DB, name string) (*types.User, error) { - err := util.CheckForFQDNRules(name) +func CreateUser(tx *gorm.DB, user types.User) (*types.User, error) { + err := util.CheckForFQDNRules(user.Name) if err != nil { return nil, err } - user := types.User{ - Name: name, - } if err := tx.Create(&user).Error; err != nil { return nil, fmt.Errorf("creating user: %w", err) } diff --git a/hscontrol/db/users_test.go b/hscontrol/db/users_test.go index 0607376277..6cec2d5a79 100644 --- a/hscontrol/db/users_test.go +++ b/hscontrol/db/users_test.go @@ -11,7 +11,7 @@ import ( ) func (s *Suite) TestCreateAndDestroyUser(c *check.C) { - user, err := db.CreateUser("test") + user, err := db.CreateUser(types.User{Name: "test"}) c.Assert(err, check.IsNil) c.Assert(user.Name, check.Equals, "test") @@ -30,7 +30,7 @@ func (s *Suite) TestDestroyUserErrors(c *check.C) { err := db.DestroyUser(9998) c.Assert(err, check.Equals, ErrUserNotFound) - user, err := db.CreateUser("test") + user, err := db.CreateUser(types.User{Name: "test"}) c.Assert(err, check.IsNil) pak, err := db.CreatePreAuthKey(types.UserID(user.ID), false, false, nil, nil) @@ -43,7 +43,7 @@ func (s *Suite) TestDestroyUserErrors(c *check.C) { // destroying a user also deletes all associated preauthkeys c.Assert(result.Error, check.Equals, gorm.ErrRecordNotFound) - user, err = db.CreateUser("test") + user, err = db.CreateUser(types.User{Name: "test"}) c.Assert(err, check.IsNil) pak, err = db.CreatePreAuthKey(types.UserID(user.ID), false, false, nil, nil) @@ -64,7 +64,7 @@ func (s *Suite) TestDestroyUserErrors(c *check.C) { } func (s *Suite) TestRenameUser(c *check.C) { - userTest, err := db.CreateUser("test") + userTest, err := db.CreateUser(types.User{Name: "test"}) c.Assert(err, check.IsNil) c.Assert(userTest.Name, check.Equals, "test") @@ -86,7 +86,7 @@ func (s *Suite) TestRenameUser(c *check.C) { err = db.RenameUser(99988, "test") c.Assert(err, check.Equals, ErrUserNotFound) - userTest2, err := db.CreateUser("test2") + userTest2, err := db.CreateUser(types.User{Name: "test2"}) c.Assert(err, check.IsNil) c.Assert(userTest2.Name, check.Equals, "test2") @@ -98,10 +98,10 @@ func (s *Suite) TestRenameUser(c *check.C) { } func (s *Suite) TestSetMachineUser(c *check.C) { - oldUser, err := db.CreateUser("old") + oldUser, err := db.CreateUser(types.User{Name: "old"}) c.Assert(err, check.IsNil) - newUser, err := db.CreateUser("new") + newUser, err := db.CreateUser(types.User{Name: "new"}) c.Assert(err, check.IsNil) pak, err := db.CreatePreAuthKey(types.UserID(oldUser.ID), false, false, nil, nil) diff --git a/hscontrol/grpcv1.go b/hscontrol/grpcv1.go index 7daa847895..b7c7e50e8d 100644 --- a/hscontrol/grpcv1.go +++ b/hscontrol/grpcv1.go @@ -43,7 +43,13 @@ func (api headscaleV1APIServer) CreateUser( ctx context.Context, request *v1.CreateUserRequest, ) (*v1.CreateUserResponse, error) { - user, err := api.h.db.CreateUser(request.GetName()) + newUser := types.User{ + Name: request.GetName(), + DisplayName: request.GetDisplayName(), + Email: request.GetEmail(), + ProfilePicURL: request.GetPictureUrl(), + } + user, err := api.h.db.CreateUser(newUser) if err != nil { return nil, err }