@jwilleke/ngdpbase-types 0.0.0 → 5.18.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 (302) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +16 -2
  3. package/lib/packages/ngdpbase-types/index.d.ts +32 -0
  4. package/lib/packages/ngdpbase-types/testing.d.ts +43 -0
  5. package/lib/packages/ngdpbase-types/testing.js +53 -0
  6. package/lib/src/cache/CacheDependencies.d.ts +50 -0
  7. package/lib/src/cache/CacheDependencies.js +50 -0
  8. package/lib/src/cache/ICacheAdapter.d.ts +86 -0
  9. package/lib/src/cache/RegionCache.d.ts +171 -0
  10. package/lib/src/context/ActorContext.d.ts +48 -0
  11. package/lib/src/context/ActorContext.js +33 -0
  12. package/lib/src/context/ApiContext.d.ts +194 -0
  13. package/lib/src/context/ApiContext.js +273 -0
  14. package/lib/src/context/BaseContext.d.ts +110 -0
  15. package/lib/src/context/BaseContext.js +143 -0
  16. package/lib/src/context/JobContext.d.ts +153 -0
  17. package/lib/src/context/JobContext.js +144 -0
  18. package/lib/src/context/WikiContext.d.ts +404 -0
  19. package/lib/src/context/bootActions.d.ts +64 -0
  20. package/lib/src/context/bootActions.js +111 -0
  21. package/lib/src/converters/HtmlConverter.d.ts +70 -0
  22. package/lib/src/converters/IContentConverter.d.ts +94 -0
  23. package/lib/src/converters/JSPWikiConverter.d.ts +117 -0
  24. package/lib/src/converters/conversionWarning.d.ts +15 -0
  25. package/lib/src/converters/ncm/bridge.d.ts +22 -0
  26. package/lib/src/converters/ncm/existing.d.ts +23 -0
  27. package/lib/src/converters/ncm/fix/blocks.d.ts +89 -0
  28. package/lib/src/converters/ncm/fix/bulletMarkers.d.ts +21 -0
  29. package/lib/src/converters/ncm/fix/index.d.ts +36 -0
  30. package/lib/src/converters/ncm/fix/jspwikiBullets.d.ts +20 -0
  31. package/lib/src/converters/ncm/fix/jspwikiCodeMarkers.d.ts +38 -0
  32. package/lib/src/converters/ncm/fix/jspwikiHeadings.d.ts +25 -0
  33. package/lib/src/converters/ncm/fix/jspwikiIndent.d.ts +24 -0
  34. package/lib/src/converters/ncm/fix/jspwikiInsert.d.ts +21 -0
  35. package/lib/src/converters/ncm/fix/jspwikiItalic.d.ts +29 -0
  36. package/lib/src/converters/ncm/fix/jspwikiLinkLeftovers.d.ts +27 -0
  37. package/lib/src/converters/ncm/fix/moreInformationFooter.d.ts +25 -0
  38. package/lib/src/converters/ncm/fix/styleClosers.d.ts +25 -0
  39. package/lib/src/converters/ncm/fix/tightenLists.d.ts +30 -0
  40. package/lib/src/converters/ncm/fix/types.d.ts +33 -0
  41. package/lib/src/converters/ncm/footnotes.d.ts +39 -0
  42. package/lib/src/converters/ncm/images.d.ts +49 -0
  43. package/lib/src/converters/ncm/index.d.ts +20 -0
  44. package/lib/src/converters/ncm/links.d.ts +21 -0
  45. package/lib/src/converters/ncm/normalize.d.ts +39 -0
  46. package/lib/src/converters/ncm/placeholder.d.ts +25 -0
  47. package/lib/src/converters/ncm/tables.d.ts +36 -0
  48. package/lib/src/converters/ncm/types.d.ts +42 -0
  49. package/lib/src/http/egressPolicy.d.ts +52 -0
  50. package/lib/src/http/guardedFetch.d.ts +89 -0
  51. package/lib/src/http/guardedFetch.js +113 -0
  52. package/lib/src/http/guardedLookup.d.ts +48 -0
  53. package/lib/src/http/guardedLookup.js +73 -0
  54. package/lib/src/http/ssrf.d.ts +83 -0
  55. package/lib/src/http/ssrf.js +311 -0
  56. package/lib/src/mail/MailProvider.d.ts +36 -0
  57. package/lib/src/mail/NodemailerMailProvider.d.ts +26 -0
  58. package/lib/src/managers/AddonsManager.d.ts +691 -0
  59. package/lib/src/managers/AgentTokenManager.d.ts +269 -0
  60. package/lib/src/managers/AssetManager.d.ts +116 -0
  61. package/lib/src/managers/AttachmentManager.d.ts +1032 -0
  62. package/lib/src/managers/AuthManager.d.ts +1257 -0
  63. package/lib/src/managers/BackgroundJobManager.d.ts +434 -0
  64. package/lib/src/managers/BaseManager.d.ts +391 -0
  65. package/lib/src/managers/BaseManager.js +415 -0
  66. package/lib/src/managers/CacheManager.d.ts +159 -0
  67. package/lib/src/managers/CatalogManager.d.ts +235 -0
  68. package/lib/src/managers/CommentManager.d.ts +75 -0
  69. package/lib/src/managers/ConfigurationManager.d.ts +747 -0
  70. package/lib/src/managers/DatabaseManager.d.ts +89 -0
  71. package/lib/src/managers/DatabaseManager.js +236 -0
  72. package/lib/src/managers/EmailManager.d.ts +47 -0
  73. package/lib/src/managers/ExportManager.d.ts +129 -0
  74. package/lib/src/managers/ExportManager.js +420 -0
  75. package/lib/src/managers/FootnoteManager.d.ts +118 -0
  76. package/lib/src/managers/MediaManager.d.ts +279 -0
  77. package/lib/src/managers/MetricsManager.d.ts +89 -0
  78. package/lib/src/managers/NotificationManager.d.ts +165 -0
  79. package/lib/src/managers/OidcManager.d.ts +210 -0
  80. package/lib/src/managers/OrganizationManager.d.ts +107 -0
  81. package/lib/src/managers/PageManager.d.ts +1645 -0
  82. package/lib/src/managers/PersonManager.d.ts +48 -0
  83. package/lib/src/managers/PluginManager.d.ts +179 -0
  84. package/lib/src/managers/PluginManager.js +393 -0
  85. package/lib/src/managers/PolicyEvaluator.d.ts +213 -0
  86. package/lib/src/managers/RenderingManager.d.ts +358 -0
  87. package/lib/src/managers/RoleManager.d.ts +134 -0
  88. package/lib/src/managers/SearchManager.d.ts +402 -0
  89. package/lib/src/managers/ShareManager.d.ts +251 -0
  90. package/lib/src/managers/TemplateManager.d.ts +176 -0
  91. package/lib/src/managers/ThemeManager.d.ts +56 -0
  92. package/lib/src/managers/UserManager.d.ts +480 -0
  93. package/lib/src/managers/ValidationManager.d.ts +426 -0
  94. package/lib/src/managers/VariableManager.d.ts +145 -0
  95. package/lib/src/middleware/csrf.d.ts +3 -0
  96. package/lib/src/parsers/LinkParser.d.ts +457 -0
  97. package/lib/src/parsers/MarkupParser.d.ts +769 -0
  98. package/lib/src/parsers/context/ParseContext.d.ts +314 -0
  99. package/lib/src/parsers/data/emoji-map.d.ts +18 -0
  100. package/lib/src/parsers/dom/DOMBuilder.d.ts +210 -0
  101. package/lib/src/parsers/dom/DOMParser.d.ts +252 -0
  102. package/lib/src/parsers/dom/Tokenizer.d.ts +358 -0
  103. package/lib/src/parsers/dom/WikiDocument.d.ts +272 -0
  104. package/lib/src/parsers/dom/handlers/DOMLinkHandler.d.ts +260 -0
  105. package/lib/src/parsers/dom/handlers/DOMPluginHandler.d.ts +212 -0
  106. package/lib/src/parsers/dom/handlers/DOMVariableHandler.d.ts +171 -0
  107. package/lib/src/parsers/filters/BaseFilter.d.ts +269 -0
  108. package/lib/src/parsers/filters/FilterChain.d.ts +320 -0
  109. package/lib/src/parsers/handlers/BaseSyntaxHandler.d.ts +331 -0
  110. package/lib/src/parsers/handlers/HandlerRegistry.d.ts +225 -0
  111. package/lib/src/parsers/handlers/JSPWikiPreprocessor.d.ts +89 -0
  112. package/lib/src/parsers/handlers/LinkParserHandler.d.ts +80 -0
  113. package/lib/src/parsers/handlers/PluginSyntaxHandler.d.ts +78 -0
  114. package/lib/src/parsers/handlers/WikiFormHandler.d.ts +149 -0
  115. package/lib/src/parsers/handlers/WikiTagHandler.d.ts +125 -0
  116. package/lib/src/parsers/jspwikiTableRow.d.ts +39 -0
  117. package/lib/src/parsers/styleBlockSyntax.d.ts +14 -0
  118. package/lib/src/plugins/types.d.ts +79 -0
  119. package/lib/src/providers/AgentTokenAuthProvider.d.ts +40 -0
  120. package/lib/src/providers/AuthentikBearerAuthProvider.d.ts +75 -0
  121. package/lib/src/providers/BaseAttachmentProvider.d.ts +197 -0
  122. package/lib/src/providers/BaseAuthProvider.d.ts +220 -0
  123. package/lib/src/providers/BaseCacheProvider.d.ts +140 -0
  124. package/lib/src/providers/BaseCredentialsProvider.d.ts +84 -0
  125. package/lib/src/providers/BaseDatabaseProvider.d.ts +22 -0
  126. package/lib/src/providers/BaseDatabaseProvider.js +12 -0
  127. package/lib/src/providers/BaseLoggingProvider.d.ts +68 -0
  128. package/lib/src/providers/BaseLoggingProvider.js +37 -0
  129. package/lib/src/providers/BaseMediaProvider.d.ts +308 -0
  130. package/lib/src/providers/BasePageProvider.d.ts +337 -0
  131. package/lib/src/providers/BaseProvider.d.ts +98 -0
  132. package/lib/src/providers/BaseProvider.js +74 -0
  133. package/lib/src/providers/BaseSearchProvider.d.ts +362 -0
  134. package/lib/src/providers/BasicAttachmentProvider.d.ts +599 -0
  135. package/lib/src/providers/CloudflareAccessAuthProvider.d.ts +72 -0
  136. package/lib/src/providers/FileCredentialsProvider.d.ts +33 -0
  137. package/lib/src/providers/FileJobStateProvider.d.ts +58 -0
  138. package/lib/src/providers/FileLoggingProvider.d.ts +43 -0
  139. package/lib/src/providers/FileLoggingProvider.js +120 -0
  140. package/lib/src/providers/FileOidcAdapter.d.ts +25 -0
  141. package/lib/src/providers/FileSystemMediaProvider.d.ts +403 -0
  142. package/lib/src/providers/LunrSearchProvider.d.ts +280 -0
  143. package/lib/src/providers/MagicLinkAuthProvider.d.ts +125 -0
  144. package/lib/src/providers/NullCacheProvider.d.ts +72 -0
  145. package/lib/src/providers/OidcAuthProvider.d.ts +180 -0
  146. package/lib/src/providers/OidcBearerAuthProvider.d.ts +30 -0
  147. package/lib/src/providers/PasskeyAuthProvider.d.ts +58 -0
  148. package/lib/src/providers/PasswordAuthProvider.d.ts +20 -0
  149. package/lib/src/providers/SqliteDatabaseProvider.d.ts +55 -0
  150. package/lib/src/providers/SqliteDatabaseProvider.js +90 -0
  151. package/lib/src/providers/SqliteJobStateProvider.d.ts +41 -0
  152. package/lib/src/providers/databaseMigrations.d.ts +8 -0
  153. package/lib/src/providers/databaseMigrations.js +47 -0
  154. package/lib/src/providers/jobState.d.ts +99 -0
  155. package/lib/src/providers/lunrQueryToMiniSearch.d.ts +32 -0
  156. package/lib/src/providers/mediaFilenameDate.d.ts +22 -0
  157. package/lib/src/providers/sqliteLocation.d.ts +17 -0
  158. package/lib/src/providers/sqliteLocation.js +55 -0
  159. package/lib/src/providers/sqliteMigrations.d.ts +48 -0
  160. package/lib/src/providers/sqliteMigrations.js +72 -0
  161. package/lib/src/rendering/githubAlerts.d.ts +22 -0
  162. package/lib/src/rendering/htmlPolicy.d.ts +76 -0
  163. package/lib/src/rendering/markdownConverter.d.ts +73 -0
  164. package/lib/src/security/PolicyDecisionPoint.d.ts +245 -0
  165. package/lib/src/security/PolicyInformationPoint.d.ts +448 -0
  166. package/lib/src/security/pageActions.d.ts +40 -0
  167. package/lib/src/security/permissions.generated.d.ts +78 -0
  168. package/lib/src/types/Asset.d.ts +414 -0
  169. package/lib/src/types/Catalog.d.ts +61 -0
  170. package/lib/src/types/Comment.d.ts +11 -0
  171. package/lib/src/types/Config.d.ts +388 -0
  172. package/lib/src/types/Organization.d.ts +78 -0
  173. package/lib/src/types/OrganizationProvider.d.ts +38 -0
  174. package/lib/src/types/Page.d.ts +220 -0
  175. package/lib/src/types/Person.d.ts +56 -0
  176. package/lib/src/types/PersonProvider.d.ts +25 -0
  177. package/lib/src/types/Policy.d.ts +139 -0
  178. package/lib/src/types/Policy.js +17 -0
  179. package/lib/src/types/Provider.d.ts +810 -0
  180. package/lib/src/types/Role.d.ts +84 -0
  181. package/lib/src/types/RoleProvider.d.ts +35 -0
  182. package/lib/src/types/Schema.d.ts +425 -0
  183. package/lib/src/types/Share.d.ts +172 -0
  184. package/lib/src/types/Share.js +81 -0
  185. package/lib/src/types/User.d.ts +304 -0
  186. package/lib/src/types/Version.d.ts +189 -0
  187. package/lib/src/types/WikiEngine.d.ts +128 -0
  188. package/lib/src/types/express.d.ts +120 -0
  189. package/lib/src/types/express.js +1 -0
  190. package/lib/src/types/guards.d.ts +78 -0
  191. package/lib/src/types/heic-decode.d.ts +16 -0
  192. package/lib/src/types/index.d.ts +19 -0
  193. package/lib/src/types/linkedom.d.ts +77 -0
  194. package/lib/src/types/markdown-it-plugins.d.ts +21 -0
  195. package/lib/src/utils/DeltaStorage.d.ts +118 -0
  196. package/lib/src/utils/LocaleUtils.d.ts +105 -0
  197. package/lib/src/utils/LocaleUtils.js +294 -0
  198. package/lib/src/utils/PageNameMatcher.d.ts +98 -0
  199. package/lib/src/utils/PathPreflight.d.ts +38 -0
  200. package/lib/src/utils/PathPreflight.js +50 -0
  201. package/lib/src/utils/SectionUtils.d.ts +40 -0
  202. package/lib/src/utils/addonConfigLayer.d.ts +144 -0
  203. package/lib/src/utils/addonConfigLayer.js +382 -0
  204. package/lib/src/utils/addonDatabaseRules.d.ts +25 -0
  205. package/lib/src/utils/addonDatabaseRules.js +57 -0
  206. package/lib/src/utils/addonHost.d.ts +51 -0
  207. package/lib/src/utils/addonHost.js +72 -0
  208. package/lib/src/utils/addonInstaller.d.ts +109 -0
  209. package/lib/src/utils/addonLock.d.ts +37 -0
  210. package/lib/src/utils/addonLock.js +48 -0
  211. package/lib/src/utils/addonPageSync.d.ts +45 -0
  212. package/lib/src/utils/addonProvenance.d.ts +48 -0
  213. package/lib/src/utils/addonTarball.d.ts +41 -0
  214. package/lib/src/utils/addonsPathResolver.d.ts +76 -0
  215. package/lib/src/utils/addonsPathResolver.js +129 -0
  216. package/lib/src/utils/assetMetadataTags.d.ts +66 -0
  217. package/lib/src/utils/atomicWrite.d.ts +28 -0
  218. package/lib/src/utils/auditConfigChange.d.ts +57 -0
  219. package/lib/src/utils/auditEventNames.d.ts +50 -0
  220. package/lib/src/utils/auditEventNames.generated.d.ts +163 -0
  221. package/lib/src/utils/auditEventNames.generated.js +168 -0
  222. package/lib/src/utils/auditEventNames.js +49 -0
  223. package/lib/src/utils/auditEvents.d.ts +265 -0
  224. package/lib/src/utils/auditEvents.js +309 -0
  225. package/lib/src/utils/auditRegistry.d.ts +102 -0
  226. package/lib/src/utils/auditRegistry.js +168 -0
  227. package/lib/src/utils/bip39English.d.ts +2 -0
  228. package/lib/src/utils/configEnvKeys.d.ts +68 -0
  229. package/lib/src/utils/configFiles.d.ts +74 -0
  230. package/lib/src/utils/configFiles.js +150 -0
  231. package/lib/src/utils/delegation.d.ts +48 -0
  232. package/lib/src/utils/deriveUsername.d.ts +21 -0
  233. package/lib/src/utils/explainMediaPath.d.ts +123 -0
  234. package/lib/src/utils/formerTitles.d.ts +69 -0
  235. package/lib/src/utils/frontmatterAccess.d.ts +54 -0
  236. package/lib/src/utils/headlessAdminPassword.d.ts +55 -0
  237. package/lib/src/utils/imageTransform.d.ts +52 -0
  238. package/lib/src/utils/instanceEnvSecret.d.ts +51 -0
  239. package/lib/src/utils/jobSlots.d.ts +43 -0
  240. package/lib/src/utils/keywordNormalizer.d.ts +127 -0
  241. package/lib/src/utils/logger.d.ts +70 -0
  242. package/lib/src/utils/logger.js +106 -0
  243. package/lib/src/utils/magicLinkDeviceState.d.ts +95 -0
  244. package/lib/src/utils/managerUtils.d.ts +40 -0
  245. package/lib/src/utils/migrateLegacyPrivateAttachments.d.ts +15 -0
  246. package/lib/src/utils/orgFilename.d.ts +22 -0
  247. package/lib/src/utils/pageFeature.d.ts +27 -0
  248. package/lib/src/utils/pageFrontmatter.d.ts +21 -0
  249. package/lib/src/utils/pageNotes.d.ts +150 -0
  250. package/lib/src/utils/pageTitleRule.d.ts +37 -0
  251. package/lib/src/utils/pageToArticle.d.ts +59 -0
  252. package/lib/src/utils/pageUrl.d.ts +18 -0
  253. package/lib/src/utils/passwordChange.d.ts +12 -0
  254. package/lib/src/utils/passwordHash.d.ts +60 -0
  255. package/lib/src/utils/permissionCatalog.d.ts +52 -0
  256. package/lib/src/utils/pluginFormatters.d.ts +452 -0
  257. package/lib/src/utils/pluginFormatters.js +714 -0
  258. package/lib/src/utils/privateLinkRewrite.d.ts +42 -0
  259. package/lib/src/utils/privateStoreAccess.d.ts +57 -0
  260. package/lib/src/utils/privateStoreAccess.js +65 -0
  261. package/lib/src/utils/privateStoreCatalogs.d.ts +40 -0
  262. package/lib/src/utils/privateStoreCrypto.d.ts +127 -0
  263. package/lib/src/utils/privateStoreDoor.d.ts +181 -0
  264. package/lib/src/utils/privateStoreExport.d.ts +72 -0
  265. package/lib/src/utils/privateStoreFiles.d.ts +120 -0
  266. package/lib/src/utils/privateStoreMeta.d.ts +64 -0
  267. package/lib/src/utils/privateStoreMigrations.d.ts +37 -0
  268. package/lib/src/utils/privateStorePath.d.ts +259 -0
  269. package/lib/src/utils/privateStorePath.js +436 -0
  270. package/lib/src/utils/privateStoreTakeout.d.ts +76 -0
  271. package/lib/src/utils/privateStoreUnlock.d.ts +175 -0
  272. package/lib/src/utils/proxyClaim.d.ts +59 -0
  273. package/lib/src/utils/proxyClaim.js +30 -0
  274. package/lib/src/utils/redactPrivateNames.d.ts +21 -0
  275. package/lib/src/utils/redactPrivateNames.js +89 -0
  276. package/lib/src/utils/redactSecrets.d.ts +58 -0
  277. package/lib/src/utils/redactSecrets.js +171 -0
  278. package/lib/src/utils/renameLinkRewrite.d.ts +112 -0
  279. package/lib/src/utils/roleGrants.d.ts +35 -0
  280. package/lib/src/utils/safeRedirect.d.ts +32 -0
  281. package/lib/src/utils/schedule.d.ts +54 -0
  282. package/lib/src/utils/secretFileMode.d.ts +17 -0
  283. package/lib/src/utils/seededShippedPages.d.ts +45 -0
  284. package/lib/src/utils/sensitiveValues.d.ts +59 -0
  285. package/lib/src/utils/sensitiveValues.js +106 -0
  286. package/lib/src/utils/sessionEnd.d.ts +12 -0
  287. package/lib/src/utils/sessionGeneration.d.ts +24 -0
  288. package/lib/src/utils/sessionIdle.d.ts +41 -0
  289. package/lib/src/utils/sessionLimits.d.ts +68 -0
  290. package/lib/src/utils/shareLockbox.d.ts +64 -0
  291. package/lib/src/utils/sigstoreTrustedRoot.d.ts +33 -0
  292. package/lib/src/utils/sniffMime.d.ts +21 -0
  293. package/lib/src/utils/storeSearchIndex.d.ts +75 -0
  294. package/lib/src/utils/subjectMayDo.d.ts +21 -0
  295. package/lib/src/utils/systemCategoryRules.d.ts +30 -0
  296. package/lib/src/utils/systemCategoryRules.js +41 -0
  297. package/lib/src/utils/userCreateError.d.ts +62 -0
  298. package/lib/src/utils/username.d.ts +53 -0
  299. package/lib/src/utils/vaultUrlRewrite.d.ts +27 -0
  300. package/lib/src/utils/version.d.ts +84 -0
  301. package/lib/src/utils/videoFrame.d.ts +21 -0
  302. package/package.json +54 -3
