mirror of
https://github.com/moul/sshportal.git
synced 2025-09-10 22:54:49 +08:00
Add 'user {create,inspect,ls,rm}' commands
This commit is contained in:
parent
9fc9300c34
commit
e256ac66cf
2 changed files with 140 additions and 46 deletions
23
db.go
23
db.go
|
@ -37,6 +37,7 @@ type Host struct {
|
|||
type User struct {
|
||||
// FIXME: use uuid for ID
|
||||
gorm.Model
|
||||
Email string // FIXME: govalidator: email
|
||||
Name string // FIXME: govalidator: min length 3, alphanum
|
||||
SSHKeys []SSHKey
|
||||
Comment string
|
||||
|
@ -48,7 +49,7 @@ func dbInit(db *gorm.DB) error {
|
|||
db.AutoMigrate(&Host{})
|
||||
db.Exec(`CREATE UNIQUE INDEX uix_keys_name ON "ssh_keys"("name") WHERE ("deleted_at" IS NULL)`)
|
||||
db.Exec(`CREATE UNIQUE INDEX uix_hosts_name ON "hosts"("name") WHERE ("deleted_at" IS NULL)`)
|
||||
db.Exec(`CREATE UNIQUE INDEX uix_users_name ON "users"("name") WHERE ("deleted_at" IS NULL)`)
|
||||
db.Exec(`CREATE UNIQUE INDEX uix_users_name ON "users"("email") WHERE ("deleted_at" IS NULL)`)
|
||||
|
||||
// create default ssh key
|
||||
var count uint
|
||||
|
@ -160,3 +161,23 @@ func FindKeysByIdOrName(db *gorm.DB, queries []string) ([]*SSHKey, error) {
|
|||
}
|
||||
return keys, nil
|
||||
}
|
||||
|
||||
func FindUserByIdOrEmail(db *gorm.DB, query string) (*User, error) {
|
||||
var user User
|
||||
if err := db.Where("id = ?", query).Or("email = ?", query).First(&user).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
func FindUsersByIdOrEmail(db *gorm.DB, queries []string) ([]*User, error) {
|
||||
var users []*User
|
||||
for _, query := range queries {
|
||||
user, err := FindUserByIdOrEmail(db, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
users = append(users, user)
|
||||
}
|
||||
return users, nil
|
||||
}
|
||||
|
|
163
shell.go
163
shell.go
|
@ -52,15 +52,15 @@ GLOBAL OPTIONS:
|
|||
app.Commands = []cli.Command{
|
||||
{
|
||||
Name: "host",
|
||||
Usage: "Manage hosts",
|
||||
Usage: "Manages hosts",
|
||||
Subcommands: []cli.Command{
|
||||
{
|
||||
Name: "create",
|
||||
Usage: "Create a new host",
|
||||
Usage: "Creates a new host",
|
||||
ArgsUsage: "<user>[:<password>]@<host>[:<port>]",
|
||||
Description: "$> host create bart@foo.org\n $> host create bob:marley@example.com:2222",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{Name: "name", Usage: "Assign a name to the host"},
|
||||
cli.StringFlag{Name: "name", Usage: "Assigns a name to the host"},
|
||||
cli.StringFlag{Name: "password", Usage: "If present, sshportal will use password-based authentication"},
|
||||
cli.StringFlag{Name: "fingerprint", Usage: "SSH host key fingerprint"},
|
||||
cli.StringFlag{Name: "comment"},
|
||||
|
@ -107,10 +107,9 @@ GLOBAL OPTIONS:
|
|||
fmt.Fprintf(s, "%d\n", host.ID)
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
}, {
|
||||
Name: "inspect",
|
||||
Usage: "Display detailed information on one or more hosts",
|
||||
Usage: "Shows detailed information on one or more hosts",
|
||||
ArgsUsage: "<id or name> [<id or name> [<ir or name>...]]",
|
||||
Action: func(c *cli.Context) error {
|
||||
if c.NArg() < 1 {
|
||||
|
@ -126,10 +125,9 @@ GLOBAL OPTIONS:
|
|||
enc.SetIndent("", " ")
|
||||
return enc.Encode(hosts)
|
||||
},
|
||||
},
|
||||
{
|
||||
}, {
|
||||
Name: "ls",
|
||||
Usage: "List hosts",
|
||||
Usage: "Lists hosts",
|
||||
Action: func(c *cli.Context) error {
|
||||
var hosts []Host
|
||||
if err := db.Find(&hosts).Error; err != nil {
|
||||
|
@ -163,10 +161,9 @@ GLOBAL OPTIONS:
|
|||
table.Render()
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
}, {
|
||||
Name: "rm",
|
||||
Usage: "Remove one or more hosts",
|
||||
Usage: "Removes one or more hosts",
|
||||
ArgsUsage: "<id or name> [<id or name> [<ir or name>...]]",
|
||||
Action: func(c *cli.Context) error {
|
||||
if c.NArg() < 1 {
|
||||
|
@ -188,7 +185,7 @@ GLOBAL OPTIONS:
|
|||
},
|
||||
}, {
|
||||
Name: "info",
|
||||
Usage: "Display system-wide information",
|
||||
Usage: "Shows system-wide information",
|
||||
Action: func(c *cli.Context) error {
|
||||
fmt.Fprintf(s, "Debug mode (server): %v\n", globalContext.Bool("debug"))
|
||||
hostname, _ := os.Hostname()
|
||||
|
@ -213,14 +210,14 @@ GLOBAL OPTIONS:
|
|||
},
|
||||
}, {
|
||||
Name: "key",
|
||||
Usage: "Manage keys",
|
||||
Usage: "Manages keys",
|
||||
Subcommands: []cli.Command{
|
||||
{
|
||||
Name: "create",
|
||||
Usage: "Create a new key",
|
||||
Usage: "Creates a new key",
|
||||
Description: "$> key create\n $> key create --name=mykey",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{Name: "name", Usage: "Assign a name to the host"},
|
||||
cli.StringFlag{Name: "name", Usage: "Assigns a name to the key"},
|
||||
cli.StringFlag{Name: "type", Value: "rsa"},
|
||||
cli.UintFlag{Name: "length", Value: 2048},
|
||||
cli.StringFlag{Name: "comment"},
|
||||
|
@ -249,10 +246,9 @@ GLOBAL OPTIONS:
|
|||
fmt.Fprintf(s, "%d\n", key.ID)
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
}, {
|
||||
Name: "inspect",
|
||||
Usage: "Display detailed information on one or more keys",
|
||||
Usage: "Shows detailed information on one or more keys",
|
||||
ArgsUsage: "<id or name> [<id or name> [<ir or name>...]]",
|
||||
Action: func(c *cli.Context) error {
|
||||
if c.NArg() < 1 {
|
||||
|
@ -268,10 +264,9 @@ GLOBAL OPTIONS:
|
|||
enc.SetIndent("", " ")
|
||||
return enc.Encode(keys)
|
||||
},
|
||||
},
|
||||
{
|
||||
}, {
|
||||
Name: "ls",
|
||||
Usage: "List keys",
|
||||
Usage: "Lists keys",
|
||||
Action: func(c *cli.Context) error {
|
||||
var keys []SSHKey
|
||||
if err := db.Find(&keys).Error; err != nil {
|
||||
|
@ -296,10 +291,9 @@ GLOBAL OPTIONS:
|
|||
table.Render()
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
}, {
|
||||
Name: "rm",
|
||||
Usage: "Remove one or more keys",
|
||||
Usage: "Removes one or more keys",
|
||||
ArgsUsage: "<id or name> [<id or name> [<ir or name>...]]",
|
||||
Action: func(c *cli.Context) error {
|
||||
if c.NArg() < 1 {
|
||||
|
@ -321,32 +315,111 @@ GLOBAL OPTIONS:
|
|||
},
|
||||
}, {
|
||||
Name: "user",
|
||||
Usage: "Manage users",
|
||||
Usage: "Manages users",
|
||||
Subcommands: []cli.Command{
|
||||
{
|
||||
Name: "create",
|
||||
Usage: "Create a new user",
|
||||
Action: func(c *cli.Context) error { return nil },
|
||||
},
|
||||
{
|
||||
Name: "inspect",
|
||||
Usage: "Display detailed information on one or more users",
|
||||
Action: func(c *cli.Context) error { return nil },
|
||||
},
|
||||
{
|
||||
Name: "ls",
|
||||
Usage: "List users",
|
||||
Action: func(c *cli.Context) error { return nil },
|
||||
},
|
||||
{
|
||||
Name: "rm",
|
||||
Usage: "Remove one or more users",
|
||||
Action: func(c *cli.Context) error { return nil },
|
||||
Name: "create",
|
||||
ArgsUsage: "<email>",
|
||||
Usage: "Creates a new user",
|
||||
Description: "$> user create bob\n $> user create --name=mykey",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{Name: "name", Usage: "Assigns a name to the user"},
|
||||
cli.StringFlag{Name: "comment"},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
if c.NArg() != 1 {
|
||||
return fmt.Errorf("invalid usage")
|
||||
}
|
||||
|
||||
email := c.Args().First()
|
||||
name := strings.Split(email, "@")[0]
|
||||
if c.String("name") != "" {
|
||||
name = c.String("name")
|
||||
}
|
||||
|
||||
user := User{
|
||||
Name: name,
|
||||
Email: email,
|
||||
Comment: c.String("comment"),
|
||||
}
|
||||
|
||||
// save the user in database
|
||||
if err := db.Create(&user).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(s, "%d\n", user.ID)
|
||||
return nil
|
||||
},
|
||||
}, {
|
||||
Name: "inspect",
|
||||
Usage: "Shows detailed information on one or more users",
|
||||
ArgsUsage: "<id or email> [<id or email> [<ir or email>...]]",
|
||||
Action: func(c *cli.Context) error {
|
||||
if c.NArg() < 1 {
|
||||
return fmt.Errorf("invalid usage")
|
||||
}
|
||||
|
||||
hosts, err := FindUsersByIdOrEmail(db, c.Args())
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
enc := json.NewEncoder(s)
|
||||
enc.SetIndent("", " ")
|
||||
return enc.Encode(hosts)
|
||||
},
|
||||
}, {
|
||||
Name: "ls",
|
||||
Usage: "Lists users",
|
||||
Action: func(c *cli.Context) error {
|
||||
var users []User
|
||||
if err := db.Find(&users).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
table := tablewriter.NewWriter(s)
|
||||
table.SetHeader([]string{"ID", "Name", "Email", "Keys", "Comment"})
|
||||
table.SetBorder(false)
|
||||
table.SetCaption(true, fmt.Sprintf("Total: %d users.", len(users)))
|
||||
for _, user := range users {
|
||||
keys := len(user.SSHKeys)
|
||||
table.Append([]string{
|
||||
fmt.Sprintf("%d", user.ID),
|
||||
user.Name,
|
||||
user.Email,
|
||||
fmt.Sprintf("%d", keys),
|
||||
user.Comment,
|
||||
//FIXME: add some stats about last access time etc
|
||||
//FIXME: add creation date
|
||||
})
|
||||
}
|
||||
table.Render()
|
||||
return nil
|
||||
},
|
||||
}, {
|
||||
Name: "rm",
|
||||
Usage: "Removes one or more users",
|
||||
ArgsUsage: "<id or email> [<id or email> [<ir or email>...]]",
|
||||
Action: func(c *cli.Context) error {
|
||||
if c.NArg() < 1 {
|
||||
return fmt.Errorf("invalid usage")
|
||||
}
|
||||
|
||||
users, err := FindUsersByIdOrEmail(db, c.Args())
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, user := range users {
|
||||
db.Where("id = ?", user.ID).Delete(&User{})
|
||||
fmt.Fprintf(s, "%d\n", user.ID)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
},
|
||||
}, {
|
||||
Name: "version",
|
||||
Usage: "Show the SSHPortal version information",
|
||||
Usage: "Shows the SSHPortal version information",
|
||||
Action: func(c *cli.Context) error {
|
||||
fmt.Fprintf(s, "%s\n", version)
|
||||
return nil
|
||||
|
|
Loading…
Add table
Reference in a new issue