access.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. package cmd
  2. import (
  3. "errors"
  4. "fmt"
  5. "github.com/urfave/cli/v2"
  6. "heckel.io/ntfy/auth"
  7. "heckel.io/ntfy/util"
  8. )
  9. /*
  10. ntfy access # Shows access control list
  11. ntfy access phil # Shows access for user phil
  12. ntfy access phil mytopic # Shows access for user phil and topic mytopic
  13. ntfy access phil mytopic rw # Allow read-write access to mytopic for user phil
  14. ntfy access everyone mytopic rw # Allow anonymous read-write access to mytopic
  15. ntfy access --reset # Reset entire access control list
  16. ntfy access --reset phil # Reset all access for user phil
  17. ntfy access --reset phil mytopic # Reset access for user phil and topic mytopic
  18. */
  19. const (
  20. userEveryone = "everyone"
  21. )
  22. var flagsAccess = append(
  23. userCommandFlags(),
  24. &cli.BoolFlag{Name: "reset", Aliases: []string{"r"}, Usage: "reset access for user (and topic)"},
  25. )
  26. var cmdAccess = &cli.Command{
  27. Name: "access",
  28. Usage: "Grant/revoke access to a topic, or show access",
  29. UsageText: "ntfy access [USERNAME [TOPIC [PERMISSION]]]",
  30. Flags: flagsAccess,
  31. Before: initConfigFileInputSource("config", flagsAccess),
  32. Action: execUserAccess,
  33. Category: categoryServer,
  34. }
  35. func execUserAccess(c *cli.Context) error {
  36. manager, err := createAuthManager(c)
  37. if err != nil {
  38. return err
  39. }
  40. username := c.Args().Get(0)
  41. if username == userEveryone {
  42. username = auth.Everyone
  43. }
  44. topic := c.Args().Get(1)
  45. perms := c.Args().Get(2)
  46. reset := c.Bool("reset")
  47. if reset {
  48. return resetAccess(c, manager, username, topic)
  49. } else if perms == "" {
  50. return showAccess(c, manager, username)
  51. }
  52. return changeAccess(c, manager, username, topic, perms)
  53. }
  54. func changeAccess(c *cli.Context, manager auth.Manager, username string, topic string, perms string) error {
  55. if !util.InStringList([]string{"", "read-write", "rw", "read-only", "read", "ro", "write-only", "write", "wo", "none", "deny"}, perms) {
  56. return errors.New("permission must be one of: read-write, read-only, write-only, or deny (or the aliases: read, ro, write, wo, none)")
  57. }
  58. read := util.InStringList([]string{"read-write", "rw", "read-only", "read", "ro"}, perms)
  59. write := util.InStringList([]string{"read-write", "rw", "write-only", "write", "wo"}, perms)
  60. if err := manager.AllowAccess(username, topic, read, write); err != nil {
  61. return err
  62. }
  63. if read && write {
  64. fmt.Fprintf(c.App.Writer, "Granted read-write access to topic %s\n\n", topic)
  65. } else if read {
  66. fmt.Fprintf(c.App.Writer, "Granted read-only access to topic %s\n\n", topic)
  67. } else if write {
  68. fmt.Fprintf(c.App.Writer, "Granted write-only access to topic %s\n\n", topic)
  69. } else {
  70. fmt.Fprintf(c.App.Writer, "Revoked all access to topic %s\n\n", topic)
  71. }
  72. return showUserAccess(c, manager, username)
  73. }
  74. func resetAccess(c *cli.Context, manager auth.Manager, username, topic string) error {
  75. if username == "" {
  76. return resetAllAccess(c, manager)
  77. } else if topic == "" {
  78. return resetUserAccess(c, manager, username)
  79. }
  80. return resetUserTopicAccess(c, manager, username, topic)
  81. }
  82. func resetAllAccess(c *cli.Context, manager auth.Manager) error {
  83. if err := manager.ResetAccess("", ""); err != nil {
  84. return err
  85. }
  86. fmt.Fprintln(c.App.Writer, "Reset access for all users")
  87. return nil
  88. }
  89. func resetUserAccess(c *cli.Context, manager auth.Manager, username string) error {
  90. if err := manager.ResetAccess(username, ""); err != nil {
  91. return err
  92. }
  93. fmt.Fprintf(c.App.Writer, "Reset access for user %s\n\n", username)
  94. return showUserAccess(c, manager, username)
  95. }
  96. func resetUserTopicAccess(c *cli.Context, manager auth.Manager, username string, topic string) error {
  97. if err := manager.ResetAccess(username, topic); err != nil {
  98. return err
  99. }
  100. fmt.Fprintf(c.App.Writer, "Reset access for user %s and topic %s\n\n", username, topic)
  101. return showUserAccess(c, manager, username)
  102. }
  103. func showAccess(c *cli.Context, manager auth.Manager, username string) error {
  104. if username == "" {
  105. return showAllAccess(c, manager)
  106. }
  107. return showUserAccess(c, manager, username)
  108. }
  109. func showAllAccess(c *cli.Context, manager auth.Manager) error {
  110. users, err := manager.Users()
  111. if err != nil {
  112. return err
  113. }
  114. return showUsers(c, manager, users)
  115. }
  116. func showUserAccess(c *cli.Context, manager auth.Manager, username string) error {
  117. users, err := manager.User(username)
  118. if err != nil {
  119. return err
  120. }
  121. return showUsers(c, manager, []*auth.User{users})
  122. }
  123. func showUsers(c *cli.Context, manager auth.Manager, users []*auth.User) error {
  124. for _, user := range users {
  125. fmt.Fprintf(c.App.Writer, "User %s (%s)\n", user.Name, user.Role)
  126. if user.Role == auth.RoleAdmin {
  127. fmt.Fprintf(c.App.ErrWriter, "- read-write access to all topics (admin role)\n")
  128. } else if len(user.Grants) > 0 {
  129. for _, grant := range user.Grants {
  130. if grant.Read && grant.Write {
  131. fmt.Fprintf(c.App.ErrWriter, "- read-write access to topic %s\n", grant.TopicPattern)
  132. } else if grant.Read {
  133. fmt.Fprintf(c.App.ErrWriter, "- read-only access to topic %s\n", grant.TopicPattern)
  134. } else if grant.Write {
  135. fmt.Fprintf(c.App.ErrWriter, "- write-only access to topic %s\n", grant.TopicPattern)
  136. } else {
  137. fmt.Fprintf(c.App.ErrWriter, "- no access to topic %s\n", grant.TopicPattern)
  138. }
  139. }
  140. } else {
  141. fmt.Fprintf(c.App.ErrWriter, "- no topic-specific permissions\n")
  142. }
  143. if user.Name == auth.Everyone {
  144. defaultRead, defaultWrite := manager.DefaultAccess()
  145. if defaultRead && defaultWrite {
  146. fmt.Fprintln(c.App.ErrWriter, "- read-write access to all (other) topics (server config)")
  147. } else if defaultRead {
  148. fmt.Fprintln(c.App.ErrWriter, "- read-only access to all (other) topics (server config)")
  149. } else if defaultWrite {
  150. fmt.Fprintln(c.App.ErrWriter, "- write-only access to all (other) topics (server config)")
  151. } else {
  152. fmt.Fprintln(c.App.ErrWriter, "- no access to any (other) topics (server config)")
  153. }
  154. }
  155. }
  156. return nil
  157. }