server_account_test.go 23 KB

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