@actual-app/sync-server 25.5.0 → 25.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (244) hide show
  1. package/{app.js → build/app.js} +4 -5
  2. package/build/bin/actual-server.js +101 -0
  3. package/build/migrations/1694360000000-create-folders.js +21 -0
  4. package/{migrations → build/migrations}/1694360479680-create-account-db.js +2 -4
  5. package/{migrations → build/migrations}/1694362247011-create-secret-table.js +2 -4
  6. package/build/migrations/1702667624000-rename-nordigen-secrets.js +9 -0
  7. package/{migrations → build/migrations}/1718889148000-openid.js +4 -10
  8. package/{migrations → build/migrations}/1719409568000-multiuser.js +10 -26
  9. package/build/src/account-db.js +182 -0
  10. package/build/src/accounts/openid.js +287 -0
  11. package/build/src/accounts/password.js +98 -0
  12. package/build/src/app-account.js +125 -0
  13. package/build/src/app-admin.js +317 -0
  14. package/build/src/app-admin.test.js +303 -0
  15. package/build/src/app-gocardless/app-gocardless.js +193 -0
  16. package/build/src/app-gocardless/bank-factory.js +84 -0
  17. package/build/src/app-gocardless/banks/abanca_caglesmm.js +17 -0
  18. package/build/src/app-gocardless/banks/abnamro_abnanl2a.js +37 -0
  19. package/build/src/app-gocardless/banks/american_express_aesudef1.js +32 -0
  20. package/build/src/app-gocardless/banks/bancsabadell_bsabesbbb.js +22 -0
  21. package/build/src/app-gocardless/banks/bank.interface.js +1 -0
  22. package/build/src/app-gocardless/banks/bank_of_ireland_b365_bofiie2d.js +25 -0
  23. package/build/src/app-gocardless/banks/bankinter_bkbkesmm.js +18 -0
  24. package/build/src/app-gocardless/banks/belfius_gkccbebb.js +13 -0
  25. package/build/src/app-gocardless/banks/berliner_sparkasse_beladebexxx.js +48 -0
  26. package/build/src/app-gocardless/banks/bnp_be_gebabebb.js +64 -0
  27. package/build/src/app-gocardless/banks/boursobank_bousfrppxxx.js +73 -0
  28. package/build/src/app-gocardless/banks/cbc_cregbebb.js +27 -0
  29. package/build/src/app-gocardless/banks/commerzbank_cobadeff.js +43 -0
  30. package/build/src/app-gocardless/banks/danskebank_dabno22.js +26 -0
  31. package/build/src/app-gocardless/banks/direkt_heladef1822.js +13 -0
  32. package/build/src/app-gocardless/banks/easybank_bawaatww.js +42 -0
  33. package/build/src/app-gocardless/banks/entercard_swednokk.js +28 -0
  34. package/build/src/app-gocardless/banks/fortuneo_ftnofrp1xxx.js +34 -0
  35. package/build/src/app-gocardless/banks/hype_hyeeit22.js +63 -0
  36. package/build/src/app-gocardless/banks/ing_ingbrobu.js +56 -0
  37. package/build/src/app-gocardless/banks/ing_ingddeff.js +34 -0
  38. package/build/src/app-gocardless/banks/ing_pl_ingbplpw.js +29 -0
  39. package/build/src/app-gocardless/banks/integration-bank.js +78 -0
  40. package/build/src/app-gocardless/banks/isybank_itbbitmm.js +13 -0
  41. package/build/src/app-gocardless/banks/kbc_kredbebb.js +26 -0
  42. package/build/src/app-gocardless/banks/lhv-lhvbee22.js +24 -0
  43. package/build/src/app-gocardless/banks/mbank_retail_brexplpw.js +41 -0
  44. package/build/src/app-gocardless/banks/nationwide_naiagb21.js +32 -0
  45. package/build/src/app-gocardless/banks/nbg_ethngraaxxx.js +39 -0
  46. package/build/src/app-gocardless/banks/norwegian_xx_norwnok1.js +61 -0
  47. package/build/src/app-gocardless/banks/revolut_revolt21.js +20 -0
  48. package/build/src/app-gocardless/banks/sandboxfinance_sfin0000.js +21 -0
  49. package/build/src/app-gocardless/banks/seb_kort_bank_ab.js +63 -0
  50. package/build/src/app-gocardless/banks/seb_privat.js +19 -0
  51. package/build/src/app-gocardless/banks/sparnord_spnodk22.js +19 -0
  52. package/build/src/app-gocardless/banks/spk_karlsruhe_karsde66.js +48 -0
  53. package/build/src/app-gocardless/banks/spk_marburg_biedenkopf_heladef1mar.js +25 -0
  54. package/build/src/app-gocardless/banks/spk_worms_alzey_ried_malade51wor.js +14 -0
  55. package/build/src/app-gocardless/banks/ssk_dusseldorf_dussdeddxxx.js +36 -0
  56. package/build/src/app-gocardless/banks/swedbank_habalv22.js +30 -0
  57. package/build/src/app-gocardless/banks/tests/abanca_caglesmm.spec.js +17 -0
  58. package/build/src/app-gocardless/banks/tests/abnamro_abnanl2a.spec.js +45 -0
  59. package/build/src/app-gocardless/banks/tests/bancsabadell_bsabesbbb.spec.js +41 -0
  60. package/build/src/app-gocardless/banks/tests/belfius_gkccbebb.spec.js +16 -0
  61. package/build/src/app-gocardless/banks/tests/boursobank_bousfrppxxx.spec.js +102 -0
  62. package/build/src/app-gocardless/banks/tests/cbc_cregbebb.spec.js +24 -0
  63. package/build/src/app-gocardless/banks/tests/commerzbank_cobadeff.spec.js +105 -0
  64. package/build/src/app-gocardless/banks/tests/easybank_bawaatww.spec.js +36 -0
  65. package/build/src/app-gocardless/banks/tests/fortuneo_ftnofrp1xxx.spec.js +159 -0
  66. package/build/src/app-gocardless/banks/tests/ing_ingddeff.spec.js +267 -0
  67. package/build/src/app-gocardless/banks/tests/ing_pl_ingbplpw.spec.js +186 -0
  68. package/build/src/app-gocardless/banks/tests/integration_bank.spec.js +127 -0
  69. package/build/src/app-gocardless/banks/tests/kbc_kredbebb.spec.js +24 -0
  70. package/build/src/app-gocardless/banks/tests/lhv-lhvbee22.spec.js +50 -0
  71. package/build/src/app-gocardless/banks/tests/mbank_retail_brexplpw.spec.js +156 -0
  72. package/build/src/app-gocardless/banks/tests/nationwide_naiagb21.spec.js +64 -0
  73. package/build/src/app-gocardless/banks/tests/nbg_ethngraaxxx.spec.js +36 -0
  74. package/build/src/app-gocardless/banks/tests/revolut_revolt21.spec.js +30 -0
  75. package/build/src/app-gocardless/banks/tests/sandboxfinance_sfin0000.spec.js +112 -0
  76. package/build/src/app-gocardless/banks/tests/spk_marburg_biedenkopf_heladef1mar.spec.js +214 -0
  77. package/build/src/app-gocardless/banks/tests/ssk_dusseldorf_dussdeddxxx.spec.js +60 -0
  78. package/build/src/app-gocardless/banks/tests/swedbank_habalv22.spec.js +45 -0
  79. package/build/src/app-gocardless/banks/tests/virgin_nrnbgb22.spec.js +36 -0
  80. package/{src → build/src}/app-gocardless/banks/util/escape-regexp.js +1 -1
  81. package/{src → build/src}/app-gocardless/banks/util/extract-payeeName-from-remittanceInfo.js +11 -16
  82. package/build/src/app-gocardless/banks/virgin_nrnbgb22.js +31 -0
  83. package/build/src/app-gocardless/errors.js +67 -0
  84. package/build/src/app-gocardless/gocardless-node.types.js +1 -0
  85. package/build/src/app-gocardless/gocardless.types.js +1 -0
  86. package/build/src/app-gocardless/services/gocardless-service.js +504 -0
  87. package/build/src/app-gocardless/services/tests/fixtures.js +165 -0
  88. package/build/src/app-gocardless/services/tests/gocardless-service.spec.js +387 -0
  89. package/build/src/app-gocardless/tests/bank-factory.spec.js +13 -0
  90. package/build/src/app-gocardless/tests/utils.spec.js +158 -0
  91. package/build/src/app-gocardless/util/handle-error.js +15 -0
  92. package/build/src/app-gocardless/utils.js +41 -0
  93. package/build/src/app-openid.js +83 -0
  94. package/build/src/app-pluggyai/app-pluggyai.js +164 -0
  95. package/build/src/app-pluggyai/pluggyai-service.js +97 -0
  96. package/build/src/app-secrets.js +48 -0
  97. package/build/src/app-simplefin/app-simplefin.js +335 -0
  98. package/build/src/app-sync/errors.js +12 -0
  99. package/build/src/app-sync/services/files-service.js +158 -0
  100. package/build/src/app-sync/tests/services/files-service.test.js +192 -0
  101. package/build/src/app-sync/validation.js +65 -0
  102. package/build/src/app-sync.js +302 -0
  103. package/build/src/app-sync.test.js +655 -0
  104. package/build/src/app.js +138 -0
  105. package/build/src/config-types.js +1 -0
  106. package/build/src/db.js +50 -0
  107. package/build/src/load-config.js +274 -0
  108. package/build/src/migrations.js +23 -0
  109. package/build/src/scripts/disable-openid.js +31 -0
  110. package/build/src/scripts/enable-openid.js +36 -0
  111. package/build/src/scripts/health-check.js +16 -0
  112. package/build/src/scripts/reset-password.js +40 -0
  113. package/build/src/scripts/run-migrations.js +6 -0
  114. package/build/src/secrets.test.js +68 -0
  115. package/build/src/services/secrets-service.js +79 -0
  116. package/build/src/services/user-service.js +201 -0
  117. package/build/src/sync-simple.js +68 -0
  118. package/{src → build/src}/util/hash.js +1 -2
  119. package/build/src/util/middlewares.js +49 -0
  120. package/{src → build/src}/util/paths.js +3 -6
  121. package/build/src/util/payee-name.js +37 -0
  122. package/build/src/util/prompt.js +70 -0
  123. package/build/src/util/title/index.js +43 -0
  124. package/build/src/util/title/lower-case.js +90 -0
  125. package/build/src/util/title/specials.js +21 -0
  126. package/build/src/util/validate-user.js +55 -0
  127. package/package.json +32 -36
  128. package/bin/actual-server.js +0 -117
  129. package/migrations/1694360000000-create-folders.js +0 -25
  130. package/migrations/1702667624000-rename-nordigen-secrets.js +0 -19
  131. package/src/account-db.js +0 -239
  132. package/src/accounts/openid.js +0 -368
  133. package/src/accounts/password.js +0 -149
  134. package/src/app-account.js +0 -155
  135. package/src/app-admin.js +0 -410
  136. package/src/app-admin.test.js +0 -381
  137. package/src/app-gocardless/app-gocardless.js +0 -274
  138. package/src/app-gocardless/bank-factory.js +0 -91
  139. package/src/app-gocardless/banks/abanca_caglesmm.js +0 -22
  140. package/src/app-gocardless/banks/abnamro_abnanl2a.js +0 -57
  141. package/src/app-gocardless/banks/american_express_aesudef1.js +0 -40
  142. package/src/app-gocardless/banks/bancsabadell_bsabesbbb.js +0 -31
  143. package/src/app-gocardless/banks/bank.interface.ts +0 -51
  144. package/src/app-gocardless/banks/bank_of_ireland_b365_bofiie2d.js +0 -39
  145. package/src/app-gocardless/banks/bankinter_bkbkesmm.js +0 -24
  146. package/src/app-gocardless/banks/belfius_gkccbebb.js +0 -17
  147. package/src/app-gocardless/banks/berliner_sparkasse_beladebexxx.js +0 -61
  148. package/src/app-gocardless/banks/bnp_be_gebabebb.js +0 -73
  149. package/src/app-gocardless/banks/cbc_cregbebb.js +0 -34
  150. package/src/app-gocardless/banks/commerzbank_cobadeff.js +0 -54
  151. package/src/app-gocardless/banks/danskebank_dabno22.js +0 -39
  152. package/src/app-gocardless/banks/direkt_heladef1822.js +0 -18
  153. package/src/app-gocardless/banks/easybank_bawaatww.js +0 -50
  154. package/src/app-gocardless/banks/entercard_swednokk.js +0 -40
  155. package/src/app-gocardless/banks/fortuneo_ftnofrp1xxx.js +0 -46
  156. package/src/app-gocardless/banks/hype_hyeeit22.js +0 -74
  157. package/src/app-gocardless/banks/ing_ingbrobu.js +0 -70
  158. package/src/app-gocardless/banks/ing_ingddeff.js +0 -47
  159. package/src/app-gocardless/banks/ing_pl_ingbplpw.js +0 -46
  160. package/src/app-gocardless/banks/integration-bank.js +0 -115
  161. package/src/app-gocardless/banks/isybank_itbbitmm.js +0 -18
  162. package/src/app-gocardless/banks/kbc_kredbebb.js +0 -33
  163. package/src/app-gocardless/banks/lhv-lhvbee22.js +0 -36
  164. package/src/app-gocardless/banks/mbank_retail_brexplpw.js +0 -56
  165. package/src/app-gocardless/banks/nationwide_naiagb21.js +0 -46
  166. package/src/app-gocardless/banks/nbg_ethngraaxxx.js +0 -51
  167. package/src/app-gocardless/banks/norwegian_xx_norwnok1.js +0 -74
  168. package/src/app-gocardless/banks/revolut_revolt21.js +0 -37
  169. package/src/app-gocardless/banks/sandboxfinance_sfin0000.js +0 -28
  170. package/src/app-gocardless/banks/seb_kort_bank_ab.js +0 -59
  171. package/src/app-gocardless/banks/seb_privat.js +0 -29
  172. package/src/app-gocardless/banks/sparnord_spnodk22.js +0 -24
  173. package/src/app-gocardless/banks/spk_karlsruhe_karsde66.js +0 -61
  174. package/src/app-gocardless/banks/spk_marburg_biedenkopf_heladef1mar.js +0 -30
  175. package/src/app-gocardless/banks/spk_worms_alzey_ried_malade51wor.js +0 -19
  176. package/src/app-gocardless/banks/ssk_dusseldorf_dussdeddxxx.js +0 -50
  177. package/src/app-gocardless/banks/swedbank_habalv22.js +0 -47
  178. package/src/app-gocardless/banks/tests/abanca_caglesmm.spec.js +0 -21
  179. package/src/app-gocardless/banks/tests/abnamro_abnanl2a.spec.js +0 -61
  180. package/src/app-gocardless/banks/tests/bancsabadell_bsabesbbb.spec.js +0 -53
  181. package/src/app-gocardless/banks/tests/belfius_gkccbebb.spec.js +0 -22
  182. package/src/app-gocardless/banks/tests/cbc_cregbebb.spec.js +0 -34
  183. package/src/app-gocardless/banks/tests/commerzbank_cobadeff.spec.js +0 -133
  184. package/src/app-gocardless/banks/tests/easybank_bawaatww.spec.js +0 -54
  185. package/src/app-gocardless/banks/tests/fortuneo_ftnofrp1xxx.spec.js +0 -206
  186. package/src/app-gocardless/banks/tests/ing_ingddeff.spec.js +0 -302
  187. package/src/app-gocardless/banks/tests/ing_pl_ingbplpw.spec.js +0 -202
  188. package/src/app-gocardless/banks/tests/integration_bank.spec.js +0 -156
  189. package/src/app-gocardless/banks/tests/kbc_kredbebb.spec.js +0 -38
  190. package/src/app-gocardless/banks/tests/lhv-lhvbee22.spec.js +0 -68
  191. package/src/app-gocardless/banks/tests/mbank_retail_brexplpw.spec.js +0 -171
  192. package/src/app-gocardless/banks/tests/nationwide_naiagb21.spec.js +0 -105
  193. package/src/app-gocardless/banks/tests/nbg_ethngraaxxx.spec.js +0 -48
  194. package/src/app-gocardless/banks/tests/revolut_revolt21.spec.js +0 -42
  195. package/src/app-gocardless/banks/tests/sandboxfinance_sfin0000.spec.js +0 -133
  196. package/src/app-gocardless/banks/tests/spk_marburg_biedenkopf_heladef1mar.spec.js +0 -255
  197. package/src/app-gocardless/banks/tests/ssk_dusseldorf_dussdeddxxx.spec.js +0 -100
  198. package/src/app-gocardless/banks/tests/swedbank_habalv22.spec.js +0 -57
  199. package/src/app-gocardless/banks/tests/virgin_nrnbgb22.spec.js +0 -54
  200. package/src/app-gocardless/banks/virgin_nrnbgb22.js +0 -39
  201. package/src/app-gocardless/errors.js +0 -84
  202. package/src/app-gocardless/gocardless-node.types.ts +0 -497
  203. package/src/app-gocardless/gocardless.types.ts +0 -93
  204. package/src/app-gocardless/link.html +0 -18
  205. package/src/app-gocardless/services/gocardless-service.js +0 -620
  206. package/src/app-gocardless/services/tests/fixtures.js +0 -181
  207. package/src/app-gocardless/services/tests/gocardless-service.spec.js +0 -537
  208. package/src/app-gocardless/tests/bank-factory.spec.js +0 -20
  209. package/src/app-gocardless/tests/utils.spec.js +0 -162
  210. package/src/app-gocardless/util/handle-error.js +0 -16
  211. package/src/app-gocardless/utils.js +0 -45
  212. package/src/app-openid.js +0 -108
  213. package/src/app-pluggyai/app-pluggyai.js +0 -215
  214. package/src/app-pluggyai/pluggyai-service.js +0 -120
  215. package/src/app-secrets.js +0 -61
  216. package/src/app-simplefin/app-simplefin.js +0 -405
  217. package/src/app-sync/errors.js +0 -13
  218. package/src/app-sync/services/files-service.js +0 -243
  219. package/src/app-sync/tests/services/files-service.test.js +0 -247
  220. package/src/app-sync/validation.js +0 -77
  221. package/src/app-sync.js +0 -391
  222. package/src/app-sync.test.js +0 -877
  223. package/src/app.js +0 -149
  224. package/src/config-types.ts +0 -44
  225. package/src/db.js +0 -58
  226. package/src/load-config.js +0 -307
  227. package/src/migrations.js +0 -36
  228. package/src/run-migrations.js +0 -8
  229. package/src/scripts/disable-openid.js +0 -44
  230. package/src/scripts/enable-openid.js +0 -53
  231. package/src/scripts/health-check.js +0 -23
  232. package/src/scripts/reset-password.js +0 -51
  233. package/src/secrets.test.js +0 -83
  234. package/src/services/secrets-service.js +0 -94
  235. package/src/services/user-service.js +0 -272
  236. package/src/sync-simple.js +0 -95
  237. package/src/util/middlewares.js +0 -62
  238. package/src/util/payee-name.js +0 -45
  239. package/src/util/prompt.js +0 -88
  240. package/src/util/title/index.js +0 -59
  241. package/src/util/title/lower-case.js +0 -93
  242. package/src/util/title/specials.js +0 -21
  243. package/src/util/validate-user.js +0 -68
  244. /package/{src → build/src}/sql/messages.sql +0 -0
