More CLI for access control
This commit is contained in:
		
							parent
							
								
									243d549975
								
							
						
					
					
						commit
						03a4e3e8e9
					
				
					 6 changed files with 243 additions and 28 deletions
				
			
		
							
								
								
									
										13
									
								
								auth/auth.go
									
										
									
									
									
								
							
							
						
						
									
										13
									
								
								auth/auth.go
									
										
									
									
									
								
							|  | @ -12,6 +12,9 @@ type Manager interface { | ||||||
| 	AddUser(username, password string, role Role) error | 	AddUser(username, password string, role Role) error | ||||||
| 	RemoveUser(username string) error | 	RemoveUser(username string) error | ||||||
| 	ChangePassword(username, password string) error | 	ChangePassword(username, password string) error | ||||||
|  | 	ChangeRole(username string, role Role) error | ||||||
|  | 	AllowAccess(username string, topic string, read bool, write bool) error | ||||||
|  | 	ResetAccess(username string, topic string) error | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type User struct { | type User struct { | ||||||
|  | @ -39,4 +42,14 @@ var Everyone = &User{ | ||||||
| 	Role: RoleNone, | 	Role: RoleNone, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | var Roles = []Role{ | ||||||
|  | 	RoleAdmin, | ||||||
|  | 	RoleUser, | ||||||
|  | 	RoleNone, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func AllowedRole(role Role) bool { | ||||||
|  | 	return role == RoleUser || role == RoleAdmin | ||||||
|  | } | ||||||
|  | 
 | ||||||
| var ErrUnauthorized = errors.New("unauthorized") | var ErrUnauthorized = errors.New("unauthorized") | ||||||
|  |  | ||||||
|  | @ -8,16 +8,16 @@ import ( | ||||||
| /* | /* | ||||||
| 
 | 
 | ||||||
| SELECT * FROM user; | SELECT * FROM user; | ||||||
| SELECT * FROM user_topic; | SELECT * FROM access; | ||||||
| 
 | 
 | ||||||
| INSERT INTO user VALUES ('phil','$2a$06$.4W0LI5mcxzxhpjUvpTaNeu0MhRO0T7B.CYnmAkRnlztIy7PrSODu', 'admin'); | INSERT INTO user VALUES ('phil','$2a$06$.4W0LI5mcxzxhpjUvpTaNeu0MhRO0T7B.CYnmAkRnlztIy7PrSODu', 'admin'); | ||||||
| INSERT INTO user VALUES ('ben','$2a$06$skJK/AecWCUmiCjr69ke.Ow/hFA616RdvJJPxnI221zyohsRlyXL.', 'user'); | INSERT INTO user VALUES ('ben','$2a$06$skJK/AecWCUmiCjr69ke.Ow/hFA616RdvJJPxnI221zyohsRlyXL.', 'user'); | ||||||
| INSERT INTO user VALUES ('marian','$2a$10$8U90swQIatvHHI4sw0Wo7.OUy6dUwzMcoOABi6BsS4uF0x3zcSXRW', 'user'); | INSERT INTO user VALUES ('marian','$2a$10$8U90swQIatvHHI4sw0Wo7.OUy6dUwzMcoOABi6BsS4uF0x3zcSXRW', 'user'); | ||||||
| 
 | 
 | ||||||
| INSERT INTO user_topic VALUES ('ben','alerts',1,1); | INSERT INTO access VALUES ('ben','alerts',1,1); | ||||||
| INSERT INTO user_topic VALUES ('marian','alerts',1,0); | INSERT INTO access VALUES ('marian','alerts',1,0); | ||||||
| INSERT INTO user_topic VALUES ('','announcements',1,0); | INSERT INTO access VALUES ('','announcements',1,0); | ||||||
| INSERT INTO user_topic VALUES ('','write-all',1,1); | INSERT INTO access VALUES ('','write-all',1,1); | ||||||
| 
 | 
 | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
|  | @ -34,7 +34,7 @@ const ( | ||||||
| 			pass TEXT NOT NULL, | 			pass TEXT NOT NULL, | ||||||
| 			role TEXT NOT NULL | 			role TEXT NOT NULL | ||||||
| 		); | 		); | ||||||
| 		CREATE TABLE IF NOT EXISTS user_topic ( | 		CREATE TABLE IF NOT EXISTS access ( | ||||||
| 			user TEXT NOT NULL,		 | 			user TEXT NOT NULL,		 | ||||||
| 			topic TEXT NOT NULL, | 			topic TEXT NOT NULL, | ||||||
| 			read INT NOT NULL, | 			read INT NOT NULL, | ||||||
|  | @ -50,7 +50,7 @@ const ( | ||||||
| 	selectUserQuery       = `SELECT pass, role FROM user WHERE user = ?` | 	selectUserQuery       = `SELECT pass, role FROM user WHERE user = ?` | ||||||
| 	selectTopicPermsQuery = ` | 	selectTopicPermsQuery = ` | ||||||
| 		SELECT read, write  | 		SELECT read, write  | ||||||
| 		FROM user_topic  | 		FROM access  | ||||||
| 		WHERE user IN ('', ?) AND topic = ? | 		WHERE user IN ('', ?) AND topic = ? | ||||||
| 		ORDER BY user DESC | 		ORDER BY user DESC | ||||||
| 	` | 	` | ||||||
|  | @ -60,8 +60,15 @@ const ( | ||||||
| const ( | const ( | ||||||
| 	insertUser     = `INSERT INTO user (user, pass, role) VALUES (?, ?, ?)` | 	insertUser     = `INSERT INTO user (user, pass, role) VALUES (?, ?, ?)` | ||||||
| 	updateUserPass = `UPDATE user SET pass = ? WHERE user = ?` | 	updateUserPass = `UPDATE user SET pass = ? WHERE user = ?` | ||||||
|  | 	updateUserRole = `UPDATE user SET role = ? WHERE user = ?` | ||||||
|  | 	upsertAccess   = ` | ||||||
|  | 		INSERT INTO access (user, topic, read, write)  | ||||||
|  | 		VALUES (?, ?, ?, ?) | ||||||
|  | 		ON CONFLICT (user, topic) DO UPDATE SET read=excluded.read, write=excluded.write | ||||||
|  | 	` | ||||||
| 	deleteUser      = `DELETE FROM user WHERE user = ?` | 	deleteUser      = `DELETE FROM user WHERE user = ?` | ||||||
| 	deleteUserTopic = `DELETE FROM user_topic WHERE user = ?` | 	deleteAllAccess = `DELETE FROM access WHERE user = ?` | ||||||
|  | 	deleteAccess    = `DELETE FROM access WHERE user = ? AND topic = ?` | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type SQLiteAuth struct { | type SQLiteAuth struct { | ||||||
|  | @ -167,7 +174,7 @@ func (a *SQLiteAuth) RemoveUser(username string) error { | ||||||
| 	if _, err := a.db.Exec(deleteUser, username); err != nil { | 	if _, err := a.db.Exec(deleteUser, username); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	if _, err := a.db.Exec(deleteUserTopic, username); err != nil { | 	if _, err := a.db.Exec(deleteAllAccess, username); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	return nil | 	return nil | ||||||
|  | @ -183,3 +190,30 @@ func (a *SQLiteAuth) ChangePassword(username, password string) error { | ||||||
| 	} | 	} | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func (a *SQLiteAuth) ChangeRole(username string, role Role) error { | ||||||
|  | 	if _, err := a.db.Exec(updateUserRole, string(role), username); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (a *SQLiteAuth) AllowAccess(username string, topic string, read bool, write bool) error { | ||||||
|  | 	if _, err := a.db.Exec(upsertAccess, username, topic, read, write); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (a *SQLiteAuth) ResetAccess(username string, topic string) error { | ||||||
|  | 	if topic == "" { | ||||||
|  | 		if _, err := a.db.Exec(deleteAllAccess, username); err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		if _, err := a.db.Exec(deleteAccess, username, topic); err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -15,8 +15,8 @@ var ( | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| const ( | const ( | ||||||
| 	categoryClient = "Client-side commands" | 	categoryClient = "Client commands" | ||||||
| 	categoryServer = "Server-side commands" | 	categoryServer = "Server commands" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // New creates a new CLI application | // New creates a new CLI application | ||||||
|  | @ -37,6 +37,8 @@ func New() *cli.App { | ||||||
| 			// Server commands | 			// Server commands | ||||||
| 			cmdServe, | 			cmdServe, | ||||||
| 			cmdUser, | 			cmdUser, | ||||||
|  | 			cmdAllow, | ||||||
|  | 			cmdDeny, | ||||||
| 
 | 
 | ||||||
| 			// Client commands | 			// Client commands | ||||||
| 			cmdPublish, | 			cmdPublish, | ||||||
|  |  | ||||||
							
								
								
									
										62
									
								
								cmd/user.go
									
										
									
									
									
								
							
							
						
						
									
										62
									
								
								cmd/user.go
									
										
									
									
									
								
							|  | @ -29,12 +29,7 @@ dabbling for CLI | ||||||
| 
 | 
 | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| var flagsUser = []cli.Flag{ | var flagsUser = userCommandFlags() | ||||||
| 	&cli.StringFlag{Name: "config", Aliases: []string{"c"}, EnvVars: []string{"NTFY_CONFIG_FILE"}, Value: "/etc/ntfy/server.yml", DefaultText: "/etc/ntfy/server.yml", Usage: "config file"}, |  | ||||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "auth-file", Aliases: []string{"H"}, EnvVars: []string{"NTFY_AUTH_FILE"}, Usage: "auth database file used for access control"}), |  | ||||||
| 	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"}), |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| var cmdUser = &cli.Command{ | var cmdUser = &cli.Command{ | ||||||
| 	Name:      "user", | 	Name:      "user", | ||||||
| 	Usage:     "Manage users and access to topics", | 	Usage:     "Manage users and access to topics", | ||||||
|  | @ -60,21 +55,33 @@ var cmdUser = &cli.Command{ | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			Name:    "change-pass", | 			Name:    "change-pass", | ||||||
| 			Aliases: []string{"ch"}, | 			Aliases: []string{"chp"}, | ||||||
| 			Usage:   "change user password", | 			Usage:   "change user password", | ||||||
| 			Action:  execUserChangePass, | 			Action:  execUserChangePass, | ||||||
| 		}, | 		}, | ||||||
|  | 		{ | ||||||
|  | 			Name:    "change-role", | ||||||
|  | 			Aliases: []string{"chr"}, | ||||||
|  | 			Usage:   "change user role", | ||||||
|  | 			Action:  execUserChangeRole, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			Name:    "list", | ||||||
|  | 			Aliases: []string{"chr"}, | ||||||
|  | 			Usage:   "change user role", | ||||||
|  | 			Action:  execUserChangeRole, | ||||||
|  | 		}, | ||||||
| 	}, | 	}, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func execUserAdd(c *cli.Context) error { | func execUserAdd(c *cli.Context) error { | ||||||
| 	role := c.String("role") | 	username := c.Args().Get(0) | ||||||
| 	if c.NArg() == 0 { | 	role := auth.Role(c.String("role")) | ||||||
|  | 	if username == "" { | ||||||
| 		return errors.New("username expected, type 'ntfy user add --help' for help") | 		return errors.New("username expected, type 'ntfy user add --help' for help") | ||||||
| 	} else if role != string(auth.RoleUser) && role != string(auth.RoleAdmin) { | 	} 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'") | ||||||
| 	} | 	} | ||||||
| 	username := c.Args().Get(0) |  | ||||||
| 	password, err := readPassword(c) | 	password, err := readPassword(c) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
|  | @ -91,10 +98,10 @@ func execUserAdd(c *cli.Context) error { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func execUserDel(c *cli.Context) error { | func execUserDel(c *cli.Context) error { | ||||||
| 	if c.NArg() == 0 { | 	username := c.Args().Get(0) | ||||||
|  | 	if username == "" { | ||||||
| 		return errors.New("username expected, type 'ntfy user del --help' for help") | 		return errors.New("username expected, type 'ntfy user del --help' for help") | ||||||
| 	} | 	} | ||||||
| 	username := c.Args().Get(0) |  | ||||||
| 	manager, err := createAuthManager(c) | 	manager, err := createAuthManager(c) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
|  | @ -107,10 +114,10 @@ func execUserDel(c *cli.Context) error { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func execUserChangePass(c *cli.Context) error { | func execUserChangePass(c *cli.Context) error { | ||||||
| 	if c.NArg() == 0 { | 	username := c.Args().Get(0) | ||||||
|  | 	if username == "" { | ||||||
| 		return errors.New("username expected, type 'ntfy user change-pass --help' for help") | 		return errors.New("username expected, type 'ntfy user change-pass --help' for help") | ||||||
| 	} | 	} | ||||||
| 	username := c.Args().Get(0) |  | ||||||
| 	password, err := readPassword(c) | 	password, err := readPassword(c) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
|  | @ -126,6 +133,23 @@ func execUserChangePass(c *cli.Context) error { | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func execUserChangeRole(c *cli.Context) error { | ||||||
|  | 	username := c.Args().Get(0) | ||||||
|  | 	role := auth.Role(c.Args().Get(1)) | ||||||
|  | 	if username == "" || !auth.AllowedRole(role) { | ||||||
|  | 		return errors.New("username and new role expected, type 'ntfy user change-role --help' for help") | ||||||
|  | 	} | ||||||
|  | 	manager, err := createAuthManager(c) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	if err := manager.ChangeRole(username, role); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	fmt.Fprintf(c.App.ErrWriter, "Changed role for user %s to %s\n", username, role) | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func createAuthManager(c *cli.Context) (auth.Manager, error) { | func createAuthManager(c *cli.Context) (auth.Manager, error) { | ||||||
| 	authFile := c.String("auth-file") | 	authFile := c.String("auth-file") | ||||||
| 	authDefaultAccess := c.String("auth-default-access") | 	authDefaultAccess := c.String("auth-default-access") | ||||||
|  | @ -158,3 +182,11 @@ func readPassword(c *cli.Context) (string, error) { | ||||||
| 	} | 	} | ||||||
| 	return string(password), nil | 	return string(password), nil | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func userCommandFlags() []cli.Flag { | ||||||
|  | 	return []cli.Flag{ | ||||||
|  | 		&cli.StringFlag{Name: "config", Aliases: []string{"c"}, EnvVars: []string{"NTFY_CONFIG_FILE"}, Value: "/etc/ntfy/server.yml", DefaultText: "/etc/ntfy/server.yml", Usage: "config file"}, | ||||||
|  | 		altsrc.NewStringFlag(&cli.StringFlag{Name: "auth-file", Aliases: []string{"H"}, EnvVars: []string{"NTFY_AUTH_FILE"}, Usage: "auth database file used for access control"}), | ||||||
|  | 		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"}), | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										99
									
								
								cmd/user_allow.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								cmd/user_allow.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,99 @@ | ||||||
|  | package cmd | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  | 	"github.com/urfave/cli/v2" | ||||||
|  | 	"heckel.io/ntfy/auth" | ||||||
|  | 	"heckel.io/ntfy/util" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var flagsAllow = append( | ||||||
|  | 	userCommandFlags(), | ||||||
|  | 	&cli.BoolFlag{Name: "reset", Aliases: []string{"r"}, Usage: "reset access for user (and topic)"}, | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var cmdAllow = &cli.Command{ | ||||||
|  | 	Name:      "allow", | ||||||
|  | 	Usage:     "Grant a user access to a topic", | ||||||
|  | 	UsageText: "ntfy allow USERNAME TOPIC [read-write|read-only|write-only]", | ||||||
|  | 	Flags:     flagsAllow, | ||||||
|  | 	Before:    initConfigFileInputSource("config", flagsAllow), | ||||||
|  | 	Action:    execUserAllow, | ||||||
|  | 	Category:  categoryServer, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func execUserAllow(c *cli.Context) error { | ||||||
|  | 	username := c.Args().Get(0) | ||||||
|  | 	topic := c.Args().Get(1) | ||||||
|  | 	perms := c.Args().Get(2) | ||||||
|  | 	reset := c.Bool("reset") | ||||||
|  | 	if username == "" { | ||||||
|  | 		return errors.New("username expected, type 'ntfy allow --help' for help") | ||||||
|  | 	} else if !reset && topic == "" { | ||||||
|  | 		return errors.New("topic expected, type 'ntfy allow --help' for help") | ||||||
|  | 	} else if !util.InStringList([]string{"", "read-write", "read-only", "read", "ro", "write-only", "write", "wo", "none"}, perms) { | ||||||
|  | 		return errors.New("permission must be one of: read-write, read-only, write-only, or none (or the aliases: read, ro, write, wo)") | ||||||
|  | 	} | ||||||
|  | 	if username == "everyone" { | ||||||
|  | 		username = "" | ||||||
|  | 	} | ||||||
|  | 	read := util.InStringList([]string{"", "read-write", "read-only", "read", "ro"}, perms) | ||||||
|  | 	write := util.InStringList([]string{"", "read-write", "write-only", "write", "wo"}, perms) | ||||||
|  | 	manager, err := createAuthManager(c) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	if reset { | ||||||
|  | 		return doAccessReset(c, manager, username, topic) | ||||||
|  | 	} | ||||||
|  | 	return doAccessAllow(c, manager, username, topic, read, write) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func doAccessAllow(c *cli.Context, manager auth.Manager, username string, topic string, read bool, write bool) error { | ||||||
|  | 	if err := manager.AllowAccess(username, topic, read, write); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	if username == "" { | ||||||
|  | 		if read && write { | ||||||
|  | 			fmt.Fprintf(c.App.ErrWriter, "Anonymous users granted full access to topic %s\n", topic) | ||||||
|  | 		} else if read { | ||||||
|  | 			fmt.Fprintf(c.App.ErrWriter, "Anonymous users granted read-only access to topic %s\n", topic) | ||||||
|  | 		} else if write { | ||||||
|  | 			fmt.Fprintf(c.App.ErrWriter, "Anonymous users granted write-only access to topic %s\n", topic) | ||||||
|  | 		} else { | ||||||
|  | 			fmt.Fprintf(c.App.ErrWriter, "Revoked all access to topic %s for all anonymous users\n", topic) | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		if read && write { | ||||||
|  | 			fmt.Fprintf(c.App.ErrWriter, "User %s now has read-write access to topic %s\n", username, topic) | ||||||
|  | 		} else if read { | ||||||
|  | 			fmt.Fprintf(c.App.ErrWriter, "User %s now has read-only access to topic %s\n", username, topic) | ||||||
|  | 		} else if write { | ||||||
|  | 			fmt.Fprintf(c.App.ErrWriter, "User %s now has write-only access to topic %s\n", username, topic) | ||||||
|  | 		} else { | ||||||
|  | 			fmt.Fprintf(c.App.ErrWriter, "Revoked all access to topic %s for user %s\n", topic, username) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func doAccessReset(c *cli.Context, manager auth.Manager, username, topic string) error { | ||||||
|  | 	if err := manager.ResetAccess(username, topic); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	if username == "" { | ||||||
|  | 		if topic == "" { | ||||||
|  | 			fmt.Fprintln(c.App.ErrWriter, "Reset access for all anonymous users and all topics") | ||||||
|  | 		} else { | ||||||
|  | 			fmt.Fprintf(c.App.ErrWriter, "Reset access to topic %s for all anonymous users\n", topic) | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		if topic == "" { | ||||||
|  | 			fmt.Fprintf(c.App.ErrWriter, "Reset access for user %s to all topics\n", username) | ||||||
|  | 		} else { | ||||||
|  | 			fmt.Fprintf(c.App.ErrWriter, "Reset access for user %s and topic %s\n", username, topic) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
							
								
								
									
										35
									
								
								cmd/user_deny.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								cmd/user_deny.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,35 @@ | ||||||
|  | package cmd | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  | 	"github.com/urfave/cli/v2" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var flagsDeny = userCommandFlags() | ||||||
|  | var cmdDeny = &cli.Command{ | ||||||
|  | 	Name:      "deny", | ||||||
|  | 	Usage:     "Revoke user access from a topic", | ||||||
|  | 	UsageText: "ntfy deny USERNAME TOPIC", | ||||||
|  | 	Flags:     flagsDeny, | ||||||
|  | 	Before:    initConfigFileInputSource("config", flagsDeny), | ||||||
|  | 	Action:    execUserDeny, | ||||||
|  | 	Category:  categoryServer, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func execUserDeny(c *cli.Context) error { | ||||||
|  | 	username := c.Args().Get(0) | ||||||
|  | 	topic := c.Args().Get(1) | ||||||
|  | 	if username == "" { | ||||||
|  | 		return errors.New("username expected, type 'ntfy allow --help' for help") | ||||||
|  | 	} else if topic == "" { | ||||||
|  | 		return errors.New("topic expected, type 'ntfy allow --help' for help") | ||||||
|  | 	} | ||||||
|  | 	if username == "everyone" { | ||||||
|  | 		username = "" | ||||||
|  | 	} | ||||||
|  | 	manager, err := createAuthManager(c) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	return doAccessAllow(c, manager, username, topic, false, false) | ||||||
|  | } | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue