domma-cms 0.92.1 → 0.94.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.
- package/CLAUDE.md +5 -3
- package/admin/css/admin.css +1 -1
- package/admin/js/app.js +2 -2
- package/admin/js/lib/action-editor-arrange.js +1 -1
- package/admin/js/lib/api-tokens-arrange.js +2 -2
- package/admin/js/lib/block-editor-arrange.js +1 -1
- package/admin/js/lib/blocks-arrange.js +1 -1
- package/admin/js/lib/collection-entries-arrange.js +1 -1
- package/admin/js/lib/components-arrange.js +1 -1
- package/admin/js/lib/dashboard-arrange.js +1 -1
- package/admin/js/lib/dates.js +1 -0
- package/admin/js/lib/forms-arrange.js +1 -1
- package/admin/js/lib/media-arrange.js +1 -1
- package/admin/js/lib/notifications-arrange.js +1 -1
- package/admin/js/lib/pages-arrange.js +1 -1
- package/admin/js/lib/related.js +1 -1
- package/admin/js/lib/timeline-builder.js +2 -2
- package/admin/js/templates/action-editor.html +6 -5
- package/admin/js/templates/actions-list.html +1 -1
- package/admin/js/templates/contacts.html +1 -1
- package/admin/js/templates/docs/api-actions.html +86 -60
- package/admin/js/templates/docs/api-authentication.html +159 -123
- package/admin/js/templates/docs/api-builder.html +197 -0
- package/admin/js/templates/docs/api-collections.html +199 -259
- package/admin/js/templates/docs/api-external.html +225 -0
- package/admin/js/templates/docs/api-forms.html +268 -0
- package/admin/js/templates/docs/api-layouts.html +70 -45
- package/admin/js/templates/docs/api-media.html +57 -80
- package/admin/js/templates/docs/api-navigation.html +66 -22
- package/admin/js/templates/docs/api-pages.html +109 -129
- package/admin/js/templates/docs/api-plugins.html +123 -61
- package/admin/js/templates/docs/api-scaffold.html +185 -0
- package/admin/js/templates/docs/api-settings.html +72 -64
- package/admin/js/templates/docs/api-users.html +74 -107
- package/admin/js/templates/docs/api-views.html +68 -54
- package/admin/js/templates/docs/components-howto.html +20 -17
- package/admin/js/templates/docs/components-reference.html +13 -16
- package/admin/js/templates/docs/components-rules.html +7 -6
- package/admin/js/templates/docs/components-walkthrough.html +19 -19
- package/admin/js/templates/docs/tutorial-crud.html +71 -40
- package/admin/js/templates/docs/tutorial-forms.html +51 -35
- package/admin/js/templates/docs/tutorial-plugin.html +132 -56
- package/admin/js/templates/docs/usage-actions.html +61 -15
- package/admin/js/templates/docs/usage-collections.html +108 -0
- package/admin/js/templates/docs/usage-cta-shortcode.html +14 -3
- package/admin/js/templates/docs/usage-dconfig.html +0 -3
- package/admin/js/templates/docs/usage-editions.html +213 -0
- package/admin/js/templates/docs/usage-media.html +22 -6
- package/admin/js/templates/docs/usage-navigation.html +74 -18
- package/admin/js/templates/docs/usage-pages.html +60 -20
- package/admin/js/templates/docs/usage-plugins.html +89 -17
- package/admin/js/templates/docs/usage-shortcodes.html +123 -70
- package/admin/js/templates/docs/usage-site-settings.html +50 -18
- package/admin/js/templates/docs/usage-tools.html +73 -0
- package/admin/js/templates/docs/usage-users-roles.html +99 -20
- package/admin/js/templates/docs/usage-views.html +36 -19
- package/admin/js/templates/documentation.html +153 -32
- package/admin/js/templates/page-editor.html +0 -5
- package/admin/js/templates/plugin-guide.html +15 -0
- package/admin/js/templates/plugin-guides.html +21 -0
- package/admin/js/templates/pro-docs.html +53 -234
- package/admin/js/templates/tutorials.html +5 -4
- package/admin/js/views/actions-list.js +3 -3
- package/admin/js/views/analytics.js +5 -5
- package/admin/js/views/api-endpoint-editor.js +2 -2
- package/admin/js/views/block-editor.js +4 -4
- package/admin/js/views/blocks.js +4 -4
- package/admin/js/views/collection-editor.js +4 -4
- package/admin/js/views/collection-entries.js +7 -7
- package/admin/js/views/component-editor.js +2 -2
- package/admin/js/views/contacts.js +22 -20
- package/admin/js/views/context-menu-editor.js +5 -5
- package/admin/js/views/doc-pages.js +1 -1
- package/admin/js/views/form-editor.js +4 -4
- package/admin/js/views/form-submissions.js +2 -2
- package/admin/js/views/index.js +1 -1
- package/admin/js/views/media.js +3 -3
- package/admin/js/views/menu-editor.js +13 -13
- package/admin/js/views/menu-locations.js +2 -2
- package/admin/js/views/my-profile.js +1 -1
- package/admin/js/views/page-editor.js +8 -8
- package/admin/js/views/plugin-guides.js +5 -0
- package/admin/js/views/project-detail.js +2 -2
- package/admin/js/views/project-settings.js +1 -1
- package/admin/js/views/role-editor.js +4 -4
- package/admin/js/views/search.js +2 -2
- package/admin/js/views/seo.js +17 -17
- package/admin/js/views/settings.js +3 -3
- package/admin/js/views/theme.js +3 -3
- package/admin/js/views/user-editor.js +1 -1
- package/admin/js/views/users.js +2 -2
- package/admin/js/views/view-editor.js +1 -1
- package/bin/cli.js +13 -13
- package/bin/lib/node-version.js +29 -0
- package/package.json +1 -1
- package/plugins/_lib/admin/mail/compose-window.js +3 -2
- package/plugins/_lib/admin/mail/reader-view.js +7 -6
- package/plugins/_lib/admin/mail/scheduling.js +4 -2
- package/plugins/_lib/admin/mail/templates.js +4 -4
- package/plugins/_lib/admin/ui/dates.js +85 -0
- package/plugins/blog/CLAUDE.md +31 -22
- package/plugins/blog/admin/views/blog.js +3 -2
- package/plugins/blog/admin/views/comments.js +2 -1
- package/plugins/blog/admin/views/post-editor.js +4 -4
- package/plugins/blog/blocks/blog-card-row.html +1 -1
- package/plugins/blog/blocks/blog-card.html +2 -2
- package/plugins/blog/blocks/blog-post-classic.html +2 -2
- package/plugins/blog/blocks/blog-post-essay.html +2 -2
- package/plugins/blog/blocks/blog-post-feature.html +2 -2
- package/plugins/blog/blocks/blog-post-minimal.html +2 -2
- package/plugins/blog/blocks/blog-post-sidebar.html +2 -2
- package/plugins/blog/blocks/blog-post-split.html +2 -2
- package/plugins/blog/docs/guide.md +205 -0
- package/plugins/blog/lib/layouts.js +3 -3
- package/plugins/blog/lib/page.js +2 -1
- package/plugins/blog/plugin.js +3 -3
- package/plugins/blog/plugin.json +4 -4
- package/plugins/blog/tests/layouts.test.js +6 -0
- package/plugins/feedback/CLAUDE.md +22 -3
- package/plugins/feedback/admin/lib/kit.js +6 -7
- package/plugins/feedback/admin/views/feedback.js +79 -10
- package/plugins/feedback/admin/views/send.js +28 -6
- package/plugins/feedback/docs/guide.md +95 -0
- package/plugins/feedback/lib/receiver.js +9 -2
- package/plugins/feedback/lib/sender.js +3 -2
- package/plugins/feedback/plugin.js +54 -6
- package/plugins/feedback/plugin.json +4 -4
- package/plugins/feedback/tests/api.test.js +74 -2
- package/plugins/free-tier.lock.json +49 -44
- package/plugins/mail-reader/CLAUDE.md +33 -18
- package/plugins/mail-reader/docs/guide.md +147 -0
- package/plugins/mail-reader/plugin.json +1 -1
- package/plugins/security/CLAUDE.md +4 -1
- package/plugins/security/admin/views/security.js +5 -5
- package/plugins/security/docs/guide.md +170 -0
- package/plugins/security/plugin.js +2 -1
- package/plugins/security/plugin.json +2 -1
- package/plugins/shopping-cart/CLAUDE.md +7 -1
- package/plugins/shopping-cart/admin/lib/kit.js +5 -2
- package/plugins/shopping-cart/admin/views/orders.js +4 -4
- package/plugins/shopping-cart/admin/views/overview.js +2 -2
- package/plugins/shopping-cart/docs/guide.md +191 -0
- package/plugins/shopping-cart/lib/render.js +2 -1
- package/plugins/shopping-cart/plugin.json +3 -3
- package/public/js/collection-browser.js +2 -2
- package/public/js/site.js +1 -1
- package/scripts/gen-instance-secret.js +3 -1
- package/scripts/setup.js +3 -1
- package/server/middleware/auth.js +2 -1
- package/server/routes/api/actions.js +47 -27
- package/server/routes/api/blocks.js +2 -1
- package/server/routes/api/collections.js +16 -52
- package/server/routes/api/contacts.js +66 -3
- package/server/routes/api/documentation.js +42 -0
- package/server/routes/api/notifications.js +3 -2
- package/server/routes/api/users.js +10 -6
- package/server/server.js +16 -1
- package/server/services/actions.js +110 -34
- package/server/services/adapterRegistry.js +169 -16
- package/server/services/adapters/FileAdapter.js +25 -0
- package/server/services/adapters/MongoAdapter.js +23 -0
- package/server/services/collections.js +104 -1
- package/server/services/connectionManager.js +12 -0
- package/server/services/dates.js +81 -0
- package/server/services/docs.js +13 -2
- package/server/services/markdown.js +75 -26
- package/server/services/notification-sources.js +6 -5
- package/server/services/passwordReset.js +2 -1
- package/server/services/permissionRegistry.js +3 -2
- package/server/services/pluginGuides.js +255 -0
- package/server/services/pluginInstaller.js +54 -13
- package/server/services/plugins.js +29 -1
- package/server/services/presetCollections.js +31 -5
- package/server/services/renderer.js +2 -2
- package/server/services/sidebarBadges.js +3 -1
- package/server/services/tools.js +4 -2
- package/server/templates/page.html +2 -2
|
@@ -1,55 +1,56 @@
|
|
|
1
1
|
{
|
|
2
2
|
"note": "Written by `make sync-free-tier` in dcms-marketplace. Do not edit these plugins here - edit them there and sync.",
|
|
3
|
-
"source": "dcms-marketplace@
|
|
3
|
+
"source": "dcms-marketplace@5dcb9db",
|
|
4
4
|
"plugins": {
|
|
5
5
|
"blog": {
|
|
6
|
-
"version": "1.9.
|
|
6
|
+
"version": "1.9.3",
|
|
7
7
|
"files": {
|
|
8
|
-
"CLAUDE.md": "
|
|
8
|
+
"CLAUDE.md": "926730d510cc38f6764ffcb9afbed1c3ae3a547117c6c0243b14f899271350fb",
|
|
9
9
|
"admin/css/index.css": "6142a6b756e1218157842528830b1e84f592f0b84b7d5ce6449db421b6f4b039",
|
|
10
10
|
"admin/templates/blog.html": "a6054c1febe764bb1edf5c9e466d44a9080d9c83ba5486437b7a8244acf5ba54",
|
|
11
11
|
"admin/templates/categories.html": "ab7d6fc2fedd48876c585bc216a1532b3bdd78c946dee976c1171bfe4664feb6",
|
|
12
12
|
"admin/templates/comments.html": "095ff03bd5e1ed9ac75edf1ceb9fbe7b2907a1e35b261672da51e00742c2814a",
|
|
13
13
|
"admin/templates/post-editor.html": "f826089f040a13188087721eaa5324707b2f7d491bad41610682242d5e86cec6",
|
|
14
14
|
"admin/templates/settings.html": "e0730cd57435e592034328a699198d5e1326084767156bfc2289852f5f1a45af",
|
|
15
|
-
"admin/views/blog.js": "
|
|
15
|
+
"admin/views/blog.js": "e260e1b7f9c4b22350d9c4f2170693fabb3d14e0ac9cab1d0e075630b5706fc4",
|
|
16
16
|
"admin/views/categories.js": "75140feb2b382ba0ab4a52c30007845bf576883c99577fc0965783adb8808f6b",
|
|
17
|
-
"admin/views/comments.js": "
|
|
17
|
+
"admin/views/comments.js": "064dad6316dd4aea6bcd414418405894f0e5d282cd5a333c878a6cdbf27b0f2e",
|
|
18
18
|
"admin/views/kit.js": "91292d63a96c1d1e9fdc0c8f931d0f31e07fa37d06f06e0fc45b308863e126aa",
|
|
19
|
-
"admin/views/post-editor.js": "
|
|
19
|
+
"admin/views/post-editor.js": "60da0f8b2d508afd8dbd7671e3b408cf72d81c46b94100cf495439e18d0d63ee",
|
|
20
20
|
"admin/views/settings-cog.js": "307efc93835863dd8511f8fb17a224cf45a77532c90b854a86d2cd1d4e5f9f18",
|
|
21
21
|
"admin/views/settings.js": "2b7f775e37e034dee4ae3dfadea5e446c2e526bed8a066ef3ca2e777146ada23",
|
|
22
22
|
"blocks/blog-card-compact.css": "eb8e8ae9a6461c362bc021ea0396c6b4481047b6b36a50eeb59e47375e49be75",
|
|
23
23
|
"blocks/blog-card-compact.html": "7e1e31923808e6108d57d34309d3442b5d93b4aa4396f0e471e870249934ab8f",
|
|
24
24
|
"blocks/blog-card-row.css": "f5f0249c51a40cc71ff8d054bfa887353badc79730b0f323c76ac32f7d893b44",
|
|
25
|
-
"blocks/blog-card-row.html": "
|
|
25
|
+
"blocks/blog-card-row.html": "da6c25793afc14381dd8aa70cd01b859a1dcce20e859770f6b3b24cea4b0f868",
|
|
26
26
|
"blocks/blog-card.css": "d480a80a7378bd55659e9549bb30d8c106bdae1a9cd450a8c0114bfaefa94cd2",
|
|
27
|
-
"blocks/blog-card.html": "
|
|
27
|
+
"blocks/blog-card.html": "60a45772f7642856fe462dc1ef7e15f6b85a451d9b1a307af7ba814f0a6b1e73",
|
|
28
28
|
"blocks/blog-post-classic.css": "9acac617847b5a10dabd5efccb601572e2751f792c4038475325f11e24142584",
|
|
29
|
-
"blocks/blog-post-classic.html": "
|
|
29
|
+
"blocks/blog-post-classic.html": "380c55a638645ca5bf5810836bcf9327d050123b513007027012f451f2d16558",
|
|
30
30
|
"blocks/blog-post-essay.css": "d1842443927ea7c93772a06ade69fc834099e6820d99767e0aab8e80981a3784",
|
|
31
|
-
"blocks/blog-post-essay.html": "
|
|
31
|
+
"blocks/blog-post-essay.html": "85bb2eafd07192f97fdf7a9690e80aab266edd43277d64fa0e91ebbc37c2d243",
|
|
32
32
|
"blocks/blog-post-feature.css": "7d8a242b627f3826df21d5470e643b386967122ea3585e69f96cce9ffc2452e9",
|
|
33
|
-
"blocks/blog-post-feature.html": "
|
|
33
|
+
"blocks/blog-post-feature.html": "d34cb682f2285f6688a86b539e76f9d2229db4cce61ef0200cf5940148983a80",
|
|
34
34
|
"blocks/blog-post-minimal.css": "2323b84a7d0a99e1c85c30faa18bb2ee16763ff08cfe87f181ffadf8cff84dd0",
|
|
35
|
-
"blocks/blog-post-minimal.html": "
|
|
35
|
+
"blocks/blog-post-minimal.html": "b0fa2e33389b186fc6834e839a424ef0b3122d13e31219cb91dd58ccd82021b9",
|
|
36
36
|
"blocks/blog-post-sidebar.css": "3c66109fa48ca448605eb5acd0c998f43649fb3747813b4a811992ec89886007",
|
|
37
|
-
"blocks/blog-post-sidebar.html": "
|
|
37
|
+
"blocks/blog-post-sidebar.html": "2fb6e1348c4800ae5cea08db02fc842916e16f64ab91ef6a20a47f7db310bba1",
|
|
38
38
|
"blocks/blog-post-split.css": "61ae29850d6c324ffbfc2110a917d5980ad17b0635870656ccd885d20ac9ec86",
|
|
39
|
-
"blocks/blog-post-split.html": "
|
|
39
|
+
"blocks/blog-post-split.html": "1b5fa63eee45b06d62757c96bd069645ace69e3b5a6e145ba1612626b2e4c7a2",
|
|
40
40
|
"collections/categories/schema.json": "0728e522ed8e3c623fd45e137cd03e0960aa5158e70613ec8628c8b3928e0929",
|
|
41
41
|
"collections/comments/schema.json": "29cbd289cbfcfc4158c9357a218db4ce06eddc3370bfbf9afb7d7f52065a849e",
|
|
42
42
|
"collections/posts/schema.json": "19a5a770d3eefea73f4117454bd1312a7a7e3d727cfcdfde141139fbc81cabd7",
|
|
43
43
|
"config.js": "ee67396262762f5c31269d258affd75f7392a3e364f72f7792c2f1cdafd94bba",
|
|
44
|
+
"docs/guide.md": "6a7466881851797789a18e0d32c4fcb515f2259b110948c55be03923c38e0de5",
|
|
44
45
|
"lib/access.js": "af47440c7233a56000641a3231d7e9ff81b12f40dfb9528aa6dd4e2dd9bca8df",
|
|
45
|
-
"lib/layouts.js": "
|
|
46
|
+
"lib/layouts.js": "0a921fb427c5ffe0a31eb687a6f8f10cb5573a1ad638a88ce386b687b49a2692",
|
|
46
47
|
"lib/nav-link.js": "6a8f9368bb8aee1c21e90fb335a691859cb9a9bc250c2b9167a33ca9189fa2ff",
|
|
47
48
|
"lib/notices.js": "a9a2918ee6f5f7e0bbaeced0d3539584279bdbe68d15472a8615bdddb4ef905b",
|
|
48
|
-
"lib/page.js": "
|
|
49
|
+
"lib/page.js": "bfb6a355a027feaf775d6d8ac871fc6d999354774e018f8e16caec551e99f40a",
|
|
49
50
|
"lib/render.js": "0e97c6a950bc962c8d8ea4b2f21d06cb73fbcdc738d8942d6935d01309a29b1d",
|
|
50
51
|
"lib/samples.js": "e8cdb77ce22e43937707f6854d3a5cb722437dc584e22ac7b24480bef686cf85",
|
|
51
|
-
"plugin.js": "
|
|
52
|
-
"plugin.json": "
|
|
52
|
+
"plugin.js": "0aa46a01b5298065497f39729b88e34a9f56ac684b0a14f8d94ab6007f0221d0",
|
|
53
|
+
"plugin.json": "f74ba12c5dfef7d0b9accd267cc0c4e333ea61a936cc8afa565db82da5b02389",
|
|
53
54
|
"plugin.public.js": "ab23fadd5655fab8eea0e636a3e1f8ced78432d6da929059a4a147f0805ff3a4",
|
|
54
55
|
"public/blog.css": "fd733e6b624190da1e70dc1b6613e2376efd7f7570a28fab311d81006d03d960",
|
|
55
56
|
"public/blog.js": "d01c72a9834dcc7c5241923371f2b164ac30d20ac9f1a5c5dc5b71fa3cb09f08",
|
|
@@ -65,47 +66,49 @@
|
|
|
65
66
|
"templates/post.html": "28e9f06071115ecc4fbba007b35782732bf12ef72528525893d424e3c4f0313f",
|
|
66
67
|
"tests/access.test.js": "65b760910117c3a44195543acdcff91074f39b4e5567911a2bd8676204152cb2",
|
|
67
68
|
"tests/comment-notices.test.js": "34026cc9a2a4746cf87bc41df8be849fadaa43091a72ac2aa1d06c1f437bf618",
|
|
68
|
-
"tests/layouts.test.js": "
|
|
69
|
+
"tests/layouts.test.js": "4219d0e1dab7ed11d176e8eb55086531fc4eaf375cdf3d7aea5b85073d2ace7e",
|
|
69
70
|
"tests/nav-link.test.js": "d36e33ad7483abca27ae6e2098ad2f75bafa18d91f3beba70372ebe6b9b88994",
|
|
70
71
|
"tests/notices.test.js": "2b02aa84e780dc4c82e6c503fc8fe17c64a63bee0709627866ef97c99cb4e131",
|
|
71
72
|
"tests/public.test.js": "a6fcdc4ede242aa050ffe5a52f970d6bec1f4a70ae78967eb8a7bdeec73df19d"
|
|
72
73
|
}
|
|
73
74
|
},
|
|
74
75
|
"feedback": {
|
|
75
|
-
"version": "1.
|
|
76
|
+
"version": "1.1.2",
|
|
76
77
|
"files": {
|
|
77
|
-
"CLAUDE.md": "
|
|
78
|
+
"CLAUDE.md": "38122c71cacfda28fa87afd3321ae77b8a8b02facfa2f0d1bc637e6cfa59e448",
|
|
78
79
|
"admin/css/index.css": "f2e934c8b94f883340148aba17945dfa725eeb2b0ddb6cabb8a8c17e2487c1de",
|
|
79
|
-
"admin/lib/kit.js": "
|
|
80
|
+
"admin/lib/kit.js": "913761a2cc19b69bed3f05267d45fdb1c08338b1edb081b9272231733d9b5790",
|
|
80
81
|
"admin/templates/feedback.html": "a366dce78f6c3e84a7cb0ac63eba53e1980a4eb44154496a0536f5214c5bb36f",
|
|
81
|
-
"admin/views/feedback.js": "
|
|
82
|
+
"admin/views/feedback.js": "ac33bf7de7445722dd055dcd9b6737a545b70379863328bc0d112abe52ce29c3",
|
|
82
83
|
"admin/views/inbox.js": "649b86844230be73939d82aa7c97432252c0b119baa102ebf53808e1d5f23737",
|
|
83
|
-
"admin/views/send.js": "
|
|
84
|
+
"admin/views/send.js": "5868038a4020158746c5705d2a0ab5f552ac5021328a1dcf64a2def890495427",
|
|
84
85
|
"collections/feedback-reports.json": "a072291b52463f7785a77f5f77d36b8238ba8f89cfc2672c6642eccdb3144486",
|
|
85
86
|
"config.js": "29d9999d1028c2c11931f67fb9abdf35132430b7cf58c161681e734c0b45143a",
|
|
86
|
-
"
|
|
87
|
-
"lib/
|
|
87
|
+
"docs/guide.md": "e006cc3f3c114583285964bc1b5d22b2a01285c2d2015d132434bfed363917d4",
|
|
88
|
+
"lib/receiver.js": "c6ab2858dc7bfff6de19b41c84295c0c918ba50ddc57f6d3d83f1352662ebd91",
|
|
89
|
+
"lib/sender.js": "037f9b4469a34ffe1d302a633e664860d625f7fb3be4dfadd01b8a3d094849b7",
|
|
88
90
|
"lib/shape.js": "67acf62f812c2c9a01b52776641ed7ae1601c59ebab8ea278a07d1087a9f299b",
|
|
89
|
-
"plugin.js": "
|
|
90
|
-
"plugin.json": "
|
|
91
|
-
"tests/api.test.js": "
|
|
91
|
+
"plugin.js": "96c95eb4c4c0b84c23822eb6e69aa8ae050d1ba14b283be848bcaa5b236a1ceb",
|
|
92
|
+
"plugin.json": "1cc8f582be6b73e39fa1600ea738a5173d6c7378b01b092d35999d8f5de80741",
|
|
93
|
+
"tests/api.test.js": "e822b0b9cd2dc5d32eb1f77ae76e34adfe13fb7d0fbe77fe3a7c3cca2a9c6b11",
|
|
92
94
|
"tests/shape.test.js": "5133578142a79cc1a100b3215436372129f01fb0de8c757fd743ff99e1d7e37f"
|
|
93
95
|
}
|
|
94
96
|
},
|
|
95
97
|
"mail-reader": {
|
|
96
|
-
"version": "1.2.
|
|
98
|
+
"version": "1.2.3",
|
|
97
99
|
"files": {
|
|
98
|
-
"CLAUDE.md": "
|
|
100
|
+
"CLAUDE.md": "e7722bf8464087e6568bac2f3cf2cf1eb4a84702e3f5d591737976db4fe5313e",
|
|
99
101
|
"admin/views/mail.js": "c5c6483f9618c75cac8f4be32d3aea99511db76d4b9d38b8ef43bdc1d35db3c5",
|
|
100
102
|
"config.js": "6e65803ad822a9acda40c203631b8eb32a87cf9d9e5f1c7cb59d01aa406075c6",
|
|
103
|
+
"docs/guide.md": "518441f4dcbd95c1318e1db9ad002b024dbe7b2aa3dee479ebb6976f00355d18",
|
|
101
104
|
"plugin.js": "7f602a60c4eca7d3637659d03d5de9e242584666846b16c9e5a1b758e4856c9f",
|
|
102
|
-
"plugin.json": "
|
|
105
|
+
"plugin.json": "2cae5b11f9975bcf76aa6369001e42ba4e5cf5bc3cee169f125720383acd7fdb"
|
|
103
106
|
}
|
|
104
107
|
},
|
|
105
108
|
"security": {
|
|
106
|
-
"version": "1.1.
|
|
109
|
+
"version": "1.1.3",
|
|
107
110
|
"files": {
|
|
108
|
-
"CLAUDE.md": "
|
|
111
|
+
"CLAUDE.md": "29507f4460053b1a16a1902d47c007213d83ad3b497e86398ccaab92d07d3d51",
|
|
109
112
|
"admin/lib/blocks.js": "5ef346b7de751518f8beb9212e3b89b270ae236560ae3d8a1f40d129c50918ff",
|
|
110
113
|
"admin/lib/health.js": "3b233a3d29b2d69c333321602c13233b8221cfe1114aa03903739d9ae8ad65d5",
|
|
111
114
|
"admin/lib/ip.js": "cf33be4fa2e2cad37bafd12ebec17f293891a88de402caad1bf9c9a57ce87680",
|
|
@@ -115,11 +118,12 @@
|
|
|
115
118
|
"admin/lib/resets.js": "3724a2aec9f3c18ada96948aa6ce375ae3505bb7623a2c556e2e2670c5ca343c",
|
|
116
119
|
"admin/lib/settings.js": "b319953914f3a6f029ba991b36fe6fcd521956ea099578be42505f30e6c32faf",
|
|
117
120
|
"admin/templates/security.html": "df5798497ca1fd5ed200ce0ff921a055168ac7720f38b2db1bebf2c0efe71f04",
|
|
118
|
-
"admin/views/security.js": "
|
|
121
|
+
"admin/views/security.js": "89c8dcaea89a0b8999798ecb84e9b41e5a08ceefa404aff529b02a6f28874361",
|
|
119
122
|
"bin/unlock.js": "5fcc3c0ef3ba3c424a366aa62896f51abad578183dfde283aa838a86549ca785",
|
|
120
123
|
"config.js": "e6a00f7816637687d6a68ebbac65a71489246a926c28523c2a78d859e75b7ae0",
|
|
121
|
-
"
|
|
122
|
-
"plugin.
|
|
124
|
+
"docs/guide.md": "a27d5303f9146057fd79c2093d7476ada1a5ee4fd14d34df7f94ad8555d88ca0",
|
|
125
|
+
"plugin.js": "9d3a2e8b56dd637407c8abd93252dda9f67042231bc79d35771f766a62022c14",
|
|
126
|
+
"plugin.json": "c3457c117c66a8434318e51e13f0569d5b0f3f5e8500c9864a95c9c91049ce15",
|
|
123
127
|
"server/common-passwords.NOTICE": "3b148a49a569bfa24feaa7879db602da8f0607fa61ab6c52b7a62391fc7c009a",
|
|
124
128
|
"server/common-passwords.txt": "68782d6a4a19a4768d5f15dd66bd534e7a33055cc755411e33f16d18c50fdcce",
|
|
125
129
|
"server/facts.js": "25538a8d1cfe012688fceb8ec0d0dd7b43ac9e168430723d6fb731183701fb46",
|
|
@@ -128,30 +132,31 @@
|
|
|
128
132
|
}
|
|
129
133
|
},
|
|
130
134
|
"shopping-cart": {
|
|
131
|
-
"version": "1.0.
|
|
135
|
+
"version": "1.0.3",
|
|
132
136
|
"files": {
|
|
133
|
-
"CLAUDE.md": "
|
|
137
|
+
"CLAUDE.md": "fb9167502ceac9b1cc264f6c287c2e778e628137c87b6f87f84959618df4f1cb",
|
|
134
138
|
"admin/css/index.css": "a6bab1d0072e364ee1d94c2d7d7b99c3660ba91c5eba537e269a579f5b17f924",
|
|
135
|
-
"admin/lib/kit.js": "
|
|
139
|
+
"admin/lib/kit.js": "c2111d1b10c6c8b18bc061f9f55c83ee8baecc2bcff66f74eb38298f39886d86",
|
|
136
140
|
"admin/templates/shop.html": "c5bb03f1f7cbabfbd8202f3533783eb1848103755b1ba25fdcf1fd8e9478cb8e",
|
|
137
|
-
"admin/views/orders.js": "
|
|
138
|
-
"admin/views/overview.js": "
|
|
141
|
+
"admin/views/orders.js": "e69694e5fe0b56662a2df3f7c7b8a5cc5f9a602debda469c2da464cb78fdd458",
|
|
142
|
+
"admin/views/overview.js": "6abd9779cf5fc359c4708f96cf0e8ecad155fb52583b2ec854400b288fc9ba98",
|
|
139
143
|
"admin/views/products.js": "4947de61aa57da59fd0e819ac0f5380bbdee6b73855bd91d3872445fdd6c3e2d",
|
|
140
144
|
"admin/views/settings.js": "28cb0b5e8d45e3723ffe77e46299bfc13fbad02a2ae8103843c6894dc232387a",
|
|
141
145
|
"admin/views/shop.js": "a53a1793251b962a87c5d01685f934b6476bcfcdd51e3dea3a319eb8c03a4137",
|
|
142
146
|
"collections/shop-orders.json": "0bca8eef2d5f9108651f73d273480265c167dc983aa115ce59613d13015ca255",
|
|
143
147
|
"collections/shop-products.json": "4d4613ecec7b8a5a0744c4f0a57b17a4429b461e060206a4bbdea5ad7c8c75dc",
|
|
144
148
|
"config.js": "dcb91db2839c1ab9e40bb1811397024fad9e37e3753d17e2baa2b9b31d4a7d7c",
|
|
149
|
+
"docs/guide.md": "cc9935594a14ea8cda1eb0d9c507bbc580ba30c8d6beb9265f55f9b03a4c1ba1",
|
|
145
150
|
"inject/body.html": "de20f92c83229545d20e5186fd37ef0046a8820881bff34e7df5391cd7a2c75d",
|
|
146
151
|
"lib/extensions.js": "2cba90efef5b437ace557c7265fe7363ac7923d155681087a63e31e1168f6601",
|
|
147
152
|
"lib/payments.js": "84ad14813688de1f38448b4935180a786cda8af2f7f4b8890a8f1d426982d1aa",
|
|
148
153
|
"lib/pricing.js": "94953075062e9b36cdbd6ea149662d013d97ee12359a9ff7459669beff99ab99",
|
|
149
|
-
"lib/render.js": "
|
|
154
|
+
"lib/render.js": "310d528f69cd0160db3bd3d3c88f16221e43004c93856587175c0bb149fe3a3d",
|
|
150
155
|
"lib/samples.js": "912b3d5bd543dffa5f870caf3c2b873f642fd55e3ebf3f97e1b31eeaaac77d3b",
|
|
151
156
|
"lib/shop.js": "36e1cea342e23f1a53b9fac63b993f860afc1bcb74b25bef9f7bf8eaf07d2d85",
|
|
152
157
|
"lib/summary.js": "a510386e28eb19d9617f488551d1057819ae9f76fc85c744f2e5dbce492607fe",
|
|
153
158
|
"plugin.js": "594c2174e36566f90ac1e9ff11cb76656ad111dc392dc8e9556d731b7dd0a41a",
|
|
154
|
-
"plugin.json": "
|
|
159
|
+
"plugin.json": "1d76fea187dea958b82e752e5d6e7a729217b08b061490c8590e2c6e6537496e",
|
|
155
160
|
"plugin.public.js": "176383dfa7af913c433e0397584c46a67a21ab3307b80a08f0aaf50da2634f9e",
|
|
156
161
|
"public/cart.js": "fcc706773a36e4bfd02ea235bcdad629137e996218e0a0e23892e33c689f2a6e",
|
|
157
162
|
"public/lib/money.js": "d22b2b6f80dde6f7887b69e24188c05ea93c02217aba639b5331aa3bd616f4fc",
|
|
@@ -1,26 +1,30 @@
|
|
|
1
|
-
# mail-reader
|
|
1
|
+
# mail-reader - AI Assistant Guide
|
|
2
2
|
|
|
3
3
|
## Purpose
|
|
4
4
|
|
|
5
5
|
Read-only IMAP mailbox reader. Connects to a **standard IMAP server** and displays mail. It
|
|
6
6
|
deliberately cannot write: no mark-as-read, no flagging, no move, no delete, no send.
|
|
7
7
|
|
|
8
|
-
Full mail (sending, flags, drafts, search, sync) is **`email-pro`**
|
|
9
|
-
that requires MongoDB. Nothing here should grow toward it by accident
|
|
8
|
+
Full mail (sending, flags, drafts, search, sync) is **`email-pro`** - a separate Pro-tier plugin
|
|
9
|
+
that requires MongoDB. Nothing here should grow toward it by accident - phase 1 keeps **no message store at
|
|
10
10
|
all**, which is what makes the Pro sync layer a clean addition rather than a migration.
|
|
11
11
|
|
|
12
12
|
## Files
|
|
13
13
|
|
|
14
|
-
- `plugin.json`, `config.js`, `plugin.js`
|
|
15
|
-
|
|
14
|
+
- `plugin.json`, `config.js`, `plugin.js` - manifest, defaults, and the wiring: it registers
|
|
15
|
+
`registerReadRoutes()` from `_lib/mail/readRoutes.js` behind the `email` permission, and nothing else
|
|
16
|
+
- `admin/views/mail.js` - the only admin file in this plugin. Its template and stylesheet are shared with
|
|
17
|
+
Email Pro and live in `plugins/_lib/admin/mail/` (`mail.html`, `mail.css`, and the section modules such
|
|
18
|
+
as `image-senders-section.js` and `diagnostics-section.js`)
|
|
16
19
|
|
|
17
|
-
The IMAP core
|
|
20
|
+
The IMAP core - crypto, account store, connection pool, renderer - is **not here**. It lives in
|
|
18
21
|
`plugins/_lib/mail/`, shared with `email-pro`, with its state at `plugins/_lib/data/`. See
|
|
19
22
|
`plugins/_lib/mail/CLAUDE.md` before changing anything about credentials or connections.
|
|
20
23
|
|
|
21
24
|
## Routes
|
|
22
25
|
|
|
23
|
-
All under `/api/plugins/mail-reader
|
|
26
|
+
All under `/api/plugins/mail-reader`. Every route but `/body` needs a signed-in user holding the `email`
|
|
27
|
+
permission (`read`); `/body` takes a short-lived signed token instead (below).
|
|
24
28
|
|
|
25
29
|
| Method | Path | Purpose |
|
|
26
30
|
|---|---|---|
|
|
@@ -34,6 +38,12 @@ All under `/api/plugins/mail-reader`, all requiring authentication.
|
|
|
34
38
|
| GET | `/messages` | One page of envelopes, newest first. `?account=&folder=&page=&limit=` |
|
|
35
39
|
| GET | `/messages/:uid` | One message, rendered. `?account=&folder=&images=load` |
|
|
36
40
|
| GET | `/messages/:uid/attachments/:index` | Streams one part as a download. `?account=&folder=` |
|
|
41
|
+
| GET | `/body` | A message body as its own document for the sandboxed iframe, with its own CSP. Authorised by a short-lived token naming one message for one user (an `<iframe src>` cannot send a Bearer header). |
|
|
42
|
+
| GET | `/diagnostics` | This build and its configuration for a bug report: hosts, usernames, the key SOURCE - never a key or password. |
|
|
43
|
+
| GET | `/image-senders` | The senders whose remote images always load, and whether remembering is on. |
|
|
44
|
+
| POST | `/image-senders` | Trust a sender's images from now on. |
|
|
45
|
+
| DELETE | `/image-senders` | Stop trusting one. |
|
|
46
|
+
| PUT | `/image-senders/remember` | Turn trusted senders on or off; off ignores the list without discarding it. |
|
|
37
47
|
|
|
38
48
|
A user may hold several mailboxes. Omitting `?account=` selects their first one, so the reader can
|
|
39
49
|
open on something rather than asking which before it has shown anything.
|
|
@@ -42,13 +52,16 @@ open on something rather than asking which before it has shown anything.
|
|
|
42
52
|
|
|
43
53
|
- **Read-only is enforced, not merely omitted.** Mailboxes open `{readOnly: true}` and ImapFlow
|
|
44
54
|
fetches with `BODY.PEEK[]`. Drop either and the server sets `\Seen` as a side effect of *reading*
|
|
45
|
-
a message
|
|
55
|
+
a message - the user's phone then shows mail they never opened. There is no route that writes;
|
|
46
56
|
keep it that way until mark-as-read is a deliberate, visible action.
|
|
47
|
-
- **
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
57
|
+
- **The `email` permission (1.2), shared with Email Pro.** plugin.json declares it with
|
|
58
|
+
`grant: ["admin"]`, so admins hold it from the moment the plugin is enabled; give it to other roles under
|
|
59
|
+
Roles. Every route checks it (`mayUse` wrapped into `authenticate` in plugin.js; an older core without
|
|
60
|
+
`requirePermission` keeps the old signed-in rule). On top of that, access is ownership: every route
|
|
61
|
+
resolves the account from `request.user`, and no route takes someone else's id. (Before 1.2 there was
|
|
62
|
+
deliberately no resource, because one declared WITHOUT a grant would have 403ed everyone - the `grant`
|
|
63
|
+
is what makes it safe.)
|
|
64
|
+
- **Credentials are not a collection.** `schema.plugin` is a badge, not a visibility gate - a
|
|
52
65
|
plugin-owned collection still appears in admin Collections with a working Entries link, is
|
|
53
66
|
reachable via `/api/v1`, and can be pointed at a shared Mongo. Hence `data/accounts.json`, 0600,
|
|
54
67
|
gitignored, and excluded from the npm `files` list.
|
|
@@ -61,12 +74,14 @@ open on something rather than asking which before it has shown anything.
|
|
|
61
74
|
- **`transformTags` runs BEFORE attribute filtering** in sanitize-html. `target` and `rel` must be
|
|
62
75
|
on `allowedAttributes.a` or the values the transform just set are stripped straight back off, and
|
|
63
76
|
links inside the sandboxed iframe silently do nothing. This has already been fixed once.
|
|
64
|
-
- **Remote images are blocked by default
|
|
65
|
-
lives in a `Set` in the view
|
|
66
|
-
|
|
77
|
+
- **Remote images are blocked by default.** "Load images" on one message is never persisted - it
|
|
78
|
+
lives in a `Set` in the view - because loading a remote image reports the open back to the sender.
|
|
79
|
+
What IS persisted is the per-user list of **trusted image senders** (`/image-senders`): a sender added
|
|
80
|
+
there always has its images loaded, and the whole list can be switched off without losing it. That is a
|
|
81
|
+
deliberate, visible choice per sender, not a forgotten global preference.
|
|
67
82
|
- **The iframe sandbox has neither `allow-scripts` nor `allow-same-origin`.** That pair is the whole
|
|
68
83
|
defence. `allow-popups` is there only so links can open in a new tab.
|
|
69
|
-
- **Attachment downloads go through `fetch` + blob**, not a plain `<a href>`
|
|
84
|
+
- **Attachment downloads go through `fetch` + blob**, not a plain `<a href>` - the route needs the
|
|
70
85
|
bearer token, which a link cannot carry.
|
|
71
86
|
- **Single-process only.** The connection pool is module state, like the messages plugin's SSE
|
|
72
87
|
registry. Multiple workers would each open their own connections and hit per-user server limits.
|
|
@@ -74,7 +89,7 @@ open on something rather than asking which before it has shown anything.
|
|
|
74
89
|
## Testing
|
|
75
90
|
|
|
76
91
|
`services/secretbox.js` and `services/render.js` are pure and unit-tested. Connection behaviour
|
|
77
|
-
should be checked against a **real IMAP server**
|
|
92
|
+
should be checked against a **real IMAP server** - `mail.dommajs.org` answers on 993 (TLS) and 143
|
|
78
93
|
(STARTTLS). A wrong-credentials attempt is enough to verify TLS, auth-failure mapping and that the
|
|
79
94
|
pool leaves nothing open; it does not verify folder listing or rendering, which need a real mailbox.
|
|
80
95
|
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Guide
|
|
3
|
+
order: 1
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Mail Reader lets you read your own email inside the admin. It connects to any standard IMAP mail server and never changes anything there: nothing is marked as read, moved, deleted or sent.
|
|
7
|
+
|
|
8
|
+
## What it does
|
|
9
|
+
|
|
10
|
+
- Three panes: **Folders**, the message list and the message itself. Drag the dividers to resize them.
|
|
11
|
+
- Several mailboxes per person. Each person sees only their own mailboxes; nobody else in the admin can see them.
|
|
12
|
+
- Read-only by design. Opening a message does not mark it as read on the server, so your phone or desktop mail app still shows exactly what you have and have not read.
|
|
13
|
+
- Remote images are blocked until you ask for them.
|
|
14
|
+
- Attachments can be downloaded.
|
|
15
|
+
- An unread count on the **Mail Reader** sidebar item, taken from each mailbox's Inbox.
|
|
16
|
+
|
|
17
|
+
Mail Reader is free. For sending, replying, flags, moving, deleting and search, see "Mail Reader or Email Pro" below.
|
|
18
|
+
|
|
19
|
+
## Getting started
|
|
20
|
+
|
|
21
|
+
You need your mailbox's IMAP details from your email provider: the server name, port, username and password.
|
|
22
|
+
|
|
23
|
+
1. Open [Mail Reader](#/plugins/mail-reader) from the admin sidebar.
|
|
24
|
+
2. If no mailbox is set up yet, click **Add a mailbox**. Otherwise click the cog at the top of the **Folders** pane (**Mail account settings**).
|
|
25
|
+
3. On the **Mailboxes** tab, click **Add mailbox**.
|
|
26
|
+
4. Fill in:
|
|
27
|
+
- **Name** - what to call this mailbox, for example "Office".
|
|
28
|
+
- **IMAP server** - for example `mail.example.com`.
|
|
29
|
+
- **Port** - 993 for TLS, 143 without.
|
|
30
|
+
- **Username** and **Password**.
|
|
31
|
+
- **Use TLS (port 993)** - leave ticked unless your provider says otherwise. Ticking or unticking it switches the port between 993 and 143 until you type a port yourself.
|
|
32
|
+
5. Click **Test connection**. Fix anything it reports.
|
|
33
|
+
6. Click **Save**. Your folders appear on the left.
|
|
34
|
+
|
|
35
|
+
## Screens
|
|
36
|
+
|
|
37
|
+
### Folders
|
|
38
|
+
|
|
39
|
+
- Click a folder to list its messages. Folders that cannot hold mail are hidden.
|
|
40
|
+
- The cog opens **Mail Settings**.
|
|
41
|
+
|
|
42
|
+
### Message list
|
|
43
|
+
|
|
44
|
+
- Newest first, 50 messages a page. Use **Newer** and **Older** to page.
|
|
45
|
+
- Icons on a row show high priority, messages you have replied to, and attachments.
|
|
46
|
+
- **Refresh** (the circular arrow) fetches the list again.
|
|
47
|
+
- Right-click a message for **Open**, **Copy sender's address**, **Copy subject** and **Add sender to contacts**. The last one is shown only when the Contacts Tool is switched on, and is greyed out when the sender is already in your contacts.
|
|
48
|
+
|
|
49
|
+
### Message
|
|
50
|
+
|
|
51
|
+
- The header shows who sent it and when. Click **Show headers** for Reply-To, all recipients and the message id; **Hide headers** folds them again. Your choice is remembered.
|
|
52
|
+
- Messages are shown in a locked-down frame: scripts in email never run.
|
|
53
|
+
- If a message has remote images, a notice says how many were blocked. Click **Load images** to load them for this message only. Loading them tells the sender you opened it.
|
|
54
|
+
- **Always from** (followed by the sender's address) trusts that sender, so their images load straight away in future. It appears only when **Offer to remember senders** is on (see Settings).
|
|
55
|
+
- Click an attachment to download it.
|
|
56
|
+
|
|
57
|
+
### Keyboard
|
|
58
|
+
|
|
59
|
+
Press `?` to see the list.
|
|
60
|
+
|
|
61
|
+
| Key | Does |
|
|
62
|
+
|---|---|
|
|
63
|
+
| Up and Down, or j and k | Move through the list |
|
|
64
|
+
| Left and Right | Move between folders and messages |
|
|
65
|
+
| Enter | Open |
|
|
66
|
+
| Esc | Clear the selection |
|
|
67
|
+
| ? | Show the shortcut list |
|
|
68
|
+
|
|
69
|
+
The list also names shortcuts for replying, starring and deleting. In Mail Reader they do nothing; they work only in Email Pro.
|
|
70
|
+
|
|
71
|
+
## Settings
|
|
72
|
+
|
|
73
|
+
Click the cog in the **Folders** pane to open **Mail Settings**. It has three tabs.
|
|
74
|
+
|
|
75
|
+
### Mailboxes
|
|
76
|
+
|
|
77
|
+
Lists your mailboxes with **Edit** and **Remove**, plus **Add mailbox**.
|
|
78
|
+
|
|
79
|
+
- When you edit a mailbox, leave **Password** blank to keep the saved one.
|
|
80
|
+
- **Remove** forgets the mailbox and deletes its stored password. Nothing on the mail server changes.
|
|
81
|
+
- Passwords are stored encrypted on the server and are never sent back to the browser.
|
|
82
|
+
|
|
83
|
+
### Images
|
|
84
|
+
|
|
85
|
+
- Lists the senders you trust. Their remote images load without asking. Click **Stop trusting** to remove one.
|
|
86
|
+
- **Offer to remember senders** switches trusted senders on or off for the current mailbox. Switching it off ignores the list but keeps it.
|
|
87
|
+
|
|
88
|
+
### Diagnostics
|
|
89
|
+
|
|
90
|
+
Shows what the screen knows about itself: the build it is running, the mailbox and folder, and recent errors. Click **Copy diagnostics** to copy it for a support request. It never shows passwords.
|
|
91
|
+
|
|
92
|
+
### Site-wide options
|
|
93
|
+
|
|
94
|
+
Whoever runs the site can change these in the plugin's configuration file (`config/plugins.json`). There is no screen for them.
|
|
95
|
+
|
|
96
|
+
| Option | Default | Meaning |
|
|
97
|
+
|---|---|---|
|
|
98
|
+
| `listLimit` | 50 | Messages per page |
|
|
99
|
+
| `allowRemoteImages` | false | Load remote images without asking |
|
|
100
|
+
| `allowInsecureTLS` | false | Accept mail server certificates that do not verify (see Tips) |
|
|
101
|
+
| `connectionTimeoutMs` | 20000 | How long to wait for a mail server, in milliseconds |
|
|
102
|
+
| `maxConnections` | 20 | Most mail server connections kept open at once |
|
|
103
|
+
| `maxMessageBytes` | 25000000 | Largest message that will be opened, in bytes |
|
|
104
|
+
|
|
105
|
+
## Permissions and roles
|
|
106
|
+
|
|
107
|
+
In System > Roles, Mail Reader uses the **Email** permission in the **Plugins** group. It has one action:
|
|
108
|
+
|
|
109
|
+
| Action | Label | Allows |
|
|
110
|
+
|---|---|---|
|
|
111
|
+
| `email.read` | Use | Add your own mailboxes and read them |
|
|
112
|
+
|
|
113
|
+
Only the **admin** role has it by default. To let other staff read their own mail here, give their role **Email > Use**. Even with this permission, people only ever see their own mailboxes.
|
|
114
|
+
|
|
115
|
+
Email Pro uses the same **Email** permission.
|
|
116
|
+
|
|
117
|
+
## Tips
|
|
118
|
+
|
|
119
|
+
- **Use the mail server's real name.** If **Test connection** says "The mail server's TLS certificate could not be verified", the server name you typed probably does not match the name on the server's certificate. This often happens with a name like `mail.yourdomain.com` when the provider's certificate is issued for their own host name. Ask your provider for the exact IMAP host name (the one their certificate covers) and use that. Your mailbox is the same either way.
|
|
120
|
+
- Only set `allowInsecureTLS` to true for a mail server you control that has a self-signed certificate. It turns off the check that the server is who it says it is, for every mailbox on the site.
|
|
121
|
+
- Other error messages mean:
|
|
122
|
+
- "That mail server hostname could not be resolved" - check the spelling of **IMAP server**.
|
|
123
|
+
- "The mail server refused the connection on that port" - check **Port** and **Use TLS**.
|
|
124
|
+
- "The mail server rejected that username and password" - check the login details. Some providers need an app password.
|
|
125
|
+
- Your pane widths and folded folders are remembered in your browser, and carry over if you move to Email Pro.
|
|
126
|
+
|
|
127
|
+
## Mail Reader or Email Pro
|
|
128
|
+
|
|
129
|
+
| | Mail Reader (free) | Email Pro (paid) |
|
|
130
|
+
|---|---|---|
|
|
131
|
+
| Read mail, folders, attachments | Yes | Yes |
|
|
132
|
+
| Marks mail as read on the server | Never | Yes, like any mail app |
|
|
133
|
+
| Send, reply, forward, drafts | No | Yes |
|
|
134
|
+
| Flag, move, delete, spam | No | Yes |
|
|
135
|
+
| Search and conversations | No | Yes |
|
|
136
|
+
| Rules, away message, send later, snooze | No | Yes |
|
|
137
|
+
| Needs MongoDB | No | For search, conversations, rules, send later, snooze and the away message. Without it, reading, filing and sending still work. |
|
|
138
|
+
|
|
139
|
+
When Email Pro is installed it takes over from Mail Reader. Your saved mailboxes, passwords and trusted senders carry across.
|
|
140
|
+
|
|
141
|
+
## Limitations
|
|
142
|
+
|
|
143
|
+
- Read only. It cannot send, reply, mark as read, flag, move or delete.
|
|
144
|
+
- No search, and no conversation (thread) view.
|
|
145
|
+
- IMAP only. There is no sign-in with Google or Microsoft accounts; use the provider's IMAP settings and, where needed, an app password.
|
|
146
|
+
- The unread badge counts each mailbox's Inbox only. It is refreshed at most once a minute.
|
|
147
|
+
- Mail connections are kept by the running site. The site must run as a single server process; several worker processes for one site are not supported.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mail-reader",
|
|
3
3
|
"displayName": "Mail Reader",
|
|
4
|
-
"version": "1.2.
|
|
4
|
+
"version": "1.2.3",
|
|
5
5
|
"tier": "free",
|
|
6
6
|
"description": "Read-only IMAP mailbox reader. Connects to a standard IMAP server and reads mail without ever writing to it.",
|
|
7
7
|
"author": "Darryl Waterhouse",
|
|
@@ -27,6 +27,8 @@ Ships with the engine (free tier, `make sync-free-tier`); switched ON when it fi
|
|
|
27
27
|
Unknown = 'info', never a pass. Cached 10 min; the sidebar badge (`/count`) = checks needing attention, red only
|
|
28
28
|
when a failing check is critical.
|
|
29
29
|
- Engines before 0.83 have no sign-in checks: the plugin logs it, the screen says so, lockout/rules are off.
|
|
30
|
+
- plugin.json `minCmsVersion: "0.83.0"` (1.1.1) states that floor; core enforces it at install/update from the release after 0.92.1,
|
|
31
|
+
so the degraded path above is only reachable on an engine too old to enforce it. Resets (0.88) stay feature-detected.
|
|
30
32
|
|
|
31
33
|
## On dcm
|
|
32
34
|
The manager proxies every site, and Security's guard runs there first: probes to ANY site's domain are answered by
|
|
@@ -47,7 +49,8 @@ within ~3 s. It must always work - keep it dependency-free.
|
|
|
47
49
|
|
|
48
50
|
## Admin
|
|
49
51
|
`admin/views/security.js` + `admin/templates/security.html`: Overview / Sign-ins / Blocked, settings slideover
|
|
50
|
-
(cog), Refresh.
|
|
52
|
+
(cog), Refresh. Sign-ins has a CSV export (browser-side, `toCsv`, formula-leading cells defused - the log holds
|
|
53
|
+
what strangers typed). Public data (emails, addresses, user-agents) only through data-bind-text; rows by index.
|
|
51
54
|
|
|
52
55
|
## Tests
|
|
53
56
|
`tests/security.test.js` (pure). Headless: throwaway CMS with TRUST_PROXY=loopback and X-Forwarded-For.
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* only, and rows are addressed by index.
|
|
11
11
|
* `#/plugins/security/<tab>` opens a tab. Pure logic: ../lib/*.js.
|
|
12
12
|
*/
|
|
13
|
+
import {fmtDate, fmtDateTime, fmtTime} from '/plugins/_lib/admin/ui/dates.js';
|
|
13
14
|
import {resetRowText} from '../lib/resets.js';
|
|
14
15
|
import {checkSettings, DEFAULT_SETTINGS, mergeDefaults} from '../lib/settings.js';
|
|
15
16
|
import {ipRuleValid} from '../lib/ip.js';
|
|
@@ -55,10 +56,9 @@ function refreshBadge() {
|
|
|
55
56
|
const when = (iso) => {
|
|
56
57
|
const d = new Date(iso);
|
|
57
58
|
const today = new Date().toDateString() === d.toDateString();
|
|
58
|
-
|
|
59
|
-
return today ? `Today ${t}` : `${d.toLocaleDateString('en-GB', {day: 'numeric', month: 'short'})} ${t}`;
|
|
59
|
+
return today ? `Today ${fmtTime(d)}` : fmtDateTime(d);
|
|
60
60
|
};
|
|
61
|
-
const until = (ms) => `until ${
|
|
61
|
+
const until = (ms) => `until ${fmtDateTime(ms)}`;
|
|
62
62
|
/** "Chrome on Windows" from a user-agent - enough to recognise one. */
|
|
63
63
|
function browserOf(ua) {
|
|
64
64
|
const s = String(ua || '');
|
|
@@ -150,7 +150,7 @@ export const securityView = {
|
|
|
150
150
|
const scoreWidth = M.computed(() => `${health.value?.score ?? 0}%`);
|
|
151
151
|
const scoreTone = M.computed(() => { const s = health.value?.score; return s === undefined ? '' : s >= 85 ? 'good' : s >= 60 ? 'poor' : 'bad'; });
|
|
152
152
|
const attentionText = M.computed(() => (health.value ? String(health.value.failing) : '—'));
|
|
153
|
-
const asOf = M.computed(() => (health.value?.at ? `Checked ${
|
|
153
|
+
const asOf = M.computed(() => (health.value?.at ? `Checked ${fmtTime(health.value.at)}` : ''));
|
|
154
154
|
const ov = M.computed(() => {
|
|
155
155
|
const o = overview.value;
|
|
156
156
|
return o ? {failed: String(o.failed24h), blocked: String(o.blocked + o.locks), probes: String(o.today?.probes || 0), resets: String(o.resets24h ?? 0)}
|
|
@@ -217,7 +217,7 @@ export const securityView = {
|
|
|
217
217
|
const b = blocks.value;
|
|
218
218
|
lockRows.value = b.locks.map((l, i) => ({id: `l${i}`, who: l.who, why: l.kind === 'account' ? `Account - ${l.locks > 1 ? `locked ${l.locks} times` : 'wrong passwords'}` : 'Address - wrong passwords', when: until(l.until)}));
|
|
219
219
|
tempRows.value = b.temp.map((t, i) => ({id: `t${i}`, who: t.ip, why: t.reason || 'Probing', when: until(t.until)}));
|
|
220
|
-
ruleRows.value = b.rules.map((r, i) => ({id: `r${i}`, who: r.rule, why: r.note || (r.by ? `Added by ${r.by}` : 'Blocked by hand'), when: r.at ? `since ${
|
|
220
|
+
ruleRows.value = b.rules.map((r, i) => ({id: `r${i}`, who: r.rule, why: r.note || (r.by ? `Added by ${r.by}` : 'Blocked by hand'), when: r.at ? `since ${fmtDate(r.at)}` : ''}));
|
|
221
221
|
}));
|
|
222
222
|
const youText = M.computed(() => (blocks.value.you ? `You are ${blocks.value.you}` : ''));
|
|
223
223
|
|