@@ -1,11 +1,10 @@
1
1
  import { run as runMigrations } from './src/migrations.js';
2
-
3
2
  runMigrations()
4
- .then(() => {
3
+ .then(() => {
5
4
  //import the app here becasue initial migrations need to be run first - they are dependencies of the app.js
6
5
  import('./src/app.js').then(app => app.run()); // run the app
7
- })
8
- .catch(err => {
6
+ })
7
+ .catch(err => {
9
8
  console.log('Error starting app:', err);
10
9
  process.exit(1);
11
- });
10
+ });
@@ -0,0 +1,101 @@
1
+ #!/usr/bin/env node
2
+ import { existsSync, readFileSync } from 'node:fs';
3
+ import { dirname, resolve } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { parseArgs } from 'node:util';
6
+ const args = process.argv;
7
+ const options = {
8
+ help: {
9
+ type: 'boolean',
10
+ short: 'h',
11
+ },
12
+ version: {
13
+ type: 'boolean',
14
+ short: 'v',
15
+ },
16
+ config: {
17
+ type: 'string',
18
+ },
19
+ };
20
+ const { values } = parseArgs({
21
+ args,
22
+ options,
23
+ allowPositionals: true,
24
+ });
25
+ if (values.help) {
26
+ console.log([
27
+ 'usage: actual-server [options]',
28
+ '',
29
+ 'options:',
30
+ ' --config Path to config file',
31
+ '',
32
+ ' -h --help Print this list and exit.',
33
+ ' -v --version Print the version and exit.',
34
+ '',
35
+ 'Examples:',
36
+ '',
37
+ 'Runs actual-server with default configuration',
38
+ ' actual-server',
39
+ '',
40
+ 'Runs actual-server with custom configuration',
41
+ ' actual-server --config ./config.json',
42
+ ].join('\n'));
43
+ process.exit();
44
+ }
45
+ if (values.version) {
46
+ const __dirname = dirname(fileURLToPath(import.meta.url));
47
+ const packageJsonPath = resolve(__dirname, '../../package.json');
48
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
49
+ console.log('v' + packageJson.version);
50
+ process.exit();
51
+ }
52
+ const setupDataDir = (dataDir = undefined) => {
53
+ if (process.env.ACTUAL_DATA_DIR) {
54
+ return; // Env variables must not be overwritten
55
+ }
56
+ if (dataDir) {
57
+ process.env.ACTUAL_DATA_DIR = dataDir; // Use the dir specified
58
+ }
59
+ else {
60
+ // Setup defaults
61
+ if (existsSync('./data')) {
62
+ // The default data directory exists - use it
63
+ console.info('Found existing data directory');
64
+ process.env.ACTUAL_DATA_DIR = resolve('./data');
65
+ }
66
+ else {
67
+ console.info('Using default data directory. You can specify a custom config with --config');
68
+ process.env.ACTUAL_DATA_DIR = resolve('./');
69
+ }
70
+ console.info(`Data directory: ${process.env.ACTUAL_DATA_DIR}`);
71
+ }
72
+ };
73
+ if (values.config) {
74
+ const configExists = existsSync(values.config);
75
+ if (!configExists) {
76
+ console.log(`Please specify a valid config path. The path ${values.config} does not exist.`);
77
+ process.exit();
78
+ }
79
+ else {
80
+ console.log(`Loading config from ${values.config}`);
81
+ const configJson = JSON.parse(readFileSync(values.config, 'utf-8'));
82
+ process.env.ACTUAL_CONFIG_PATH = values.config;
83
+ setupDataDir(configJson.dataDir);
84
+ }
85
+ }
86
+ else {
87
+ // If no config is specified, check for a default config in the current directory
88
+ const defaultConfigJsonFile = './config.json';
89
+ const configExists = existsSync(defaultConfigJsonFile);
90
+ if (configExists) {
91
+ console.info('Found config.json in the current directory');
92
+ const configJson = JSON.parse(readFileSync(defaultConfigJsonFile, 'utf-8'));
93
+ process.env.ACTUAL_CONFIG_PATH = defaultConfigJsonFile;
94
+ setupDataDir(configJson.dataDir);
95
+ }
96
+ else {
97
+ setupDataDir(); // No default config exists - setup data dir with defaults
98
+ }
99
+ }
100
+ // start the sync server
101
+ import('../app.js');
@@ -0,0 +1,21 @@
1
+ import fs from 'node:fs/promises';
2
+ import { config } from '../src/load-config.js';
3
+ async function ensureExists(path) {
4
+ try {
5
+ await fs.mkdir(path);
6
+ }
7
+ catch (err) {
8
+ if (err.code === 'EEXIST') {
9
+ return null;
10
+ }
11
+ throw err;
12
+ }
13
+ }
14
+ export const up = async function () {
15
+ await ensureExists(config.get('serverFiles'));
16
+ await ensureExists(config.get('userFiles'));
17
+ };
18
+ export const down = async function () {
19
+ await fs.rm(config.get('serverFiles'), { recursive: true, force: true });
20
+ await fs.rm(config.get('userFiles'), { recursive: true, force: true });
21
+ };
@@ -1,7 +1,6 @@
1
1
  import { getAccountDb } from '../src/account-db.js';
