@fiduswriter/editor 0.1.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 (525) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +22 -0
  3. package/dist/bibliography/tools.js +53 -0
  4. package/dist/bibliography/tools.js.map +1 -0
  5. package/dist/citations/index.js +339 -0
  6. package/dist/citations/index.js.map +1 -0
  7. package/dist/citations/render.js +47 -0
  8. package/dist/citations/render.js.map +1 -0
  9. package/dist/clipboard/copy/index.js +2 -0
  10. package/dist/clipboard/copy/index.js.map +1 -0
  11. package/dist/clipboard/copy/schema.js +54 -0
  12. package/dist/clipboard/copy/schema.js.map +1 -0
  13. package/dist/clipboard/copy/serializers.js +132 -0
  14. package/dist/clipboard/copy/serializers.js.map +1 -0
  15. package/dist/clipboard/paste/fidus_writer.js +45 -0
  16. package/dist/clipboard/paste/fidus_writer.js.map +1 -0
  17. package/dist/clipboard/paste/general.js +76 -0
  18. package/dist/clipboard/paste/general.js.map +1 -0
  19. package/dist/clipboard/paste/google_docs.js +24 -0
  20. package/dist/clipboard/paste/google_docs.js.map +1 -0
  21. package/dist/clipboard/paste/html.js +68 -0
  22. package/dist/clipboard/paste/html.js.map +1 -0
  23. package/dist/clipboard/paste/index.js +3 -0
  24. package/dist/clipboard/paste/index.js.map +1 -0
  25. package/dist/clipboard/paste/libreoffice_writer.js +27 -0
  26. package/dist/clipboard/paste/libreoffice_writer.js.map +1 -0
  27. package/dist/clipboard/paste/microsoft_word.js +79 -0
  28. package/dist/clipboard/paste/microsoft_word.js.map +1 -0
  29. package/dist/clipboard/paste/text.js +41 -0
  30. package/dist/clipboard/paste/text.js.map +1 -0
  31. package/dist/collab/chat.js +154 -0
  32. package/dist/collab/chat.js.map +1 -0
  33. package/dist/collab/colors.js +62 -0
  34. package/dist/collab/colors.js.map +1 -0
  35. package/dist/collab/doc.js +1090 -0
  36. package/dist/collab/doc.js.map +1 -0
  37. package/dist/collab/index.js +75 -0
  38. package/dist/collab/index.js.map +1 -0
  39. package/dist/collab/merge/changeset.js +90 -0
  40. package/dist/collab/merge/changeset.js.map +1 -0
  41. package/dist/collab/merge/editor.js +708 -0
  42. package/dist/collab/merge/editor.js.map +1 -0
  43. package/dist/collab/merge/footnotes.js +149 -0
  44. package/dist/collab/merge/footnotes.js.map +1 -0
  45. package/dist/collab/merge/index.js +270 -0
  46. package/dist/collab/merge/index.js.map +1 -0
  47. package/dist/collab/merge/recreate_transform.js +259 -0
  48. package/dist/collab/merge/recreate_transform.js.map +1 -0
  49. package/dist/collab/merge/schema.js +117 -0
  50. package/dist/collab/merge/schema.js.map +1 -0
  51. package/dist/collab/merge/state_plugins/action.js +138 -0
  52. package/dist/collab/merge/state_plugins/action.js.map +1 -0
  53. package/dist/collab/merge/state_plugins/clipboard.js +32 -0
  54. package/dist/collab/merge/state_plugins/clipboard.js.map +1 -0
  55. package/dist/collab/merge/state_plugins/diff.js +541 -0
  56. package/dist/collab/merge/state_plugins/diff.js.map +1 -0
  57. package/dist/collab/merge/state_plugins/index.js +3 -0
  58. package/dist/collab/merge/state_plugins/index.js.map +1 -0
  59. package/dist/collab/merge/tools.js +175 -0
  60. package/dist/collab/merge/tools.js.map +1 -0
  61. package/dist/collab/templates.js +10 -0
  62. package/dist/collab/templates.js.map +1 -0
  63. package/dist/comments/comment.js +17 -0
  64. package/dist/comments/comment.js.map +1 -0
  65. package/dist/comments/editors/answer.js +43 -0
  66. package/dist/comments/editors/answer.js.map +1 -0
  67. package/dist/comments/editors/comment.js +278 -0
  68. package/dist/comments/editors/comment.js.map +1 -0
  69. package/dist/comments/editors/index.js +4 -0
  70. package/dist/comments/editors/index.js.map +1 -0
  71. package/dist/comments/editors/notify.js +13 -0
  72. package/dist/comments/editors/notify.js.map +1 -0
  73. package/dist/comments/editors/schema.js +60 -0
  74. package/dist/comments/editors/schema.js.map +1 -0
  75. package/dist/comments/index.js +11 -0
  76. package/dist/comments/index.js.map +1 -0
  77. package/dist/comments/interactions.js +379 -0
  78. package/dist/comments/interactions.js.map +1 -0
  79. package/dist/comments/store.js +438 -0
  80. package/dist/comments/store.js.map +1 -0
  81. package/dist/contacts/add_dialog.js +88 -0
  82. package/dist/contacts/add_dialog.js.map +1 -0
  83. package/dist/contacts/templates.js +23 -0
  84. package/dist/contacts/templates.js.map +1 -0
  85. package/dist/copyright_dialog/index.js +148 -0
  86. package/dist/copyright_dialog/index.js.map +1 -0
  87. package/dist/copyright_dialog/templates.js +48 -0
  88. package/dist/copyright_dialog/templates.js.map +1 -0
  89. package/dist/databases/bibliography.js +162 -0
  90. package/dist/databases/bibliography.js.map +1 -0
  91. package/dist/databases/images.js +260 -0
  92. package/dist/databases/images.js.map +1 -0
  93. package/dist/databases/index.js +55 -0
  94. package/dist/databases/index.js.map +1 -0
  95. package/dist/dialogs/citation.js +321 -0
  96. package/dist/dialogs/citation.js.map +1 -0
  97. package/dist/dialogs/code_block.js +192 -0
  98. package/dist/dialogs/code_block.js.map +1 -0
  99. package/dist/dialogs/contributor.js +132 -0
  100. package/dist/dialogs/contributor.js.map +1 -0
  101. package/dist/dialogs/figure.js +378 -0
  102. package/dist/dialogs/figure.js.map +1 -0
  103. package/dist/dialogs/index.js +11 -0
  104. package/dist/dialogs/index.js.map +1 -0
  105. package/dist/dialogs/language.js +47 -0
  106. package/dist/dialogs/language.js.map +1 -0
  107. package/dist/dialogs/link.js +243 -0
  108. package/dist/dialogs/link.js.map +1 -0
  109. package/dist/dialogs/math.js +121 -0
  110. package/dist/dialogs/math.js.map +1 -0
  111. package/dist/dialogs/ordered_list.js +67 -0
  112. package/dist/dialogs/ordered_list.js.map +1 -0
  113. package/dist/dialogs/revision.js +36 -0
  114. package/dist/dialogs/revision.js.map +1 -0
  115. package/dist/dialogs/subsup.js +109 -0
  116. package/dist/dialogs/subsup.js.map +1 -0
  117. package/dist/dialogs/table.js +217 -0
  118. package/dist/dialogs/table.js.map +1 -0
  119. package/dist/dialogs/templates.js +366 -0
  120. package/dist/dialogs/templates.js.map +1 -0
  121. package/dist/document_template/exporter.js +83 -0
  122. package/dist/document_template/exporter.js.map +1 -0
  123. package/dist/document_template/index.js +327 -0
  124. package/dist/document_template/index.js.map +1 -0
  125. package/dist/documents/access_rights/index.js +532 -0
  126. package/dist/documents/access_rights/index.js.map +1 -0
  127. package/dist/documents/access_rights/templates.js +150 -0
  128. package/dist/documents/access_rights/templates.js.map +1 -0
  129. package/dist/e2ee/encryptor.js +201 -0
  130. package/dist/e2ee/encryptor.js.map +1 -0
  131. package/dist/e2ee/key-manager.js +171 -0
  132. package/dist/e2ee/key-manager.js.map +1 -0
  133. package/dist/e2ee/passphrase-crypto.js +365 -0
  134. package/dist/e2ee/passphrase-crypto.js.map +1 -0
  135. package/dist/e2ee/passphrase-dialog.js +548 -0
  136. package/dist/e2ee/passphrase-dialog.js.map +1 -0
  137. package/dist/e2ee/passphrase-manager.js +350 -0
  138. package/dist/e2ee/passphrase-manager.js.map +1 -0
  139. package/dist/e2ee/password-dialog.js +552 -0
  140. package/dist/e2ee/password-dialog.js.map +1 -0
  141. package/dist/e2ee/snapshot-manager.js +238 -0
  142. package/dist/e2ee/snapshot-manager.js.map +1 -0
  143. package/dist/exporter/native/copy.js +29 -0
  144. package/dist/exporter/native/copy.js.map +1 -0
  145. package/dist/exporter/native/file.js +19 -0
  146. package/dist/exporter/native/file.js.map +1 -0
  147. package/dist/exporter/native/index.js +4 -0
  148. package/dist/exporter/native/index.js.map +1 -0
  149. package/dist/exporter/native/revision.js +54 -0
  150. package/dist/exporter/native/revision.js.map +1 -0
  151. package/dist/exporter/native/zip.js +2 -0
  152. package/dist/exporter/native/zip.js.map +1 -0
  153. package/dist/footnotes/editor.js +180 -0
  154. package/dist/footnotes/editor.js.map +1 -0
  155. package/dist/footnotes/index.js +15 -0
  156. package/dist/footnotes/index.js.map +1 -0
  157. package/dist/footnotes/layout.js +125 -0
  158. package/dist/footnotes/layout.js.map +1 -0
  159. package/dist/footnotes/state_plugins/access_rights.js +25 -0
  160. package/dist/footnotes/state_plugins/access_rights.js.map +1 -0
  161. package/dist/footnotes/state_plugins/index.js +2 -0
  162. package/dist/footnotes/state_plugins/index.js.map +1 -0
  163. package/dist/images/edit_dialog/edit_dialog/index.js +186 -0
  164. package/dist/images/edit_dialog/edit_dialog/index.js.map +1 -0
  165. package/dist/images/edit_dialog/edit_dialog/model.js +152 -0
  166. package/dist/images/edit_dialog/edit_dialog/model.js.map +1 -0
  167. package/dist/images/edit_dialog/edit_dialog/templates.js +33 -0
  168. package/dist/images/edit_dialog/edit_dialog/templates.js.map +1 -0
  169. package/dist/images/edit_dialog/model.js +6 -0
  170. package/dist/images/edit_dialog/model.js.map +1 -0
  171. package/dist/images/selection_dialog/index.js +149 -0
  172. package/dist/images/selection_dialog/index.js.map +1 -0
  173. package/dist/index.js +1002 -0
  174. package/dist/index.js.map +1 -0
  175. package/dist/keymap.js +73 -0
  176. package/dist/keymap.js.map +1 -0
  177. package/dist/marginboxes/index.js +674 -0
  178. package/dist/marginboxes/index.js.map +1 -0
  179. package/dist/marginboxes/templates.js +447 -0
  180. package/dist/marginboxes/templates.js.map +1 -0
  181. package/dist/menus/code_block/index.js +2 -0
  182. package/dist/menus/code_block/index.js.map +1 -0
  183. package/dist/menus/code_block/model.js +49 -0
  184. package/dist/menus/code_block/model.js.map +1 -0
  185. package/dist/menus/figure/index.js +3 -0
  186. package/dist/menus/figure/index.js.map +1 -0
  187. package/dist/menus/figure/model.js +80 -0
  188. package/dist/menus/figure/model.js.map +1 -0
  189. package/dist/menus/figure/utils.js +6 -0
  190. package/dist/menus/figure/utils.js.map +1 -0
  191. package/dist/menus/headerbar/index.js +3 -0
  192. package/dist/menus/headerbar/index.js.map +1 -0
  193. package/dist/menus/headerbar/model.js +743 -0
  194. package/dist/menus/headerbar/model.js.map +1 -0
  195. package/dist/menus/headerbar/view.js +579 -0
  196. package/dist/menus/headerbar/view.js.map +1 -0
  197. package/dist/menus/image/index.js +2 -0
  198. package/dist/menus/image/index.js.map +1 -0
  199. package/dist/menus/image/model.js +32 -0
  200. package/dist/menus/image/model.js.map +1 -0
  201. package/dist/menus/index.js +10 -0
  202. package/dist/menus/index.js.map +1 -0
  203. package/dist/menus/navigator/index.js +2 -0
  204. package/dist/menus/navigator/index.js.map +1 -0
  205. package/dist/menus/navigator/model.js +29 -0
  206. package/dist/menus/navigator/model.js.map +1 -0
  207. package/dist/menus/ordered_list/index.js +2 -0
  208. package/dist/menus/ordered_list/index.js.map +1 -0
  209. package/dist/menus/ordered_list/model.js +17 -0
  210. package/dist/menus/ordered_list/model.js.map +1 -0
  211. package/dist/menus/selection/index.js +3 -0
  212. package/dist/menus/selection/index.js.map +1 -0
  213. package/dist/menus/selection/model.js +108 -0
  214. package/dist/menus/selection/model.js.map +1 -0
  215. package/dist/menus/selection/view.js +125 -0
  216. package/dist/menus/selection/view.js.map +1 -0
  217. package/dist/menus/table/index.js +2 -0
  218. package/dist/menus/table/index.js.map +1 -0
  219. package/dist/menus/table/model.js +319 -0
  220. package/dist/menus/table/model.js.map +1 -0
  221. package/dist/menus/toolbar/index.js +3 -0
  222. package/dist/menus/toolbar/index.js.map +1 -0
  223. package/dist/menus/toolbar/model.js +747 -0
  224. package/dist/menus/toolbar/model.js.map +1 -0
  225. package/dist/menus/toolbar/view.js +314 -0
  226. package/dist/menus/toolbar/view.js.map +1 -0
  227. package/dist/navigator/index.js +435 -0
  228. package/dist/navigator/index.js.map +1 -0
  229. package/dist/no_collab_save/index.js +169 -0
  230. package/dist/no_collab_save/index.js.map +1 -0
  231. package/dist/plugins/citation_dialog/index.js +2 -0
  232. package/dist/plugins/citation_dialog/index.js.map +1 -0
  233. package/dist/plugins/editor/index.js +2 -0
  234. package/dist/plugins/editor/index.js.map +1 -0
  235. package/dist/state_plugins/access_rights.js +30 -0
  236. package/dist/state_plugins/access_rights.js.map +1 -0
  237. package/dist/state_plugins/citation_render.js +78 -0
  238. package/dist/state_plugins/citation_render.js.map +1 -0
  239. package/dist/state_plugins/clipboard.js +217 -0
  240. package/dist/state_plugins/clipboard.js.map +1 -0
  241. package/dist/state_plugins/code_block.js +165 -0
  242. package/dist/state_plugins/code_block.js.map +1 -0
  243. package/dist/state_plugins/collab_carets.js +115 -0
  244. package/dist/state_plugins/collab_carets.js.map +1 -0
  245. package/dist/state_plugins/comments.js +197 -0
  246. package/dist/state_plugins/comments.js.map +1 -0
  247. package/dist/state_plugins/contributor_input/add_button.js +101 -0
  248. package/dist/state_plugins/contributor_input/add_button.js.map +1 -0
  249. package/dist/state_plugins/contributor_input/dropup.js +273 -0
  250. package/dist/state_plugins/contributor_input/dropup.js.map +1 -0
  251. package/dist/state_plugins/contributor_input/helpers.js +23 -0
  252. package/dist/state_plugins/contributor_input/helpers.js.map +1 -0
  253. package/dist/state_plugins/contributor_input/index.js +3 -0
  254. package/dist/state_plugins/contributor_input/index.js.map +1 -0
  255. package/dist/state_plugins/contributor_input/node_view.js +76 -0
  256. package/dist/state_plugins/contributor_input/node_view.js.map +1 -0
  257. package/dist/state_plugins/contributor_input/plugin.js +236 -0
  258. package/dist/state_plugins/contributor_input/plugin.js.map +1 -0
  259. package/dist/state_plugins/document_template.js +213 -0
  260. package/dist/state_plugins/document_template.js.map +1 -0
  261. package/dist/state_plugins/figure.js +90 -0
  262. package/dist/state_plugins/figure.js.map +1 -0
  263. package/dist/state_plugins/footnote_markers.js +187 -0
  264. package/dist/state_plugins/footnote_markers.js.map +1 -0
  265. package/dist/state_plugins/headerbar.js +10 -0
  266. package/dist/state_plugins/headerbar.js.map +1 -0
  267. package/dist/state_plugins/index.js +27 -0
  268. package/dist/state_plugins/index.js.map +1 -0
  269. package/dist/state_plugins/inline_math.js +719 -0
  270. package/dist/state_plugins/inline_math.js.map +1 -0
  271. package/dist/state_plugins/inline_reference/dropup.js +182 -0
  272. package/dist/state_plugins/inline_reference/dropup.js.map +1 -0
  273. package/dist/state_plugins/inline_reference/index.js +2 -0
  274. package/dist/state_plugins/inline_reference/index.js.map +1 -0
  275. package/dist/state_plugins/inline_reference/plugin.js +1134 -0
  276. package/dist/state_plugins/inline_reference/plugin.js.map +1 -0
  277. package/dist/state_plugins/jump_hidden_nodes.js +47 -0
  278. package/dist/state_plugins/jump_hidden_nodes.js.map +1 -0
  279. package/dist/state_plugins/links.js +622 -0
  280. package/dist/state_plugins/links.js.map +1 -0
  281. package/dist/state_plugins/marginboxes.js +13 -0
  282. package/dist/state_plugins/marginboxes.js.map +1 -0
  283. package/dist/state_plugins/ordered_list_menu.js +72 -0
  284. package/dist/state_plugins/ordered_list_menu.js.map +1 -0
  285. package/dist/state_plugins/placeholders.js +98 -0
  286. package/dist/state_plugins/placeholders.js.map +1 -0
  287. package/dist/state_plugins/search.js +212 -0
  288. package/dist/state_plugins/search.js.map +1 -0
  289. package/dist/state_plugins/selection_menu.js +10 -0
  290. package/dist/state_plugins/selection_menu.js.map +1 -0
  291. package/dist/state_plugins/settings.js +191 -0
  292. package/dist/state_plugins/settings.js.map +1 -0
  293. package/dist/state_plugins/table.js +104 -0
  294. package/dist/state_plugins/table.js.map +1 -0
  295. package/dist/state_plugins/tag_input/helpers.js +55 -0
  296. package/dist/state_plugins/tag_input/helpers.js.map +1 -0
  297. package/dist/state_plugins/tag_input/index.js +3 -0
  298. package/dist/state_plugins/tag_input/index.js.map +1 -0
  299. package/dist/state_plugins/tag_input/node_view.js +77 -0
  300. package/dist/state_plugins/tag_input/node_view.js.map +1 -0
  301. package/dist/state_plugins/tag_input/plugin.js +199 -0
  302. package/dist/state_plugins/tag_input/plugin.js.map +1 -0
  303. package/dist/state_plugins/tag_input/tag_editor.js +159 -0
  304. package/dist/state_plugins/tag_input/tag_editor.js.map +1 -0
  305. package/dist/state_plugins/tag_input/tag_editor_plugins.js +61 -0
  306. package/dist/state_plugins/tag_input/tag_editor_plugins.js.map +1 -0
  307. package/dist/state_plugins/toc_render.js +142 -0
  308. package/dist/state_plugins/toc_render.js.map +1 -0
  309. package/dist/state_plugins/toolbar.js +10 -0
  310. package/dist/state_plugins/toolbar.js.map +1 -0
  311. package/dist/state_plugins/track/find_selected_changes.js +82 -0
  312. package/dist/state_plugins/track/find_selected_changes.js.map +1 -0
  313. package/dist/state_plugins/track/helpers.js +67 -0
  314. package/dist/state_plugins/track/helpers.js.map +1 -0
  315. package/dist/state_plugins/track/index.js +3 -0
  316. package/dist/state_plugins/track/index.js.map +1 -0
  317. package/dist/state_plugins/track/plugin.js +114 -0
  318. package/dist/state_plugins/track/plugin.js.map +1 -0
  319. package/dist/tools/index.js +4 -0
  320. package/dist/tools/index.js.map +1 -0
  321. package/dist/tools/key_bindings/index.js +20 -0
  322. package/dist/tools/key_bindings/index.js.map +1 -0
  323. package/dist/tools/key_bindings/templates.js +68 -0
  324. package/dist/tools/key_bindings/templates.js.map +1 -0
  325. package/dist/tools/search_replace/index.js +275 -0
  326. package/dist/tools/search_replace/index.js.map +1 -0
  327. package/dist/tools/search_replace/templates.js +18 -0
  328. package/dist/tools/search_replace/templates.js.map +1 -0
  329. package/dist/tools/word_count/index.js +40 -0
  330. package/dist/tools/word_count/index.js.map +1 -0
  331. package/dist/tools/word_count/templates.js +27 -0
  332. package/dist/tools/word_count/templates.js.map +1 -0
  333. package/dist/track/accept.js +66 -0
  334. package/dist/track/accept.js.map +1 -0
  335. package/dist/track/accept_all.js +51 -0
  336. package/dist/track/accept_all.js.map +1 -0
  337. package/dist/track/accept_all_no_insertions.js +63 -0
  338. package/dist/track/accept_all_no_insertions.js.map +1 -0
  339. package/dist/track/amend_transaction.js +390 -0
  340. package/dist/track/amend_transaction.js.map +1 -0
  341. package/dist/track/delete.js +62 -0
  342. package/dist/track/delete.js.map +1 -0
  343. package/dist/track/index.js +6 -0
  344. package/dist/track/index.js.map +1 -0
  345. package/dist/track/mod.js +86 -0
  346. package/dist/track/mod.js.map +1 -0
  347. package/dist/track/reject.js +67 -0
  348. package/dist/track/reject.js.map +1 -0
  349. package/dist/track/reject_all.js +56 -0
  350. package/dist/track/reject_all.js.map +1 -0
  351. package/package.json +80 -0
  352. package/src/bibliography/tools.js +58 -0
  353. package/src/citations/index.js +443 -0
  354. package/src/citations/render.js +68 -0
  355. package/src/clipboard/copy/index.js +1 -0
  356. package/src/clipboard/copy/schema.js +62 -0
  357. package/src/clipboard/copy/serializers.js +179 -0
  358. package/src/clipboard/paste/fidus_writer.js +55 -0
  359. package/src/clipboard/paste/general.js +80 -0
  360. package/src/clipboard/paste/google_docs.js +26 -0
  361. package/src/clipboard/paste/html.js +76 -0
  362. package/src/clipboard/paste/index.js +2 -0
  363. package/src/clipboard/paste/libreoffice_writer.js +32 -0
  364. package/src/clipboard/paste/microsoft_word.js +87 -0
  365. package/src/clipboard/paste/text.js +58 -0
  366. package/src/collab/chat.js +195 -0
  367. package/src/collab/colors.js +67 -0
  368. package/src/collab/doc.js +1436 -0
  369. package/src/collab/index.js +81 -0
  370. package/src/collab/merge/changeset.js +103 -0
  371. package/src/collab/merge/editor.js +1065 -0
  372. package/src/collab/merge/footnotes.js +175 -0
  373. package/src/collab/merge/index.js +401 -0
  374. package/src/collab/merge/recreate_transform.js +326 -0
  375. package/src/collab/merge/schema.js +135 -0
  376. package/src/collab/merge/state_plugins/action.js +171 -0
  377. package/src/collab/merge/state_plugins/clipboard.js +32 -0
  378. package/src/collab/merge/state_plugins/diff.js +780 -0
  379. package/src/collab/merge/state_plugins/index.js +2 -0
  380. package/src/collab/merge/tools.js +217 -0
  381. package/src/collab/templates.js +10 -0
  382. package/src/comments/comment.js +29 -0
  383. package/src/comments/editors/answer.js +55 -0
  384. package/src/comments/editors/comment.js +318 -0
  385. package/src/comments/editors/index.js +4 -0
  386. package/src/comments/editors/notify.js +13 -0
  387. package/src/comments/editors/schema.js +65 -0
  388. package/src/comments/index.js +11 -0
  389. package/src/comments/interactions.js +465 -0
  390. package/src/comments/store.js +513 -0
  391. package/src/contacts/add_dialog.js +110 -0
  392. package/src/contacts/templates.js +28 -0
  393. package/src/copyright_dialog/index.js +179 -0
  394. package/src/copyright_dialog/templates.js +56 -0
  395. package/src/databases/bibliography.js +179 -0
  396. package/src/databases/images.js +320 -0
  397. package/src/databases/index.js +69 -0
  398. package/src/dialogs/citation.js +428 -0
  399. package/src/dialogs/code_block.js +242 -0
  400. package/src/dialogs/contributor.js +173 -0
  401. package/src/dialogs/figure.js +479 -0
  402. package/src/dialogs/index.js +10 -0
  403. package/src/dialogs/language.js +58 -0
  404. package/src/dialogs/link.js +358 -0
  405. package/src/dialogs/math.js +148 -0
  406. package/src/dialogs/ordered_list.js +84 -0
  407. package/src/dialogs/revision.js +43 -0
  408. package/src/dialogs/subsup.js +116 -0
  409. package/src/dialogs/table.js +258 -0
  410. package/src/dialogs/templates.js +426 -0
  411. package/src/document_template/exporter.js +97 -0
  412. package/src/document_template/index.js +483 -0
  413. package/src/documents/access_rights/index.js +693 -0
  414. package/src/documents/access_rights/templates.js +178 -0
  415. package/src/e2ee/encryptor.js +228 -0
  416. package/src/e2ee/key-manager.js +202 -0
  417. package/src/e2ee/passphrase-crypto.js +606 -0
  418. package/src/e2ee/passphrase-dialog.js +655 -0
  419. package/src/e2ee/passphrase-manager.js +502 -0
  420. package/src/e2ee/password-dialog.js +652 -0
  421. package/src/e2ee/snapshot-manager.js +305 -0
  422. package/src/exporter/native/copy.js +54 -0
  423. package/src/exporter/native/file.js +37 -0
  424. package/src/exporter/native/index.js +3 -0
  425. package/src/exporter/native/revision.js +86 -0
  426. package/src/exporter/native/zip.js +1 -0
  427. package/src/footnotes/editor.js +227 -0
  428. package/src/footnotes/index.js +16 -0
  429. package/src/footnotes/layout.js +190 -0
  430. package/src/footnotes/state_plugins/access_rights.js +39 -0
  431. package/src/footnotes/state_plugins/index.js +1 -0
  432. package/src/images/edit_dialog/edit_dialog/index.js +222 -0
  433. package/src/images/edit_dialog/edit_dialog/model.js +183 -0
  434. package/src/images/edit_dialog/edit_dialog/templates.js +41 -0
  435. package/src/images/edit_dialog/model.js +5 -0
  436. package/src/images/selection_dialog/index.js +176 -0
  437. package/src/index.js +1252 -0
  438. package/src/keymap.js +102 -0
  439. package/src/marginboxes/index.js +946 -0
  440. package/src/marginboxes/templates.js +573 -0
  441. package/src/menus/code_block/index.js +1 -0
  442. package/src/menus/code_block/model.js +52 -0
  443. package/src/menus/figure/index.js +2 -0
  444. package/src/menus/figure/model.js +91 -0
  445. package/src/menus/figure/utils.js +5 -0
  446. package/src/menus/headerbar/index.js +2 -0
  447. package/src/menus/headerbar/model.js +1077 -0
  448. package/src/menus/headerbar/view.js +675 -0
  449. package/src/menus/image/index.js +1 -0
  450. package/src/menus/image/model.js +32 -0
  451. package/src/menus/index.js +9 -0
  452. package/src/menus/navigator/index.js +1 -0
  453. package/src/menus/navigator/model.js +28 -0
  454. package/src/menus/ordered_list/index.js +1 -0
  455. package/src/menus/ordered_list/model.js +19 -0
  456. package/src/menus/selection/index.js +2 -0
  457. package/src/menus/selection/model.js +134 -0
  458. package/src/menus/selection/view.js +154 -0
  459. package/src/menus/table/index.js +1 -0
  460. package/src/menus/table/model.js +414 -0
  461. package/src/menus/toolbar/index.js +2 -0
  462. package/src/menus/toolbar/model.js +920 -0
  463. package/src/menus/toolbar/view.js +354 -0
  464. package/src/navigator/index.js +515 -0
  465. package/src/no_collab_save/index.js +209 -0
  466. package/src/plugins/citation_dialog/index.js +1 -0
  467. package/src/plugins/editor/index.js +1 -0
  468. package/src/state_plugins/access_rights.js +47 -0
  469. package/src/state_plugins/citation_render.js +88 -0
  470. package/src/state_plugins/clipboard.js +289 -0
  471. package/src/state_plugins/code_block.js +201 -0
  472. package/src/state_plugins/collab_carets.js +152 -0
  473. package/src/state_plugins/comments.js +259 -0
  474. package/src/state_plugins/contributor_input/add_button.js +134 -0
  475. package/src/state_plugins/contributor_input/dropup.js +318 -0
  476. package/src/state_plugins/contributor_input/helpers.js +24 -0
  477. package/src/state_plugins/contributor_input/index.js +2 -0
  478. package/src/state_plugins/contributor_input/node_view.js +86 -0
  479. package/src/state_plugins/contributor_input/plugin.js +318 -0
  480. package/src/state_plugins/document_template.js +315 -0
  481. package/src/state_plugins/figure.js +108 -0
  482. package/src/state_plugins/footnote_markers.js +238 -0
  483. package/src/state_plugins/headerbar.js +12 -0
  484. package/src/state_plugins/index.js +73 -0
  485. package/src/state_plugins/inline_math.js +918 -0
  486. package/src/state_plugins/inline_reference/dropup.js +208 -0
  487. package/src/state_plugins/inline_reference/index.js +5 -0
  488. package/src/state_plugins/inline_reference/plugin.js +1429 -0
  489. package/src/state_plugins/jump_hidden_nodes.js +58 -0
  490. package/src/state_plugins/links.js +830 -0
  491. package/src/state_plugins/marginboxes.js +14 -0
  492. package/src/state_plugins/ordered_list_menu.js +84 -0
  493. package/src/state_plugins/placeholders.js +123 -0
  494. package/src/state_plugins/search.js +251 -0
  495. package/src/state_plugins/selection_menu.js +12 -0
  496. package/src/state_plugins/settings.js +223 -0
  497. package/src/state_plugins/table.js +127 -0
  498. package/src/state_plugins/tag_input/helpers.js +69 -0
  499. package/src/state_plugins/tag_input/index.js +2 -0
  500. package/src/state_plugins/tag_input/node_view.js +85 -0
  501. package/src/state_plugins/tag_input/plugin.js +278 -0
  502. package/src/state_plugins/tag_input/tag_editor.js +202 -0
  503. package/src/state_plugins/tag_input/tag_editor_plugins.js +74 -0
  504. package/src/state_plugins/toc_render.js +160 -0
  505. package/src/state_plugins/toolbar.js +12 -0
  506. package/src/state_plugins/track/find_selected_changes.js +107 -0
  507. package/src/state_plugins/track/helpers.js +108 -0
  508. package/src/state_plugins/track/index.js +6 -0
  509. package/src/state_plugins/track/plugin.js +140 -0
  510. package/src/tools/index.js +3 -0
  511. package/src/tools/key_bindings/index.js +21 -0
  512. package/src/tools/key_bindings/templates.js +68 -0
  513. package/src/tools/search_replace/index.js +421 -0
  514. package/src/tools/search_replace/templates.js +19 -0
  515. package/src/tools/word_count/index.js +59 -0
  516. package/src/tools/word_count/templates.js +34 -0
  517. package/src/track/accept.js +102 -0
  518. package/src/track/accept_all.js +103 -0
  519. package/src/track/accept_all_no_insertions.js +102 -0
  520. package/src/track/amend_transaction.js +562 -0
  521. package/src/track/delete.js +92 -0
  522. package/src/track/index.js +8 -0
  523. package/src/track/mod.js +116 -0
  524. package/src/track/reject.js +116 -0
  525. package/src/track/reject_all.js +121 -0
@@ -0,0 +1,502 @@
1
+ /**
2
+ * PassphraseManager - Manages the personal passphrase system for E2EE.
3
+ *
4
+ * This module ties together PassphraseCrypto with the server API to provide:
5
+ * - Setup flow: generate keys, derive KWK, encrypt, send to server
6
+ * - Unlock flow: fetch from server, derive KWK, decrypt, store in sessionStorage
7
+ * - Recovery flow: use recovery key to decrypt backup, re-encrypt with new passphrase
8
+ * - Key checking: determine if user has encryption keys set up
9
+ * - DEK retrieval: get the document encryption key for a document
10
+ * - DEK sharing: encrypt DEK with recipient's public key
11
+ */
12
+
13
+ import {getJson, post, postJson} from "fwtoolkit"
14
+ import {E2EEKeyManager} from "./key-manager"
15
+ import {PassphraseCrypto} from "./passphrase-crypto"
16
+
17
+ export class PassphraseManager {
18
+ /**
19
+ * Check if the user has set up encryption keys on the server.
20
+ */
21
+ static async hasEncryptionKeys() {
22
+ try {
23
+ const data = await getJson("/api/user/encryption_key/")
24
+ return data.has_key === true
25
+ } catch (_e) {
26
+ return false
27
+ }
28
+ }
29
+
30
+ /**
31
+ * Check if the master key and private key are in sessionStorage.
32
+ */
33
+ static hasKeysInSession() {
34
+ return PassphraseCrypto.hasKeysInSession()
35
+ }
36
+
37
+ /**
38
+ * Get keys from sessionStorage.
39
+ * Returns {masterKey, privateKey} or {masterKey: null, privateKey: null}
40
+ */
41
+ static getKeysFromSession() {
42
+ return PassphraseCrypto.getKeysFromSession()
43
+ }
44
+
45
+ /**
46
+ * Clear keys from sessionStorage (e.g., on sign-out).
47
+ */
48
+ static clearKeysFromSession() {
49
+ PassphraseCrypto.clearKeysFromSession()
50
+ }
51
+
52
+ /**
53
+ * Set up encryption keys for the first time.
54
+ *
55
+ * @param {string} passphrase - The user's chosen passphrase
56
+ * @returns {Promise<Object>} {recoveryKey: string} - The recovery key to display
57
+ */
58
+ static async setupEncryption(passphrase) {
59
+ // 1. Generate keys
60
+ const masterKey = await PassphraseCrypto.generateMasterKey()
61
+ const keyPair = await PassphraseCrypto.generateKeyPair()
62
+ const recoveryKey = PassphraseCrypto.generateRecoveryKey()
63
+ const salt = PassphraseCrypto.generateSalt()
64
+
65
+ // 2. Derive KWK from passphrase
66
+ const kwk = await PassphraseCrypto.deriveKWK(passphrase, salt)
67
+
68
+ // 3. Encrypt master key and private key with KWK
69
+ const encryptedMasterKey = await PassphraseCrypto.encryptKey(
70
+ masterKey,
71
+ kwk
72
+ )
73
+ const encryptedPrivateKey = await PassphraseCrypto.encryptPrivateKey(
74
+ keyPair.privateKey,
75
+ kwk
76
+ )
77
+
78
+ // 4. Encrypt backup of master key with recovery key
79
+ const recoveryKeyRaw = PassphraseCrypto._hexToBytes(recoveryKey)
80
+ const recoveryKeyCryptoKey = await crypto.subtle.importKey(
81
+ "raw",
82
+ recoveryKeyRaw,
83
+ {name: "AES-GCM", length: 256},
84
+ false,
85
+ ["encrypt", "decrypt"]
86
+ )
87
+ const encryptedMasterKeyBackup = await PassphraseCrypto.encryptKey(
88
+ masterKey,
89
+ recoveryKeyCryptoKey
90
+ )
91
+
92
+ // 5. Export public key as JWK
93
+ const publicKeyJwk = await PassphraseCrypto.exportPublicKey(
94
+ keyPair.publicKey
95
+ )
96
+
97
+ // 6. Send to server
98
+ const saveData = {
99
+ data: JSON.stringify({
100
+ public_key: publicKeyJwk,
101
+ encrypted_master_key: encryptedMasterKey,
102
+ encrypted_private_key: encryptedPrivateKey,
103
+ user_salt: PassphraseCrypto._bytesToBase64(salt),
104
+ user_iterations: 600000,
105
+ encrypted_master_key_backup: encryptedMasterKeyBackup
106
+ })
107
+ }
108
+ const {status} = await postJson(
109
+ "/api/user/encryption_key/save/",
110
+ saveData
111
+ )
112
+ if (status >= 400) {
113
+ throw new Error("Failed to save encryption keys")
114
+ }
115
+
116
+ // 7. Store in sessionStorage
117
+ await PassphraseCrypto.storeKeysInSession(masterKey, keyPair.privateKey)
118
+
119
+ return {recoveryKey}
120
+ }
121
+
122
+ /**
123
+ * Unlock encryption keys using the passphrase.
124
+ *
125
+ * @param {string} passphrase - The user's passphrase
126
+ * @returns {Promise<boolean>} true if successful
127
+ */
128
+ static async unlockWithPassphrase(passphrase) {
129
+ // 1. Fetch encrypted keys from server
130
+ const data = await getJson("/api/user/encryption_key/")
131
+ if (!data.has_key) {
132
+ throw new Error("No encryption keys found")
133
+ }
134
+
135
+ // 2. Derive KWK
136
+ const salt = PassphraseCrypto._base64ToBytes(data.user_salt)
137
+ const kwk = await PassphraseCrypto.deriveKWK(
138
+ passphrase,
139
+ salt,
140
+ data.user_iterations
141
+ )
142
+
143
+ // 3. Decrypt master key and private key
144
+ const masterKey = await PassphraseCrypto.decryptKey(
145
+ data.encrypted_master_key,
146
+ kwk
147
+ )
148
+ const privateKey = await PassphraseCrypto.decryptPrivateKey(
149
+ data.encrypted_private_key,
150
+ kwk
151
+ )
152
+
153
+ // 4. Store in sessionStorage
154
+ await PassphraseCrypto.storeKeysInSession(masterKey, privateKey)
155
+
156
+ return true
157
+ }
158
+
159
+ /**
160
+ * Change the passphrase without rotating keys.
161
+ *
162
+ * @param {string} oldPassphrase - Current passphrase
163
+ * @param {string} newPassphrase - New passphrase
164
+ * @returns {Promise<boolean>} true if successful
165
+ */
166
+ static async changePassphrase(oldPassphrase, newPassphrase) {
167
+ // 1. Fetch encrypted keys from server
168
+ const data = await getJson("/api/user/encryption_key/")
169
+ if (!data.has_key) {
170
+ throw new Error("No encryption keys found")
171
+ }
172
+
173
+ // 2. Derive old KWK and decrypt keys
174
+ const oldSalt = PassphraseCrypto._base64ToBytes(data.user_salt)
175
+ const oldKwk = await PassphraseCrypto.deriveKWK(
176
+ oldPassphrase,
177
+ oldSalt,
178
+ data.user_iterations
179
+ )
180
+ const masterKey = await PassphraseCrypto.decryptKey(
181
+ data.encrypted_master_key,
182
+ oldKwk
183
+ )
184
+ const privateKey = await PassphraseCrypto.decryptPrivateKey(
185
+ data.encrypted_private_key,
186
+ oldKwk
187
+ )
188
+
189
+ // 3. Generate new salt and derive new KWK
190
+ const newSalt = PassphraseCrypto.generateSalt()
191
+ const newKwk = await PassphraseCrypto.deriveKWK(newPassphrase, newSalt)
192
+
193
+ // 4. Re-encrypt master key and private key with new KWK
194
+ const encryptedMasterKey = await PassphraseCrypto.encryptKey(
195
+ masterKey,
196
+ newKwk
197
+ )
198
+ const encryptedPrivateKey = await PassphraseCrypto.encryptPrivateKey(
199
+ privateKey,
200
+ newKwk
201
+ )
202
+
203
+ // 5. Re-encrypt master key backup with existing recovery key
204
+ // (We keep the same recovery key so the user doesn't need to update
205
+ // their stored backup. The backup is encrypted with the recovery key,
206
+ // not the passphrase, so it remains valid.)
207
+ const encryptedMasterKeyBackup = data.encrypted_master_key_backup
208
+
209
+ // 6. Send updated keys to server
210
+ const saveData = {
211
+ data: JSON.stringify({
212
+ public_key: data.public_key,
213
+ encrypted_master_key: encryptedMasterKey,
214
+ encrypted_private_key: encryptedPrivateKey,
215
+ user_salt: PassphraseCrypto._bytesToBase64(newSalt),
216
+ user_iterations: 600000,
217
+ encrypted_master_key_backup: encryptedMasterKeyBackup
218
+ })
219
+ }
220
+ const {status} = await postJson(
221
+ "/api/user/encryption_key/save/",
222
+ saveData
223
+ )
224
+ if (status >= 400) {
225
+ throw new Error("Failed to save updated encryption keys")
226
+ }
227
+
228
+ // 7. Update sessionStorage
229
+ await PassphraseCrypto.storeKeysInSession(masterKey, privateKey)
230
+
231
+ return true
232
+ }
233
+
234
+ /**
235
+ * Recover encryption keys using the recovery key.
236
+ *
237
+ * @param {string} recoveryKey - The recovery key (hex string)
238
+ * @param {string} newPassphrase - The new passphrase to set
239
+ * @returns {Promise<Object>} {newRecoveryKey: string}
240
+ */
241
+ static async recoverWithRecoveryKey(recoveryKey, newPassphrase) {
242
+ // 1. Fetch encrypted keys from server
243
+ const data = await getJson("/api/user/encryption_key/")
244
+ if (!data.has_key) {
245
+ throw new Error("No encryption keys found")
246
+ }
247
+
248
+ // 2. Decrypt master key backup with recovery key
249
+ const recoveryKeyRaw = PassphraseCrypto._hexToBytes(recoveryKey)
250
+ const recoveryKeyCryptoKey = await crypto.subtle.importKey(
251
+ "raw",
252
+ recoveryKeyRaw,
253
+ {name: "AES-GCM", length: 256},
254
+ false,
255
+ ["encrypt", "decrypt"]
256
+ )
257
+ const masterKey = await PassphraseCrypto.decryptKey(
258
+ data.encrypted_master_key_backup,
259
+ recoveryKeyCryptoKey
260
+ )
261
+
262
+ // 3. Generate new key pair
263
+ const newKeyPair = await PassphraseCrypto.generateKeyPair()
264
+ const newRecoveryKey = PassphraseCrypto.generateRecoveryKey()
265
+ const newSalt = PassphraseCrypto.generateSalt()
266
+
267
+ // 4. Derive new KWK from new passphrase
268
+ const newKwk = await PassphraseCrypto.deriveKWK(newPassphrase, newSalt)
269
+
270
+ // 5. Re-encrypt master key and new private key
271
+ const encryptedMasterKey = await PassphraseCrypto.encryptKey(
272
+ masterKey,
273
+ newKwk
274
+ )
275
+ const encryptedPrivateKey = await PassphraseCrypto.encryptPrivateKey(
276
+ newKeyPair.privateKey,
277
+ newKwk
278
+ )
279
+
280
+ // 6. Create new backup
281
+ const newRecoveryKeyRaw = PassphraseCrypto._hexToBytes(newRecoveryKey)
282
+ const newRecoveryKeyCryptoKey = await crypto.subtle.importKey(
283
+ "raw",
284
+ newRecoveryKeyRaw,
285
+ {name: "AES-GCM", length: 256},
286
+ false,
287
+ ["encrypt", "decrypt"]
288
+ )
289
+ const encryptedMasterKeyBackup = await PassphraseCrypto.encryptKey(
290
+ masterKey,
291
+ newRecoveryKeyCryptoKey
292
+ )
293
+
294
+ // 7. Export new public key
295
+ const publicKeyJwk = await PassphraseCrypto.exportPublicKey(
296
+ newKeyPair.publicKey
297
+ )
298
+
299
+ // 8. Send updated keys to server
300
+ const saveData = {
301
+ data: JSON.stringify({
302
+ public_key: publicKeyJwk,
303
+ encrypted_master_key: encryptedMasterKey,
304
+ encrypted_private_key: encryptedPrivateKey,
305
+ user_salt: PassphraseCrypto._bytesToBase64(newSalt),
306
+ user_iterations: 600000,
307
+ encrypted_master_key_backup: encryptedMasterKeyBackup
308
+ })
309
+ }
310
+ const {status} = await postJson(
311
+ "/api/user/encryption_key/save/",
312
+ saveData
313
+ )
314
+ if (status >= 400) {
315
+ throw new Error("Failed to save updated encryption keys")
316
+ }
317
+
318
+ // 9. Store in sessionStorage
319
+ await PassphraseCrypto.storeKeysInSession(
320
+ masterKey,
321
+ newKeyPair.privateKey
322
+ )
323
+
324
+ return {newRecoveryKey}
325
+ }
326
+
327
+ /**
328
+ * Get the document password for a document.
329
+ *
330
+ * If encrypted with the user's master key, decrypts it directly.
331
+ * If encrypted with the user's public key, decrypts with private key and
332
+ * upgrades to master-key encryption.
333
+ *
334
+ * @param {number} documentId - The document ID
335
+ * @returns {Promise<string|null>} The document password, or null if not available
336
+ */
337
+ static async getDocumentPassword(documentId) {
338
+ const {masterKey, privateKey} =
339
+ await PassphraseCrypto.getKeysFromSession()
340
+ if (!masterKey || !privateKey) {
341
+ return null
342
+ }
343
+
344
+ const {json} = await postJson("/api/document/encryption_key/get/", {
345
+ document_id: documentId
346
+ })
347
+ if (!json.has_key) {
348
+ return null
349
+ }
350
+
351
+ let password
352
+ if (json.encrypted_with_master_key) {
353
+ password = await PassphraseCrypto.decryptString(
354
+ json.encrypted_key,
355
+ masterKey
356
+ )
357
+ } else {
358
+ const parts = json.encrypted_key.split(":")
359
+ if (parts.length !== 2) {
360
+ return null
361
+ }
362
+ password = await PassphraseCrypto.decryptStringWithPrivateKey(
363
+ parts[1],
364
+ parts[0],
365
+ privateKey
366
+ )
367
+ // Upgrade to master-key encryption for next time
368
+ const upgradedEncryptedPassword =
369
+ await PassphraseCrypto.encryptString(password, masterKey)
370
+ await postJson("/api/document/encryption_key/update/", {
371
+ id: json.id,
372
+ encrypted_key: upgradedEncryptedPassword,
373
+ encrypted_with_master_key: true
374
+ })
375
+ }
376
+
377
+ return password
378
+ }
379
+
380
+ /**
381
+ * Create or store a document password for a document.
382
+ *
383
+ * Used when:
384
+ * - Creating a new encrypted document (owner's password encrypted with MK)
385
+ * - Sharing with another passphrase user (password encrypted with their public key)
386
+ *
387
+ * @param {number} documentId - The document ID
388
+ * @param {string} password - The document password
389
+ * @param {number} holderId - The user ID to store the password for (default: current user)
390
+ * @param {string} holderType - "user" or "userinvite"
391
+ * @param {boolean} encryptedWithMasterKey - Whether to encrypt with MK or public key
392
+ * @returns {Promise<Object>} Server response
393
+ */
394
+ static async saveDocumentPassword(
395
+ documentId,
396
+ password,
397
+ holderId = null,
398
+ _holderType = "user",
399
+ encryptedWithMasterKey = true
400
+ ) {
401
+ let encryptedKey
402
+ if (encryptedWithMasterKey) {
403
+ const {masterKey} = await PassphraseCrypto.getKeysFromSession()
404
+ if (!masterKey) {
405
+ throw new Error("Master key not available in session")
406
+ }
407
+ encryptedKey = await PassphraseCrypto.encryptString(
408
+ password,
409
+ masterKey
410
+ )
411
+ } else {
412
+ const pkJson = await getJson(
413
+ `/api/user/encryption_public_key/${holderId}/`
414
+ )
415
+ if (!pkJson.has_key) {
416
+ throw new Error("Recipient has not set up encryption")
417
+ }
418
+ const recipientPublicKey = await PassphraseCrypto.importPublicKey(
419
+ pkJson.public_key
420
+ )
421
+ const encryptedData =
422
+ await PassphraseCrypto.encryptStringWithPublicKey(
423
+ password,
424
+ recipientPublicKey
425
+ )
426
+ encryptedKey = `${encryptedData.ephemeralPublicKeyJwk}:${encryptedData.encryptedData}`
427
+ }
428
+
429
+ const saveData = {
430
+ document_id: documentId,
431
+ encrypted_key: encryptedKey,
432
+ encrypted_with_master_key: encryptedWithMasterKey
433
+ }
434
+ if (holderId) {
435
+ saveData.holder_id = holderId
436
+ }
437
+ const {json, status} = await postJson(
438
+ "/api/document/encryption_key/save/",
439
+ saveData
440
+ )
441
+ if (status >= 400) {
442
+ throw new Error("Failed to save document password")
443
+ }
444
+ return json
445
+ }
446
+
447
+ /**
448
+ * Generate a new random document password that is itself a valid raw DEK.
449
+ * Returns a 44-character base64-encoded 32-byte AES key.
450
+ */
451
+ static generateDocumentPassword() {
452
+ return PassphraseCrypto.generateDocumentPassword()
453
+ }
454
+
455
+ /**
456
+ * Resolve a document password to an AES-GCM key.
457
+ * If the password is a raw DEK (43/44 char base64), use it directly.
458
+ * Otherwise, derive the key via PBKDF2.
459
+ */
460
+ static resolvePasswordToKey(password, salt, iterations) {
461
+ return E2EEKeyManager.resolvePasswordToKey(password, salt, iterations)
462
+ }
463
+
464
+ /**
465
+ * Check if a user has set up encryption keys (for sharing).
466
+ */
467
+ static async userHasEncryptionKeys(userId) {
468
+ try {
469
+ const data = await getJson(
470
+ `/api/user/encryption_public_key/${userId}/`
471
+ )
472
+ return data.has_key === true
473
+ } catch (_e) {
474
+ return false
475
+ }
476
+ }
477
+
478
+ /**
479
+ * Check if user has dismissed the passphrase setup offer.
480
+ */
481
+ static async hasUserDismissedPassphraseOffer() {
482
+ try {
483
+ const data = await getJson("/api/user/preferences/get/")
484
+ return data.preferences?.has_dismissed_passphrase_offer === true
485
+ } catch (_e) {
486
+ return false
487
+ }
488
+ }
489
+
490
+ /**
491
+ * Mark that user has dismissed the passphrase setup offer.
492
+ */
493
+ static async markPassphraseDismissed() {
494
+ try {
495
+ await post("/api/user/preferences/update/", {
496
+ has_dismissed_passphrase_offer: true
497
+ })
498
+ } catch (_e) {
499
+ // Silently fail - preference saving is best-effort
500
+ }
501
+ }
502
+ }