clear_sessions_2fa.mjs 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. import { promisify, promiseMapWithLimit } from '@overleaf/promise-utils'
  2. import UserSessionsRedis from '../app/src/Features/User/UserSessionsRedis.js'
  3. import minimist from 'minimist'
  4. const rClient = UserSessionsRedis.client()
  5. const args = minimist(process.argv.slice(2))
  6. const CURSOR = args.cursor
  7. const COMMIT = args.commit === 'true'
  8. const CONCURRENCY = parseInt(args.concurrency, 10) || 50
  9. const LOG_EVERY_IN_S = parseInt(args['log-every-in-s'], 10) || 5
  10. function shouldDelete(session) {
  11. if (session.twoFactorAuthenticationPendingUser) {
  12. // twoFactorAuthenticationPendingUserId migration
  13. return true
  14. }
  15. // default: keep
  16. return false
  17. }
  18. async function processSession(key) {
  19. if (!key || !key.startsWith('sess:')) {
  20. throw new Error(`unexpected session key: ${key}`)
  21. }
  22. const blob = await rClient.get(key)
  23. if (!blob) return false // expired or deleted
  24. const session = JSON.parse(blob)
  25. if (shouldDelete(session)) {
  26. const deleteLabel = COMMIT ? 'delete' : 'would delete'
  27. console.warn(deleteLabel, key)
  28. if (COMMIT) {
  29. await rClient.del(key)
  30. }
  31. return true
  32. }
  33. return false
  34. }
  35. async function main() {
  36. console.warn({ COMMIT, CONCURRENCY, CURSOR, LOG_EVERY_IN_S })
  37. console.warn('starting in 10s')
  38. await promisify(setTimeout)(10_000)
  39. let processed = 0
  40. let deleted = 0
  41. function logProgress() {
  42. const deletedLabel = COMMIT ? 'deleted' : 'would have deleted'
  43. console.log(
  44. `processed ${processed} | ${deletedLabel} ${deleted} | cursor ${cursor}`
  45. )
  46. }
  47. let cursor = CURSOR
  48. let lastLog = 0
  49. while (cursor !== '0') {
  50. let keys
  51. ;[cursor, keys] = await rClient.scan(cursor || 0, 'MATCH', 'sess:*')
  52. const results = await promiseMapWithLimit(CONCURRENCY, keys, processSession)
  53. processed += keys.length
  54. for (const r of results) {
  55. if (r) deleted++
  56. }
  57. if (Date.now() - lastLog >= LOG_EVERY_IN_S * 1000) {
  58. logProgress()
  59. lastLog = Date.now()
  60. }
  61. }
  62. logProgress()
  63. console.log('Done.')
  64. await rClient.disconnect()
  65. }
  66. try {
  67. await main()
  68. } catch (error) {
  69. console.error(error)
  70. process.exit(1)
  71. }