server_account_test.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641
  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. "strings"
  9. "testing"
  10. "time"
  11. )
  12. func TestAccount_Signup_Success(t *testing.T) {
  13. conf := newTestConfigWithAuthFile(t)
  14. conf.EnableSignup = true
  15. s := newTestServer(t, conf)
  16. rr := request(t, s, "POST", "/v1/account", `{"username":"phil", "password":"mypass"}`, nil)
  17. require.Equal(t, 200, rr.Code)
  18. rr = request(t, s, "POST", "/v1/account/token", "", map[string]string{
  19. "Authorization": util.BasicAuth("phil", "mypass"),
  20. })
  21. require.Equal(t, 200, rr.Code)
  22. token, _ := util.UnmarshalJSON[apiAccountTokenResponse](io.NopCloser(rr.Body))
  23. require.NotEmpty(t, token.Token)
  24. require.True(t, time.Now().Add(71*time.Hour).Unix() < token.Expires)
  25. rr = request(t, s, "GET", "/v1/account", "", map[string]string{
  26. "Authorization": util.BearerAuth(token.Token),
  27. })
  28. require.Equal(t, 200, rr.Code)
  29. account, _ := util.UnmarshalJSON[apiAccountResponse](io.NopCloser(rr.Body))
  30. require.Equal(t, "phil", account.Username)
  31. require.Equal(t, "user", account.Role)
  32. }
  33. func TestAccount_Signup_UserExists(t *testing.T) {
  34. conf := newTestConfigWithAuthFile(t)
  35. conf.EnableSignup = true
  36. s := newTestServer(t, conf)
  37. rr := request(t, s, "POST", "/v1/account", `{"username":"phil", "password":"mypass"}`, nil)
  38. require.Equal(t, 200, rr.Code)
  39. rr = request(t, s, "POST", "/v1/account", `{"username":"phil", "password":"mypass"}`, nil)
  40. require.Equal(t, 409, rr.Code)
  41. require.Equal(t, 40901, toHTTPError(t, rr.Body.String()).Code)
  42. }
  43. func TestAccount_Signup_LimitReached(t *testing.T) {
  44. conf := newTestConfigWithAuthFile(t)
  45. conf.EnableSignup = true
  46. s := newTestServer(t, conf)
  47. for i := 0; i < 3; i++ {
  48. rr := request(t, s, "POST", "/v1/account", fmt.Sprintf(`{"username":"phil%d", "password":"mypass"}`, i), nil)
  49. require.Equal(t, 200, rr.Code)
  50. }
  51. rr := request(t, s, "POST", "/v1/account", `{"username":"thiswontwork", "password":"mypass"}`, nil)
  52. require.Equal(t, 429, rr.Code)
  53. require.Equal(t, 42906, toHTTPError(t, rr.Body.String()).Code)
  54. }
  55. func TestAccount_Signup_AsUser(t *testing.T) {
  56. conf := newTestConfigWithAuthFile(t)
  57. conf.EnableSignup = true
  58. s := newTestServer(t, conf)
  59. require.Nil(t, s.userManager.AddUser("phil", "phil", user.RoleAdmin))
  60. require.Nil(t, s.userManager.AddUser("ben", "ben", user.RoleUser))
  61. rr := request(t, s, "POST", "/v1/account", `{"username":"emma", "password":"emma"}`, map[string]string{
  62. "Authorization": util.BasicAuth("phil", "phil"),
  63. })
  64. require.Equal(t, 200, rr.Code)
  65. rr = request(t, s, "POST", "/v1/account", `{"username":"marian", "password":"marian"}`, map[string]string{
  66. "Authorization": util.BasicAuth("ben", "ben"),
  67. })
  68. require.Equal(t, 401, rr.Code)
  69. }
  70. func TestAccount_Signup_Disabled(t *testing.T) {
  71. conf := newTestConfigWithAuthFile(t)
  72. conf.EnableSignup = false
  73. s := newTestServer(t, conf)
  74. rr := request(t, s, "POST", "/v1/account", `{"username":"phil", "password":"mypass"}`, nil)
  75. require.Equal(t, 400, rr.Code)
  76. require.Equal(t, 40022, toHTTPError(t, rr.Body.String()).Code)
  77. }
  78. func TestAccount_Signup_Rate_Limit(t *testing.T) {
  79. conf := newTestConfigWithAuthFile(t)
  80. conf.EnableSignup = true
  81. s := newTestServer(t, conf)
  82. for i := 0; i < 3; i++ {
  83. rr := request(t, s, "POST", "/v1/account", fmt.Sprintf(`{"username":"phil%d", "password":"mypass"}`, i), nil)
  84. require.Equal(t, 200, rr.Code, "failed on iteration %d", i)
  85. }
  86. rr := request(t, s, "POST", "/v1/account", `{"username":"notallowed", "password":"mypass"}`, nil)
  87. require.Equal(t, 429, rr.Code)
  88. require.Equal(t, 42906, toHTTPError(t, rr.Body.String()).Code)
  89. }
  90. func TestAccount_Get_Anonymous(t *testing.T) {
  91. conf := newTestConfigWithAuthFile(t)
  92. conf.VisitorRequestLimitReplenish = 86 * time.Second
  93. conf.VisitorEmailLimitReplenish = time.Hour
  94. conf.VisitorAttachmentTotalSizeLimit = 5123
  95. conf.AttachmentFileSizeLimit = 512
  96. s := newTestServer(t, conf)
  97. s.smtpSender = &testMailer{}
  98. rr := request(t, s, "GET", "/v1/account", "", nil)
  99. require.Equal(t, 200, rr.Code)
  100. account, _ := util.UnmarshalJSON[apiAccountResponse](io.NopCloser(rr.Body))
  101. require.Equal(t, "*", account.Username)
  102. require.Equal(t, string(user.RoleAnonymous), account.Role)
  103. require.Equal(t, "ip", account.Limits.Basis)
  104. require.Equal(t, int64(1004), account.Limits.Messages) // I hate this
  105. require.Equal(t, int64(24), account.Limits.Emails) // I hate this
  106. require.Equal(t, int64(5123), account.Limits.AttachmentTotalSize)
  107. require.Equal(t, int64(512), account.Limits.AttachmentFileSize)
  108. require.Equal(t, int64(0), account.Stats.Messages)
  109. require.Equal(t, int64(1004), account.Stats.MessagesRemaining)
  110. require.Equal(t, int64(0), account.Stats.Emails)
  111. require.Equal(t, int64(24), account.Stats.EmailsRemaining)
  112. rr = request(t, s, "POST", "/mytopic", "", nil)
  113. require.Equal(t, 200, rr.Code)
  114. rr = request(t, s, "POST", "/mytopic", "", map[string]string{
  115. "Email": "phil@ntfy.sh",
  116. })
  117. require.Equal(t, 200, rr.Code)
  118. rr = request(t, s, "GET", "/v1/account", "", nil)
  119. require.Equal(t, 200, rr.Code)
  120. account, _ = util.UnmarshalJSON[apiAccountResponse](io.NopCloser(rr.Body))
  121. require.Equal(t, int64(2), account.Stats.Messages)
  122. require.Equal(t, int64(1002), account.Stats.MessagesRemaining)
  123. require.Equal(t, int64(1), account.Stats.Emails)
  124. require.Equal(t, int64(23), account.Stats.EmailsRemaining)
  125. }
  126. func TestAccount_ChangeSettings(t *testing.T) {
  127. s := newTestServer(t, newTestConfigWithAuthFile(t))
  128. require.Nil(t, s.userManager.AddUser("phil", "phil", user.RoleUser))
  129. user, _ := s.userManager.User("phil")
  130. token, _ := s.userManager.CreateToken(user)
  131. rr := request(t, s, "PATCH", "/v1/account/settings", `{"notification": {"sound": "juntos"},"ignored": true}`, map[string]string{
  132. "Authorization": util.BasicAuth("phil", "phil"),
  133. })
  134. require.Equal(t, 200, rr.Code)
  135. rr = request(t, s, "PATCH", "/v1/account/settings", `{"notification": {"delete_after": 86400}, "language": "de"}`, map[string]string{
  136. "Authorization": util.BearerAuth(token.Value),
  137. })
  138. require.Equal(t, 200, rr.Code)
  139. rr = request(t, s, "GET", "/v1/account", `{"username":"marian", "password":"marian"}`, map[string]string{
  140. "Authorization": util.BearerAuth(token.Value),
  141. })
  142. require.Equal(t, 200, rr.Code)
  143. account, _ := util.UnmarshalJSON[apiAccountResponse](io.NopCloser(rr.Body))
  144. require.Equal(t, "de", account.Language)
  145. require.Equal(t, util.Int(86400), account.Notification.DeleteAfter)
  146. require.Equal(t, util.String("juntos"), account.Notification.Sound)
  147. require.Nil(t, account.Notification.MinPriority) // Not set
  148. }
  149. func TestAccount_Subscription_AddUpdateDelete(t *testing.T) {
  150. s := newTestServer(t, newTestConfigWithAuthFile(t))
  151. require.Nil(t, s.userManager.AddUser("phil", "phil", user.RoleUser))
  152. rr := request(t, s, "POST", "/v1/account/subscription", `{"base_url": "http://abc.com", "topic": "def"}`, map[string]string{
  153. "Authorization": util.BasicAuth("phil", "phil"),
  154. })
  155. require.Equal(t, 200, rr.Code)
  156. rr = request(t, s, "GET", "/v1/account", "", map[string]string{
  157. "Authorization": util.BasicAuth("phil", "phil"),
  158. })
  159. require.Equal(t, 200, rr.Code)
  160. account, _ := util.UnmarshalJSON[apiAccountResponse](io.NopCloser(rr.Body))
  161. require.Equal(t, 1, len(account.Subscriptions))
  162. require.NotEmpty(t, account.Subscriptions[0].ID)
  163. require.Equal(t, "http://abc.com", account.Subscriptions[0].BaseURL)
  164. require.Equal(t, "def", account.Subscriptions[0].Topic)
  165. require.Nil(t, account.Subscriptions[0].DisplayName)
  166. subscriptionID := account.Subscriptions[0].ID
  167. rr = request(t, s, "PATCH", "/v1/account/subscription/"+subscriptionID, `{"display_name": "ding dong"}`, map[string]string{
  168. "Authorization": util.BasicAuth("phil", "phil"),
  169. })
  170. require.Equal(t, 200, rr.Code)
  171. rr = request(t, s, "GET", "/v1/account", "", map[string]string{
  172. "Authorization": util.BasicAuth("phil", "phil"),
  173. })
  174. require.Equal(t, 200, rr.Code)
  175. account, _ = util.UnmarshalJSON[apiAccountResponse](io.NopCloser(rr.Body))
  176. require.Equal(t, 1, len(account.Subscriptions))
  177. require.Equal(t, subscriptionID, account.Subscriptions[0].ID)
  178. require.Equal(t, "http://abc.com", account.Subscriptions[0].BaseURL)
  179. require.Equal(t, "def", account.Subscriptions[0].Topic)
  180. require.Equal(t, util.String("ding dong"), account.Subscriptions[0].DisplayName)
  181. rr = request(t, s, "DELETE", "/v1/account/subscription/"+subscriptionID, "", map[string]string{
  182. "Authorization": util.BasicAuth("phil", "phil"),
  183. })
  184. require.Equal(t, 200, rr.Code)
  185. rr = request(t, s, "GET", "/v1/account", "", map[string]string{
  186. "Authorization": util.BasicAuth("phil", "phil"),
  187. })
  188. require.Equal(t, 200, rr.Code)
  189. account, _ = util.UnmarshalJSON[apiAccountResponse](io.NopCloser(rr.Body))
  190. require.Equal(t, 0, len(account.Subscriptions))
  191. }
  192. func TestAccount_ChangePassword(t *testing.T) {
  193. s := newTestServer(t, newTestConfigWithAuthFile(t))
  194. require.Nil(t, s.userManager.AddUser("phil", "phil", user.RoleUser))
  195. rr := request(t, s, "POST", "/v1/account/password", `{"password": "phil", "new_password": "new password"}`, map[string]string{
  196. "Authorization": util.BasicAuth("phil", "phil"),
  197. })
  198. require.Equal(t, 200, rr.Code)
  199. rr = request(t, s, "GET", "/v1/account", "", map[string]string{
  200. "Authorization": util.BasicAuth("phil", "phil"),
  201. })
  202. require.Equal(t, 401, rr.Code)
  203. rr = request(t, s, "GET", "/v1/account", "", map[string]string{
  204. "Authorization": util.BasicAuth("phil", "new password"),
  205. })
  206. require.Equal(t, 200, rr.Code)
  207. }
  208. func TestAccount_ChangePassword_NoAccount(t *testing.T) {
  209. s := newTestServer(t, newTestConfigWithAuthFile(t))
  210. rr := request(t, s, "POST", "/v1/account/password", `{"password": "new password"}`, nil)
  211. require.Equal(t, 401, rr.Code)
  212. }
  213. func TestAccount_ExtendToken(t *testing.T) {
  214. s := newTestServer(t, newTestConfigWithAuthFile(t))
  215. require.Nil(t, s.userManager.AddUser("phil", "phil", user.RoleUser))
  216. rr := request(t, s, "POST", "/v1/account/token", "", map[string]string{
  217. "Authorization": util.BasicAuth("phil", "phil"),
  218. })
  219. require.Equal(t, 200, rr.Code)
  220. token, err := util.UnmarshalJSON[apiAccountTokenResponse](io.NopCloser(rr.Body))
  221. require.Nil(t, err)
  222. time.Sleep(time.Second)
  223. rr = request(t, s, "PATCH", "/v1/account/token", "", map[string]string{
  224. "Authorization": util.BearerAuth(token.Token),
  225. })
  226. require.Equal(t, 200, rr.Code)
  227. extendedToken, err := util.UnmarshalJSON[apiAccountTokenResponse](io.NopCloser(rr.Body))
  228. require.Nil(t, err)
  229. require.Equal(t, token.Token, extendedToken.Token)
  230. require.True(t, token.Expires < extendedToken.Expires)
  231. }
  232. func TestAccount_ExtendToken_NoTokenProvided(t *testing.T) {
  233. s := newTestServer(t, newTestConfigWithAuthFile(t))
  234. require.Nil(t, s.userManager.AddUser("phil", "phil", user.RoleUser))
  235. rr := request(t, s, "PATCH", "/v1/account/token", "", map[string]string{
  236. "Authorization": util.BasicAuth("phil", "phil"), // Not Bearer!
  237. })
  238. require.Equal(t, 400, rr.Code)
  239. require.Equal(t, 40023, toHTTPError(t, rr.Body.String()).Code)
  240. }
  241. func TestAccount_DeleteToken(t *testing.T) {
  242. s := newTestServer(t, newTestConfigWithAuthFile(t))
  243. require.Nil(t, s.userManager.AddUser("phil", "phil", user.RoleUser))
  244. rr := request(t, s, "POST", "/v1/account/token", "", map[string]string{
  245. "Authorization": util.BasicAuth("phil", "phil"),
  246. })
  247. require.Equal(t, 200, rr.Code)
  248. token, err := util.UnmarshalJSON[apiAccountTokenResponse](io.NopCloser(rr.Body))
  249. require.Nil(t, err)
  250. // Delete token failure (using basic auth)
  251. rr = request(t, s, "DELETE", "/v1/account/token", "", map[string]string{
  252. "Authorization": util.BasicAuth("phil", "phil"), // Not Bearer!
  253. })
  254. require.Equal(t, 400, rr.Code)
  255. require.Equal(t, 40023, toHTTPError(t, rr.Body.String()).Code)
  256. // Delete token with wrong token
  257. rr = request(t, s, "DELETE", "/v1/account/token", "", map[string]string{
  258. "Authorization": util.BearerAuth("invalidtoken"),
  259. })
  260. require.Equal(t, 401, rr.Code)
  261. // Delete token with correct token
  262. rr = request(t, s, "DELETE", "/v1/account/token", "", map[string]string{
  263. "Authorization": util.BearerAuth(token.Token),
  264. })
  265. require.Equal(t, 200, rr.Code)
  266. // Cannot get account anymore
  267. rr = request(t, s, "GET", "/v1/account", "", map[string]string{
  268. "Authorization": util.BearerAuth(token.Token),
  269. })
  270. require.Equal(t, 401, rr.Code)
  271. }
  272. func TestAccount_Delete_Success(t *testing.T) {
  273. conf := newTestConfigWithAuthFile(t)
  274. conf.EnableSignup = true
  275. s := newTestServer(t, conf)
  276. rr := request(t, s, "POST", "/v1/account", `{"username":"phil", "password":"mypass"}`, nil)
  277. require.Equal(t, 200, rr.Code)
  278. rr = request(t, s, "GET", "/v1/account", "", map[string]string{
  279. "Authorization": util.BasicAuth("phil", "mypass"),
  280. })
  281. require.Equal(t, 200, rr.Code)
  282. rr = request(t, s, "DELETE", "/v1/account", `{"password":"mypass"}`, map[string]string{
  283. "Authorization": util.BasicAuth("phil", "mypass"),
  284. })
  285. require.Equal(t, 200, rr.Code)
  286. // Account was marked deleted
  287. rr = request(t, s, "GET", "/v1/account", "", map[string]string{
  288. "Authorization": util.BasicAuth("phil", "mypass"),
  289. })
  290. require.Equal(t, 401, rr.Code)
  291. // Cannot re-create account, since still exists
  292. rr = request(t, s, "POST", "/v1/account", `{"username":"phil", "password":"mypass"}`, nil)
  293. require.Equal(t, 409, rr.Code)
  294. }
  295. func TestAccount_Delete_Not_Allowed(t *testing.T) {
  296. conf := newTestConfigWithAuthFile(t)
  297. conf.EnableSignup = true
  298. s := newTestServer(t, conf)
  299. rr := request(t, s, "POST", "/v1/account", `{"username":"phil", "password":"mypass"}`, nil)
  300. require.Equal(t, 200, rr.Code)
  301. rr = request(t, s, "DELETE", "/v1/account", "", nil)
  302. require.Equal(t, 401, rr.Code)
  303. rr = request(t, s, "DELETE", "/v1/account", `{"password":"mypass"}`, nil)
  304. require.Equal(t, 401, rr.Code)
  305. rr = request(t, s, "DELETE", "/v1/account", `{"password":"INCORRECT"}`, map[string]string{
  306. "Authorization": util.BasicAuth("phil", "mypass"),
  307. })
  308. require.Equal(t, 400, rr.Code)
  309. require.Equal(t, 40030, toHTTPError(t, rr.Body.String()).Code)
  310. }
  311. func TestAccount_Reservation_AddWithoutTierFails(t *testing.T) {
  312. conf := newTestConfigWithAuthFile(t)
  313. conf.EnableSignup = true
  314. s := newTestServer(t, conf)
  315. rr := request(t, s, "POST", "/v1/account", `{"username":"phil", "password":"mypass"}`, nil)
  316. require.Equal(t, 200, rr.Code)
  317. rr = request(t, s, "POST", "/v1/account/reservation", `{"topic":"mytopic", "everyone":"deny-all"}`, map[string]string{
  318. "Authorization": util.BasicAuth("phil", "mypass"),
  319. })
  320. require.Equal(t, 401, rr.Code)
  321. }
  322. func TestAccount_Reservation_AddAdminSuccess(t *testing.T) {
  323. conf := newTestConfigWithAuthFile(t)
  324. conf.EnableSignup = true
  325. s := newTestServer(t, conf)
  326. require.Nil(t, s.userManager.AddUser("phil", "adminpass", user.RoleAdmin))
  327. rr := request(t, s, "POST", "/v1/account/reservation", `{"topic":"mytopic","everyone":"deny-all"}`, map[string]string{
  328. "Authorization": util.BasicAuth("phil", "adminpass"),
  329. })
  330. require.Equal(t, 400, rr.Code)
  331. require.Equal(t, 40026, toHTTPError(t, rr.Body.String()).Code)
  332. }
  333. func TestAccount_Reservation_AddRemoveUserWithTierSuccess(t *testing.T) {
  334. conf := newTestConfigWithAuthFile(t)
  335. conf.EnableSignup = true
  336. s := newTestServer(t, conf)
  337. // Create user
  338. rr := request(t, s, "POST", "/v1/account", `{"username":"phil", "password":"mypass"}`, nil)
  339. require.Equal(t, 200, rr.Code)
  340. // Create a tier
  341. require.Nil(t, s.userManager.CreateTier(&user.Tier{
  342. Code: "pro",
  343. MessageLimit: 123,
  344. MessageExpiryDuration: 86400 * time.Second,
  345. EmailLimit: 32,
  346. ReservationLimit: 2,
  347. AttachmentFileSizeLimit: 1231231,
  348. AttachmentTotalSizeLimit: 123123,
  349. AttachmentExpiryDuration: 10800 * time.Second,
  350. AttachmentBandwidthLimit: 21474836480,
  351. }))
  352. require.Nil(t, s.userManager.ChangeTier("phil", "pro"))
  353. // Reserve two topics
  354. rr = request(t, s, "POST", "/v1/account/reservation", `{"topic": "mytopic", "everyone":"deny-all"}`, map[string]string{
  355. "Authorization": util.BasicAuth("phil", "mypass"),
  356. })
  357. require.Equal(t, 200, rr.Code)
  358. rr = request(t, s, "POST", "/v1/account/reservation", `{"topic": "another", "everyone":"read-only"}`, map[string]string{
  359. "Authorization": util.BasicAuth("phil", "mypass"),
  360. })
  361. require.Equal(t, 200, rr.Code)
  362. // Trying to reserve a third should fail
  363. rr = request(t, s, "POST", "/v1/account/reservation", `{"topic": "yet-another", "everyone":"deny-all"}`, map[string]string{
  364. "Authorization": util.BasicAuth("phil", "mypass"),
  365. })
  366. require.Equal(t, 429, rr.Code)
  367. // Modify existing should still work
  368. rr = request(t, s, "POST", "/v1/account/reservation", `{"topic": "another", "everyone":"write-only"}`, map[string]string{
  369. "Authorization": util.BasicAuth("phil", "mypass"),
  370. })
  371. require.Equal(t, 200, rr.Code)
  372. // Check account result
  373. rr = request(t, s, "GET", "/v1/account", "", map[string]string{
  374. "Authorization": util.BasicAuth("phil", "mypass"),
  375. })
  376. require.Equal(t, 200, rr.Code)
  377. account, _ := util.UnmarshalJSON[apiAccountResponse](io.NopCloser(rr.Body))
  378. require.Equal(t, "pro", account.Tier.Code)
  379. require.Equal(t, int64(123), account.Limits.Messages)
  380. require.Equal(t, int64(86400), account.Limits.MessagesExpiryDuration)
  381. require.Equal(t, int64(32), account.Limits.Emails)
  382. require.Equal(t, int64(2), account.Limits.Reservations)
  383. require.Equal(t, int64(1231231), account.Limits.AttachmentFileSize)
  384. require.Equal(t, int64(123123), account.Limits.AttachmentTotalSize)
  385. require.Equal(t, int64(10800), account.Limits.AttachmentExpiryDuration)
  386. require.Equal(t, int64(21474836480), account.Limits.AttachmentBandwidth)
  387. require.Equal(t, 2, len(account.Reservations))
  388. require.Equal(t, "another", account.Reservations[0].Topic)
  389. require.Equal(t, "write-only", account.Reservations[0].Everyone)
  390. require.Equal(t, "mytopic", account.Reservations[1].Topic)
  391. require.Equal(t, "deny-all", account.Reservations[1].Everyone)
  392. // Delete and re-check
  393. rr = request(t, s, "DELETE", "/v1/account/reservation/another", "", map[string]string{
  394. "Authorization": util.BasicAuth("phil", "mypass"),
  395. })
  396. require.Equal(t, 200, rr.Code)
  397. rr = request(t, s, "GET", "/v1/account", "", map[string]string{
  398. "Authorization": util.BasicAuth("phil", "mypass"),
  399. })
  400. require.Equal(t, 200, rr.Code)
  401. account, _ = util.UnmarshalJSON[apiAccountResponse](io.NopCloser(rr.Body))
  402. require.Equal(t, 1, len(account.Reservations))
  403. require.Equal(t, "mytopic", account.Reservations[0].Topic)
  404. }
  405. func TestAccount_Reservation_PublishByAnonymousFails(t *testing.T) {
  406. conf := newTestConfigWithAuthFile(t)
  407. conf.AuthDefault = user.PermissionReadWrite
  408. conf.EnableSignup = true
  409. s := newTestServer(t, conf)
  410. // Create user with tier
  411. rr := request(t, s, "POST", "/v1/account", `{"username":"phil", "password":"mypass"}`, nil)
  412. require.Equal(t, 200, rr.Code)
  413. require.Nil(t, s.userManager.CreateTier(&user.Tier{
  414. Code: "pro",
  415. MessageLimit: 20,
  416. ReservationLimit: 2,
  417. }))
  418. require.Nil(t, s.userManager.ChangeTier("phil", "pro"))
  419. // Reserve a topic
  420. rr = request(t, s, "POST", "/v1/account/reservation", `{"topic": "mytopic", "everyone":"deny-all"}`, map[string]string{
  421. "Authorization": util.BasicAuth("phil", "mypass"),
  422. })
  423. require.Equal(t, 200, rr.Code)
  424. // Publish a message
  425. rr = request(t, s, "POST", "/mytopic", `Howdy`, map[string]string{
  426. "Authorization": util.BasicAuth("phil", "mypass"),
  427. })
  428. require.Equal(t, 200, rr.Code)
  429. // Publish a message (as anonymous)
  430. rr = request(t, s, "POST", "/mytopic", `Howdy`, nil)
  431. require.Equal(t, 403, rr.Code)
  432. }
  433. func TestAccount_Reservation_Add_Kills_Other_Subscribers(t *testing.T) {
  434. conf := newTestConfigWithAuthFile(t)
  435. conf.AuthDefault = user.PermissionReadWrite
  436. conf.EnableSignup = true
  437. s := newTestServer(t, conf)
  438. // Create user with tier
  439. rr := request(t, s, "POST", "/v1/account", `{"username":"phil", "password":"mypass"}`, nil)
  440. require.Equal(t, 200, rr.Code)
  441. require.Nil(t, s.userManager.CreateTier(&user.Tier{
  442. Code: "pro",
  443. MessageLimit: 20,
  444. ReservationLimit: 2,
  445. }))
  446. require.Nil(t, s.userManager.ChangeTier("phil", "pro"))
  447. // Subscribe anonymously
  448. anonCh, userCh := make(chan bool), make(chan bool)
  449. go func() {
  450. rr := request(t, s, "GET", "/mytopic/json", ``, nil)
  451. require.Equal(t, 200, rr.Code)
  452. messages := toMessages(t, rr.Body.String())
  453. require.Equal(t, 2, len(messages)) // This is the meat. We should NOT receive the second message!
  454. require.Equal(t, "open", messages[0].Event)
  455. require.Equal(t, "message before reservation", messages[1].Message)
  456. anonCh <- true
  457. }()
  458. // Subscribe with user
  459. go func() {
  460. rr := request(t, s, "GET", "/mytopic/json", ``, map[string]string{
  461. "Authorization": util.BasicAuth("phil", "mypass"),
  462. })
  463. require.Equal(t, 200, rr.Code)
  464. messages := toMessages(t, rr.Body.String())
  465. require.Equal(t, 3, len(messages))
  466. require.Equal(t, "open", messages[0].Event)
  467. require.Equal(t, "message before reservation", messages[1].Message)
  468. require.Equal(t, "message after reservation", messages[2].Message)
  469. userCh <- true
  470. }()
  471. // Publish message (before reservation)
  472. time.Sleep(700 * time.Millisecond) // Wait for subscribers
  473. rr = request(t, s, "POST", "/mytopic", "message before reservation", nil)
  474. require.Equal(t, 200, rr.Code)
  475. time.Sleep(700 * time.Millisecond) // Wait for subscribers to receive message
  476. // Reserve a topic
  477. rr = request(t, s, "POST", "/v1/account/reservation", `{"topic": "mytopic", "everyone":"deny-all"}`, map[string]string{
  478. "Authorization": util.BasicAuth("phil", "mypass"),
  479. })
  480. require.Equal(t, 200, rr.Code)
  481. // Everyone but phil should be killed
  482. <-anonCh
  483. // Publish a message
  484. rr = request(t, s, "POST", "/mytopic", "message after reservation", map[string]string{
  485. "Authorization": util.BasicAuth("phil", "mypass"),
  486. })
  487. require.Equal(t, 200, rr.Code)
  488. // Kill user Go routine
  489. s.topics["mytopic"].CancelSubscribers("<invalid>")
  490. <-userCh
  491. }
  492. func TestAccount_Tier_Create(t *testing.T) {
  493. conf := newTestConfigWithAuthFile(t)
  494. s := newTestServer(t, conf)
  495. // Create tier and user
  496. require.Nil(t, s.userManager.CreateTier(&user.Tier{
  497. Code: "pro",
  498. Name: "Pro",
  499. MessageLimit: 123,
  500. MessageExpiryDuration: 86400 * time.Second,
  501. EmailLimit: 32,
  502. ReservationLimit: 2,
  503. AttachmentFileSizeLimit: 1231231,
  504. AttachmentTotalSizeLimit: 123123,
  505. AttachmentExpiryDuration: 10800 * time.Second,
  506. AttachmentBandwidthLimit: 21474836480,
  507. }))
  508. require.Nil(t, s.userManager.AddUser("phil", "phil", user.RoleUser))
  509. require.Nil(t, s.userManager.ChangeTier("phil", "pro"))
  510. ti, err := s.userManager.Tier("pro")
  511. require.Nil(t, err)
  512. u, err := s.userManager.User("phil")
  513. require.Nil(t, err)
  514. // These are populated by different SQL queries
  515. require.Equal(t, ti, u.Tier)
  516. // Fields
  517. require.True(t, strings.HasPrefix(ti.ID, "ti_"))
  518. require.Equal(t, "pro", ti.Code)
  519. require.Equal(t, "Pro", ti.Name)
  520. require.Equal(t, int64(123), ti.MessageLimit)
  521. require.Equal(t, 86400*time.Second, ti.MessageExpiryDuration)
  522. require.Equal(t, int64(32), ti.EmailLimit)
  523. require.Equal(t, int64(2), ti.ReservationLimit)
  524. require.Equal(t, int64(1231231), ti.AttachmentFileSizeLimit)
  525. require.Equal(t, int64(123123), ti.AttachmentTotalSizeLimit)
  526. require.Equal(t, 10800*time.Second, ti.AttachmentExpiryDuration)
  527. require.Equal(t, int64(21474836480), ti.AttachmentBandwidthLimit)
  528. }
  529. func TestAccount_Tier_Create_With_ID(t *testing.T) {
  530. conf := newTestConfigWithAuthFile(t)
  531. s := newTestServer(t, conf)
  532. require.Nil(t, s.userManager.CreateTier(&user.Tier{
  533. ID: "ti_123",
  534. Code: "pro",
  535. }))
  536. ti, err := s.userManager.Tier("pro")
  537. require.Nil(t, err)
  538. require.Equal(t, "ti_123", ti.ID)
  539. }