From b90d7a7051f49262baa25f7b39aa4ffb4c294ec7 Mon Sep 17 00:00:00 2001 From: Cam Proudlock Date: Fri, 21 Aug 2026 16:10:52 -0400 Subject: [PATCH] Secure send settings page --- plugins/tools/frontend/routes.js | 8 ++ .../frontend/views/SecureSendSettings.vue | 77 +++++++++++++++++++ plugins/tools/plugin.py | 22 ++++++ 3 files changed, 107 insertions(+) create mode 100644 plugins/tools/frontend/views/SecureSendSettings.vue diff --git a/plugins/tools/frontend/routes.js b/plugins/tools/frontend/routes.js index f306aa24..7e15889b 100644 --- a/plugins/tools/frontend/routes.js +++ b/plugins/tools/frontend/routes.js @@ -28,6 +28,14 @@ export default [ // Browser-only: no API, no data, nothing to protect. meta: { plugin: 'tools' } }, + { + path: 'settings/secure-send', + name: 'secure-send-settings', + component: () => import('./views/SecureSendSettings.vue'), + // Admin, like every other settings page: this decides whether an + // unauthenticated caller may write to the site. + meta: { requiresAuth: true, requiresAdmin: true, plugin: 'tools' } + }, { path: 'tools/secure-send', name: 'tools-secure-send', diff --git a/plugins/tools/frontend/views/SecureSendSettings.vue b/plugins/tools/frontend/views/SecureSendSettings.vue new file mode 100644 index 00000000..3c1a345d --- /dev/null +++ b/plugins/tools/frontend/views/SecureSendSettings.vue @@ -0,0 +1,77 @@ + + + + + diff --git a/plugins/tools/plugin.py b/plugins/tools/plugin.py index 6f369519..b86a564b 100644 --- a/plugins/tools/plugin.py +++ b/plugins/tools/plugin.py @@ -92,6 +92,28 @@ class ToolsPlugin(BasePlugin): }, ] + def get_settings_cards(self) -> List[dict]: + """A page for the one switch this plugin owns (ADR-010). + + get_settings_defaults SEEDS the row; this is what gives somebody a place + to change it. Declaring only the first left the setting in the database + with no way to reach it, which is indistinguishable from the feature not + existing. + """ + return [ + { + 'group': 'Tools', + 'to': '/settings/secure-send', + # From the settings iconMap; an unknown key falls back to a + # puzzle piece, which reads as "nobody chose this". + 'icon': 'wrench', + 'title': 'Secure Send', + 'description': 'Whether people without an account can create ' + 'one-view password links', + 'position': 60, + }, + ] + def get_navigation_items(self) -> List[dict]: return [ {