2
-
3
2
  export const up = async function () {
4
- await getAccountDb().exec(`
3
+ await getAccountDb().exec(`
5
4
  CREATE TABLE IF NOT EXISTS auth
6
5
  (password TEXT PRIMARY KEY);
7
6
 
@@ -20,9 +19,8 @@ export const up = async function () {
20
19
  name TEXT);
21
20
  `);
22
21
  };
23
-
24
22
  export const down = async function () {
25
- await getAccountDb().exec(`
23
+ await getAccountDb().exec(`
26
24
  DROP TABLE auth;
27
25
  DROP TABLE sessions;
28
26
  DROP TABLE files;
@@ -1,16 +1,14 @@
1
1
  import { getAccountDb } from '../src/account-db.js';
2
-
3
2
  export const up = async function () {
4
- await getAccountDb().exec(`
3
+ await getAccountDb().exec(`
5
4
  CREATE TABLE IF NOT EXISTS secrets (
6
5
  name TEXT PRIMARY KEY,
7
6
  value BLOB
8
7
  );
9
8
  `);
10
9
  };
11
-
12
10
  export const down = async function () {
13
- await getAccountDb().exec(`
11
+ await getAccountDb().exec(`
14
12
  DROP TABLE secrets;
15
13
  `);
16
14
  };
@@ -0,0 +1,9 @@
1
+ import { getAccountDb } from '../src/account-db.js';
2
+ export const up = async function () {
3
+ await getAccountDb().exec(`UPDATE secrets SET name = 'gocardless_secretId' WHERE name = 'nordigen_secretId'`);
4
+ await getAccountDb().exec(`UPDATE secrets SET name = 'gocardless_secretKey' WHERE name = 'nordigen_secretKey'`);
5
+ };
6
+ export const down = async function () {
7
+ await getAccountDb().exec(`UPDATE secrets SET name = 'nordigen_secretId' WHERE name = 'gocardless_secretId'`);
8
+ await getAccountDb().exec(`UPDATE secrets SET name = 'nordigen_secretKey' WHERE name = 'gocardless_secretKey'`);
9
+ };
@@ -1,8 +1,6 @@
1
1
  import { getAccountDb } from '../src/account-db.js';
2
-
3
2
  export const up = async function () {
4
- await getAccountDb().exec(
5
- `
3
+ await getAccountDb().exec(`
6
4
  BEGIN TRANSACTION;
7
5
  CREATE TABLE auth_new
8
6
  (method TEXT PRIMARY KEY,
@@ -19,13 +17,10 @@ export const up = async function () {
19
17
  code_verifier TEXT,
20
18
  return_url TEXT,
21
19
  expiry_time INTEGER);
22
- COMMIT;`,
23
- );
20
+ COMMIT;`);
24
21
  };
25
-
26
22
  export const down = async function () {
27
- await getAccountDb().exec(
28
- `
23
+ await getAccountDb().exec(`
29
24
  BEGIN TRANSACTION;
30
25
  ALTER TABLE auth RENAME TO auth_temp;
31
26
  CREATE TABLE auth
@@ -36,6 +31,5 @@ export const down = async function () {
36
31
 
37
32
  DROP TABLE pending_openid_requests;
38
33
  COMMIT;
39
- `,
40
- );
34
+ `);
41
35
  };
@@ -1,13 +1,9 @@
1
1
  import { v4 as uuidv4 } from 'uuid';
2
-
3
2
  import { getAccountDb } from '../src/account-db.js';
4
-
5
3
  export const up = async function () {
6
- const accountDb = getAccountDb();
7
-
8
- accountDb.transaction(() => {
9
- accountDb.exec(
10
- `
4
+ const accountDb = getAccountDb();
5
+ accountDb.transaction(() => {
6
+ accountDb.exec(`
11
7
  CREATE TABLE users
12
8
  (id TEXT PRIMARY KEY,
13
9
  user_name TEXT,
@@ -35,25 +31,14 @@ export const up = async function () {
35
31
 
36
32
  ALTER TABLE sessions
37
33
  ADD COLUMN auth_method TEXT;
38
- `,
39
- );
40
-
41
- const userId = uuidv4();
42
- accountDb.mutate(
43
- 'INSERT INTO users (id, user_name, display_name, enabled, owner, role) VALUES (?, ?, ?, 1, 1, ?)',
44
- [userId, '', '', 'ADMIN'],
45
- );
46
-
47
- accountDb.mutate(
48
- 'UPDATE sessions SET user_id = ?, expires_at = ?, auth_method = ? WHERE auth_method IS NULL',
49
- [userId, -1, 'password'],
50
- );
51
- });
34
+ `);
35
+ const userId = uuidv4();
36
+ accountDb.mutate('INSERT INTO users (id, user_name, display_name, enabled, owner, role) VALUES (?, ?, ?, 1, 1, ?)', [userId, '', '', 'ADMIN']);
37
+ accountDb.mutate('UPDATE sessions SET user_id = ?, expires_at = ?, auth_method = ? WHERE auth_method IS NULL', [userId, -1, 'password']);
38
+ });
52
39
  };
53
-
54
40
  export const down = async function () {
55
- await getAccountDb().exec(
56
- `
41
+ await getAccountDb().exec(`
57
42
  BEGIN TRANSACTION;
58
43
 
59
44
  DROP TABLE IF EXISTS user_access;
@@ -111,6 +96,5 @@ export const down = async function () {
111
96
  DROP TABLE IF EXISTS users;
112
97
 
113
98
  COMMIT;
114
- `,
115
- );
99
+ `);
116
100
  };
@@ -0,0 +1,182 @@
1
+ import { join, resolve } from 'node:path';
2
+ import * as bcrypt from 'bcrypt';
3
+ import { bootstrapOpenId } from './accounts/openid.js';
4
+ import { bootstrapPassword, loginWithPassword } from './accounts/password.js';
5
+ import { openDatabase } from './db.js';
6
+ import { config } from './load-config.js';
7
+ let _accountDb;
8
+ export function getAccountDb() {
9
+ if (_accountDb === undefined) {
10
+ const dbPath = join(resolve(config.get('serverFiles')), 'account.sqlite');
11
+ _accountDb = openDatabase(dbPath);
12
+ }
13
+ return _accountDb;
14
+ }
15
+ export function needsBootstrap() {
16
+ const accountDb = getAccountDb();
17
+ const rows = accountDb.all('SELECT * FROM auth');
18
+ return rows.length === 0;
19
+ }
20
+ export function listLoginMethods() {
21
+ const accountDb = getAccountDb();
22
+ const rows = accountDb.all('SELECT method, display_name, active FROM auth');
23
+ return rows
24
+ .filter(f => rows.length > 1 && config.get('enforceOpenId')
25
+ ? f.method === 'openid'
26
+ : true)
27
+ .map(r => ({
28
+ method: r.method,
29
+ active: r.active,
30
+ displayName: r.display_name,
31
+ }));
32
+ }
33
+ export function getActiveLoginMethod() {
34
+ const accountDb = getAccountDb();
35
+ const { method } = accountDb.first('SELECT method FROM auth WHERE active = 1') || {};
36
+ return method;
37
+ }
38
+ /*
39
+ * Get the Login Method in the following order
40
+ * req (the frontend can say which method in the case it wants to resort to forcing password auth)
41
+ * config options
42
+ * fall back to using password
43
+ */
44
+ export function getLoginMethod(req) {
45
+ if (typeof req !== 'undefined' &&
46
+ (req.body || { loginMethod: null }).loginMethod &&
47
+ config.get('allowedLoginMethods').includes(req.body.loginMethod)) {
48
+ return req.body.loginMethod;
49
+ }
50
+ //BY-PASS ANY OTHER CONFIGURATION TO ENSURE HEADER AUTH
51
+ if (config.get('loginMethod') === 'header' &&
52
+ config.get('allowedLoginMethods').includes('header')) {
53
+ return config.get('loginMethod');
54
+ }
55
+ const activeMethod = getActiveLoginMethod();
56
+ return activeMethod || config.get('loginMethod');
57
+ }
58
+ export async function bootstrap(loginSettings, forced = false) {
59
+ if (!loginSettings) {
60
+ return { error: 'invalid-login-settings' };
61
+ }
62
+ const passEnabled = 'password' in loginSettings;
63
+ const openIdEnabled = 'openId' in loginSettings;
64
+ const accountDb = getAccountDb();
65
+ accountDb.mutate('BEGIN TRANSACTION');
66
+ try {
67
+ const { countOfOwner } = accountDb.first(`SELECT count(*) as countOfOwner
68
+ FROM users
69
+ WHERE users.user_name <> '' and users.owner = 1`) || {};
70
+ if (!forced && (!openIdEnabled || countOfOwner > 0)) {
71
+ if (!needsBootstrap()) {
72
+ accountDb.mutate('ROLLBACK');
73
+ return { error: 'already-bootstrapped' };
74
+ }
75
+ }
76
+ if (!passEnabled && !openIdEnabled) {
77
+ accountDb.mutate('ROLLBACK');
78
+ return { error: 'no-auth-method-selected' };
79
+ }
80
+ if (passEnabled && openIdEnabled && !forced) {
81
+ accountDb.mutate('ROLLBACK');
82
+ return { error: 'max-one-method-allowed' };
83
+ }
84
+ if (passEnabled) {
85
+ const { error } = bootstrapPassword(loginSettings.password);
86
+ if (error) {
87
+ accountDb.mutate('ROLLBACK');
88
+ return { error };
89
+ }
90
+ }
91
+ if (openIdEnabled && forced) {
92
+ const { error } = await bootstrapOpenId(loginSettings.openId);
93
+ if (error) {
94
+ accountDb.mutate('ROLLBACK');
95
+ return { error };
96
+ }
97
+ }
98
+ accountDb.mutate('COMMIT');
99
+ return passEnabled ? loginWithPassword(loginSettings.password) : {};
100
+ }
101
+ catch (error) {
102
+ accountDb.mutate('ROLLBACK');
103
+ throw error;
104
+ }
105
+ }
106
+ export function isAdmin(userId) {
107
+ return hasPermission(userId, 'ADMIN');
108
+ }
109
+ export function hasPermission(userId, permission) {
110
+ return getUserPermission(userId) === permission;
111
+ }
112
+ export async function enableOpenID(loginSettings) {
113
+ if (!loginSettings || !loginSettings.openId) {
114
+ return { error: 'invalid-login-settings' };
115
+ }
116
+ const { error } = (await bootstrapOpenId(loginSettings.openId)) || {};
117
+ if (error) {
118
+ return { error };
119
+ }
120
+ getAccountDb().mutate('DELETE FROM sessions');
121
+ }
122
+ export async function disableOpenID(loginSettings) {
123
+ if (!loginSettings || !loginSettings.password) {
124
+ return { error: 'invalid-login-settings' };
125
+ }
126
+ const accountDb = getAccountDb();
127
+ const { extra_data: passwordHash } = accountDb.first('SELECT extra_data FROM auth WHERE method = ?', [
128
+ 'password',
129
+ ]) || {};
130
+ if (!passwordHash) {
131
+ return { error: 'invalid-password' };
132
+ }
133
+ if (!loginSettings?.password) {
134
+ return { error: 'invalid-password' };
135
+ }
136
+ if (passwordHash) {
137
+ const confirmed = bcrypt.compareSync(loginSettings.password, passwordHash);
138
+ if (!confirmed) {
139
+ return { error: 'invalid-password' };
140
+ }
141
+ }
142
+ const { error } = (await bootstrapPassword(loginSettings.password)) || {};
143
+ if (error) {
144
+ return { error };
145
+ }
146
+ try {
147
+ accountDb.transaction(() => {
148
+ accountDb.mutate('DELETE FROM sessions');
149
+ accountDb.mutate(`DELETE FROM user_access
150
+ WHERE user_access.user_id IN (
151
+ SELECT users.id
152
+ FROM users
153
+ WHERE users.user_name <> ?
154
+ );`, ['']);
155
+ accountDb.mutate('DELETE FROM users WHERE user_name <> ?', ['']);
156
+ accountDb.mutate('DELETE FROM auth WHERE method = ?', ['openid']);
157
+ });
158
+ }
159
+ catch (err) {
160
+ console.error('Error cleaning up openid information:', err);
161
+ return { error: 'database-error' };
162
+ }
163
+ }
164
+ export function getSession(token) {
165
+ const accountDb = getAccountDb();
166
+ return accountDb.first('SELECT * FROM sessions WHERE token = ?', [token]);
167
+ }
168
+ export function getUserInfo(userId) {
169
+ const accountDb = getAccountDb();
170
+ return accountDb.first('SELECT * FROM users WHERE id = ?', [userId]);
171
+ }
172
+ export function getUserPermission(userId) {
173
+ const accountDb = getAccountDb();
174
+ const { role } = accountDb.first(`SELECT role FROM users
175
+ WHERE users.id = ?`, [userId]) || { role: '' };
176
+ return role;
177
+ }
178
+ export function clearExpiredSessions() {
179
+ const clearThreshold = Math.floor(Date.now() / 1000) - 3600;
180
+ const deletedSessions = getAccountDb().mutate('DELETE FROM sessions WHERE expires_at <> -1 and expires_at < ?', [clearThreshold]).changes;
181
+ console.log(`Deleted ${deletedSessions} old sessions`);
182
+ }