1
0

manager.go 58 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708
  1. // Package user deals with authentication and authorization against topics
  2. package user
  3. import (
  4. "database/sql"
  5. "encoding/json"
  6. "errors"
  7. "fmt"
  8. "github.com/mattn/go-sqlite3"
  9. "github.com/stripe/stripe-go/v74"
  10. "golang.org/x/crypto/bcrypt"
  11. "heckel.io/ntfy/v2/log"
  12. "heckel.io/ntfy/v2/util"
  13. "net/netip"
  14. "strings"
  15. "sync"
  16. "time"
  17. )
  18. const (
  19. tierIDPrefix = "ti_"
  20. tierIDLength = 8
  21. syncTopicPrefix = "st_"
  22. syncTopicLength = 16
  23. userIDPrefix = "u_"
  24. userIDLength = 12
  25. userAuthIntentionalSlowDownHash = "$2a$10$YFCQvqQDwIIwnJM1xkAYOeih0dg17UVGanaTStnrSzC8NCWxcLDwy" // Cost should match DefaultUserPasswordBcryptCost
  26. userHardDeleteAfterDuration = 7 * 24 * time.Hour
  27. tokenPrefix = "tk_"
  28. tokenLength = 32
  29. tokenMaxCount = 60 // Only keep this many tokens in the table per user
  30. tag = "user_manager"
  31. )
  32. // Default constants that may be overridden by configs
  33. const (
  34. DefaultUserStatsQueueWriterInterval = 33 * time.Second
  35. DefaultUserPasswordBcryptCost = 10
  36. )
  37. var (
  38. errNoTokenProvided = errors.New("no token provided")
  39. errTopicOwnedByOthers = errors.New("topic owned by others")
  40. errNoRows = errors.New("no rows found")
  41. )
  42. // Manager-related queries
  43. const (
  44. createTablesQueries = `
  45. BEGIN;
  46. CREATE TABLE IF NOT EXISTS tier (
  47. id TEXT PRIMARY KEY,
  48. code TEXT NOT NULL,
  49. name TEXT NOT NULL,
  50. messages_limit INT NOT NULL,
  51. messages_expiry_duration INT NOT NULL,
  52. emails_limit INT NOT NULL,
  53. calls_limit INT NOT NULL,
  54. reservations_limit INT NOT NULL,
  55. attachment_file_size_limit INT NOT NULL,
  56. attachment_total_size_limit INT NOT NULL,
  57. attachment_expiry_duration INT NOT NULL,
  58. attachment_bandwidth_limit INT NOT NULL,
  59. stripe_monthly_price_id TEXT,
  60. stripe_yearly_price_id TEXT
  61. );
  62. CREATE UNIQUE INDEX idx_tier_code ON tier (code);
  63. CREATE UNIQUE INDEX idx_tier_stripe_monthly_price_id ON tier (stripe_monthly_price_id);
  64. CREATE UNIQUE INDEX idx_tier_stripe_yearly_price_id ON tier (stripe_yearly_price_id);
  65. CREATE TABLE IF NOT EXISTS user (
  66. id TEXT PRIMARY KEY,
  67. tier_id TEXT,
  68. user TEXT NOT NULL,
  69. pass TEXT NOT NULL,
  70. role TEXT CHECK (role IN ('anonymous', 'admin', 'user')) NOT NULL,
  71. prefs JSON NOT NULL DEFAULT '{}',
  72. sync_topic TEXT NOT NULL,
  73. stats_messages INT NOT NULL DEFAULT (0),
  74. stats_emails INT NOT NULL DEFAULT (0),
  75. stats_calls INT NOT NULL DEFAULT (0),
  76. stripe_customer_id TEXT,
  77. stripe_subscription_id TEXT,
  78. stripe_subscription_status TEXT,
  79. stripe_subscription_interval TEXT,
  80. stripe_subscription_paid_until INT,
  81. stripe_subscription_cancel_at INT,
  82. created INT NOT NULL,
  83. deleted INT,
  84. FOREIGN KEY (tier_id) REFERENCES tier (id)
  85. );
  86. CREATE UNIQUE INDEX idx_user ON user (user);
  87. CREATE UNIQUE INDEX idx_user_stripe_customer_id ON user (stripe_customer_id);
  88. CREATE UNIQUE INDEX idx_user_stripe_subscription_id ON user (stripe_subscription_id);
  89. CREATE TABLE IF NOT EXISTS user_access (
  90. user_id TEXT NOT NULL,
  91. topic TEXT NOT NULL,
  92. read INT NOT NULL,
  93. write INT NOT NULL,
  94. owner_user_id INT,
  95. PRIMARY KEY (user_id, topic),
  96. FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE,
  97. FOREIGN KEY (owner_user_id) REFERENCES user (id) ON DELETE CASCADE
  98. );
  99. CREATE TABLE IF NOT EXISTS user_token (
  100. user_id TEXT NOT NULL,
  101. token TEXT NOT NULL,
  102. label TEXT NOT NULL,
  103. last_access INT NOT NULL,
  104. last_origin TEXT NOT NULL,
  105. expires INT NOT NULL,
  106. PRIMARY KEY (user_id, token),
  107. FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE
  108. );
  109. CREATE TABLE IF NOT EXISTS user_phone (
  110. user_id TEXT NOT NULL,
  111. phone_number TEXT NOT NULL,
  112. PRIMARY KEY (user_id, phone_number),
  113. FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE
  114. );
  115. CREATE TABLE IF NOT EXISTS schemaVersion (
  116. id INT PRIMARY KEY,
  117. version INT NOT NULL
  118. );
  119. INSERT INTO user (id, user, pass, role, sync_topic, created)
  120. VALUES ('` + everyoneID + `', '*', '', 'anonymous', '', UNIXEPOCH())
  121. ON CONFLICT (id) DO NOTHING;
  122. COMMIT;
  123. `
  124. builtinStartupQueries = `
  125. PRAGMA foreign_keys = ON;
  126. `
  127. selectUserByIDQuery = `
  128. SELECT u.id, u.user, u.pass, u.role, u.prefs, u.sync_topic, u.stats_messages, u.stats_emails, u.stats_calls, u.stripe_customer_id, u.stripe_subscription_id, u.stripe_subscription_status, u.stripe_subscription_interval, u.stripe_subscription_paid_until, u.stripe_subscription_cancel_at, deleted, t.id, t.code, t.name, t.messages_limit, t.messages_expiry_duration, t.emails_limit, t.calls_limit, t.reservations_limit, t.attachment_file_size_limit, t.attachment_total_size_limit, t.attachment_expiry_duration, t.attachment_bandwidth_limit, t.stripe_monthly_price_id, t.stripe_yearly_price_id
  129. FROM user u
  130. LEFT JOIN tier t on t.id = u.tier_id
  131. WHERE u.id = ?
  132. `
  133. selectUserByNameQuery = `
  134. SELECT u.id, u.user, u.pass, u.role, u.prefs, u.sync_topic, u.stats_messages, u.stats_emails, u.stats_calls, u.stripe_customer_id, u.stripe_subscription_id, u.stripe_subscription_status, u.stripe_subscription_interval, u.stripe_subscription_paid_until, u.stripe_subscription_cancel_at, deleted, t.id, t.code, t.name, t.messages_limit, t.messages_expiry_duration, t.emails_limit, t.calls_limit, t.reservations_limit, t.attachment_file_size_limit, t.attachment_total_size_limit, t.attachment_expiry_duration, t.attachment_bandwidth_limit, t.stripe_monthly_price_id, t.stripe_yearly_price_id
  135. FROM user u
  136. LEFT JOIN tier t on t.id = u.tier_id
  137. WHERE user = ?
  138. `
  139. selectUserByTokenQuery = `
  140. SELECT u.id, u.user, u.pass, u.role, u.prefs, u.sync_topic, u.stats_messages, u.stats_emails, u.stats_calls, u.stripe_customer_id, u.stripe_subscription_id, u.stripe_subscription_status, u.stripe_subscription_interval, u.stripe_subscription_paid_until, u.stripe_subscription_cancel_at, deleted, t.id, t.code, t.name, t.messages_limit, t.messages_expiry_duration, t.emails_limit, t.calls_limit, t.reservations_limit, t.attachment_file_size_limit, t.attachment_total_size_limit, t.attachment_expiry_duration, t.attachment_bandwidth_limit, t.stripe_monthly_price_id, t.stripe_yearly_price_id
  141. FROM user u
  142. JOIN user_token tk on u.id = tk.user_id
  143. LEFT JOIN tier t on t.id = u.tier_id
  144. WHERE tk.token = ? AND (tk.expires = 0 OR tk.expires >= ?)
  145. `
  146. selectUserByStripeCustomerIDQuery = `
  147. SELECT u.id, u.user, u.pass, u.role, u.prefs, u.sync_topic, u.stats_messages, u.stats_emails, u.stats_calls, u.stripe_customer_id, u.stripe_subscription_id, u.stripe_subscription_status, u.stripe_subscription_interval, u.stripe_subscription_paid_until, u.stripe_subscription_cancel_at, deleted, t.id, t.code, t.name, t.messages_limit, t.messages_expiry_duration, t.emails_limit, t.calls_limit, t.reservations_limit, t.attachment_file_size_limit, t.attachment_total_size_limit, t.attachment_expiry_duration, t.attachment_bandwidth_limit, t.stripe_monthly_price_id, t.stripe_yearly_price_id
  148. FROM user u
  149. LEFT JOIN tier t on t.id = u.tier_id
  150. WHERE u.stripe_customer_id = ?
  151. `
  152. selectTopicPermsQuery = `
  153. SELECT read, write
  154. FROM user_access a
  155. JOIN user u ON u.id = a.user_id
  156. WHERE (u.user = ? OR u.user = ?) AND ? LIKE a.topic ESCAPE '\'
  157. ORDER BY u.user DESC, LENGTH(a.topic) DESC, a.write DESC
  158. `
  159. insertUserQuery = `
  160. INSERT INTO user (id, user, pass, role, sync_topic, created)
  161. VALUES (?, ?, ?, ?, ?, ?)
  162. `
  163. selectUsernamesQuery = `
  164. SELECT user
  165. FROM user
  166. ORDER BY
  167. CASE role
  168. WHEN 'admin' THEN 1
  169. WHEN 'anonymous' THEN 3
  170. ELSE 2
  171. END, user
  172. `
  173. selectUserCountQuery = `SELECT COUNT(*) FROM user`
  174. updateUserPassQuery = `UPDATE user SET pass = ? WHERE user = ?`
  175. updateUserRoleQuery = `UPDATE user SET role = ? WHERE user = ?`
  176. updateUserPrefsQuery = `UPDATE user SET prefs = ? WHERE id = ?`
  177. updateUserStatsQuery = `UPDATE user SET stats_messages = ?, stats_emails = ?, stats_calls = ? WHERE id = ?`
  178. updateUserStatsResetAllQuery = `UPDATE user SET stats_messages = 0, stats_emails = 0, stats_calls = 0`
  179. updateUserDeletedQuery = `UPDATE user SET deleted = ? WHERE id = ?`
  180. deleteUsersMarkedQuery = `DELETE FROM user WHERE deleted < ?`
  181. deleteUserQuery = `DELETE FROM user WHERE user = ?`
  182. upsertUserAccessQuery = `
  183. INSERT INTO user_access (user_id, topic, read, write, owner_user_id)
  184. VALUES ((SELECT id FROM user WHERE user = ?), ?, ?, ?, (SELECT IIF(?='',NULL,(SELECT id FROM user WHERE user=?))))
  185. ON CONFLICT (user_id, topic)
  186. DO UPDATE SET read=excluded.read, write=excluded.write, owner_user_id=excluded.owner_user_id
  187. `
  188. selectUserAllAccessQuery = `
  189. SELECT user_id, topic, read, write
  190. FROM user_access
  191. ORDER BY LENGTH(topic) DESC, write DESC, read DESC, topic
  192. `
  193. selectUserAccessQuery = `
  194. SELECT topic, read, write
  195. FROM user_access
  196. WHERE user_id = (SELECT id FROM user WHERE user = ?)
  197. ORDER BY LENGTH(topic) DESC, write DESC, read DESC, topic
  198. `
  199. selectUserReservationsQuery = `
  200. SELECT a_user.topic, a_user.read, a_user.write, a_everyone.read AS everyone_read, a_everyone.write AS everyone_write
  201. FROM user_access a_user
  202. LEFT JOIN user_access a_everyone ON a_user.topic = a_everyone.topic AND a_everyone.user_id = (SELECT id FROM user WHERE user = ?)
  203. WHERE a_user.user_id = a_user.owner_user_id
  204. AND a_user.owner_user_id = (SELECT id FROM user WHERE user = ?)
  205. ORDER BY a_user.topic
  206. `
  207. selectUserReservationsCountQuery = `
  208. SELECT COUNT(*)
  209. FROM user_access
  210. WHERE user_id = owner_user_id
  211. AND owner_user_id = (SELECT id FROM user WHERE user = ?)
  212. `
  213. selectUserReservationsOwnerQuery = `
  214. SELECT owner_user_id
  215. FROM user_access
  216. WHERE topic = ?
  217. AND user_id = owner_user_id
  218. `
  219. selectUserHasReservationQuery = `
  220. SELECT COUNT(*)
  221. FROM user_access
  222. WHERE user_id = owner_user_id
  223. AND owner_user_id = (SELECT id FROM user WHERE user = ?)
  224. AND topic = ?
  225. `
  226. selectOtherAccessCountQuery = `
  227. SELECT COUNT(*)
  228. FROM user_access
  229. WHERE (topic = ? OR ? LIKE topic ESCAPE '\')
  230. AND (owner_user_id IS NULL OR owner_user_id != (SELECT id FROM user WHERE user = ?))
  231. `
  232. deleteAllAccessQuery = `DELETE FROM user_access`
  233. deleteUserAccessQuery = `
  234. DELETE FROM user_access
  235. WHERE user_id = (SELECT id FROM user WHERE user = ?)
  236. OR owner_user_id = (SELECT id FROM user WHERE user = ?)
  237. `
  238. deleteTopicAccessQuery = `
  239. DELETE FROM user_access
  240. WHERE (user_id = (SELECT id FROM user WHERE user = ?) OR owner_user_id = (SELECT id FROM user WHERE user = ?))
  241. AND topic = ?
  242. `
  243. selectTokenCountQuery = `SELECT COUNT(*) FROM user_token WHERE user_id = ?`
  244. selectTokensQuery = `SELECT token, label, last_access, last_origin, expires FROM user_token WHERE user_id = ?`
  245. selectTokenQuery = `SELECT token, label, last_access, last_origin, expires FROM user_token WHERE user_id = ? AND token = ?`
  246. insertTokenQuery = `INSERT INTO user_token (user_id, token, label, last_access, last_origin, expires) VALUES (?, ?, ?, ?, ?, ?)`
  247. updateTokenExpiryQuery = `UPDATE user_token SET expires = ? WHERE user_id = ? AND token = ?`
  248. updateTokenLabelQuery = `UPDATE user_token SET label = ? WHERE user_id = ? AND token = ?`
  249. updateTokenLastAccessQuery = `UPDATE user_token SET last_access = ?, last_origin = ? WHERE token = ?`
  250. deleteTokenQuery = `DELETE FROM user_token WHERE user_id = ? AND token = ?`
  251. deleteAllTokenQuery = `DELETE FROM user_token WHERE user_id = ?`
  252. deleteExpiredTokensQuery = `DELETE FROM user_token WHERE expires > 0 AND expires < ?`
  253. deleteExcessTokensQuery = `
  254. DELETE FROM user_token
  255. WHERE user_id = ?
  256. AND (user_id, token) NOT IN (
  257. SELECT user_id, token
  258. FROM user_token
  259. WHERE user_id = ?
  260. ORDER BY expires DESC
  261. LIMIT ?
  262. )
  263. `
  264. selectPhoneNumbersQuery = `SELECT phone_number FROM user_phone WHERE user_id = ?`
  265. insertPhoneNumberQuery = `INSERT INTO user_phone (user_id, phone_number) VALUES (?, ?)`
  266. deletePhoneNumberQuery = `DELETE FROM user_phone WHERE user_id = ? AND phone_number = ?`
  267. insertTierQuery = `
  268. INSERT INTO tier (id, code, name, messages_limit, messages_expiry_duration, emails_limit, calls_limit, reservations_limit, attachment_file_size_limit, attachment_total_size_limit, attachment_expiry_duration, attachment_bandwidth_limit, stripe_monthly_price_id, stripe_yearly_price_id)
  269. VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
  270. `
  271. updateTierQuery = `
  272. UPDATE tier
  273. SET name = ?, messages_limit = ?, messages_expiry_duration = ?, emails_limit = ?, calls_limit = ?, reservations_limit = ?, attachment_file_size_limit = ?, attachment_total_size_limit = ?, attachment_expiry_duration = ?, attachment_bandwidth_limit = ?, stripe_monthly_price_id = ?, stripe_yearly_price_id = ?
  274. WHERE code = ?
  275. `
  276. selectTiersQuery = `
  277. SELECT id, code, name, messages_limit, messages_expiry_duration, emails_limit, calls_limit, reservations_limit, attachment_file_size_limit, attachment_total_size_limit, attachment_expiry_duration, attachment_bandwidth_limit, stripe_monthly_price_id, stripe_yearly_price_id
  278. FROM tier
  279. `
  280. selectTierByCodeQuery = `
  281. SELECT id, code, name, messages_limit, messages_expiry_duration, emails_limit, calls_limit, reservations_limit, attachment_file_size_limit, attachment_total_size_limit, attachment_expiry_duration, attachment_bandwidth_limit, stripe_monthly_price_id, stripe_yearly_price_id
  282. FROM tier
  283. WHERE code = ?
  284. `
  285. selectTierByPriceIDQuery = `
  286. SELECT id, code, name, messages_limit, messages_expiry_duration, emails_limit, calls_limit, reservations_limit, attachment_file_size_limit, attachment_total_size_limit, attachment_expiry_duration, attachment_bandwidth_limit, stripe_monthly_price_id, stripe_yearly_price_id
  287. FROM tier
  288. WHERE (stripe_monthly_price_id = ? OR stripe_yearly_price_id = ?)
  289. `
  290. updateUserTierQuery = `UPDATE user SET tier_id = (SELECT id FROM tier WHERE code = ?) WHERE user = ?`
  291. deleteUserTierQuery = `UPDATE user SET tier_id = null WHERE user = ?`
  292. deleteTierQuery = `DELETE FROM tier WHERE code = ?`
  293. updateBillingQuery = `
  294. UPDATE user
  295. SET stripe_customer_id = ?, stripe_subscription_id = ?, stripe_subscription_status = ?, stripe_subscription_interval = ?, stripe_subscription_paid_until = ?, stripe_subscription_cancel_at = ?
  296. WHERE user = ?
  297. `
  298. )
  299. // Schema management queries
  300. const (
  301. currentSchemaVersion = 5
  302. insertSchemaVersion = `INSERT INTO schemaVersion VALUES (1, ?)`
  303. updateSchemaVersion = `UPDATE schemaVersion SET version = ? WHERE id = 1`
  304. selectSchemaVersionQuery = `SELECT version FROM schemaVersion WHERE id = 1`
  305. // 1 -> 2 (complex migration!)
  306. migrate1To2CreateTablesQueries = `
  307. ALTER TABLE user RENAME TO user_old;
  308. CREATE TABLE IF NOT EXISTS tier (
  309. id TEXT PRIMARY KEY,
  310. code TEXT NOT NULL,
  311. name TEXT NOT NULL,
  312. messages_limit INT NOT NULL,
  313. messages_expiry_duration INT NOT NULL,
  314. emails_limit INT NOT NULL,
  315. reservations_limit INT NOT NULL,
  316. attachment_file_size_limit INT NOT NULL,
  317. attachment_total_size_limit INT NOT NULL,
  318. attachment_expiry_duration INT NOT NULL,
  319. attachment_bandwidth_limit INT NOT NULL,
  320. stripe_price_id TEXT
  321. );
  322. CREATE UNIQUE INDEX idx_tier_code ON tier (code);
  323. CREATE UNIQUE INDEX idx_tier_price_id ON tier (stripe_price_id);
  324. CREATE TABLE IF NOT EXISTS user (
  325. id TEXT PRIMARY KEY,
  326. tier_id TEXT,
  327. user TEXT NOT NULL,
  328. pass TEXT NOT NULL,
  329. role TEXT CHECK (role IN ('anonymous', 'admin', 'user')) NOT NULL,
  330. prefs JSON NOT NULL DEFAULT '{}',
  331. sync_topic TEXT NOT NULL,
  332. stats_messages INT NOT NULL DEFAULT (0),
  333. stats_emails INT NOT NULL DEFAULT (0),
  334. stripe_customer_id TEXT,
  335. stripe_subscription_id TEXT,
  336. stripe_subscription_status TEXT,
  337. stripe_subscription_paid_until INT,
  338. stripe_subscription_cancel_at INT,
  339. created INT NOT NULL,
  340. deleted INT,
  341. FOREIGN KEY (tier_id) REFERENCES tier (id)
  342. );
  343. CREATE UNIQUE INDEX idx_user ON user (user);
  344. CREATE UNIQUE INDEX idx_user_stripe_customer_id ON user (stripe_customer_id);
  345. CREATE UNIQUE INDEX idx_user_stripe_subscription_id ON user (stripe_subscription_id);
  346. CREATE TABLE IF NOT EXISTS user_access (
  347. user_id TEXT NOT NULL,
  348. topic TEXT NOT NULL,
  349. read INT NOT NULL,
  350. write INT NOT NULL,
  351. owner_user_id INT,
  352. PRIMARY KEY (user_id, topic),
  353. FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE,
  354. FOREIGN KEY (owner_user_id) REFERENCES user (id) ON DELETE CASCADE
  355. );
  356. CREATE TABLE IF NOT EXISTS user_token (
  357. user_id TEXT NOT NULL,
  358. token TEXT NOT NULL,
  359. label TEXT NOT NULL,
  360. last_access INT NOT NULL,
  361. last_origin TEXT NOT NULL,
  362. expires INT NOT NULL,
  363. PRIMARY KEY (user_id, token),
  364. FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE
  365. );
  366. CREATE TABLE IF NOT EXISTS schemaVersion (
  367. id INT PRIMARY KEY,
  368. version INT NOT NULL
  369. );
  370. INSERT INTO user (id, user, pass, role, sync_topic, created)
  371. VALUES ('u_everyone', '*', '', 'anonymous', '', UNIXEPOCH())
  372. ON CONFLICT (id) DO NOTHING;
  373. `
  374. migrate1To2SelectAllOldUsernamesNoTx = `SELECT user FROM user_old`
  375. migrate1To2InsertUserNoTx = `
  376. INSERT INTO user (id, user, pass, role, sync_topic, created)
  377. SELECT ?, user, pass, role, ?, UNIXEPOCH() FROM user_old WHERE user = ?
  378. `
  379. migrate1To2InsertFromOldTablesAndDropNoTx = `
  380. INSERT INTO user_access (user_id, topic, read, write)
  381. SELECT u.id, a.topic, a.read, a.write
  382. FROM user u
  383. JOIN access a ON u.user = a.user;
  384. DROP TABLE access;
  385. DROP TABLE user_old;
  386. `
  387. // 2 -> 3
  388. migrate2To3UpdateQueries = `
  389. ALTER TABLE user ADD COLUMN stripe_subscription_interval TEXT;
  390. ALTER TABLE tier RENAME COLUMN stripe_price_id TO stripe_monthly_price_id;
  391. ALTER TABLE tier ADD COLUMN stripe_yearly_price_id TEXT;
  392. DROP INDEX IF EXISTS idx_tier_price_id;
  393. CREATE UNIQUE INDEX idx_tier_stripe_monthly_price_id ON tier (stripe_monthly_price_id);
  394. CREATE UNIQUE INDEX idx_tier_stripe_yearly_price_id ON tier (stripe_yearly_price_id);
  395. `
  396. // 3 -> 4
  397. migrate3To4UpdateQueries = `
  398. ALTER TABLE tier ADD COLUMN calls_limit INT NOT NULL DEFAULT (0);
  399. ALTER TABLE user ADD COLUMN stats_calls INT NOT NULL DEFAULT (0);
  400. CREATE TABLE IF NOT EXISTS user_phone (
  401. user_id TEXT NOT NULL,
  402. phone_number TEXT NOT NULL,
  403. PRIMARY KEY (user_id, phone_number),
  404. FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE
  405. );
  406. `
  407. // 4 -> 5
  408. migrate4To5UpdateQueries = `
  409. UPDATE user_access SET topic = REPLACE(topic, '_', '\_');
  410. `
  411. )
  412. var (
  413. migrations = map[int]func(db *sql.DB) error{
  414. 1: migrateFrom1,
  415. 2: migrateFrom2,
  416. 3: migrateFrom3,
  417. 4: migrateFrom4,
  418. }
  419. )
  420. // Manager is an implementation of Manager. It stores users and access control list
  421. // in a SQLite database.
  422. type Manager struct {
  423. config *Config
  424. db *sql.DB
  425. statsQueue map[string]*Stats // "Queue" to asynchronously write user stats to the database (UserID -> Stats)
  426. tokenQueue map[string]*TokenUpdate // "Queue" to asynchronously write token access stats to the database (Token ID -> TokenUpdate)
  427. mu sync.Mutex
  428. }
  429. type Config struct {
  430. Filename string
  431. StartupQueries string
  432. DefaultAccess Permission // Default permission if no ACL matches
  433. ProvisionedUsers []*User // Predefined users to create on startup
  434. ProvisionedAccess map[string][]*Grant // Predefined access grants to create on startup
  435. BcryptCost int // Makes testing easier
  436. QueueWriterInterval time.Duration
  437. }
  438. var _ Auther = (*Manager)(nil)
  439. // NewManager creates a new Manager instance
  440. func NewManager(config *Config) (*Manager, error) {
  441. // Set defaults
  442. if config.BcryptCost <= 0 {
  443. config.BcryptCost = DefaultUserPasswordBcryptCost
  444. }
  445. if config.QueueWriterInterval.Seconds() <= 0 {
  446. config.QueueWriterInterval = DefaultUserStatsQueueWriterInterval
  447. }
  448. // Open DB and run setup queries
  449. db, err := sql.Open("sqlite3", config.Filename)
  450. if err != nil {
  451. return nil, err
  452. }
  453. if err := setupDB(db); err != nil {
  454. return nil, err
  455. }
  456. if err := runStartupQueries(db, config.StartupQueries); err != nil {
  457. return nil, err
  458. }
  459. manager := &Manager{
  460. db: db,
  461. config: config,
  462. statsQueue: make(map[string]*Stats),
  463. tokenQueue: make(map[string]*TokenUpdate),
  464. }
  465. go manager.asyncQueueWriter(config.QueueWriterInterval)
  466. return manager, nil
  467. }
  468. // Authenticate checks username and password and returns a User if correct, and the user has not been
  469. // marked as deleted. The method returns in constant-ish time, regardless of whether the user exists or
  470. // the password is correct or incorrect.
  471. func (a *Manager) Authenticate(username, password string) (*User, error) {
  472. if username == Everyone {
  473. return nil, ErrUnauthenticated
  474. }
  475. user, err := a.User(username)
  476. if err != nil {
  477. log.Tag(tag).Field("user_name", username).Err(err).Trace("Authentication of user failed (1)")
  478. bcrypt.CompareHashAndPassword([]byte(userAuthIntentionalSlowDownHash), []byte("intentional slow-down to avoid timing attacks"))
  479. return nil, ErrUnauthenticated
  480. } else if user.Deleted {
  481. log.Tag(tag).Field("user_name", username).Trace("Authentication of user failed (2): user marked deleted")
  482. bcrypt.CompareHashAndPassword([]byte(userAuthIntentionalSlowDownHash), []byte("intentional slow-down to avoid timing attacks"))
  483. return nil, ErrUnauthenticated
  484. } else if err := bcrypt.CompareHashAndPassword([]byte(user.Hash), []byte(password)); err != nil {
  485. log.Tag(tag).Field("user_name", username).Err(err).Trace("Authentication of user failed (3)")
  486. return nil, ErrUnauthenticated
  487. }
  488. return user, nil
  489. }
  490. // AuthenticateToken checks if the token exists and returns the associated User if it does.
  491. // The method sets the User.Token value to the token that was used for authentication.
  492. func (a *Manager) AuthenticateToken(token string) (*User, error) {
  493. if len(token) != tokenLength {
  494. return nil, ErrUnauthenticated
  495. }
  496. user, err := a.userByToken(token)
  497. if err != nil {
  498. log.Tag(tag).Field("token", token).Err(err).Trace("Authentication of token failed")
  499. return nil, ErrUnauthenticated
  500. }
  501. user.Token = token
  502. return user, nil
  503. }
  504. // CreateToken generates a random token for the given user and returns it. The token expires
  505. // after a fixed duration unless ChangeToken is called. This function also prunes tokens for the
  506. // given user, if there are too many of them.
  507. func (a *Manager) CreateToken(userID, label string, expires time.Time, origin netip.Addr) (*Token, error) {
  508. token := util.RandomLowerStringPrefix(tokenPrefix, tokenLength) // Lowercase only to support "<topic>+<token>@<domain>" email addresses
  509. tx, err := a.db.Begin()
  510. if err != nil {
  511. return nil, err
  512. }
  513. defer tx.Rollback()
  514. access := time.Now()
  515. if _, err := tx.Exec(insertTokenQuery, userID, token, label, access.Unix(), origin.String(), expires.Unix()); err != nil {
  516. return nil, err
  517. }
  518. rows, err := tx.Query(selectTokenCountQuery, userID)
  519. if err != nil {
  520. return nil, err
  521. }
  522. defer rows.Close()
  523. if !rows.Next() {
  524. return nil, errNoRows
  525. }
  526. var tokenCount int
  527. if err := rows.Scan(&tokenCount); err != nil {
  528. return nil, err
  529. }
  530. if tokenCount >= tokenMaxCount {
  531. // This pruning logic is done in two queries for efficiency. The SELECT above is a lookup
  532. // on two indices, whereas the query below is a full table scan.
  533. if _, err := tx.Exec(deleteExcessTokensQuery, userID, userID, tokenMaxCount); err != nil {
  534. return nil, err
  535. }
  536. }
  537. if err := tx.Commit(); err != nil {
  538. return nil, err
  539. }
  540. return &Token{
  541. Value: token,
  542. Label: label,
  543. LastAccess: access,
  544. LastOrigin: origin,
  545. Expires: expires,
  546. }, nil
  547. }
  548. // Tokens returns all existing tokens for the user with the given user ID
  549. func (a *Manager) Tokens(userID string) ([]*Token, error) {
  550. rows, err := a.db.Query(selectTokensQuery, userID)
  551. if err != nil {
  552. return nil, err
  553. }
  554. defer rows.Close()
  555. tokens := make([]*Token, 0)
  556. for {
  557. token, err := a.readToken(rows)
  558. if err == ErrTokenNotFound {
  559. break
  560. } else if err != nil {
  561. return nil, err
  562. }
  563. tokens = append(tokens, token)
  564. }
  565. return tokens, nil
  566. }
  567. // Token returns a specific token for a user
  568. func (a *Manager) Token(userID, token string) (*Token, error) {
  569. rows, err := a.db.Query(selectTokenQuery, userID, token)
  570. if err != nil {
  571. return nil, err
  572. }
  573. defer rows.Close()
  574. return a.readToken(rows)
  575. }
  576. func (a *Manager) readToken(rows *sql.Rows) (*Token, error) {
  577. var token, label, lastOrigin string
  578. var lastAccess, expires int64
  579. if !rows.Next() {
  580. return nil, ErrTokenNotFound
  581. }
  582. if err := rows.Scan(&token, &label, &lastAccess, &lastOrigin, &expires); err != nil {
  583. return nil, err
  584. } else if err := rows.Err(); err != nil {
  585. return nil, err
  586. }
  587. lastOriginIP, err := netip.ParseAddr(lastOrigin)
  588. if err != nil {
  589. lastOriginIP = netip.IPv4Unspecified()
  590. }
  591. return &Token{
  592. Value: token,
  593. Label: label,
  594. LastAccess: time.Unix(lastAccess, 0),
  595. LastOrigin: lastOriginIP,
  596. Expires: time.Unix(expires, 0),
  597. }, nil
  598. }
  599. // ChangeToken updates a token's label and/or expiry date
  600. func (a *Manager) ChangeToken(userID, token string, label *string, expires *time.Time) (*Token, error) {
  601. if token == "" {
  602. return nil, errNoTokenProvided
  603. }
  604. tx, err := a.db.Begin()
  605. if err != nil {
  606. return nil, err
  607. }
  608. defer tx.Rollback()
  609. if label != nil {
  610. if _, err := tx.Exec(updateTokenLabelQuery, *label, userID, token); err != nil {
  611. return nil, err
  612. }
  613. }
  614. if expires != nil {
  615. if _, err := tx.Exec(updateTokenExpiryQuery, expires.Unix(), userID, token); err != nil {
  616. return nil, err
  617. }
  618. }
  619. if err := tx.Commit(); err != nil {
  620. return nil, err
  621. }
  622. return a.Token(userID, token)
  623. }
  624. // RemoveToken deletes the token defined in User.Token
  625. func (a *Manager) RemoveToken(userID, token string) error {
  626. if token == "" {
  627. return errNoTokenProvided
  628. }
  629. if _, err := a.db.Exec(deleteTokenQuery, userID, token); err != nil {
  630. return err
  631. }
  632. return nil
  633. }
  634. // RemoveExpiredTokens deletes all expired tokens from the database
  635. func (a *Manager) RemoveExpiredTokens() error {
  636. if _, err := a.db.Exec(deleteExpiredTokensQuery, time.Now().Unix()); err != nil {
  637. return err
  638. }
  639. return nil
  640. }
  641. // PhoneNumbers returns all phone numbers for the user with the given user ID
  642. func (a *Manager) PhoneNumbers(userID string) ([]string, error) {
  643. rows, err := a.db.Query(selectPhoneNumbersQuery, userID)
  644. if err != nil {
  645. return nil, err
  646. }
  647. defer rows.Close()
  648. phoneNumbers := make([]string, 0)
  649. for {
  650. phoneNumber, err := a.readPhoneNumber(rows)
  651. if err == ErrPhoneNumberNotFound {
  652. break
  653. } else if err != nil {
  654. return nil, err
  655. }
  656. phoneNumbers = append(phoneNumbers, phoneNumber)
  657. }
  658. return phoneNumbers, nil
  659. }
  660. func (a *Manager) readPhoneNumber(rows *sql.Rows) (string, error) {
  661. var phoneNumber string
  662. if !rows.Next() {
  663. return "", ErrPhoneNumberNotFound
  664. }
  665. if err := rows.Scan(&phoneNumber); err != nil {
  666. return "", err
  667. } else if err := rows.Err(); err != nil {
  668. return "", err
  669. }
  670. return phoneNumber, nil
  671. }
  672. // AddPhoneNumber adds a phone number to the user with the given user ID
  673. func (a *Manager) AddPhoneNumber(userID string, phoneNumber string) error {
  674. if _, err := a.db.Exec(insertPhoneNumberQuery, userID, phoneNumber); err != nil {
  675. if sqliteErr, ok := err.(sqlite3.Error); ok && sqliteErr.ExtendedCode == sqlite3.ErrConstraintUnique {
  676. return ErrPhoneNumberExists
  677. }
  678. return err
  679. }
  680. return nil
  681. }
  682. // RemovePhoneNumber deletes a phone number from the user with the given user ID
  683. func (a *Manager) RemovePhoneNumber(userID string, phoneNumber string) error {
  684. _, err := a.db.Exec(deletePhoneNumberQuery, userID, phoneNumber)
  685. return err
  686. }
  687. // RemoveDeletedUsers deletes all users that have been marked deleted for
  688. func (a *Manager) RemoveDeletedUsers() error {
  689. if _, err := a.db.Exec(deleteUsersMarkedQuery, time.Now().Unix()); err != nil {
  690. return err
  691. }
  692. return nil
  693. }
  694. // ChangeSettings persists the user settings
  695. func (a *Manager) ChangeSettings(userID string, prefs *Prefs) error {
  696. b, err := json.Marshal(prefs)
  697. if err != nil {
  698. return err
  699. }
  700. if _, err := a.db.Exec(updateUserPrefsQuery, string(b), userID); err != nil {
  701. return err
  702. }
  703. return nil
  704. }
  705. // ResetStats resets all user stats in the user database. This touches all users.
  706. func (a *Manager) ResetStats() error {
  707. a.mu.Lock() // Includes database query to avoid races!
  708. defer a.mu.Unlock()
  709. if _, err := a.db.Exec(updateUserStatsResetAllQuery); err != nil {
  710. return err
  711. }
  712. a.statsQueue = make(map[string]*Stats)
  713. return nil
  714. }
  715. // EnqueueUserStats adds the user to a queue which writes out user stats (messages, emails, ..) in
  716. // batches at a regular interval
  717. func (a *Manager) EnqueueUserStats(userID string, stats *Stats) {
  718. a.mu.Lock()
  719. defer a.mu.Unlock()
  720. a.statsQueue[userID] = stats
  721. }
  722. // EnqueueTokenUpdate adds the token update to a queue which writes out token access times
  723. // in batches at a regular interval
  724. func (a *Manager) EnqueueTokenUpdate(tokenID string, update *TokenUpdate) {
  725. a.mu.Lock()
  726. defer a.mu.Unlock()
  727. a.tokenQueue[tokenID] = update
  728. }
  729. func (a *Manager) asyncQueueWriter(interval time.Duration) {
  730. ticker := time.NewTicker(interval)
  731. for range ticker.C {
  732. if err := a.writeUserStatsQueue(); err != nil {
  733. log.Tag(tag).Err(err).Warn("Writing user stats queue failed")
  734. }
  735. if err := a.writeTokenUpdateQueue(); err != nil {
  736. log.Tag(tag).Err(err).Warn("Writing token update queue failed")
  737. }
  738. }
  739. }
  740. func (a *Manager) writeUserStatsQueue() error {
  741. a.mu.Lock()
  742. if len(a.statsQueue) == 0 {
  743. a.mu.Unlock()
  744. log.Tag(tag).Trace("No user stats updates to commit")
  745. return nil
  746. }
  747. statsQueue := a.statsQueue
  748. a.statsQueue = make(map[string]*Stats)
  749. a.mu.Unlock()
  750. tx, err := a.db.Begin()
  751. if err != nil {
  752. return err
  753. }
  754. defer tx.Rollback()
  755. log.Tag(tag).Debug("Writing user stats queue for %d user(s)", len(statsQueue))
  756. for userID, update := range statsQueue {
  757. log.
  758. Tag(tag).
  759. Fields(log.Context{
  760. "user_id": userID,
  761. "messages_count": update.Messages,
  762. "emails_count": update.Emails,
  763. "calls_count": update.Calls,
  764. }).
  765. Trace("Updating stats for user %s", userID)
  766. if _, err := tx.Exec(updateUserStatsQuery, update.Messages, update.Emails, update.Calls, userID); err != nil {
  767. return err
  768. }
  769. }
  770. return tx.Commit()
  771. }
  772. func (a *Manager) writeTokenUpdateQueue() error {
  773. a.mu.Lock()
  774. if len(a.tokenQueue) == 0 {
  775. a.mu.Unlock()
  776. log.Tag(tag).Trace("No token updates to commit")
  777. return nil
  778. }
  779. tokenQueue := a.tokenQueue
  780. a.tokenQueue = make(map[string]*TokenUpdate)
  781. a.mu.Unlock()
  782. tx, err := a.db.Begin()
  783. if err != nil {
  784. return err
  785. }
  786. defer tx.Rollback()
  787. log.Tag(tag).Debug("Writing token update queue for %d token(s)", len(tokenQueue))
  788. for tokenID, update := range tokenQueue {
  789. log.Tag(tag).Trace("Updating token %s with last access time %v", tokenID, update.LastAccess.Unix())
  790. if _, err := tx.Exec(updateTokenLastAccessQuery, update.LastAccess.Unix(), update.LastOrigin.String(), tokenID); err != nil {
  791. return err
  792. }
  793. }
  794. return tx.Commit()
  795. }
  796. // Authorize returns nil if the given user has access to the given topic using the desired
  797. // permission. The user param may be nil to signal an anonymous user.
  798. func (a *Manager) Authorize(user *User, topic string, perm Permission) error {
  799. if user != nil && user.Role == RoleAdmin {
  800. return nil // Admin can do everything
  801. }
  802. username := Everyone
  803. if user != nil {
  804. username = user.Name
  805. }
  806. // Select the read/write permissions for this user/topic combo.
  807. // - The query may return two rows (one for everyone, and one for the user), but prioritizes the user.
  808. // - Furthermore, the query prioritizes more specific permissions (longer!) over more generic ones, e.g. "test*" > "*"
  809. // - It also prioritizes write permissions over read permissions
  810. rows, err := a.db.Query(selectTopicPermsQuery, Everyone, username, topic)
  811. if err != nil {
  812. return err
  813. }
  814. defer rows.Close()
  815. if !rows.Next() {
  816. return a.resolvePerms(a.config.DefaultAccess, perm)
  817. }
  818. var read, write bool
  819. if err := rows.Scan(&read, &write); err != nil {
  820. return err
  821. } else if err := rows.Err(); err != nil {
  822. return err
  823. }
  824. return a.resolvePerms(NewPermission(read, write), perm)
  825. }
  826. func (a *Manager) resolvePerms(base, perm Permission) error {
  827. if perm == PermissionRead && base.IsRead() {
  828. return nil
  829. } else if perm == PermissionWrite && base.IsWrite() {
  830. return nil
  831. }
  832. return ErrUnauthorized
  833. }
  834. // AddUser adds a user with the given username, password and role
  835. func (a *Manager) AddUser(username, password string, role Role, hashed bool) error {
  836. if !AllowedUsername(username) || !AllowedRole(role) {
  837. return ErrInvalidArgument
  838. }
  839. var hash []byte
  840. var err error = nil
  841. if hashed {
  842. hash = []byte(password)
  843. } else {
  844. hash, err = bcrypt.GenerateFromPassword([]byte(password), a.config.BcryptCost)
  845. if err != nil {
  846. return err
  847. }
  848. }
  849. userID := util.RandomStringPrefix(userIDPrefix, userIDLength)
  850. syncTopic, now := util.RandomStringPrefix(syncTopicPrefix, syncTopicLength), time.Now().Unix()
  851. if _, err = a.db.Exec(insertUserQuery, userID, username, hash, role, syncTopic, now); err != nil {
  852. if sqliteErr, ok := err.(sqlite3.Error); ok && sqliteErr.ExtendedCode == sqlite3.ErrConstraintUnique {
  853. return ErrUserExists
  854. }
  855. return err
  856. }
  857. return nil
  858. }
  859. // RemoveUser deletes the user with the given username. The function returns nil on success, even
  860. // if the user did not exist in the first place.
  861. func (a *Manager) RemoveUser(username string) error {
  862. if !AllowedUsername(username) {
  863. return ErrInvalidArgument
  864. }
  865. // Rows in user_access, user_token, etc. are deleted via foreign keys
  866. if _, err := a.db.Exec(deleteUserQuery, username); err != nil {
  867. return err
  868. }
  869. return nil
  870. }
  871. // MarkUserRemoved sets the deleted flag on the user, and deletes all access tokens. This prevents
  872. // successful auth via Authenticate. A background process will delete the user at a later date.
  873. func (a *Manager) MarkUserRemoved(user *User) error {
  874. if !AllowedUsername(user.Name) {
  875. return ErrInvalidArgument
  876. }
  877. tx, err := a.db.Begin()
  878. if err != nil {
  879. return err
  880. }
  881. defer tx.Rollback()
  882. if _, err := tx.Exec(deleteUserAccessQuery, user.Name, user.Name); err != nil {
  883. return err
  884. }
  885. if _, err := tx.Exec(deleteAllTokenQuery, user.ID); err != nil {
  886. return err
  887. }
  888. if _, err := tx.Exec(updateUserDeletedQuery, time.Now().Add(userHardDeleteAfterDuration).Unix(), user.ID); err != nil {
  889. return err
  890. }
  891. return tx.Commit()
  892. }
  893. // Users returns a list of users. It always also returns the Everyone user ("*").
  894. func (a *Manager) Users() ([]*User, error) {
  895. rows, err := a.db.Query(selectUsernamesQuery)
  896. if err != nil {
  897. return nil, err
  898. }
  899. defer rows.Close()
  900. usernames := make([]string, 0)
  901. for rows.Next() {
  902. var username string
  903. if err := rows.Scan(&username); err != nil {
  904. return nil, err
  905. } else if err := rows.Err(); err != nil {
  906. return nil, err
  907. }
  908. usernames = append(usernames, username)
  909. }
  910. rows.Close()
  911. users := make([]*User, 0)
  912. for _, username := range usernames {
  913. user, err := a.User(username)
  914. if err != nil {
  915. return nil, err
  916. }
  917. users = append(users, user)
  918. }
  919. return users, nil
  920. }
  921. // UsersCount returns the number of users in the databsae
  922. func (a *Manager) UsersCount() (int64, error) {
  923. rows, err := a.db.Query(selectUserCountQuery)
  924. if err != nil {
  925. return 0, err
  926. }
  927. defer rows.Close()
  928. if !rows.Next() {
  929. return 0, errNoRows
  930. }
  931. var count int64
  932. if err := rows.Scan(&count); err != nil {
  933. return 0, err
  934. }
  935. return count, nil
  936. }
  937. // User returns the user with the given username if it exists, or ErrUserNotFound otherwise.
  938. // You may also pass Everyone to retrieve the anonymous user and its Grant list.
  939. func (a *Manager) User(username string) (*User, error) {
  940. rows, err := a.db.Query(selectUserByNameQuery, username)
  941. if err != nil {
  942. return nil, err
  943. }
  944. return a.readUser(rows)
  945. }
  946. // UserByID returns the user with the given ID if it exists, or ErrUserNotFound otherwise
  947. func (a *Manager) UserByID(id string) (*User, error) {
  948. rows, err := a.db.Query(selectUserByIDQuery, id)
  949. if err != nil {
  950. return nil, err
  951. }
  952. return a.readUser(rows)
  953. }
  954. // UserByStripeCustomer returns the user with the given Stripe customer ID if it exists, or ErrUserNotFound otherwise.
  955. func (a *Manager) UserByStripeCustomer(stripeCustomerID string) (*User, error) {
  956. rows, err := a.db.Query(selectUserByStripeCustomerIDQuery, stripeCustomerID)
  957. if err != nil {
  958. return nil, err
  959. }
  960. return a.readUser(rows)
  961. }
  962. func (a *Manager) userByToken(token string) (*User, error) {
  963. rows, err := a.db.Query(selectUserByTokenQuery, token, time.Now().Unix())
  964. if err != nil {
  965. return nil, err
  966. }
  967. return a.readUser(rows)
  968. }
  969. func (a *Manager) readUser(rows *sql.Rows) (*User, error) {
  970. defer rows.Close()
  971. var id, username, hash, role, prefs, syncTopic string
  972. var stripeCustomerID, stripeSubscriptionID, stripeSubscriptionStatus, stripeSubscriptionInterval, stripeMonthlyPriceID, stripeYearlyPriceID, tierID, tierCode, tierName sql.NullString
  973. var messages, emails, calls int64
  974. var messagesLimit, messagesExpiryDuration, emailsLimit, callsLimit, reservationsLimit, attachmentFileSizeLimit, attachmentTotalSizeLimit, attachmentExpiryDuration, attachmentBandwidthLimit, stripeSubscriptionPaidUntil, stripeSubscriptionCancelAt, deleted sql.NullInt64
  975. if !rows.Next() {
  976. return nil, ErrUserNotFound
  977. }
  978. if err := rows.Scan(&id, &username, &hash, &role, &prefs, &syncTopic, &messages, &emails, &calls, &stripeCustomerID, &stripeSubscriptionID, &stripeSubscriptionStatus, &stripeSubscriptionInterval, &stripeSubscriptionPaidUntil, &stripeSubscriptionCancelAt, &deleted, &tierID, &tierCode, &tierName, &messagesLimit, &messagesExpiryDuration, &emailsLimit, &callsLimit, &reservationsLimit, &attachmentFileSizeLimit, &attachmentTotalSizeLimit, &attachmentExpiryDuration, &attachmentBandwidthLimit, &stripeMonthlyPriceID, &stripeYearlyPriceID); err != nil {
  979. return nil, err
  980. } else if err := rows.Err(); err != nil {
  981. return nil, err
  982. }
  983. user := &User{
  984. ID: id,
  985. Name: username,
  986. Hash: hash,
  987. Role: Role(role),
  988. Prefs: &Prefs{},
  989. SyncTopic: syncTopic,
  990. Stats: &Stats{
  991. Messages: messages,
  992. Emails: emails,
  993. Calls: calls,
  994. },
  995. Billing: &Billing{
  996. StripeCustomerID: stripeCustomerID.String, // May be empty
  997. StripeSubscriptionID: stripeSubscriptionID.String, // May be empty
  998. StripeSubscriptionStatus: stripe.SubscriptionStatus(stripeSubscriptionStatus.String), // May be empty
  999. StripeSubscriptionInterval: stripe.PriceRecurringInterval(stripeSubscriptionInterval.String), // May be empty
  1000. StripeSubscriptionPaidUntil: time.Unix(stripeSubscriptionPaidUntil.Int64, 0), // May be zero
  1001. StripeSubscriptionCancelAt: time.Unix(stripeSubscriptionCancelAt.Int64, 0), // May be zero
  1002. },
  1003. Deleted: deleted.Valid,
  1004. }
  1005. if err := json.Unmarshal([]byte(prefs), user.Prefs); err != nil {
  1006. return nil, err
  1007. }
  1008. if tierCode.Valid {
  1009. // See readTier() when this is changed!
  1010. user.Tier = &Tier{
  1011. ID: tierID.String,
  1012. Code: tierCode.String,
  1013. Name: tierName.String,
  1014. MessageLimit: messagesLimit.Int64,
  1015. MessageExpiryDuration: time.Duration(messagesExpiryDuration.Int64) * time.Second,
  1016. EmailLimit: emailsLimit.Int64,
  1017. CallLimit: callsLimit.Int64,
  1018. ReservationLimit: reservationsLimit.Int64,
  1019. AttachmentFileSizeLimit: attachmentFileSizeLimit.Int64,
  1020. AttachmentTotalSizeLimit: attachmentTotalSizeLimit.Int64,
  1021. AttachmentExpiryDuration: time.Duration(attachmentExpiryDuration.Int64) * time.Second,
  1022. AttachmentBandwidthLimit: attachmentBandwidthLimit.Int64,
  1023. StripeMonthlyPriceID: stripeMonthlyPriceID.String, // May be empty
  1024. StripeYearlyPriceID: stripeYearlyPriceID.String, // May be empty
  1025. }
  1026. }
  1027. return user, nil
  1028. }
  1029. // AllGrants returns all user-specific access control entries, mapped to their respective user IDs
  1030. func (a *Manager) AllGrants() (map[string][]Grant, error) {
  1031. rows, err := a.db.Query(selectUserAllAccessQuery)
  1032. if err != nil {
  1033. return nil, err
  1034. }
  1035. defer rows.Close()
  1036. grants := make(map[string][]Grant, 0)
  1037. for rows.Next() {
  1038. var userID, topic string
  1039. var read, write bool
  1040. if err := rows.Scan(&userID, &topic, &read, &write); err != nil {
  1041. return nil, err
  1042. } else if err := rows.Err(); err != nil {
  1043. return nil, err
  1044. }
  1045. if _, ok := grants[userID]; !ok {
  1046. grants[userID] = make([]Grant, 0)
  1047. }
  1048. grants[userID] = append(grants[userID], Grant{
  1049. TopicPattern: fromSQLWildcard(topic),
  1050. Allow: NewPermission(read, write),
  1051. })
  1052. }
  1053. return grants, nil
  1054. }
  1055. // Grants returns all user-specific access control entries
  1056. func (a *Manager) Grants(username string) ([]Grant, error) {
  1057. rows, err := a.db.Query(selectUserAccessQuery, username)
  1058. if err != nil {
  1059. return nil, err
  1060. }
  1061. defer rows.Close()
  1062. grants := make([]Grant, 0)
  1063. for rows.Next() {
  1064. var topic string
  1065. var read, write bool
  1066. if err := rows.Scan(&topic, &read, &write); err != nil {
  1067. return nil, err
  1068. } else if err := rows.Err(); err != nil {
  1069. return nil, err
  1070. }
  1071. grants = append(grants, Grant{
  1072. TopicPattern: fromSQLWildcard(topic),
  1073. Allow: NewPermission(read, write),
  1074. })
  1075. }
  1076. return grants, nil
  1077. }
  1078. // Reservations returns all user-owned topics, and the associated everyone-access
  1079. func (a *Manager) Reservations(username string) ([]Reservation, error) {
  1080. rows, err := a.db.Query(selectUserReservationsQuery, Everyone, username)
  1081. if err != nil {
  1082. return nil, err
  1083. }
  1084. defer rows.Close()
  1085. reservations := make([]Reservation, 0)
  1086. for rows.Next() {
  1087. var topic string
  1088. var ownerRead, ownerWrite bool
  1089. var everyoneRead, everyoneWrite sql.NullBool
  1090. if err := rows.Scan(&topic, &ownerRead, &ownerWrite, &everyoneRead, &everyoneWrite); err != nil {
  1091. return nil, err
  1092. } else if err := rows.Err(); err != nil {
  1093. return nil, err
  1094. }
  1095. reservations = append(reservations, Reservation{
  1096. Topic: unescapeUnderscore(topic),
  1097. Owner: NewPermission(ownerRead, ownerWrite),
  1098. Everyone: NewPermission(everyoneRead.Bool, everyoneWrite.Bool), // false if null
  1099. })
  1100. }
  1101. return reservations, nil
  1102. }
  1103. // HasReservation returns true if the given topic access is owned by the user
  1104. func (a *Manager) HasReservation(username, topic string) (bool, error) {
  1105. rows, err := a.db.Query(selectUserHasReservationQuery, username, escapeUnderscore(topic))
  1106. if err != nil {
  1107. return false, err
  1108. }
  1109. defer rows.Close()
  1110. if !rows.Next() {
  1111. return false, errNoRows
  1112. }
  1113. var count int64
  1114. if err := rows.Scan(&count); err != nil {
  1115. return false, err
  1116. }
  1117. return count > 0, nil
  1118. }
  1119. // ReservationsCount returns the number of reservations owned by this user
  1120. func (a *Manager) ReservationsCount(username string) (int64, error) {
  1121. rows, err := a.db.Query(selectUserReservationsCountQuery, username)
  1122. if err != nil {
  1123. return 0, err
  1124. }
  1125. defer rows.Close()
  1126. if !rows.Next() {
  1127. return 0, errNoRows
  1128. }
  1129. var count int64
  1130. if err := rows.Scan(&count); err != nil {
  1131. return 0, err
  1132. }
  1133. return count, nil
  1134. }
  1135. // ReservationOwner returns user ID of the user that owns this topic, or an
  1136. // empty string if it's not owned by anyone
  1137. func (a *Manager) ReservationOwner(topic string) (string, error) {
  1138. rows, err := a.db.Query(selectUserReservationsOwnerQuery, escapeUnderscore(topic))
  1139. if err != nil {
  1140. return "", err
  1141. }
  1142. defer rows.Close()
  1143. if !rows.Next() {
  1144. return "", nil
  1145. }
  1146. var ownerUserID string
  1147. if err := rows.Scan(&ownerUserID); err != nil {
  1148. return "", err
  1149. }
  1150. return ownerUserID, nil
  1151. }
  1152. // ChangePassword changes a user's password
  1153. func (a *Manager) ChangePassword(username, password string, hashed bool) error {
  1154. var hash []byte
  1155. var err error
  1156. if hashed {
  1157. hash = []byte(password)
  1158. } else {
  1159. hash, err = bcrypt.GenerateFromPassword([]byte(password), a.config.BcryptCost)
  1160. if err != nil {
  1161. return err
  1162. }
  1163. }
  1164. if _, err := a.db.Exec(updateUserPassQuery, hash, username); err != nil {
  1165. return err
  1166. }
  1167. return nil
  1168. }
  1169. // ChangeRole changes a user's role. When a role is changed from RoleUser to RoleAdmin,
  1170. // all existing access control entries (Grant) are removed, since they are no longer needed.
  1171. func (a *Manager) ChangeRole(username string, role Role) error {
  1172. if !AllowedUsername(username) || !AllowedRole(role) {
  1173. return ErrInvalidArgument
  1174. }
  1175. if _, err := a.db.Exec(updateUserRoleQuery, string(role), username); err != nil {
  1176. return err
  1177. }
  1178. if role == RoleAdmin {
  1179. if _, err := a.db.Exec(deleteUserAccessQuery, username, username); err != nil {
  1180. return err
  1181. }
  1182. }
  1183. return nil
  1184. }
  1185. // ChangeTier changes a user's tier using the tier code. This function does not delete reservations, messages,
  1186. // or attachments, even if the new tier has lower limits in this regard. That has to be done elsewhere.
  1187. func (a *Manager) ChangeTier(username, tier string) error {
  1188. if !AllowedUsername(username) {
  1189. return ErrInvalidArgument
  1190. }
  1191. t, err := a.Tier(tier)
  1192. if err != nil {
  1193. return err
  1194. } else if err := a.checkReservationsLimit(username, t.ReservationLimit); err != nil {
  1195. return err
  1196. }
  1197. if _, err := a.db.Exec(updateUserTierQuery, tier, username); err != nil {
  1198. return err
  1199. }
  1200. return nil
  1201. }
  1202. // ResetTier removes the tier from the given user
  1203. func (a *Manager) ResetTier(username string) error {
  1204. if !AllowedUsername(username) && username != Everyone && username != "" {
  1205. return ErrInvalidArgument
  1206. } else if err := a.checkReservationsLimit(username, 0); err != nil {
  1207. return err
  1208. }
  1209. _, err := a.db.Exec(deleteUserTierQuery, username)
  1210. return err
  1211. }
  1212. func (a *Manager) checkReservationsLimit(username string, reservationsLimit int64) error {
  1213. u, err := a.User(username)
  1214. if err != nil {
  1215. return err
  1216. }
  1217. if u.Tier != nil && reservationsLimit < u.Tier.ReservationLimit {
  1218. reservations, err := a.Reservations(username)
  1219. if err != nil {
  1220. return err
  1221. } else if int64(len(reservations)) > reservationsLimit {
  1222. return ErrTooManyReservations
  1223. }
  1224. }
  1225. return nil
  1226. }
  1227. // AllowReservation tests if a user may create an access control entry for the given topic.
  1228. // If there are any ACL entries that are not owned by the user, an error is returned.
  1229. func (a *Manager) AllowReservation(username string, topic string) error {
  1230. if (!AllowedUsername(username) && username != Everyone) || !AllowedTopic(topic) {
  1231. return ErrInvalidArgument
  1232. }
  1233. rows, err := a.db.Query(selectOtherAccessCountQuery, escapeUnderscore(topic), escapeUnderscore(topic), username)
  1234. if err != nil {
  1235. return err
  1236. }
  1237. defer rows.Close()
  1238. if !rows.Next() {
  1239. return errNoRows
  1240. }
  1241. var otherCount int
  1242. if err := rows.Scan(&otherCount); err != nil {
  1243. return err
  1244. }
  1245. if otherCount > 0 {
  1246. return errTopicOwnedByOthers
  1247. }
  1248. return nil
  1249. }
  1250. // AllowAccess adds or updates an entry in th access control list for a specific user. It controls
  1251. // read/write access to a topic. The parameter topicPattern may include wildcards (*). The ACL entry
  1252. // owner may either be a user (username), or the system (empty).
  1253. func (a *Manager) AllowAccess(username string, topicPattern string, permission Permission) error {
  1254. if !AllowedUsername(username) && username != Everyone {
  1255. return ErrInvalidArgument
  1256. } else if !AllowedTopicPattern(topicPattern) {
  1257. return ErrInvalidArgument
  1258. }
  1259. owner := ""
  1260. if _, err := a.db.Exec(upsertUserAccessQuery, username, toSQLWildcard(topicPattern), permission.IsRead(), permission.IsWrite(), owner, owner); err != nil {
  1261. return err
  1262. }
  1263. return nil
  1264. }
  1265. // ResetAccess removes an access control list entry for a specific username/topic, or (if topic is
  1266. // empty) for an entire user. The parameter topicPattern may include wildcards (*).
  1267. func (a *Manager) ResetAccess(username string, topicPattern string) error {
  1268. if !AllowedUsername(username) && username != Everyone && username != "" {
  1269. return ErrInvalidArgument
  1270. } else if !AllowedTopicPattern(topicPattern) && topicPattern != "" {
  1271. return ErrInvalidArgument
  1272. }
  1273. if username == "" && topicPattern == "" {
  1274. _, err := a.db.Exec(deleteAllAccessQuery, username)
  1275. return err
  1276. } else if topicPattern == "" {
  1277. _, err := a.db.Exec(deleteUserAccessQuery, username, username)
  1278. return err
  1279. }
  1280. _, err := a.db.Exec(deleteTopicAccessQuery, username, username, toSQLWildcard(topicPattern))
  1281. return err
  1282. }
  1283. // AddReservation creates two access control entries for the given topic: one with full read/write access for the
  1284. // given user, and one for Everyone with the permission passed as everyone. The user also owns the entries, and
  1285. // can modify or delete them.
  1286. func (a *Manager) AddReservation(username string, topic string, everyone Permission) error {
  1287. if !AllowedUsername(username) || username == Everyone || !AllowedTopic(topic) {
  1288. return ErrInvalidArgument
  1289. }
  1290. tx, err := a.db.Begin()
  1291. if err != nil {
  1292. return err
  1293. }
  1294. defer tx.Rollback()
  1295. if _, err := tx.Exec(upsertUserAccessQuery, username, escapeUnderscore(topic), true, true, username, username); err != nil {
  1296. return err
  1297. }
  1298. if _, err := tx.Exec(upsertUserAccessQuery, Everyone, escapeUnderscore(topic), everyone.IsRead(), everyone.IsWrite(), username, username); err != nil {
  1299. return err
  1300. }
  1301. return tx.Commit()
  1302. }
  1303. // RemoveReservations deletes the access control entries associated with the given username/topic, as
  1304. // well as all entries with Everyone/topic. This is the counterpart for AddReservation.
  1305. func (a *Manager) RemoveReservations(username string, topics ...string) error {
  1306. if !AllowedUsername(username) || username == Everyone || len(topics) == 0 {
  1307. return ErrInvalidArgument
  1308. }
  1309. for _, topic := range topics {
  1310. if !AllowedTopic(topic) {
  1311. return ErrInvalidArgument
  1312. }
  1313. }
  1314. tx, err := a.db.Begin()
  1315. if err != nil {
  1316. return err
  1317. }
  1318. defer tx.Rollback()
  1319. for _, topic := range topics {
  1320. if _, err := tx.Exec(deleteTopicAccessQuery, username, username, escapeUnderscore(topic)); err != nil {
  1321. return err
  1322. }
  1323. if _, err := tx.Exec(deleteTopicAccessQuery, Everyone, Everyone, escapeUnderscore(topic)); err != nil {
  1324. return err
  1325. }
  1326. }
  1327. return tx.Commit()
  1328. }
  1329. // DefaultAccess returns the default read/write access if no access control entry matches
  1330. func (a *Manager) DefaultAccess() Permission {
  1331. return a.config.DefaultAccess
  1332. }
  1333. // AddTier creates a new tier in the database
  1334. func (a *Manager) AddTier(tier *Tier) error {
  1335. if tier.ID == "" {
  1336. tier.ID = util.RandomStringPrefix(tierIDPrefix, tierIDLength)
  1337. }
  1338. if _, err := a.db.Exec(insertTierQuery, tier.ID, tier.Code, tier.Name, tier.MessageLimit, int64(tier.MessageExpiryDuration.Seconds()), tier.EmailLimit, tier.CallLimit, tier.ReservationLimit, tier.AttachmentFileSizeLimit, tier.AttachmentTotalSizeLimit, int64(tier.AttachmentExpiryDuration.Seconds()), tier.AttachmentBandwidthLimit, nullString(tier.StripeMonthlyPriceID), nullString(tier.StripeYearlyPriceID)); err != nil {
  1339. return err
  1340. }
  1341. return nil
  1342. }
  1343. // UpdateTier updates a tier's properties in the database
  1344. func (a *Manager) UpdateTier(tier *Tier) error {
  1345. if _, err := a.db.Exec(updateTierQuery, tier.Name, tier.MessageLimit, int64(tier.MessageExpiryDuration.Seconds()), tier.EmailLimit, tier.CallLimit, tier.ReservationLimit, tier.AttachmentFileSizeLimit, tier.AttachmentTotalSizeLimit, int64(tier.AttachmentExpiryDuration.Seconds()), tier.AttachmentBandwidthLimit, nullString(tier.StripeMonthlyPriceID), nullString(tier.StripeYearlyPriceID), tier.Code); err != nil {
  1346. return err
  1347. }
  1348. return nil
  1349. }
  1350. // RemoveTier deletes the tier with the given code
  1351. func (a *Manager) RemoveTier(code string) error {
  1352. if !AllowedTier(code) {
  1353. return ErrInvalidArgument
  1354. }
  1355. // This fails if any user has this tier
  1356. if _, err := a.db.Exec(deleteTierQuery, code); err != nil {
  1357. return err
  1358. }
  1359. return nil
  1360. }
  1361. // ChangeBilling updates a user's billing fields, namely the Stripe customer ID, and subscription information
  1362. func (a *Manager) ChangeBilling(username string, billing *Billing) error {
  1363. if _, err := a.db.Exec(updateBillingQuery, nullString(billing.StripeCustomerID), nullString(billing.StripeSubscriptionID), nullString(string(billing.StripeSubscriptionStatus)), nullString(string(billing.StripeSubscriptionInterval)), nullInt64(billing.StripeSubscriptionPaidUntil.Unix()), nullInt64(billing.StripeSubscriptionCancelAt.Unix()), username); err != nil {
  1364. return err
  1365. }
  1366. return nil
  1367. }
  1368. // Tiers returns a list of all Tier structs
  1369. func (a *Manager) Tiers() ([]*Tier, error) {
  1370. rows, err := a.db.Query(selectTiersQuery)
  1371. if err != nil {
  1372. return nil, err
  1373. }
  1374. defer rows.Close()
  1375. tiers := make([]*Tier, 0)
  1376. for {
  1377. tier, err := a.readTier(rows)
  1378. if err == ErrTierNotFound {
  1379. break
  1380. } else if err != nil {
  1381. return nil, err
  1382. }
  1383. tiers = append(tiers, tier)
  1384. }
  1385. return tiers, nil
  1386. }
  1387. // Tier returns a Tier based on the code, or ErrTierNotFound if it does not exist
  1388. func (a *Manager) Tier(code string) (*Tier, error) {
  1389. rows, err := a.db.Query(selectTierByCodeQuery, code)
  1390. if err != nil {
  1391. return nil, err
  1392. }
  1393. defer rows.Close()
  1394. return a.readTier(rows)
  1395. }
  1396. // TierByStripePrice returns a Tier based on the Stripe price ID, or ErrTierNotFound if it does not exist
  1397. func (a *Manager) TierByStripePrice(priceID string) (*Tier, error) {
  1398. rows, err := a.db.Query(selectTierByPriceIDQuery, priceID, priceID)
  1399. if err != nil {
  1400. return nil, err
  1401. }
  1402. defer rows.Close()
  1403. return a.readTier(rows)
  1404. }
  1405. func (a *Manager) readTier(rows *sql.Rows) (*Tier, error) {
  1406. var id, code, name string
  1407. var stripeMonthlyPriceID, stripeYearlyPriceID sql.NullString
  1408. var messagesLimit, messagesExpiryDuration, emailsLimit, callsLimit, reservationsLimit, attachmentFileSizeLimit, attachmentTotalSizeLimit, attachmentExpiryDuration, attachmentBandwidthLimit sql.NullInt64
  1409. if !rows.Next() {
  1410. return nil, ErrTierNotFound
  1411. }
  1412. if err := rows.Scan(&id, &code, &name, &messagesLimit, &messagesExpiryDuration, &emailsLimit, &callsLimit, &reservationsLimit, &attachmentFileSizeLimit, &attachmentTotalSizeLimit, &attachmentExpiryDuration, &attachmentBandwidthLimit, &stripeMonthlyPriceID, &stripeYearlyPriceID); err != nil {
  1413. return nil, err
  1414. } else if err := rows.Err(); err != nil {
  1415. return nil, err
  1416. }
  1417. // When changed, note readUser() as well
  1418. return &Tier{
  1419. ID: id,
  1420. Code: code,
  1421. Name: name,
  1422. MessageLimit: messagesLimit.Int64,
  1423. MessageExpiryDuration: time.Duration(messagesExpiryDuration.Int64) * time.Second,
  1424. EmailLimit: emailsLimit.Int64,
  1425. CallLimit: callsLimit.Int64,
  1426. ReservationLimit: reservationsLimit.Int64,
  1427. AttachmentFileSizeLimit: attachmentFileSizeLimit.Int64,
  1428. AttachmentTotalSizeLimit: attachmentTotalSizeLimit.Int64,
  1429. AttachmentExpiryDuration: time.Duration(attachmentExpiryDuration.Int64) * time.Second,
  1430. AttachmentBandwidthLimit: attachmentBandwidthLimit.Int64,
  1431. StripeMonthlyPriceID: stripeMonthlyPriceID.String, // May be empty
  1432. StripeYearlyPriceID: stripeYearlyPriceID.String, // May be empty
  1433. }, nil
  1434. }
  1435. // Close closes the underlying database
  1436. func (a *Manager) Close() error {
  1437. return a.db.Close()
  1438. }
  1439. // toSQLWildcard converts a wildcard string to a SQL wildcard string. It only allows '*' as wildcards,
  1440. // and escapes '_', assuming '\' as escape character.
  1441. func toSQLWildcard(s string) string {
  1442. return escapeUnderscore(strings.ReplaceAll(s, "*", "%"))
  1443. }
  1444. // fromSQLWildcard converts a SQL wildcard string to a wildcard string. It converts '%' to '*',
  1445. // and removes the '\_' escape character.
  1446. func fromSQLWildcard(s string) string {
  1447. return strings.ReplaceAll(unescapeUnderscore(s), "%", "*")
  1448. }
  1449. func escapeUnderscore(s string) string {
  1450. return strings.ReplaceAll(s, "_", "\\_")
  1451. }
  1452. func unescapeUnderscore(s string) string {
  1453. return strings.ReplaceAll(s, "\\_", "_")
  1454. }
  1455. func runStartupQueries(db *sql.DB, startupQueries string) error {
  1456. if _, err := db.Exec(startupQueries); err != nil {
  1457. return err
  1458. }
  1459. if _, err := db.Exec(builtinStartupQueries); err != nil {
  1460. return err
  1461. }
  1462. return nil
  1463. }
  1464. func setupDB(db *sql.DB) error {
  1465. // If 'schemaVersion' table does not exist, this must be a new database
  1466. rowsSV, err := db.Query(selectSchemaVersionQuery)
  1467. if err != nil {
  1468. return setupNewDB(db)
  1469. }
  1470. defer rowsSV.Close()
  1471. // If 'schemaVersion' table exists, read version and potentially upgrade
  1472. schemaVersion := 0
  1473. if !rowsSV.Next() {
  1474. return errors.New("cannot determine schema version: database file may be corrupt")
  1475. }
  1476. if err := rowsSV.Scan(&schemaVersion); err != nil {
  1477. return err
  1478. }
  1479. rowsSV.Close()
  1480. // Do migrations
  1481. if schemaVersion == currentSchemaVersion {
  1482. return nil
  1483. } else if schemaVersion > currentSchemaVersion {
  1484. return fmt.Errorf("unexpected schema version: version %d is higher than current version %d", schemaVersion, currentSchemaVersion)
  1485. }
  1486. for i := schemaVersion; i < currentSchemaVersion; i++ {
  1487. fn, ok := migrations[i]
  1488. if !ok {
  1489. return fmt.Errorf("cannot find migration step from schema version %d to %d", i, i+1)
  1490. } else if err := fn(db); err != nil {
  1491. return err
  1492. }
  1493. }
  1494. return nil
  1495. }
  1496. func setupNewDB(db *sql.DB) error {
  1497. if _, err := db.Exec(createTablesQueries); err != nil {
  1498. return err
  1499. }
  1500. if _, err := db.Exec(insertSchemaVersion, currentSchemaVersion); err != nil {
  1501. return err
  1502. }
  1503. return nil
  1504. }
  1505. func migrateFrom1(db *sql.DB) error {
  1506. log.Tag(tag).Info("Migrating user database schema: from 1 to 2")
  1507. tx, err := db.Begin()
  1508. if err != nil {
  1509. return err
  1510. }
  1511. defer tx.Rollback()
  1512. // Rename user -> user_old, and create new tables
  1513. if _, err := tx.Exec(migrate1To2CreateTablesQueries); err != nil {
  1514. return err
  1515. }
  1516. // Insert users from user_old into new user table, with ID and sync_topic
  1517. rows, err := tx.Query(migrate1To2SelectAllOldUsernamesNoTx)
  1518. if err != nil {
  1519. return err
  1520. }
  1521. defer rows.Close()
  1522. usernames := make([]string, 0)
  1523. for rows.Next() {
  1524. var username string
  1525. if err := rows.Scan(&username); err != nil {
  1526. return err
  1527. }
  1528. usernames = append(usernames, username)
  1529. }
  1530. if err := rows.Close(); err != nil {
  1531. return err
  1532. }
  1533. for _, username := range usernames {
  1534. userID := util.RandomStringPrefix(userIDPrefix, userIDLength)
  1535. syncTopic := util.RandomStringPrefix(syncTopicPrefix, syncTopicLength)
  1536. if _, err := tx.Exec(migrate1To2InsertUserNoTx, userID, syncTopic, username); err != nil {
  1537. return err
  1538. }
  1539. }
  1540. // Migrate old "access" table to "user_access" and drop "access" and "user_old"
  1541. if _, err := tx.Exec(migrate1To2InsertFromOldTablesAndDropNoTx); err != nil {
  1542. return err
  1543. }
  1544. if _, err := tx.Exec(updateSchemaVersion, 2); err != nil {
  1545. return err
  1546. }
  1547. if err := tx.Commit(); err != nil {
  1548. return err
  1549. }
  1550. return nil
  1551. }
  1552. func migrateFrom2(db *sql.DB) error {
  1553. log.Tag(tag).Info("Migrating user database schema: from 2 to 3")
  1554. tx, err := db.Begin()
  1555. if err != nil {
  1556. return err
  1557. }
  1558. defer tx.Rollback()
  1559. if _, err := tx.Exec(migrate2To3UpdateQueries); err != nil {
  1560. return err
  1561. }
  1562. if _, err := tx.Exec(updateSchemaVersion, 3); err != nil {
  1563. return err
  1564. }
  1565. return tx.Commit()
  1566. }
  1567. func migrateFrom3(db *sql.DB) error {
  1568. log.Tag(tag).Info("Migrating user database schema: from 3 to 4")
  1569. tx, err := db.Begin()
  1570. if err != nil {
  1571. return err
  1572. }
  1573. defer tx.Rollback()
  1574. if _, err := tx.Exec(migrate3To4UpdateQueries); err != nil {
  1575. return err
  1576. }
  1577. if _, err := tx.Exec(updateSchemaVersion, 4); err != nil {
  1578. return err
  1579. }
  1580. return tx.Commit()
  1581. }
  1582. func migrateFrom4(db *sql.DB) error {
  1583. log.Tag(tag).Info("Migrating user database schema: from 4 to 5")
  1584. tx, err := db.Begin()
  1585. if err != nil {
  1586. return err
  1587. }
  1588. defer tx.Rollback()
  1589. if _, err := tx.Exec(migrate4To5UpdateQueries); err != nil {
  1590. return err
  1591. }
  1592. if _, err := tx.Exec(updateSchemaVersion, 5); err != nil {
  1593. return err
  1594. }
  1595. return tx.Commit()
  1596. }
  1597. func nullString(s string) sql.NullString {
  1598. if s == "" {
  1599. return sql.NullString{}
  1600. }
  1601. return sql.NullString{String: s, Valid: true}
  1602. }
  1603. func nullInt64(v int64) sql.NullInt64 {
  1604. if v == 0 {
  1605. return sql.NullInt64{}
  1606. }
  1607. return sql.NullInt64{Int64: v, Valid: true}
  1608. }