manager_test.go 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085
  1. package user
  2. import (
  3. "database/sql"
  4. "fmt"
  5. "github.com/stretchr/testify/require"
  6. "github.com/stripe/stripe-go/v74"
  7. "golang.org/x/crypto/bcrypt"
  8. "heckel.io/ntfy/util"
  9. "net/netip"
  10. "path/filepath"
  11. "strings"
  12. "testing"
  13. "time"
  14. )
  15. const minBcryptTimingMillis = int64(50) // Ideally should be >100ms, but this should also run on a Raspberry Pi without massive resources
  16. func TestManager_FullScenario_Default_DenyAll(t *testing.T) {
  17. a := newTestManagerFromFile(t, filepath.Join(t.TempDir(), "user.db"), "", PermissionDenyAll, DefaultUserPasswordBcryptCost, DefaultUserStatsQueueWriterInterval)
  18. require.Nil(t, a.AddUser("phil", "phil", RoleAdmin))
  19. require.Nil(t, a.AddUser("ben", "ben", RoleUser))
  20. require.Nil(t, a.AllowAccess("ben", "mytopic", PermissionReadWrite))
  21. require.Nil(t, a.AllowAccess("ben", "readme", PermissionRead))
  22. require.Nil(t, a.AllowAccess("ben", "writeme", PermissionWrite))
  23. require.Nil(t, a.AllowAccess("ben", "everyonewrite", PermissionDenyAll)) // How unfair!
  24. require.Nil(t, a.AllowAccess(Everyone, "announcements", PermissionRead))
  25. require.Nil(t, a.AllowAccess(Everyone, "everyonewrite", PermissionReadWrite))
  26. require.Nil(t, a.AllowAccess(Everyone, "up*", PermissionWrite)) // Everyone can write to /up*
  27. phil, err := a.Authenticate("phil", "phil")
  28. require.Nil(t, err)
  29. require.Equal(t, "phil", phil.Name)
  30. require.True(t, strings.HasPrefix(phil.Hash, "$2a$10$"))
  31. require.Equal(t, RoleAdmin, phil.Role)
  32. philGrants, err := a.Grants("phil")
  33. require.Nil(t, err)
  34. require.Equal(t, []Grant{}, philGrants)
  35. ben, err := a.Authenticate("ben", "ben")
  36. require.Nil(t, err)
  37. require.Equal(t, "ben", ben.Name)
  38. require.True(t, strings.HasPrefix(ben.Hash, "$2a$10$"))
  39. require.Equal(t, RoleUser, ben.Role)
  40. benGrants, err := a.Grants("ben")
  41. require.Nil(t, err)
  42. require.Equal(t, []Grant{
  43. {"mytopic", PermissionReadWrite},
  44. {"writeme", PermissionWrite},
  45. {"readme", PermissionRead},
  46. {"everyonewrite", PermissionDenyAll},
  47. }, benGrants)
  48. notben, err := a.Authenticate("ben", "this is wrong")
  49. require.Nil(t, notben)
  50. require.Equal(t, ErrUnauthenticated, err)
  51. // Admin can do everything
  52. require.Nil(t, a.Authorize(phil, "sometopic", PermissionWrite))
  53. require.Nil(t, a.Authorize(phil, "mytopic", PermissionRead))
  54. require.Nil(t, a.Authorize(phil, "readme", PermissionWrite))
  55. require.Nil(t, a.Authorize(phil, "writeme", PermissionWrite))
  56. require.Nil(t, a.Authorize(phil, "announcements", PermissionWrite))
  57. require.Nil(t, a.Authorize(phil, "everyonewrite", PermissionWrite))
  58. // User cannot do everything
  59. require.Nil(t, a.Authorize(ben, "mytopic", PermissionWrite))
  60. require.Nil(t, a.Authorize(ben, "mytopic", PermissionRead))
  61. require.Nil(t, a.Authorize(ben, "readme", PermissionRead))
  62. require.Equal(t, ErrUnauthorized, a.Authorize(ben, "readme", PermissionWrite))
  63. require.Equal(t, ErrUnauthorized, a.Authorize(ben, "writeme", PermissionRead))
  64. require.Nil(t, a.Authorize(ben, "writeme", PermissionWrite))
  65. require.Nil(t, a.Authorize(ben, "writeme", PermissionWrite))
  66. require.Equal(t, ErrUnauthorized, a.Authorize(ben, "everyonewrite", PermissionRead))
  67. require.Equal(t, ErrUnauthorized, a.Authorize(ben, "everyonewrite", PermissionWrite))
  68. require.Nil(t, a.Authorize(ben, "announcements", PermissionRead))
  69. require.Equal(t, ErrUnauthorized, a.Authorize(ben, "announcements", PermissionWrite))
  70. // Everyone else can do barely anything
  71. require.Equal(t, ErrUnauthorized, a.Authorize(nil, "sometopicnotinthelist", PermissionRead))
  72. require.Equal(t, ErrUnauthorized, a.Authorize(nil, "sometopicnotinthelist", PermissionWrite))
  73. require.Equal(t, ErrUnauthorized, a.Authorize(nil, "mytopic", PermissionRead))
  74. require.Equal(t, ErrUnauthorized, a.Authorize(nil, "mytopic", PermissionWrite))
  75. require.Equal(t, ErrUnauthorized, a.Authorize(nil, "readme", PermissionRead))
  76. require.Equal(t, ErrUnauthorized, a.Authorize(nil, "readme", PermissionWrite))
  77. require.Equal(t, ErrUnauthorized, a.Authorize(nil, "writeme", PermissionRead))
  78. require.Equal(t, ErrUnauthorized, a.Authorize(nil, "writeme", PermissionWrite))
  79. require.Equal(t, ErrUnauthorized, a.Authorize(nil, "announcements", PermissionWrite))
  80. require.Nil(t, a.Authorize(nil, "announcements", PermissionRead))
  81. require.Nil(t, a.Authorize(nil, "everyonewrite", PermissionRead))
  82. require.Nil(t, a.Authorize(nil, "everyonewrite", PermissionWrite))
  83. require.Nil(t, a.Authorize(nil, "up1234", PermissionWrite)) // Wildcard permission
  84. require.Nil(t, a.Authorize(nil, "up5678", PermissionWrite))
  85. }
  86. func TestManager_AddUser_Invalid(t *testing.T) {
  87. a := newTestManager(t, PermissionDenyAll)
  88. require.Equal(t, ErrInvalidArgument, a.AddUser(" invalid ", "pass", RoleAdmin))
  89. require.Equal(t, ErrInvalidArgument, a.AddUser("validuser", "pass", "invalid-role"))
  90. }
  91. func TestManager_AddUser_Timing(t *testing.T) {
  92. a := newTestManagerFromFile(t, filepath.Join(t.TempDir(), "user.db"), "", PermissionDenyAll, DefaultUserPasswordBcryptCost, DefaultUserStatsQueueWriterInterval)
  93. start := time.Now().UnixMilli()
  94. require.Nil(t, a.AddUser("user", "pass", RoleAdmin))
  95. require.GreaterOrEqual(t, time.Now().UnixMilli()-start, minBcryptTimingMillis)
  96. }
  97. func TestManager_AddUser_And_Query(t *testing.T) {
  98. a := newTestManagerFromFile(t, filepath.Join(t.TempDir(), "user.db"), "", PermissionDenyAll, DefaultUserPasswordBcryptCost, DefaultUserStatsQueueWriterInterval)
  99. require.Nil(t, a.AddUser("user", "pass", RoleAdmin))
  100. require.Nil(t, a.ChangeBilling("user", &Billing{
  101. StripeCustomerID: "acct_123",
  102. StripeSubscriptionID: "sub_123",
  103. StripeSubscriptionStatus: stripe.SubscriptionStatusActive,
  104. StripeSubscriptionInterval: stripe.PriceRecurringIntervalMonth,
  105. StripeSubscriptionPaidUntil: time.Now().Add(time.Hour),
  106. StripeSubscriptionCancelAt: time.Unix(0, 0),
  107. }))
  108. u, err := a.User("user")
  109. require.Nil(t, err)
  110. require.Equal(t, "user", u.Name)
  111. u2, err := a.UserByID(u.ID)
  112. require.Nil(t, err)
  113. require.Equal(t, u.Name, u2.Name)
  114. u3, err := a.UserByStripeCustomer("acct_123")
  115. require.Nil(t, err)
  116. require.Equal(t, u.ID, u3.ID)
  117. }
  118. func TestManager_MarkUserRemoved_RemoveDeletedUsers(t *testing.T) {
  119. a := newTestManager(t, PermissionDenyAll)
  120. // Create user, add reservations and token
  121. require.Nil(t, a.AddUser("user", "pass", RoleAdmin))
  122. require.Nil(t, a.AddReservation("user", "mytopic", PermissionRead))
  123. u, err := a.User("user")
  124. require.Nil(t, err)
  125. require.False(t, u.Deleted)
  126. token, err := a.CreateToken(u.ID, "", time.Now().Add(time.Hour), netip.IPv4Unspecified())
  127. require.Nil(t, err)
  128. u, err = a.Authenticate("user", "pass")
  129. require.Nil(t, err)
  130. _, err = a.AuthenticateToken(token.Value)
  131. require.Nil(t, err)
  132. reservations, err := a.Reservations("user")
  133. require.Nil(t, err)
  134. require.Equal(t, 1, len(reservations))
  135. // Mark deleted: cannot auth anymore, and all reservations are gone
  136. require.Nil(t, a.MarkUserRemoved(u))
  137. _, err = a.Authenticate("user", "pass")
  138. require.Equal(t, ErrUnauthenticated, err)
  139. _, err = a.AuthenticateToken(token.Value)
  140. require.Equal(t, ErrUnauthenticated, err)
  141. reservations, err = a.Reservations("user")
  142. require.Nil(t, err)
  143. require.Equal(t, 0, len(reservations))
  144. // Make sure user is still there
  145. u, err = a.User("user")
  146. require.Nil(t, err)
  147. require.True(t, u.Deleted)
  148. _, err = a.db.Exec("UPDATE user SET deleted = ? WHERE id = ?", time.Now().Add(-1*(userHardDeleteAfterDuration+time.Hour)).Unix(), u.ID)
  149. require.Nil(t, err)
  150. require.Nil(t, a.RemoveDeletedUsers())
  151. _, err = a.User("user")
  152. require.Equal(t, ErrUserNotFound, err)
  153. }
  154. func TestManager_CreateToken_Only_Lower(t *testing.T) {
  155. a := newTestManager(t, PermissionDenyAll)
  156. // Create user, add reservations and token
  157. require.Nil(t, a.AddUser("user", "pass", RoleAdmin))
  158. u, err := a.User("user")
  159. require.Nil(t, err)
  160. token, err := a.CreateToken(u.ID, "", time.Now().Add(time.Hour), netip.IPv4Unspecified())
  161. require.Nil(t, err)
  162. require.Equal(t, token.Value, strings.ToLower(token.Value))
  163. }
  164. func TestManager_UserManagement(t *testing.T) {
  165. a := newTestManager(t, PermissionDenyAll)
  166. require.Nil(t, a.AddUser("phil", "phil", RoleAdmin))
  167. require.Nil(t, a.AddUser("ben", "ben", RoleUser))
  168. require.Nil(t, a.AllowAccess("ben", "mytopic", PermissionReadWrite))
  169. require.Nil(t, a.AllowAccess("ben", "readme", PermissionRead))
  170. require.Nil(t, a.AllowAccess("ben", "writeme", PermissionWrite))
  171. require.Nil(t, a.AllowAccess("ben", "everyonewrite", PermissionDenyAll)) // How unfair!
  172. require.Nil(t, a.AllowAccess(Everyone, "announcements", PermissionRead))
  173. require.Nil(t, a.AllowAccess(Everyone, "everyonewrite", PermissionReadWrite))
  174. // Query user details
  175. phil, err := a.User("phil")
  176. require.Nil(t, err)
  177. require.Equal(t, "phil", phil.Name)
  178. require.True(t, strings.HasPrefix(phil.Hash, "$2a$04$")) // Min cost for testing
  179. require.Equal(t, RoleAdmin, phil.Role)
  180. philGrants, err := a.Grants("phil")
  181. require.Nil(t, err)
  182. require.Equal(t, []Grant{}, philGrants)
  183. ben, err := a.User("ben")
  184. require.Nil(t, err)
  185. require.Equal(t, "ben", ben.Name)
  186. require.True(t, strings.HasPrefix(ben.Hash, "$2a$04$")) // Min cost for testing
  187. require.Equal(t, RoleUser, ben.Role)
  188. benGrants, err := a.Grants("ben")
  189. require.Nil(t, err)
  190. require.Equal(t, []Grant{
  191. {"mytopic", PermissionReadWrite},
  192. {"writeme", PermissionWrite},
  193. {"readme", PermissionRead},
  194. {"everyonewrite", PermissionDenyAll},
  195. }, benGrants)
  196. everyone, err := a.User(Everyone)
  197. require.Nil(t, err)
  198. require.Equal(t, "*", everyone.Name)
  199. require.Equal(t, "", everyone.Hash)
  200. require.Equal(t, RoleAnonymous, everyone.Role)
  201. everyoneGrants, err := a.Grants(Everyone)
  202. require.Nil(t, err)
  203. require.Equal(t, []Grant{
  204. {"everyonewrite", PermissionReadWrite},
  205. {"announcements", PermissionRead},
  206. }, everyoneGrants)
  207. // Ben: Before revoking
  208. require.Nil(t, a.AllowAccess("ben", "mytopic", PermissionReadWrite)) // Overwrite!
  209. require.Nil(t, a.AllowAccess("ben", "readme", PermissionRead))
  210. require.Nil(t, a.AllowAccess("ben", "writeme", PermissionWrite))
  211. require.Nil(t, a.Authorize(ben, "mytopic", PermissionRead))
  212. require.Nil(t, a.Authorize(ben, "mytopic", PermissionWrite))
  213. require.Nil(t, a.Authorize(ben, "readme", PermissionRead))
  214. require.Nil(t, a.Authorize(ben, "writeme", PermissionWrite))
  215. // Revoke access for "ben" to "mytopic", then check again
  216. require.Nil(t, a.ResetAccess("ben", "mytopic"))
  217. require.Equal(t, ErrUnauthorized, a.Authorize(ben, "mytopic", PermissionWrite)) // Revoked
  218. require.Equal(t, ErrUnauthorized, a.Authorize(ben, "mytopic", PermissionRead)) // Revoked
  219. require.Nil(t, a.Authorize(ben, "readme", PermissionRead)) // Unchanged
  220. require.Nil(t, a.Authorize(ben, "writeme", PermissionWrite)) // Unchanged
  221. // Revoke rest of the access
  222. require.Nil(t, a.ResetAccess("ben", ""))
  223. require.Equal(t, ErrUnauthorized, a.Authorize(ben, "readme", PermissionRead)) // Revoked
  224. require.Equal(t, ErrUnauthorized, a.Authorize(ben, "wrtiteme", PermissionWrite)) // Revoked
  225. // User list
  226. users, err := a.Users()
  227. require.Nil(t, err)
  228. require.Equal(t, 3, len(users))
  229. require.Equal(t, "phil", users[0].Name)
  230. require.Equal(t, "ben", users[1].Name)
  231. require.Equal(t, "*", users[2].Name)
  232. // Remove user
  233. require.Nil(t, a.RemoveUser("ben"))
  234. _, err = a.User("ben")
  235. require.Equal(t, ErrUserNotFound, err)
  236. users, err = a.Users()
  237. require.Nil(t, err)
  238. require.Equal(t, 2, len(users))
  239. require.Equal(t, "phil", users[0].Name)
  240. require.Equal(t, "*", users[1].Name)
  241. }
  242. func TestManager_ChangePassword(t *testing.T) {
  243. a := newTestManager(t, PermissionDenyAll)
  244. require.Nil(t, a.AddUser("phil", "phil", RoleAdmin))
  245. _, err := a.Authenticate("phil", "phil")
  246. require.Nil(t, err)
  247. require.Nil(t, a.ChangePassword("phil", "newpass"))
  248. _, err = a.Authenticate("phil", "phil")
  249. require.Equal(t, ErrUnauthenticated, err)
  250. _, err = a.Authenticate("phil", "newpass")
  251. require.Nil(t, err)
  252. }
  253. func TestManager_ChangeRole(t *testing.T) {
  254. a := newTestManager(t, PermissionDenyAll)
  255. require.Nil(t, a.AddUser("ben", "ben", RoleUser))
  256. require.Nil(t, a.AllowAccess("ben", "mytopic", PermissionReadWrite))
  257. require.Nil(t, a.AllowAccess("ben", "readme", PermissionRead))
  258. ben, err := a.User("ben")
  259. require.Nil(t, err)
  260. require.Equal(t, RoleUser, ben.Role)
  261. benGrants, err := a.Grants("ben")
  262. require.Nil(t, err)
  263. require.Equal(t, 2, len(benGrants))
  264. require.Nil(t, a.ChangeRole("ben", RoleAdmin))
  265. ben, err = a.User("ben")
  266. require.Nil(t, err)
  267. require.Equal(t, RoleAdmin, ben.Role)
  268. benGrants, err = a.Grants("ben")
  269. require.Nil(t, err)
  270. require.Equal(t, 0, len(benGrants))
  271. }
  272. func TestManager_Reservations(t *testing.T) {
  273. a := newTestManager(t, PermissionDenyAll)
  274. require.Nil(t, a.AddUser("phil", "phil", RoleUser))
  275. require.Nil(t, a.AddUser("ben", "ben", RoleUser))
  276. require.Nil(t, a.AddReservation("ben", "ztopic", PermissionDenyAll))
  277. require.Nil(t, a.AddReservation("ben", "readme", PermissionRead))
  278. require.Nil(t, a.AllowAccess("ben", "something-else", PermissionRead))
  279. reservations, err := a.Reservations("ben")
  280. require.Nil(t, err)
  281. require.Equal(t, 2, len(reservations))
  282. require.Equal(t, Reservation{
  283. Topic: "readme",
  284. Owner: PermissionReadWrite,
  285. Everyone: PermissionRead,
  286. }, reservations[0])
  287. require.Equal(t, Reservation{
  288. Topic: "ztopic",
  289. Owner: PermissionReadWrite,
  290. Everyone: PermissionDenyAll,
  291. }, reservations[1])
  292. b, err := a.HasReservation("ben", "readme")
  293. require.Nil(t, err)
  294. require.True(t, b)
  295. b, err = a.HasReservation("notben", "readme")
  296. require.Nil(t, err)
  297. require.False(t, b)
  298. b, err = a.HasReservation("ben", "something-else")
  299. require.Nil(t, err)
  300. require.False(t, b)
  301. count, err := a.ReservationsCount("ben")
  302. require.Nil(t, err)
  303. require.Equal(t, int64(2), count)
  304. count, err = a.ReservationsCount("phil")
  305. require.Nil(t, err)
  306. require.Equal(t, int64(0), count)
  307. err = a.AllowReservation("phil", "readme")
  308. require.Equal(t, errTopicOwnedByOthers, err)
  309. err = a.AllowReservation("phil", "not-reserved")
  310. require.Nil(t, err)
  311. // Now remove them again
  312. require.Nil(t, a.RemoveReservations("ben", "ztopic", "readme"))
  313. count, err = a.ReservationsCount("ben")
  314. require.Nil(t, err)
  315. require.Equal(t, int64(0), count)
  316. }
  317. func TestManager_ChangeRoleFromTierUserToAdmin(t *testing.T) {
  318. a := newTestManager(t, PermissionDenyAll)
  319. require.Nil(t, a.AddTier(&Tier{
  320. Code: "pro",
  321. Name: "ntfy Pro",
  322. StripeMonthlyPriceID: "price123",
  323. MessageLimit: 5_000,
  324. MessageExpiryDuration: 3 * 24 * time.Hour,
  325. EmailLimit: 50,
  326. ReservationLimit: 5,
  327. AttachmentFileSizeLimit: 52428800,
  328. AttachmentTotalSizeLimit: 524288000,
  329. AttachmentExpiryDuration: 24 * time.Hour,
  330. }))
  331. require.Nil(t, a.AddUser("ben", "ben", RoleUser))
  332. require.Nil(t, a.ChangeTier("ben", "pro"))
  333. require.Nil(t, a.AddReservation("ben", "mytopic", PermissionDenyAll))
  334. ben, err := a.User("ben")
  335. require.Nil(t, err)
  336. require.Equal(t, RoleUser, ben.Role)
  337. require.Equal(t, "pro", ben.Tier.Code)
  338. require.Equal(t, int64(5000), ben.Tier.MessageLimit)
  339. require.Equal(t, 3*24*time.Hour, ben.Tier.MessageExpiryDuration)
  340. require.Equal(t, int64(50), ben.Tier.EmailLimit)
  341. require.Equal(t, int64(5), ben.Tier.ReservationLimit)
  342. require.Equal(t, int64(52428800), ben.Tier.AttachmentFileSizeLimit)
  343. require.Equal(t, int64(524288000), ben.Tier.AttachmentTotalSizeLimit)
  344. require.Equal(t, 24*time.Hour, ben.Tier.AttachmentExpiryDuration)
  345. benGrants, err := a.Grants("ben")
  346. require.Nil(t, err)
  347. require.Equal(t, 1, len(benGrants))
  348. require.Equal(t, PermissionReadWrite, benGrants[0].Allow)
  349. everyoneGrants, err := a.Grants(Everyone)
  350. require.Nil(t, err)
  351. require.Equal(t, 1, len(everyoneGrants))
  352. require.Equal(t, PermissionDenyAll, everyoneGrants[0].Allow)
  353. benReservations, err := a.Reservations("ben")
  354. require.Nil(t, err)
  355. require.Equal(t, 1, len(benReservations))
  356. require.Equal(t, "mytopic", benReservations[0].Topic)
  357. require.Equal(t, PermissionReadWrite, benReservations[0].Owner)
  358. require.Equal(t, PermissionDenyAll, benReservations[0].Everyone)
  359. // Switch to admin, this should remove all grants and owned ACL entries
  360. require.Nil(t, a.ChangeRole("ben", RoleAdmin))
  361. benGrants, err = a.Grants("ben")
  362. require.Nil(t, err)
  363. require.Equal(t, 0, len(benGrants))
  364. everyoneGrants, err = a.Grants(Everyone)
  365. require.Nil(t, err)
  366. require.Equal(t, 0, len(everyoneGrants))
  367. }
  368. func TestManager_Token_Valid(t *testing.T) {
  369. a := newTestManager(t, PermissionDenyAll)
  370. require.Nil(t, a.AddUser("ben", "ben", RoleUser))
  371. u, err := a.User("ben")
  372. require.Nil(t, err)
  373. // Create token for user
  374. token, err := a.CreateToken(u.ID, "some label", time.Now().Add(72*time.Hour), netip.IPv4Unspecified())
  375. require.Nil(t, err)
  376. require.NotEmpty(t, token.Value)
  377. require.Equal(t, "some label", token.Label)
  378. require.True(t, time.Now().Add(71*time.Hour).Unix() < token.Expires.Unix())
  379. u2, err := a.AuthenticateToken(token.Value)
  380. require.Nil(t, err)
  381. require.Equal(t, u.Name, u2.Name)
  382. require.Equal(t, token.Value, u2.Token)
  383. token2, err := a.Token(u.ID, token.Value)
  384. require.Nil(t, err)
  385. require.Equal(t, token.Value, token2.Value)
  386. require.Equal(t, "some label", token2.Label)
  387. tokens, err := a.Tokens(u.ID)
  388. require.Nil(t, err)
  389. require.Equal(t, 1, len(tokens))
  390. require.Equal(t, "some label", tokens[0].Label)
  391. tokens, err = a.Tokens("u_notauser")
  392. require.Nil(t, err)
  393. require.Equal(t, 0, len(tokens))
  394. // Remove token and auth again
  395. require.Nil(t, a.RemoveToken(u2.ID, u2.Token))
  396. u3, err := a.AuthenticateToken(token.Value)
  397. require.Equal(t, ErrUnauthenticated, err)
  398. require.Nil(t, u3)
  399. tokens, err = a.Tokens(u.ID)
  400. require.Nil(t, err)
  401. require.Equal(t, 0, len(tokens))
  402. }
  403. func TestManager_Token_Invalid(t *testing.T) {
  404. a := newTestManager(t, PermissionDenyAll)
  405. require.Nil(t, a.AddUser("ben", "ben", RoleUser))
  406. u, err := a.AuthenticateToken(strings.Repeat("x", 32)) // 32 == token length
  407. require.Nil(t, u)
  408. require.Equal(t, ErrUnauthenticated, err)
  409. u, err = a.AuthenticateToken("not long enough anyway")
  410. require.Nil(t, u)
  411. require.Equal(t, ErrUnauthenticated, err)
  412. }
  413. func TestManager_Token_NotFound(t *testing.T) {
  414. a := newTestManager(t, PermissionDenyAll)
  415. _, err := a.Token("u_bla", "notfound")
  416. require.Equal(t, ErrTokenNotFound, err)
  417. }
  418. func TestManager_Token_Expire(t *testing.T) {
  419. a := newTestManager(t, PermissionDenyAll)
  420. require.Nil(t, a.AddUser("ben", "ben", RoleUser))
  421. u, err := a.User("ben")
  422. require.Nil(t, err)
  423. // Create tokens for user
  424. token1, err := a.CreateToken(u.ID, "", time.Now().Add(72*time.Hour), netip.IPv4Unspecified())
  425. require.Nil(t, err)
  426. require.NotEmpty(t, token1.Value)
  427. require.True(t, time.Now().Add(71*time.Hour).Unix() < token1.Expires.Unix())
  428. token2, err := a.CreateToken(u.ID, "", time.Now().Add(72*time.Hour), netip.IPv4Unspecified())
  429. require.Nil(t, err)
  430. require.NotEmpty(t, token2.Value)
  431. require.NotEqual(t, token1.Value, token2.Value)
  432. require.True(t, time.Now().Add(71*time.Hour).Unix() < token2.Expires.Unix())
  433. // See that tokens work
  434. _, err = a.AuthenticateToken(token1.Value)
  435. require.Nil(t, err)
  436. _, err = a.AuthenticateToken(token2.Value)
  437. require.Nil(t, err)
  438. // Modify token expiration in database
  439. _, err = a.db.Exec("UPDATE user_token SET expires = 1 WHERE token = ?", token1.Value)
  440. require.Nil(t, err)
  441. // Now token1 shouldn't work anymore
  442. _, err = a.AuthenticateToken(token1.Value)
  443. require.Equal(t, ErrUnauthenticated, err)
  444. result, err := a.db.Query("SELECT * from user_token WHERE token = ?", token1.Value)
  445. require.Nil(t, err)
  446. require.True(t, result.Next()) // Still a matching row
  447. require.Nil(t, result.Close())
  448. // Expire tokens and check database rows
  449. require.Nil(t, a.RemoveExpiredTokens())
  450. result, err = a.db.Query("SELECT * from user_token WHERE token = ?", token1.Value)
  451. require.Nil(t, err)
  452. require.False(t, result.Next()) // No matching row!
  453. require.Nil(t, result.Close())
  454. }
  455. func TestManager_Token_Extend(t *testing.T) {
  456. a := newTestManager(t, PermissionDenyAll)
  457. require.Nil(t, a.AddUser("ben", "ben", RoleUser))
  458. // Try to extend token for user without token
  459. u, err := a.User("ben")
  460. require.Nil(t, err)
  461. _, err = a.ChangeToken(u.ID, u.Token, util.String("some label"), util.Time(time.Now().Add(time.Hour)))
  462. require.Equal(t, errNoTokenProvided, err)
  463. // Create token for user
  464. token, err := a.CreateToken(u.ID, "", time.Now().Add(72*time.Hour), netip.IPv4Unspecified())
  465. require.Nil(t, err)
  466. require.NotEmpty(t, token.Value)
  467. userWithToken, err := a.AuthenticateToken(token.Value)
  468. require.Nil(t, err)
  469. extendedToken, err := a.ChangeToken(userWithToken.ID, userWithToken.Token, util.String("changed label"), util.Time(time.Now().Add(100*time.Hour)))
  470. require.Nil(t, err)
  471. require.Equal(t, token.Value, extendedToken.Value)
  472. require.Equal(t, "changed label", extendedToken.Label)
  473. require.True(t, token.Expires.Unix() < extendedToken.Expires.Unix())
  474. require.True(t, time.Now().Add(99*time.Hour).Unix() < extendedToken.Expires.Unix())
  475. }
  476. func TestManager_Token_MaxCount_AutoDelete(t *testing.T) {
  477. // Tests that tokens are automatically deleted when the maximum number of tokens is reached
  478. a := newTestManager(t, PermissionDenyAll)
  479. require.Nil(t, a.AddUser("ben", "ben", RoleUser))
  480. require.Nil(t, a.AddUser("phil", "phil", RoleUser))
  481. ben, err := a.User("ben")
  482. require.Nil(t, err)
  483. phil, err := a.User("phil")
  484. require.Nil(t, err)
  485. // Create 2 tokens for phil
  486. philTokens := make([]string, 0)
  487. token, err := a.CreateToken(phil.ID, "", time.Now().Add(72*time.Hour), netip.IPv4Unspecified())
  488. require.Nil(t, err)
  489. require.NotEmpty(t, token.Value)
  490. philTokens = append(philTokens, token.Value)
  491. token, err = a.CreateToken(phil.ID, "", time.Unix(0, 0), netip.IPv4Unspecified())
  492. require.Nil(t, err)
  493. require.NotEmpty(t, token.Value)
  494. philTokens = append(philTokens, token.Value)
  495. // Create 22 tokens for ben (only 20 allowed!)
  496. baseTime := time.Now().Add(24 * time.Hour)
  497. benTokens := make([]string, 0)
  498. for i := 0; i < 22; i++ { //
  499. token, err := a.CreateToken(ben.ID, "", time.Now().Add(72*time.Hour), netip.IPv4Unspecified())
  500. require.Nil(t, err)
  501. require.NotEmpty(t, token.Value)
  502. benTokens = append(benTokens, token.Value)
  503. // Manually modify expiry date to avoid sorting issues (this is a hack)
  504. _, err = a.db.Exec(`UPDATE user_token SET expires=? WHERE token=?`, baseTime.Add(time.Duration(i)*time.Minute).Unix(), token.Value)
  505. require.Nil(t, err)
  506. }
  507. // Ben: The first 2 tokens should have been wiped and should not work anymore!
  508. _, err = a.AuthenticateToken(benTokens[0])
  509. require.Equal(t, ErrUnauthenticated, err)
  510. _, err = a.AuthenticateToken(benTokens[1])
  511. require.Equal(t, ErrUnauthenticated, err)
  512. // Ben: The other tokens should still work
  513. for i := 2; i < 22; i++ {
  514. userWithToken, err := a.AuthenticateToken(benTokens[i])
  515. require.Nil(t, err, "token[%d]=%s failed", i, benTokens[i])
  516. require.Equal(t, "ben", userWithToken.Name)
  517. require.Equal(t, benTokens[i], userWithToken.Token)
  518. }
  519. // Phil: All tokens should still work
  520. for i := 0; i < 2; i++ {
  521. userWithToken, err := a.AuthenticateToken(philTokens[i])
  522. require.Nil(t, err, "token[%d]=%s failed", i, philTokens[i])
  523. require.Equal(t, "phil", userWithToken.Name)
  524. require.Equal(t, philTokens[i], userWithToken.Token)
  525. }
  526. var benCount int
  527. rows, err := a.db.Query(`SELECT COUNT(*) FROM user_token WHERE user_id=?`, ben.ID)
  528. require.Nil(t, err)
  529. require.True(t, rows.Next())
  530. require.Nil(t, rows.Scan(&benCount))
  531. require.Equal(t, 20, benCount)
  532. var philCount int
  533. rows, err = a.db.Query(`SELECT COUNT(*) FROM user_token WHERE user_id=?`, phil.ID)
  534. require.Nil(t, err)
  535. require.True(t, rows.Next())
  536. require.Nil(t, rows.Scan(&philCount))
  537. require.Equal(t, 2, philCount)
  538. }
  539. func TestManager_EnqueueStats_ResetStats(t *testing.T) {
  540. a, err := NewManager(filepath.Join(t.TempDir(), "db"), "", PermissionReadWrite, bcrypt.MinCost, 1500*time.Millisecond)
  541. require.Nil(t, err)
  542. require.Nil(t, a.AddUser("ben", "ben", RoleUser))
  543. // Baseline: No messages or emails
  544. u, err := a.User("ben")
  545. require.Nil(t, err)
  546. require.Equal(t, int64(0), u.Stats.Messages)
  547. require.Equal(t, int64(0), u.Stats.Emails)
  548. a.EnqueueUserStats(u.ID, &Stats{
  549. Messages: 11,
  550. Emails: 2,
  551. })
  552. // Still no change, because it's queued asynchronously
  553. u, err = a.User("ben")
  554. require.Nil(t, err)
  555. require.Equal(t, int64(0), u.Stats.Messages)
  556. require.Equal(t, int64(0), u.Stats.Emails)
  557. // After 2 seconds they should be persisted
  558. time.Sleep(2 * time.Second)
  559. u, err = a.User("ben")
  560. require.Nil(t, err)
  561. require.Equal(t, int64(11), u.Stats.Messages)
  562. require.Equal(t, int64(2), u.Stats.Emails)
  563. // Now reset stats (enqueued stats will be thrown out)
  564. a.EnqueueUserStats(u.ID, &Stats{
  565. Messages: 99,
  566. Emails: 23,
  567. })
  568. require.Nil(t, a.ResetStats())
  569. u, err = a.User("ben")
  570. require.Nil(t, err)
  571. require.Equal(t, int64(0), u.Stats.Messages)
  572. require.Equal(t, int64(0), u.Stats.Emails)
  573. }
  574. func TestManager_EnqueueTokenUpdate(t *testing.T) {
  575. a, err := NewManager(filepath.Join(t.TempDir(), "db"), "", PermissionReadWrite, bcrypt.MinCost, 500*time.Millisecond)
  576. require.Nil(t, err)
  577. require.Nil(t, a.AddUser("ben", "ben", RoleUser))
  578. // Create user and token
  579. u, err := a.User("ben")
  580. require.Nil(t, err)
  581. token, err := a.CreateToken(u.ID, "", time.Now().Add(time.Hour), netip.IPv4Unspecified())
  582. require.Nil(t, err)
  583. // Queue token update
  584. a.EnqueueTokenUpdate(token.Value, &TokenUpdate{
  585. LastAccess: time.Unix(111, 0).UTC(),
  586. LastOrigin: netip.MustParseAddr("1.2.3.3"),
  587. })
  588. // Token has not changed yet.
  589. token2, err := a.Token(u.ID, token.Value)
  590. require.Nil(t, err)
  591. require.Equal(t, token.LastAccess.Unix(), token2.LastAccess.Unix())
  592. require.Equal(t, token.LastOrigin, token2.LastOrigin)
  593. // After a second or so they should be persisted
  594. time.Sleep(time.Second)
  595. token3, err := a.Token(u.ID, token.Value)
  596. require.Nil(t, err)
  597. require.Equal(t, time.Unix(111, 0).UTC().Unix(), token3.LastAccess.Unix())
  598. require.Equal(t, netip.MustParseAddr("1.2.3.3"), token3.LastOrigin)
  599. }
  600. func TestManager_ChangeSettings(t *testing.T) {
  601. a, err := NewManager(filepath.Join(t.TempDir(), "db"), "", PermissionReadWrite, bcrypt.MinCost, 1500*time.Millisecond)
  602. require.Nil(t, err)
  603. require.Nil(t, a.AddUser("ben", "ben", RoleUser))
  604. // No settings
  605. u, err := a.User("ben")
  606. require.Nil(t, err)
  607. require.Nil(t, u.Prefs.Subscriptions)
  608. require.Nil(t, u.Prefs.Notification)
  609. require.Nil(t, u.Prefs.Language)
  610. // Save with new settings
  611. prefs := &Prefs{
  612. Language: util.String("de"),
  613. Notification: &NotificationPrefs{
  614. Sound: util.String("ding"),
  615. MinPriority: util.Int(2),
  616. },
  617. Subscriptions: []*Subscription{
  618. {
  619. BaseURL: "https://ntfy.sh",
  620. Topic: "mytopic",
  621. DisplayName: util.String("My Topic"),
  622. },
  623. },
  624. }
  625. require.Nil(t, a.ChangeSettings(u.ID, prefs))
  626. // Read again
  627. u, err = a.User("ben")
  628. require.Nil(t, err)
  629. require.Equal(t, util.String("de"), u.Prefs.Language)
  630. require.Equal(t, util.String("ding"), u.Prefs.Notification.Sound)
  631. require.Equal(t, util.Int(2), u.Prefs.Notification.MinPriority)
  632. require.Nil(t, u.Prefs.Notification.DeleteAfter)
  633. require.Equal(t, "https://ntfy.sh", u.Prefs.Subscriptions[0].BaseURL)
  634. require.Equal(t, "mytopic", u.Prefs.Subscriptions[0].Topic)
  635. require.Equal(t, util.String("My Topic"), u.Prefs.Subscriptions[0].DisplayName)
  636. }
  637. func TestManager_Tier_Create_Update_List_Delete(t *testing.T) {
  638. a := newTestManager(t, PermissionDenyAll)
  639. // Create tier and user
  640. require.Nil(t, a.AddTier(&Tier{
  641. Code: "supporter",
  642. Name: "Supporter",
  643. MessageLimit: 1,
  644. MessageExpiryDuration: time.Second,
  645. EmailLimit: 1,
  646. ReservationLimit: 1,
  647. AttachmentFileSizeLimit: 1,
  648. AttachmentTotalSizeLimit: 1,
  649. AttachmentExpiryDuration: time.Second,
  650. AttachmentBandwidthLimit: 1,
  651. StripeMonthlyPriceID: "price_1",
  652. }))
  653. require.Nil(t, a.AddTier(&Tier{
  654. Code: "pro",
  655. Name: "Pro",
  656. MessageLimit: 123,
  657. MessageExpiryDuration: 86400 * time.Second,
  658. EmailLimit: 32,
  659. ReservationLimit: 2,
  660. AttachmentFileSizeLimit: 1231231,
  661. AttachmentTotalSizeLimit: 123123,
  662. AttachmentExpiryDuration: 10800 * time.Second,
  663. AttachmentBandwidthLimit: 21474836480,
  664. StripeMonthlyPriceID: "price_2",
  665. }))
  666. require.Nil(t, a.AddUser("phil", "phil", RoleUser))
  667. require.Nil(t, a.ChangeTier("phil", "pro"))
  668. ti, err := a.Tier("pro")
  669. require.Nil(t, err)
  670. u, err := a.User("phil")
  671. require.Nil(t, err)
  672. // These are populated by different SQL queries
  673. require.Equal(t, ti, u.Tier)
  674. // Fields
  675. require.True(t, strings.HasPrefix(ti.ID, "ti_"))
  676. require.Equal(t, "pro", ti.Code)
  677. require.Equal(t, "Pro", ti.Name)
  678. require.Equal(t, int64(123), ti.MessageLimit)
  679. require.Equal(t, 86400*time.Second, ti.MessageExpiryDuration)
  680. require.Equal(t, int64(32), ti.EmailLimit)
  681. require.Equal(t, int64(2), ti.ReservationLimit)
  682. require.Equal(t, int64(1231231), ti.AttachmentFileSizeLimit)
  683. require.Equal(t, int64(123123), ti.AttachmentTotalSizeLimit)
  684. require.Equal(t, 10800*time.Second, ti.AttachmentExpiryDuration)
  685. require.Equal(t, int64(21474836480), ti.AttachmentBandwidthLimit)
  686. require.Equal(t, "price_2", ti.StripeMonthlyPriceID)
  687. // Update tier
  688. ti.EmailLimit = 999999
  689. require.Nil(t, a.UpdateTier(ti))
  690. // List tiers
  691. tiers, err := a.Tiers()
  692. require.Nil(t, err)
  693. require.Equal(t, 2, len(tiers))
  694. ti = tiers[0]
  695. require.Equal(t, "supporter", ti.Code)
  696. require.Equal(t, "Supporter", ti.Name)
  697. require.Equal(t, int64(1), ti.MessageLimit)
  698. require.Equal(t, time.Second, ti.MessageExpiryDuration)
  699. require.Equal(t, int64(1), ti.EmailLimit)
  700. require.Equal(t, int64(1), ti.ReservationLimit)
  701. require.Equal(t, int64(1), ti.AttachmentFileSizeLimit)
  702. require.Equal(t, int64(1), ti.AttachmentTotalSizeLimit)
  703. require.Equal(t, time.Second, ti.AttachmentExpiryDuration)
  704. require.Equal(t, int64(1), ti.AttachmentBandwidthLimit)
  705. require.Equal(t, "price_1", ti.StripeMonthlyPriceID)
  706. ti = tiers[1]
  707. require.Equal(t, "pro", ti.Code)
  708. require.Equal(t, "Pro", ti.Name)
  709. require.Equal(t, int64(123), ti.MessageLimit)
  710. require.Equal(t, 86400*time.Second, ti.MessageExpiryDuration)
  711. require.Equal(t, int64(999999), ti.EmailLimit) // Updatedd!
  712. require.Equal(t, int64(2), ti.ReservationLimit)
  713. require.Equal(t, int64(1231231), ti.AttachmentFileSizeLimit)
  714. require.Equal(t, int64(123123), ti.AttachmentTotalSizeLimit)
  715. require.Equal(t, 10800*time.Second, ti.AttachmentExpiryDuration)
  716. require.Equal(t, int64(21474836480), ti.AttachmentBandwidthLimit)
  717. require.Equal(t, "price_2", ti.StripeMonthlyPriceID)
  718. ti, err = a.TierByStripePrice("price_1")
  719. require.Nil(t, err)
  720. require.Equal(t, "supporter", ti.Code)
  721. require.Equal(t, "Supporter", ti.Name)
  722. require.Equal(t, int64(1), ti.MessageLimit)
  723. require.Equal(t, time.Second, ti.MessageExpiryDuration)
  724. require.Equal(t, int64(1), ti.EmailLimit)
  725. require.Equal(t, int64(1), ti.ReservationLimit)
  726. require.Equal(t, int64(1), ti.AttachmentFileSizeLimit)
  727. require.Equal(t, int64(1), ti.AttachmentTotalSizeLimit)
  728. require.Equal(t, time.Second, ti.AttachmentExpiryDuration)
  729. require.Equal(t, int64(1), ti.AttachmentBandwidthLimit)
  730. require.Equal(t, "price_1", ti.StripeMonthlyPriceID)
  731. // Cannot remove tier, since user has this tier
  732. require.Error(t, a.RemoveTier("pro"))
  733. // CAN remove this tier
  734. require.Nil(t, a.RemoveTier("supporter"))
  735. tiers, err = a.Tiers()
  736. require.Nil(t, err)
  737. require.Equal(t, 1, len(tiers))
  738. require.Equal(t, "pro", tiers[0].Code)
  739. require.Equal(t, "pro", tiers[0].Code)
  740. }
  741. func TestAccount_Tier_Create_With_ID(t *testing.T) {
  742. a := newTestManager(t, PermissionDenyAll)
  743. require.Nil(t, a.AddTier(&Tier{
  744. ID: "ti_123",
  745. Code: "pro",
  746. }))
  747. ti, err := a.Tier("pro")
  748. require.Nil(t, err)
  749. require.Equal(t, "ti_123", ti.ID)
  750. }
  751. func TestManager_Tier_Change_And_Reset(t *testing.T) {
  752. a := newTestManager(t, PermissionDenyAll)
  753. // Create tier and user
  754. require.Nil(t, a.AddTier(&Tier{
  755. Code: "supporter",
  756. Name: "Supporter",
  757. ReservationLimit: 3,
  758. }))
  759. require.Nil(t, a.AddTier(&Tier{
  760. Code: "pro",
  761. Name: "Pro",
  762. ReservationLimit: 4,
  763. }))
  764. require.Nil(t, a.AddUser("phil", "phil", RoleUser))
  765. require.Nil(t, a.ChangeTier("phil", "pro"))
  766. // Add 10 reservations (pro tier allows that)
  767. for i := 0; i < 4; i++ {
  768. require.Nil(t, a.AddReservation("phil", fmt.Sprintf("topic%d", i), PermissionWrite))
  769. }
  770. // Downgrading will not work (too many reservations)
  771. require.Equal(t, ErrTooManyReservations, a.ChangeTier("phil", "supporter"))
  772. // Downgrade after removing a reservation
  773. require.Nil(t, a.RemoveReservations("phil", "topic0"))
  774. require.Nil(t, a.ChangeTier("phil", "supporter"))
  775. // Resetting will not work (too many reservations)
  776. require.Equal(t, ErrTooManyReservations, a.ResetTier("phil"))
  777. // Resetting after removing all reservations
  778. require.Nil(t, a.RemoveReservations("phil", "topic1", "topic2", "topic3"))
  779. require.Nil(t, a.ResetTier("phil"))
  780. }
  781. func TestUser_PhoneNumberAddListRemove(t *testing.T) {
  782. a := newTestManager(t, PermissionDenyAll)
  783. require.Nil(t, a.AddUser("phil", "phil", RoleUser))
  784. phil, err := a.User("phil")
  785. require.Nil(t, err)
  786. require.Nil(t, a.AddPhoneNumber(phil.ID, "+1234567890"))
  787. phoneNumbers, err := a.PhoneNumbers(phil.ID)
  788. require.Nil(t, err)
  789. require.Equal(t, 1, len(phoneNumbers))
  790. require.Equal(t, "+1234567890", phoneNumbers[0])
  791. require.Nil(t, a.RemovePhoneNumber(phil.ID, "+1234567890"))
  792. phoneNumbers, err = a.PhoneNumbers(phil.ID)
  793. require.Nil(t, err)
  794. require.Equal(t, 0, len(phoneNumbers))
  795. // Paranoia check: We do NOT want to keep phone numbers in there
  796. rows, err := a.db.Query(`SELECT * FROM user_phone`)
  797. require.Nil(t, err)
  798. require.False(t, rows.Next())
  799. require.Nil(t, rows.Close())
  800. }
  801. func TestUser_PhoneNumberAdd_Multiple_Users_Same_Number(t *testing.T) {
  802. a := newTestManager(t, PermissionDenyAll)
  803. require.Nil(t, a.AddUser("phil", "phil", RoleUser))
  804. require.Nil(t, a.AddUser("ben", "ben", RoleUser))
  805. phil, err := a.User("phil")
  806. require.Nil(t, err)
  807. ben, err := a.User("ben")
  808. require.Nil(t, err)
  809. require.Nil(t, a.AddPhoneNumber(phil.ID, "+1234567890"))
  810. require.Nil(t, a.AddPhoneNumber(ben.ID, "+1234567890"))
  811. }
  812. func TestSqliteCache_Migration_From1(t *testing.T) {
  813. filename := filepath.Join(t.TempDir(), "user.db")
  814. db, err := sql.Open("sqlite3", filename)
  815. require.Nil(t, err)
  816. // Create "version 1" schema
  817. _, err = db.Exec(`
  818. BEGIN;
  819. CREATE TABLE IF NOT EXISTS user (
  820. user TEXT NOT NULL PRIMARY KEY,
  821. pass TEXT NOT NULL,
  822. role TEXT NOT NULL
  823. );
  824. CREATE TABLE IF NOT EXISTS access (
  825. user TEXT NOT NULL,
  826. topic TEXT NOT NULL,
  827. read INT NOT NULL,
  828. write INT NOT NULL,
  829. PRIMARY KEY (topic, user)
  830. );
  831. CREATE TABLE IF NOT EXISTS schemaVersion (
  832. id INT PRIMARY KEY,
  833. version INT NOT NULL
  834. );
  835. INSERT INTO schemaVersion (id, version) VALUES (1, 1);
  836. COMMIT;
  837. `)
  838. require.Nil(t, err)
  839. // Insert a bunch of users and ACL entries
  840. _, err = db.Exec(`
  841. BEGIN;
  842. INSERT INTO user (user, pass, role) VALUES ('ben', '$2a$10$EEp6gBheOsqEFsXlo523E.gBVoeg1ytphXiEvTPlNzkenBlHZBPQy', 'user');
  843. INSERT INTO user (user, pass, role) VALUES ('phil', '$2a$10$YLiO8U21sX1uhZamTLJXHuxgVC0Z/GKISibrKCLohPgtG7yIxSk4C', 'admin');
  844. INSERT INTO access (user, topic, read, write) VALUES ('ben', 'stats', 1, 1);
  845. INSERT INTO access (user, topic, read, write) VALUES ('ben', 'secret', 1, 0);
  846. INSERT INTO access (user, topic, read, write) VALUES ('*', 'stats', 1, 0);
  847. COMMIT;
  848. `)
  849. require.Nil(t, err)
  850. // Create manager to trigger migration
  851. a := newTestManagerFromFile(t, filename, "", PermissionDenyAll, bcrypt.MinCost, DefaultUserStatsQueueWriterInterval)
  852. checkSchemaVersion(t, a.db)
  853. users, err := a.Users()
  854. require.Nil(t, err)
  855. require.Equal(t, 3, len(users))
  856. phil, ben, everyone := users[0], users[1], users[2]
  857. philGrants, err := a.Grants("phil")
  858. require.Nil(t, err)
  859. benGrants, err := a.Grants("ben")
  860. require.Nil(t, err)
  861. everyoneGrants, err := a.Grants(Everyone)
  862. require.Nil(t, err)
  863. require.True(t, strings.HasPrefix(phil.ID, "u_"))
  864. require.Equal(t, "phil", phil.Name)
  865. require.Equal(t, RoleAdmin, phil.Role)
  866. require.Equal(t, syncTopicLength, len(phil.SyncTopic))
  867. require.Equal(t, 0, len(philGrants))
  868. require.True(t, strings.HasPrefix(ben.ID, "u_"))
  869. require.NotEqual(t, phil.ID, ben.ID)
  870. require.Equal(t, "ben", ben.Name)
  871. require.Equal(t, RoleUser, ben.Role)
  872. require.Equal(t, syncTopicLength, len(ben.SyncTopic))
  873. require.NotEqual(t, ben.SyncTopic, phil.SyncTopic)
  874. require.Equal(t, 2, len(benGrants))
  875. require.Equal(t, "stats", benGrants[0].TopicPattern)
  876. require.Equal(t, PermissionReadWrite, benGrants[0].Allow)
  877. require.Equal(t, "secret", benGrants[1].TopicPattern)
  878. require.Equal(t, PermissionRead, benGrants[1].Allow)
  879. require.Equal(t, "u_everyone", everyone.ID)
  880. require.Equal(t, Everyone, everyone.Name)
  881. require.Equal(t, RoleAnonymous, everyone.Role)
  882. require.Equal(t, 1, len(everyoneGrants))
  883. require.Equal(t, "stats", everyoneGrants[0].TopicPattern)
  884. require.Equal(t, PermissionRead, everyoneGrants[0].Allow)
  885. }
  886. func checkSchemaVersion(t *testing.T, db *sql.DB) {
  887. rows, err := db.Query(`SELECT version FROM schemaVersion`)
  888. require.Nil(t, err)
  889. require.True(t, rows.Next())
  890. var schemaVersion int
  891. require.Nil(t, rows.Scan(&schemaVersion))
  892. require.Equal(t, currentSchemaVersion, schemaVersion)
  893. require.Nil(t, rows.Close())
  894. }
  895. func newTestManager(t *testing.T, defaultAccess Permission) *Manager {
  896. return newTestManagerFromFile(t, filepath.Join(t.TempDir(), "user.db"), "", defaultAccess, bcrypt.MinCost, DefaultUserStatsQueueWriterInterval)
  897. }
  898. func newTestManagerFromFile(t *testing.T, filename, startupQueries string, defaultAccess Permission, bcryptCost int, statsWriterInterval time.Duration) *Manager {
  899. a, err := NewManager(filename, startupQueries, defaultAccess, bcryptCost, statsWriterInterval)
  900. require.Nil(t, err)
  901. return a
  902. }