@@ -0,0 +1,125 @@
1
+ /**
2
+ * MagicLinkAuthProvider — passwordless authentication via one-time email links.
3
+ *
4
+ * Registered by AuthManager when `ngdpbase.auth.magic-link.enabled` is true.
5
+ *
6
+ * Flow:
7
+ * 1. initiate() — look up user by email, generate token, send link via mail transport
8
+ * 2. verify() — validate token (exists + not expired), return AuthResult
9
+ * 3. consumeToken() — delete token; its return value gates the session (#1021)
10
+ *
11
+ * `verify()` being side-effect free is load-bearing, not incidental (#1019): the
12
+ * route layer calls it twice, once on the GET that renders the sign-in
13
+ * confirmation page and again on the POST that completes the login. Only the
14
+ * POST consumes. Moving consumption into verify() would reintroduce the bug
15
+ * where a mail scanner's link pre-fetch burns the token before the user clicks.
16
+ *
17
+ * Tokens are in-memory only — lost on restart, acceptable for the default 15-min TTL.
18
+ *
19
+ * @see AuthManager
20
+ * @see BaseAuthProvider
21
+ */
22
+ import type { AuthProvider, AuthInitiateContext, AuthVerifyCredentials, AuthResult, FactorDescription } from './BaseAuthProvider.js';
23
+ import type { WikiEngine } from '../types/WikiEngine.js';
24
+ import type { MailProvider } from '../mail/MailProvider.js';
25
+ /**
26
+ * What an email link gives, in either role — starting a sign-in or confirming
27
+ * one as a second factor (#1523: one email-link factor). Email is never
28
+ * phishing-resistant and never above AAL1 (SP 800-63B §5.1.3.1).
29
+ */
30
+ export declare const EMAIL_FACTOR: {
31
+ amr: string[];
32
+ aal: 1;
33
+ };
34
+ export interface MagicLinkConfig {
35
+ ttlMs: number;
36
+ mailProvider: MailProvider;
37
+ }
38
+ export declare class MagicLinkAuthProvider implements AuthProvider {
39
+ private engine;
40
+ private config;
41
+ readonly id = "magic-link";
42
+ readonly displayName = "Magic Link";
43
+ /** Email is never phishing-resistant and never above AAL1: SP 800-63B §5.1.3.1 bars it as out-of-band (#1523). */
44
+ readonly factor: FactorDescription;
45
+ /** token → entry */
46
+ private tokens;
47
+ /** email → timestamp of last request (rate-limit) */
48
+ private rateLimitMap;
49
+ constructor(engine: WikiEngine, config: MagicLinkConfig);
50
+ /**
51
+ * Initiate the magic-link flow: look up the user, generate a token, send the email.
52
+ * Silently succeeds if the email is not registered — prevents user enumeration.
53
+ */
54
+ initiate(context: AuthInitiateContext): Promise<void>;
55
+ /**
56
+ * Verify a token. Returns AuthResult on success, null if invalid or expired.
57
+ * Does NOT consume the token — call consumeToken() after the session is created.
58
+ */
59
+ verify(credentials: AuthVerifyCredentials): Promise<AuthResult | null>;
60
+ /**
61
+ * Delete the token and report whether THIS caller was the one that did.
62
+ *
63
+ * #1021: the return value is the single-use gate, not a courtesy. The route
64
+ * used to verify, then consume, with an `await` between the two — so two
65
+ * POSTs carrying the same token (a double-clicked confirmation button, a
66
+ * client retry, a prefetch racing the real submit) could both clear
67
+ * verification before either consumed, and both would then establish a
68
+ * session. #1019's CSRF-protected POST does not close that: both submits
69
+ * come from the same session with the same valid token.
70
+ *
71
+ * `Map.delete` returns true only for the call that found an entry, and it is
72
+ * synchronous so it cannot interleave. Exactly one caller can ever see true,
73
+ * which makes consumption — not verification — the thing a session is gated
74
+ * on.
75
+ */
76
+ consumeToken(token: string): boolean;
77
+ /**
78
+ * The requesting browser's state value for this token (#1022), or null.
79
+ *
80
+ * Must be read BEFORE consumeToken(), which deletes the entry — same
81
+ * constraint as getFlowRedirect below, and for the same reason.
82
+ */
83
+ getDeviceState(token: string): string | null;
84
+ /**
85
+ * Where the user was headed before the link was issued (#1049).
86
+ *
87
+ * Named for the capability rather than the mechanism: GoogleOIDCProvider
88
+ * answers the same question keyed by a state nonce, and the two used to be
89
+ * `getTokenRedirect` / `getStateRedirect`, which is why AuthManager needed a
90
+ * method per provider to ask it.
91
+ *
92
+ * Must be read BEFORE consumeToken(), which deletes the entry.
93
+ */
94
+ getFlowRedirect(token: string): string;
95
+ /**
96
+ * Create the account behind a new-user token (#1026).
97
+ *
98
+ * Called from the POST that completes sign-in, never from the GET — so a mail
99
+ * scanner pre-fetching the link cannot bring an account into existence, for
100
+ * the same reason it cannot consume the token (#1019).
101
+ *
102
+ * The account is created with `isExternal: true`, which stores an empty
103
+ * password hash. `UserManager.verifyPassword` refuses an empty stored hash
104
+ * outright (#1042), so these accounts cannot be logged into with a password
105
+ * by any input — magic link is structurally their only way in.
106
+ *
107
+ * Idempotent: a token whose account already exists is a no-op, so a double
108
+ * submit cannot fail the second time.
109
+ *
110
+ * @returns true if the token is usable (existing user, or newly created)
111
+ */
112
+ provisionIfNew(token: string): Promise<boolean>;
113
+ /** Whether an unknown email may create an account by verifying a link (#1026). */
114
+ private isAutoProvisionEnabled;
115
+ /**
116
+ * Role for auto-provisioned users. An unknown role name falls back to
117
+ * `reader` with a warning — a typo should degrade to read-only, not throw
118
+ * mid-signup or silently mint a more privileged account than intended.
119
+ */
120
+ private resolveDefaultRole;
121
+ private isRateLimited;
122
+ private cleanupExpired;
123
+ /** Exposed for testing */
124
+ getTokenCount(): number;
125
+ }
@@ -0,0 +1,72 @@
1
+ import BaseCacheProvider, { CacheStats } from './BaseCacheProvider.js';
2
+ import type { ProviderInfo } from '../types/Provider.js';
3
+ import type { WikiEngine } from '../types/WikiEngine.js';
4
+ /**
5
+ * NullCacheProvider - No-op cache provider
6
+ *
7
+ * Used when caching is disabled or for testing.
8
+ * All cache operations are no-ops that return immediately.
9
+ */
10
+ declare class NullCacheProvider extends BaseCacheProvider {
11
+ constructor(engine: WikiEngine);
12
+ /**
13
+ * Initialize the null cache provider (no-op)
14
+ * @returns {Promise<void>}
15
+ */
16
+ initialize(): Promise<void>;
17
+ /**
18
+ * Get provider information
19
+ * @returns {ProviderInfo} Provider metadata
20
+ */
21
+ getProviderInfo(): ProviderInfo;
22
+ /**
23
+ * Get a value from the cache (always returns undefined)
24
+ * @template T
25
+ * @param {string} _key - The cache key
26
+ * @returns {Promise<T | undefined>} Always undefined
27
+ */
28
+ get<T = unknown>(_key: string): Promise<T | undefined>;
29
+ /**
30
+ * Set a value in the cache (no-op)
31
+ * @template T
32
+ * @param {string} _key - The cache key
33
+ * @param {T} _value - The value to cache
34
+ * @param {number} [_ttlSec] - Time to live in seconds
35
+ * @returns {Promise<void>}
36
+ */
37
+ set<T = unknown>(_key: string, _value: T, _ttlSec?: number): Promise<void>;
38
+ /**
39
+ * Delete one or more keys from the cache (no-op)
40
+ * @param {string | string[]} _keys - Single key or array of keys to delete
41
+ * @returns {Promise<void>}
42
+ */
43
+ del(_keys: string | string[]): Promise<void>;
44
+ /**
45
+ * Clear cache entries (no-op)
46
+ * @param {string} [_pattern] - Optional pattern to match keys
47
+ * @returns {Promise<void>}
48
+ */
49
+ clear(_pattern?: string): Promise<void>;
50
+ /**
51
+ * Get keys matching a pattern (always returns empty array)
52
+ * @param {string} [_pattern='*'] - Pattern to match
53
+ * @returns {Promise<string[]>} Empty array
54
+ */
55
+ keys(_pattern?: string): Promise<string[]>;
56
+ /**
57
+ * Get cache statistics (all zeros)
58
+ * @returns {Promise<CacheStats>} Cache statistics with all zeros
59
+ */
60
+ stats(): Promise<CacheStats>;
61
+ /**
62
+ * Check if the cache provider is healthy (always true)
63
+ * @returns {Promise<boolean>} Always true
64
+ */
65
+ isHealthy(): Promise<boolean>;
66
+ /**
67
+ * Close/cleanup the cache provider (no-op)
68
+ * @returns {Promise<void>}
69
+ */
70
+ close(): Promise<void>;
71
+ }
72
+ export default NullCacheProvider;
@@ -0,0 +1,180 @@
1
+ /**
2
+ * OidcAuthProvider — signing in through an outside OpenID Connect provider (#1743).
3
+ *
4
+ * One class, one registered instance per configured issuer (`oidc:<name>`),
5
+ * registered by AuthManager from `ngdpbase.auth.oidc.providers` (and the old
6
+ * `ngdpbase.auth.google-oidc.*` keys, read as the `google` entry). Routes never
7
+ * call it: AuthManager is the one door.
8
+ *
9
+ * What an outside sign-in may do (decided 2026-10-10, docs/planning/authentication.md):
10
+ * - The identity is the issuer plus the subject (`iss` + `sub`, OIDC Core §5.7),
11
+ * stored as a credentials-store row of kind `identity`. Only an identity
12
+ * already connected to an account signs anyone in. Email never matches or
13
+ * signs anyone in here.
14
+ * - It gives no roles: a provider's groups and roles claims are never read.
15
+ * - No access or refresh token is kept; nothing needs them.
16
+ *
17
+ * Each flow is protected as `GoogleOIDCProvider` was (#1630): a single-use
18
+ * `state` bound to the starting browser by an HTTP-only cookie, PKCE (S256),
19
+ * an OIDC `nonce`, and the ID token's signature, issuer, audience and expiry.
20
+ *
21
+ * Apple (slice 4b) differs in two ways handled here: its client secret is a
22
+ * JWT signed per exchange (`SignedClientSecret`), and it POSTs the callback
23
+ * (`responseMode: 'form_post'`), which `middleware/outsideCallbackRelay.ts`
24
+ * turns into the usual GET before the session and CSRF see it.
25
+ *
26
+ * Discovery (`/.well-known/openid-configuration`) and the issuer's keys are
27
+ * fetched through `guardedFetch`, like every outbound request (#1133), and
28
+ * cached. Flow state is in memory: a restart drops a sign-in in progress.
29
+ *
30
+ * @see AuthManager
31
+ * @see BaseAuthProvider
32
+ */
33
+ import * as crypto from 'crypto';
34
+ import type { EgressPolicy } from '../http/ssrf.js';
35
+ import type { AuthInitiateContext, AuthProvider, AuthResult, AuthVerifyCredentials, FactorDescription, ReportedAssurance } from './BaseAuthProvider.js';
36
+ /**
37
+ * A provider button's icon (#1781): an image (an `https://` address or a site
38
+ * path), a Font Awesome class, or a logo the button partial draws itself.
39
+ */
40
+ export type OutsideProviderIcon = {
41
+ kind: 'image';
42
+ src: string;
43
+ } | {
44
+ kind: 'fa';
45
+ className: string;
46
+ } | {
47
+ kind: 'builtin';
48
+ id: 'google';
49
+ };
50
+ /** One configured provider, as AuthManager resolved it from configuration. */
51
+ export interface OidcProviderConfig {
52
+ /** The entry's name; the provider's id is `oidc:<name>`, its URLs `/auth/oauth/<name>`. */
53
+ name: string;
54
+ displayName: string;
55
+ /** What its sign-in and Connect buttons show beside `displayName` (#1781). */
56
+ icon: OutsideProviderIcon;
57
+ /** The issuer identifier, exactly as the issuer's discovery document states it. */
58
+ issuer: string;
59
+ clientId: string;
60
+ /**
61
+ * How the site proves itself at the token endpoint: a shared secret,
62
+ * already resolved from its environment reference, or (Apple) a key it signs
63
+ * a short-lived client secret with. Never logged.
64
+ */
65
+ clientSecret: string | SignedClientSecret;
66
+ /** This site's callback, registered with the provider. */
67
+ redirectUri: string;
68
+ /** Where outbound requests may go (ngdpbase.security.egress.*). */
69
+ policy: EgressPolicy;
70
+ /**
71
+ * `form_post`: the issuer POSTs the code and state back (Apple, whenever
72
+ * scopes are asked for). AuthManager answers `callbackIsPosted` from it, and
73
+ * the relay in `middleware/outsideCallbackRelay.ts` turns the POST into the
74
+ * usual GET callback.
75
+ */
76
+ responseMode?: 'form_post';
77
+ /** The issuer may send `email_verified` as the string `"true"` / `"false"` (Apple); only true counts either way. */
78
+ emailVerifiedMayBeString?: boolean;
79
+ }
80
+ /**
81
+ * Apple's client secret is not a shared secret but a JWT the site signs
82
+ * (ES256) with a key from its Apple developer account: `kid` the key's id,
83
+ * `iss` the team id, `sub` the client id, `aud` the issuer, and an expiry
84
+ * of at most six months. Signed afresh for each code exchange, valid 5 minutes.
85
+ */
86
+ export interface SignedClientSecret {
87
+ teamId: string;
88
+ keyId: string;
89
+ /** The EC P-256 private key (Apple's `.p8`), checked by AuthManager when it registers the provider. */
90
+ privateKey: crypto.KeyObject;
91
+ }
92
+ /** An outside identity, as the provider vouched for it. */
93
+ export interface OidcIdentity {
94
+ /** `${iss}#${sub}`, with the configured issuer — the credentials-store subject. */
95
+ subject: string;
96
+ /** The provider's email, only when it reports it verified; '' otherwise. */
97
+ email: string;
98
+ /** The ID token's `amr` and `acr`, as sent (#1633); AuthManager decides what they count for. */
99
+ reported: ReportedAssurance;
100
+ }
101
+ /** How the provider reaches connected identities: the credentials store, through AuthManager. */
102
+ export interface IdentityStore {
103
+ /** The row connecting this subject to an account, or null. */
104
+ find(subject: string): {
105
+ id: string;
106
+ username: string;
107
+ } | null;
108
+ /** Record a sign-in with it, and the provider's current verified email. */
109
+ used(id: string, at: string, email: string): Promise<void>;
110
+ }
111
+ export declare class OidcAuthProvider implements AuthProvider {
112
+ private readonly config;
113
+ private readonly identities;
114
+ readonly id: string;
115
+ readonly displayName: string;
116
+ readonly icon: OutsideProviderIcon;
117
+ /**
118
+ * AAL1 with no `amr`: what is offered, and what a sign-in counts for unless
119
+ * the admin trusts this provider's own second factor (`trust-mfa`, #1633),
120
+ * when AuthManager maps the reported `amr` / `acr` instead
121
+ * (`outsideLevel`). Primary: it starts a sign-in on its own.
122
+ */
123
+ readonly factor: FactorDescription;
124
+ private readonly flows;
125
+ private discovery;
126
+ private keys;
127
+ constructor(config: OidcProviderConfig, identities: IdentityStore);
128
+ /** The configured issuer; an identity row's subject starts with it and `#`. */
129
+ get issuer(): string;
130
+ /** The entry's name, as in its URLs. */
131
+ get name(): string;
132
+ /** Whether the issuer POSTs the callback (`response_mode=form_post`) instead of redirecting to it. */
133
+ get callbackIsPosted(): boolean;
134
+ /**
135
+ * Begin a sign-in, or a connection when `connectFor` names the signed-in
136
+ * account: keep the flow's state and return the provider's authorization URL.
137
+ */
138
+ startFlow({ redirect, deviceState, connectFor }?: AuthInitiateContext): Promise<string>;
139
+ /** Where the person was headed when the flow began; read before `consumeToken`. */
140
+ getFlowRedirect(state: string): string;
141
+ /** The account this flow is connecting an identity to, or null for a sign-in or an unknown flow. */
142
+ getFlowConnectFor(state: string): string | null;
143
+ /**
144
+ * Finish a sign-in: the account whose connected identity this is, or null.
145
+ * A flow started to connect never signs in. An identity connected to no
146
+ * account is refused, and kept on the flow until it is consumed, so
147
+ * AuthManager can decide what happens next (`unconnectedIdentity`);
148
+ * nothing here says whether an account exists.
149
+ */
150
+ verify(credentials: AuthVerifyCredentials): Promise<AuthResult | null>;
151
+ /**
152
+ * Finish a connection for `username`: the identity the provider vouched
153
+ * for, or null. Only a flow started to connect that same account counts.
154
+ */
155
+ verifyIdentity(credentials: AuthVerifyCredentials, username: string): Promise<OidcIdentity | null>;
156
+ /**
157
+ * The verified identity a refused sign-in brought that no account has
158
+ * connected, or null; read before `consumeToken` (#1743 slice 3).
159
+ */
160
+ unconnectedIdentity(state: string): OidcIdentity | null;
161
+ /** Spend the flow's state; true only for the caller that did (#1021). */
162
+ consumeToken(state: string): boolean;
163
+ /**
164
+ * The state, the browser, the code exchange and the ID token, checked in
165
+ * that order. `connectFor` is the account a connection is for, or null for
166
+ * a sign-in; a flow of the other kind is refused.
167
+ */
168
+ private redeem;
169
+ /** Exchange the code for the ID token. No access or refresh token is kept. */
170
+ private exchange;
171
+ /** The client secret for one code exchange: the shared one, or a freshly signed JWT (Apple). */
172
+ private clientSecret;
173
+ /** Signature, issuer, audience and expiry; the keys are fetched again once if none matches (rotation). */
174
+ private verifyIdToken;
175
+ private keySet;
176
+ /** The issuer's discovery document, cached; its `issuer` must be the configured one (OIDC Discovery §4.3). */
177
+ private discover;
178
+ private getJson;
179
+ private sweep;
180
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * OidcBearerAuthProvider — accepts access tokens issued by this instance's own
3
+ * OpenID Connect provider on ngdpbase's API (#1576).
4
+ *
5
+ * An app that a person allowed through /oidc holds a token for the audience
6
+ * `<base-url>/api`. That token is a delegation from the person, like an agent
7
+ * token: its scopes are permission names and ride on `viaToken`, so the PDP
8
+ * ceiling and the edge gate (#1173) bound it exactly as they bound an agent
9
+ * token, and authority stays the person's, resolved live. Unlike an agent
10
+ * token it also carries how the person signed in, so roles above that level
11
+ * step down (`aal`), as in a web session.
12
+ *
13
+ * Verification is OidcManager's, in process; this provider only adapts it.
14
+ */
15
+ import type { AuthProvider, AuthResult, AuthVerifyCredentials, ViaToken } from './BaseAuthProvider.js';
16
+ import type { WikiEngine } from '../types/WikiEngine.js';
17
+ export interface OidcBearerAuthResult extends AuthResult {
18
+ viaToken: ViaToken;
19
+ aal: 1 | 2 | 3;
20
+ }
21
+ export declare class OidcBearerAuthProvider implements AuthProvider {
22
+ private readonly engine;
23
+ readonly id = "oidc-bearer";
24
+ readonly displayName = "OpenID Connect access token";
25
+ /** Marks this provider as usable by the bearer middleware. */
26
+ readonly acceptsBearer = true;
27
+ constructor(engine: WikiEngine);
28
+ verify(credentials: AuthVerifyCredentials): Promise<OidcBearerAuthResult | null>;
29
+ }
30
+ export default OidcBearerAuthProvider;
@@ -0,0 +1,58 @@
1
+ import type { PublicKeyCredentialCreationOptionsJSON, PublicKeyCredentialRequestOptionsJSON, RegistrationResponseJSON } from '@simplewebauthn/server';
2
+ import type { AuthProvider, AuthResult, AuthVerifyCredentials, FactorDescription } from './BaseAuthProvider.js';
3
+ import type { CredentialRecord } from './BaseCredentialsProvider.js';
4
+ /** What a passkey row's `secret` holds. Public material only. */
5
+ export interface PasskeySecret {
6
+ publicKey: string;
7
+ counter: number;
8
+ /** As the authenticator reported them; v14 types transports as plain strings. */
9
+ transports?: string[];
10
+ deviceType: 'singleDevice' | 'multiDevice';
11
+ backedUp: boolean;
12
+ }
13
+ export interface PasskeyRelyingParty {
14
+ /** The host of base-url — the relying-party id. */
15
+ rpID: string;
16
+ /** The origin of base-url — what the browser must report. */
17
+ origin: string;
18
+ /** Shown by the authenticator when creating a passkey. */
19
+ rpName: string;
20
+ }
21
+ /** The store access AuthManager grants: find by credential id, record a use. */
22
+ export interface PasskeyStoreAccess {
23
+ find(credentialId: string): CredentialRecord | null;
24
+ used(id: string, at: string, secret: string): Promise<void>;
25
+ }
26
+ /** The base-url origin, its host, and whether WebAuthn may run there (https, or localhost). */
27
+ export declare function relyingPartyFrom(baseUrl: string, rpName: string): PasskeyRelyingParty | null;
28
+ export declare class PasskeyAuthProvider implements AuthProvider {
29
+ private readonly rp;
30
+ private readonly store;
31
+ readonly id = "passkey";
32
+ readonly displayName = "Passkey";
33
+ /**
34
+ * Something you have (the key) unlocked by something you know or are (the
35
+ * PIN or biometric the authenticator requires): AAL2, phishing-resistant.
36
+ * `swk` because most passkeys sync; a device-bound key is stronger, never
37
+ * weaker, than what is claimed here.
38
+ */
39
+ readonly factor: FactorDescription;
40
+ constructor(rp: PasskeyRelyingParty, store: PasskeyStoreAccess);
41
+ /** The relying party passkeys are tied to — for the admin page and the enrol screen. */
42
+ relyingParty(): PasskeyRelyingParty;
43
+ /** Options for enrolling a passkey; `existing` keeps one authenticator from enrolling twice. */
44
+ registrationOptions(username: string, displayName: string, existing: readonly CredentialRecord[]): Promise<PublicKeyCredentialCreationOptionsJSON>;
45
+ /** Verify an enrolment; returns what the credentials store keeps, or null when it does not verify. */
46
+ verifyRegistration(response: RegistrationResponseJSON, expectedChallenge: string): Promise<{
47
+ subject: string;
48
+ secret: string;
49
+ } | null>;
50
+ /** Options for signing in: no username asked, any passkey for this host may answer. */
51
+ authenticationOptions(): Promise<PublicKeyCredentialRequestOptionsJSON>;
52
+ /**
53
+ * Verify a sign-in. The credential id names the passkey; its public key and
54
+ * counter come from the store. A counter that does not move forward (where
55
+ * the authenticator keeps one) is a cloned key and fails.
56
+ */
57
+ verify(credentials: AuthVerifyCredentials): Promise<AuthResult | null>;
58
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * PasswordAuthProvider — username/password authentication.
3
+ *
4
+ * The password method's check (#1758): AuthManager is the one door for every
5
+ * check of a secret, and this provider is its connection to the password.
6
+ * The hash stays on the account (UserManager keeps it and hands it only to
7
+ * this check); the check, and the decision to re-hash at the current cost
8
+ * (#1042), are made here. Registered by AuthManager as the default provider.
9
+ */
10
+ import type { AuthProvider, AuthVerifyCredentials, AuthResult, FactorDescription } from './BaseAuthProvider.js';
11
+ import type { WikiEngine } from '../types/WikiEngine.js';
12
+ export declare class PasswordAuthProvider implements AuthProvider {
13
+ private engine;
14
+ readonly id = "password";
15
+ readonly displayName = "Username & Password";
16
+ /** Something you know (#1523). */
17
+ readonly factor: FactorDescription;
18
+ constructor(engine: WikiEngine);
19
+ verify(credentials: AuthVerifyCredentials): Promise<AuthResult | null>;
20
+ }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * The application database as one SQLite file, encrypted with SQLCipher when a
3
+ * key is given (#1536). Ported from yourPHR (yourphr#617).
4
+ *
5
+ * Opened and migrated in the constructor, so every provider built over the
6
+ * handle sees a finished schema. WAL mode with `synchronous = FULL`: a
7
+ * committed transaction is on the device before the call returns. WAL needs
8
+ * shared memory, which network filesystems do not provide, so the file's
9
+ * location is checked first (`refuseNetworkFilesystem`).
10
+ */
11
+ import Database from 'better-sqlite3-multiple-ciphers';
12
+ import BaseDatabaseProvider from './BaseDatabaseProvider.js';
13
+ import type { ProviderDurability } from './BaseProvider.js';
14
+ import { type Migration, type MigrationReport } from './sqliteMigrations.js';
15
+ export type SqliteHandle = InstanceType<typeof Database>;
16
+ /** The lock wait when none is configured: the driver's own default, stated (#1710). */
17
+ export declare const DEFAULT_BUSY_TIMEOUT_MS = 5000;
18
+ declare class SqliteDatabaseProvider extends BaseDatabaseProvider<SqliteHandle> {
19
+ private readonly file;
20
+ protected providerName: string;
21
+ protected providerDescription: string;
22
+ private readonly db;
23
+ private closed;
24
+ private readonly encrypted;
25
+ /** What the ledger did at open: the ids applied now, and how many were already there. */
26
+ readonly migrations: MigrationReport;
27
+ /**
28
+ * @param file the database file; created when absent
29
+ * @param key the SQLCipher key; '' opens the file unencrypted
30
+ * @param ledger the migrations, strictly ascending by id
31
+ * @param ledgerTable where applied ids are recorded; an add-on's database names its own (#13)
32
+ * @param options.busyTimeoutMs how long a statement waits for a lock another connection holds
33
+ * (`ngdpbase.database.busy-timeout-ms`, #1710) before failing with SQLITE_BUSY
34
+ */
35
+ constructor(file: string, key: string, ledger: Migration[], ledgerTable?: string, options?: {
36
+ busyTimeoutMs?: number;
37
+ });
38
+ /**
39
+ * Run a further migration ledger on this connection, recorded in its own
40
+ * table: an add-on that depends on the add-on owning this database brings
41
+ * its own tables (ngdp-accounting-addons#13). Same rules as the ledger run at
42
+ * open: once, in order, transactional, and a newer schema is refused.
43
+ */
44
+ migrate(ledger: Migration[], ledgerTable: string): MigrationReport;
45
+ get handle(): SqliteHandle;
46
+ storage(): {
47
+ location: string;
48
+ sizeBytes: number;
49
+ encrypted: boolean;
50
+ };
51
+ integrityOk(): boolean;
52
+ getDurability(): ProviderDurability;
53
+ close(): void;
54
+ }
55
+ export default SqliteDatabaseProvider;
@@ -0,0 +1,90 @@
1
+ /**
2
+ * The application database as one SQLite file, encrypted with SQLCipher when a
3
+ * key is given (#1536). Ported from yourPHR (yourphr#617).
4
+ *
5
+ * Opened and migrated in the constructor, so every provider built over the
6
+ * handle sees a finished schema. WAL mode with `synchronous = FULL`: a
7
+ * committed transaction is on the device before the call returns. WAL needs
8
+ * shared memory, which network filesystems do not provide, so the file's
9
+ * location is checked first (`refuseNetworkFilesystem`).
10
+ */
11
+ import Database from 'better-sqlite3-multiple-ciphers';
12
+ import { existsSync, statSync } from 'node:fs';
13
+ import BaseDatabaseProvider from './BaseDatabaseProvider.js';
14
+ import { runMigrations } from './sqliteMigrations.js';
15
+ import { refuseNetworkFilesystem } from './sqliteLocation.js';
16
+ /** The lock wait when none is configured: the driver's own default, stated (#1710). */
17
+ export const DEFAULT_BUSY_TIMEOUT_MS = 5000;
18
+ class SqliteDatabaseProvider extends BaseDatabaseProvider {
19
+ file;
20
+ providerName = 'SqliteDatabaseProvider';
21
+ providerDescription = 'SQLite application database, SQLCipher-encrypted when a key is set';
22
+ db;
23
+ closed = false;
24
+ encrypted;
25
+ /** What the ledger did at open: the ids applied now, and how many were already there. */
26
+ migrations;
27
+ /**
28
+ * @param file the database file; created when absent
29
+ * @param key the SQLCipher key; '' opens the file unencrypted
30
+ * @param ledger the migrations, strictly ascending by id
31
+ * @param ledgerTable where applied ids are recorded; an add-on's database names its own (#13)
32
+ * @param options.busyTimeoutMs how long a statement waits for a lock another connection holds
33
+ * (`ngdpbase.database.busy-timeout-ms`, #1710) before failing with SQLITE_BUSY
34
+ */
35
+ constructor(file, key, ledger, ledgerTable = 'schema_migrations', options = {}) {
36
+ super();
37
+ this.file = file;
38
+ refuseNetworkFilesystem(file);
39
+ this.db = new Database(file, { timeout: options.busyTimeoutMs ?? DEFAULT_BUSY_TIMEOUT_MS });
40
+ this.encrypted = key !== '';
41
+ try {
42
+ if (this.encrypted) {
43
+ this.db.pragma("cipher='sqlcipher'");
44
+ this.db.pragma(`key='${key.replace(/'/g, "''")}'`);
45
+ }
46
+ // The first read: a wrong key fails here, before anything is written.
47
+ this.db.pragma('journal_mode = WAL');
48
+ this.db.pragma('synchronous = FULL');
49
+ this.migrations = runMigrations(this.db, ledger, ledgerTable);
50
+ }
51
+ catch (err) {
52
+ this.db.close();
53
+ throw err;
54
+ }
55
+ }
56
+ /**
57
+ * Run a further migration ledger on this connection, recorded in its own
58
+ * table: an add-on that depends on the add-on owning this database brings
59
+ * its own tables (ngdp-accounting-addons#13). Same rules as the ledger run at
60
+ * open: once, in order, transactional, and a newer schema is refused.
61
+ */
62
+ migrate(ledger, ledgerTable) {
63
+ return runMigrations(this.db, ledger, ledgerTable);
64
+ }
65
+ get handle() {
66
+ return this.db;
67
+ }
68
+ storage() {
69
+ return { location: this.file, sizeBytes: existsSync(this.file) ? statSync(this.file).size : 0, encrypted: this.encrypted };
70
+ }
71
+ integrityOk() {
72
+ try {
73
+ const rows = this.db.pragma('quick_check');
74
+ return String(rows[0]?.quick_check ?? '').toLowerCase() === 'ok';
75
+ }
76
+ catch {
77
+ return false;
78
+ }
79
+ }
80
+ getDurability() {
81
+ return { bufferedForMs: 0, bufferedRecords: 0, fsync: true };
82
+ }
83
+ close() {
84
+ if (this.closed)
85
+ return;
86
+ this.closed = true;
87
+ this.db.close();
88
+ }
89
+ }
90
+ export default SqliteDatabaseProvider;