server_account_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. package server
  2. import (
  3. "fmt"
  4. "github.com/stretchr/testify/require"
  5. "heckel.io/ntfy/user"
  6. "heckel.io/ntfy/util"
  7. "io"
  8. "testing"
  9. "time"
  10. )
  11. func TestAccount_Signup_Success(t *testing.T) {
  12. conf := newTestConfigWithUsers(t)
  13. conf.EnableSignup = true
  14. s := newTestServer(t, conf)
  15. rr := request(t, s, "POST", "/v1/account", `{"username":"phil", "password":"mypass"}`, nil)
  16. require.Equal(t, 200, rr.Code)
  17. rr = request(t, s, "POST", "/v1/account/token", "", map[string]string{
  18. "Authorization": util.BasicAuth("phil", "mypass"),
  19. })
  20. require.Equal(t, 200, rr.Code)
  21. token, _ := util.ReadJSON[apiAccountTokenResponse](io.NopCloser(rr.Body))
  22. require.NotEmpty(t, token.Token)
  23. require.True(t, time.Now().Add(71*time.Hour).Unix() < token.Expires)
  24. rr = request(t, s, "GET", "/v1/account", "", map[string]string{
  25. "Authorization": util.BearerAuth(token.Token),
  26. })
  27. require.Equal(t, 200, rr.Code)
  28. account, _ := util.ReadJSON[apiAccountResponse](io.NopCloser(rr.Body))
  29. require.Equal(t, "phil", account.Username)
  30. require.Equal(t, "user", account.Role)
  31. }
  32. func TestAccount_Signup_UserExists(t *testing.T) {
  33. conf := newTestConfigWithUsers(t)
  34. conf.EnableSignup = true
  35. s := newTestServer(t, conf)
  36. rr := request(t, s, "POST", "/v1/account", `{"username":"phil", "password":"mypass"}`, nil)
  37. require.Equal(t, 200, rr.Code)
  38. rr = request(t, s, "POST", "/v1/account", `{"username":"phil", "password":"mypass"}`, nil)
  39. require.Equal(t, 409, rr.Code)
  40. require.Equal(t, 40901, toHTTPError(t, rr.Body.String()).Code)
  41. }
  42. func TestAccount_Signup_LimitReached(t *testing.T) {
  43. conf := newTestConfigWithUsers(t)
  44. conf.EnableSignup = true
  45. s := newTestServer(t, conf)
  46. for i := 0; i < 3; i++ {
  47. rr := request(t, s, "POST", "/v1/account", fmt.Sprintf(`{"username":"phil%d", "password":"mypass"}`, i), nil)
  48. require.Equal(t, 200, rr.Code)
  49. }
  50. rr := request(t, s, "POST", "/v1/account", `{"username":"thiswontwork", "password":"mypass"}`, nil)
  51. require.Equal(t, 429, rr.Code)
  52. require.Equal(t, 42906, toHTTPError(t, rr.Body.String()).Code)
  53. }
  54. func TestAccount_Signup_AsUser(t *testing.T) {
  55. conf := newTestConfigWithUsers(t)
  56. conf.EnableSignup = true
  57. s := newTestServer(t, conf)
  58. require.Nil(t, s.userManager.AddUser("phil", "phil", user.RoleAdmin))
  59. require.Nil(t, s.userManager.AddUser("ben", "ben", user.RoleUser))
  60. rr := request(t, s, "POST", "/v1/account", `{"username":"emma", "password":"emma"}`, map[string]string{
  61. "Authorization": util.BasicAuth("phil", "phil"),
  62. })
  63. require.Equal(t, 200, rr.Code)
  64. rr = request(t, s, "POST", "/v1/account", `{"username":"marian", "password":"marian"}`, map[string]string{
  65. "Authorization": util.BasicAuth("ben", "ben"),
  66. })
  67. require.Equal(t, 401, rr.Code)
  68. }
  69. func TestAccount_Signup_Disabled(t *testing.T) {
  70. conf := newTestConfigWithUsers(t)
  71. conf.EnableSignup = false
  72. s := newTestServer(t, conf)
  73. rr := request(t, s, "POST", "/v1/account", `{"username":"phil", "password":"mypass"}`, nil)
  74. require.Equal(t, 400, rr.Code)
  75. require.Equal(t, 40022, toHTTPError(t, rr.Body.String()).Code)
  76. }
  77. func TestAccount_Get_Anonymous(t *testing.T) {
  78. conf := newTestConfigWithUsers(t)
  79. conf.VisitorRequestLimitReplenish = 86 * time.Second
  80. conf.VisitorEmailLimitReplenish = time.Hour
  81. conf.VisitorAttachmentTotalSizeLimit = 5123
  82. conf.AttachmentFileSizeLimit = 512
  83. s := newTestServer(t, conf)
  84. s.smtpSender = &testMailer{}
  85. rr := request(t, s, "GET", "/v1/account", "", nil)
  86. require.Equal(t, 200, rr.Code)
  87. account, _ := util.ReadJSON[apiAccountResponse](io.NopCloser(rr.Body))
  88. require.Equal(t, "*", account.Username)
  89. require.Equal(t, string(user.RoleAnonymous), account.Role)
  90. require.Equal(t, "ip", account.Limits.Basis)
  91. require.Equal(t, int64(1004), account.Limits.Messages) // I hate this
  92. require.Equal(t, int64(24), account.Limits.Emails) // I hate this
  93. require.Equal(t, int64(5123), account.Limits.AttachmentTotalSize)
  94. require.Equal(t, int64(512), account.Limits.AttachmentFileSize)
  95. require.Equal(t, int64(0), account.Stats.Messages)
  96. require.Equal(t, int64(1004), account.Stats.MessagesRemaining)
  97. require.Equal(t, int64(0), account.Stats.Emails)
  98. require.Equal(t, int64(24), account.Stats.EmailsRemaining)
  99. rr = request(t, s, "POST", "/mytopic", "", nil)
  100. require.Equal(t, 200, rr.Code)
  101. rr = request(t, s, "POST", "/mytopic", "", map[string]string{
  102. "Email": "phil@ntfy.sh",
  103. })
  104. require.Equal(t, 200, rr.Code)
  105. rr = request(t, s, "GET", "/v1/account", "", nil)
  106. require.Equal(t, 200, rr.Code)
  107. account, _ = util.ReadJSON[apiAccountResponse](io.NopCloser(rr.Body))
  108. require.Equal(t, int64(2), account.Stats.Messages)
  109. require.Equal(t, int64(1002), account.Stats.MessagesRemaining)
  110. require.Equal(t, int64(1), account.Stats.Emails)
  111. require.Equal(t, int64(23), account.Stats.EmailsRemaining)
  112. }
  113. func TestAccount_ChangeSettings(t *testing.T) {
  114. s := newTestServer(t, newTestConfigWithUsers(t))
  115. require.Nil(t, s.userManager.AddUser("phil", "phil", user.RoleUser))
  116. user, _ := s.userManager.User("phil")
  117. token, _ := s.userManager.CreateToken(user)
  118. rr := request(t, s, "PATCH", "/v1/account/settings", `{"notification": {"sound": "juntos"},"ignored": true}`, map[string]string{
  119. "Authorization": util.BasicAuth("phil", "phil"),
  120. })
  121. require.Equal(t, 200, rr.Code)
  122. rr = request(t, s, "PATCH", "/v1/account/settings", `{"notification": {"delete_after": 86400}, "language": "de"}`, map[string]string{
  123. "Authorization": util.BearerAuth(token.Value),
  124. })
  125. require.Equal(t, 200, rr.Code)
  126. rr = request(t, s, "GET", "/v1/account", `{"username":"marian", "password":"marian"}`, map[string]string{
  127. "Authorization": util.BearerAuth(token.Value),
  128. })
  129. require.Equal(t, 200, rr.Code)
  130. account, _ := util.ReadJSON[apiAccountResponse](io.NopCloser(rr.Body))
  131. require.Equal(t, "de", account.Language)
  132. require.Equal(t, 86400, account.Notification.DeleteAfter)
  133. require.Equal(t, "juntos", account.Notification.Sound)
  134. require.Equal(t, 0, account.Notification.MinPriority) // Not set
  135. }
  136. func TestAccount_Subscription_AddUpdateDelete(t *testing.T) {
  137. s := newTestServer(t, newTestConfigWithUsers(t))
  138. require.Nil(t, s.userManager.AddUser("phil", "phil", user.RoleUser))
  139. rr := request(t, s, "POST", "/v1/account/subscription", `{"base_url": "http://abc.com", "topic": "def"}`, map[string]string{
  140. "Authorization": util.BasicAuth("phil", "phil"),
  141. })
  142. require.Equal(t, 200, rr.Code)
  143. rr = request(t, s, "GET", "/v1/account", "", map[string]string{
  144. "Authorization": util.BasicAuth("phil", "phil"),
  145. })
  146. require.Equal(t, 200, rr.Code)
  147. account, _ := util.ReadJSON[apiAccountResponse](io.NopCloser(rr.Body))
  148. require.Equal(t, 1, len(account.Subscriptions))
  149. require.NotEmpty(t, account.Subscriptions[0].ID)
  150. require.Equal(t, "http://abc.com", account.Subscriptions[0].BaseURL)
  151. require.Equal(t, "def", account.Subscriptions[0].Topic)
  152. require.Equal(t, "", account.Subscriptions[0].DisplayName)
  153. subscriptionID := account.Subscriptions[0].ID
  154. rr = request(t, s, "PATCH", "/v1/account/subscription/"+subscriptionID, `{"display_name": "ding dong"}`, map[string]string{
  155. "Authorization": util.BasicAuth("phil", "phil"),
  156. })
  157. require.Equal(t, 200, rr.Code)
  158. rr = request(t, s, "GET", "/v1/account", "", map[string]string{
  159. "Authorization": util.BasicAuth("phil", "phil"),
  160. })
  161. require.Equal(t, 200, rr.Code)
  162. account, _ = util.ReadJSON[apiAccountResponse](io.NopCloser(rr.Body))
  163. require.Equal(t, 1, len(account.Subscriptions))
  164. require.Equal(t, subscriptionID, account.Subscriptions[0].ID)
  165. require.Equal(t, "http://abc.com", account.Subscriptions[0].BaseURL)
  166. require.Equal(t, "def", account.Subscriptions[0].Topic)
  167. require.Equal(t, "ding dong", account.Subscriptions[0].DisplayName)
  168. rr = request(t, s, "DELETE", "/v1/account/subscription/"+subscriptionID, "", map[string]string{
  169. "Authorization": util.BasicAuth("phil", "phil"),
  170. })
  171. require.Equal(t, 200, rr.Code)
  172. rr = request(t, s, "GET", "/v1/account", "", map[string]string{
  173. "Authorization": util.BasicAuth("phil", "phil"),
  174. })
  175. require.Equal(t, 200, rr.Code)
  176. account, _ = util.ReadJSON[apiAccountResponse](io.NopCloser(rr.Body))
  177. require.Equal(t, 0, len(account.Subscriptions))
  178. }
  179. func TestAccount_ChangePassword(t *testing.T) {
  180. s := newTestServer(t, newTestConfigWithUsers(t))
  181. require.Nil(t, s.userManager.AddUser("phil", "phil", user.RoleUser))
  182. rr := request(t, s, "POST", "/v1/account/password", `{"password": "new password"}`, map[string]string{
  183. "Authorization": util.BasicAuth("phil", "phil"),
  184. })
  185. require.Equal(t, 200, rr.Code)
  186. rr = request(t, s, "GET", "/v1/account", "", map[string]string{
  187. "Authorization": util.BasicAuth("phil", "phil"),
  188. })
  189. require.Equal(t, 401, rr.Code)
  190. rr = request(t, s, "GET", "/v1/account", "", map[string]string{
  191. "Authorization": util.BasicAuth("phil", "new password"),
  192. })
  193. require.Equal(t, 200, rr.Code)
  194. }
  195. func TestAccount_ChangePassword_NoAccount(t *testing.T) {
  196. s := newTestServer(t, newTestConfigWithUsers(t))
  197. rr := request(t, s, "POST", "/v1/account/password", `{"password": "new password"}`, nil)
  198. require.Equal(t, 401, rr.Code)
  199. }
  200. func TestAccount_ExtendToken(t *testing.T) {
  201. s := newTestServer(t, newTestConfigWithUsers(t))
  202. require.Nil(t, s.userManager.AddUser("phil", "phil", user.RoleUser))
  203. rr := request(t, s, "POST", "/v1/account/token", "", map[string]string{
  204. "Authorization": util.BasicAuth("phil", "phil"),
  205. })
  206. require.Equal(t, 200, rr.Code)
  207. token, err := util.ReadJSON[apiAccountTokenResponse](io.NopCloser(rr.Body))
  208. require.Nil(t, err)
  209. time.Sleep(time.Second)
  210. rr = request(t, s, "PATCH", "/v1/account/token", "", map[string]string{
  211. "Authorization": util.BearerAuth(token.Token),
  212. })
  213. require.Equal(t, 200, rr.Code)
  214. extendedToken, err := util.ReadJSON[apiAccountTokenResponse](io.NopCloser(rr.Body))
  215. require.Nil(t, err)
  216. require.Equal(t, token.Token, extendedToken.Token)
  217. require.True(t, token.Expires < extendedToken.Expires)
  218. }
  219. func TestAccount_ExtendToken_NoTokenProvided(t *testing.T) {
  220. s := newTestServer(t, newTestConfigWithUsers(t))
  221. require.Nil(t, s.userManager.AddUser("phil", "phil", user.RoleUser))
  222. rr := request(t, s, "PATCH", "/v1/account/token", "", map[string]string{
  223. "Authorization": util.BasicAuth("phil", "phil"), // Not Bearer!
  224. })
  225. require.Equal(t, 400, rr.Code)
  226. require.Equal(t, 40023, toHTTPError(t, rr.Body.String()).Code)
  227. }
  228. func TestAccount_Delete_Success(t *testing.T) {
  229. conf := newTestConfigWithUsers(t)
  230. conf.EnableSignup = true
  231. s := newTestServer(t, conf)
  232. rr := request(t, s, "POST", "/v1/account", `{"username":"phil", "password":"mypass"}`, nil)
  233. require.Equal(t, 200, rr.Code)
  234. rr = request(t, s, "GET", "/v1/account", "", map[string]string{
  235. "Authorization": util.BasicAuth("phil", "mypass"),
  236. })
  237. require.Equal(t, 200, rr.Code)
  238. rr = request(t, s, "DELETE", "/v1/account", "", map[string]string{
  239. "Authorization": util.BasicAuth("phil", "mypass"),
  240. })
  241. require.Equal(t, 200, rr.Code)
  242. rr = request(t, s, "GET", "/v1/account", "", map[string]string{
  243. "Authorization": util.BasicAuth("phil", "mypass"),
  244. })
  245. require.Equal(t, 401, rr.Code)
  246. }
  247. func TestAccount_Delete_Not_Allowed(t *testing.T) {
  248. conf := newTestConfigWithUsers(t)
  249. conf.EnableSignup = true
  250. s := newTestServer(t, conf)
  251. rr := request(t, s, "POST", "/v1/account", `{"username":"phil", "password":"mypass"}`, nil)
  252. require.Equal(t, 200, rr.Code)
  253. rr = request(t, s, "DELETE", "/v1/account", "", nil)
  254. require.Equal(t, 401, rr.Code)
  255. }