Secure send settings page
This commit is contained in:
@@ -28,6 +28,14 @@ export default [
|
|||||||
// Browser-only: no API, no data, nothing to protect.
|
// Browser-only: no API, no data, nothing to protect.
|
||||||
meta: { plugin: 'tools' }
|
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',
|
path: 'tools/secure-send',
|
||||||
name: 'tools-secure-send',
|
name: 'tools-secure-send',
|
||||||
|
|||||||
77
plugins/tools/frontend/views/SecureSendSettings.vue
Normal file
77
plugins/tools/frontend/views/SecureSendSettings.vue
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="page-header">
|
||||||
|
<h1>Secure Send</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="loading" class="card loading">Loading...</div>
|
||||||
|
|
||||||
|
<div v-else class="card">
|
||||||
|
<label class="switch-row">
|
||||||
|
<input v-model="allowGuests" type="checkbox" />
|
||||||
|
<span>
|
||||||
|
<strong>Let people without an account create links</strong>
|
||||||
|
<span class="hint">
|
||||||
|
Off by default. With it off, creating a link needs a login and the
|
||||||
|
<code>tools.secrets</code> permission. Receiving one never needs an
|
||||||
|
account either way.
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<!-- The cost, stated where the decision is made rather than in a document
|
||||||
|
nobody opens. -->
|
||||||
|
<p class="control-note" v-if="allowGuests">
|
||||||
|
A link created by a guest has no creator recorded. The audit trail can
|
||||||
|
say when it was made and from where, but never who made it.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<button class="btn btn-primary" :disabled="saving" @click="save">
|
||||||
|
{{ saving ? 'Saving...' : 'Save' }}
|
||||||
|
</button>
|
||||||
|
<span v-if="saved" class="saved">Saved</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted } from 'vue'
|
||||||
|
import { settingsApi } from '@/api'
|
||||||
|
|
||||||
|
const KEY = 'securesend_allow_guests'
|
||||||
|
|
||||||
|
const allowGuests = ref(false)
|
||||||
|
const loading = ref(true)
|
||||||
|
const saving = ref(false)
|
||||||
|
const saved = ref(false)
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
try {
|
||||||
|
const response = await settingsApi.list({ category: 'tools' })
|
||||||
|
const rows = response.data.data || []
|
||||||
|
const row = rows.find(setting => setting.key === KEY)
|
||||||
|
allowGuests.value = String(row?.value).toLowerCase() === 'true'
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
async function save() {
|
||||||
|
saving.value = true
|
||||||
|
try {
|
||||||
|
await settingsApi.update(KEY, allowGuests.value ? 'true' : 'false')
|
||||||
|
saved.value = true
|
||||||
|
setTimeout(() => { saved.value = false }, 2000)
|
||||||
|
} finally {
|
||||||
|
saving.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.switch-row { display: flex; gap: 10px; align-items: flex-start; margin-bottom: 1rem; }
|
||||||
|
.switch-row span { display: block; }
|
||||||
|
.hint { display: block; color: var(--text-light); font-size: 0.875rem; margin-top: 4px; }
|
||||||
|
.control-note { color: var(--warning); font-size: 0.875rem; margin: 0 0 1rem; }
|
||||||
|
.saved { margin-left: 10px; color: var(--text-light); font-size: 0.875rem; }
|
||||||
|
</style>
|
||||||
@@ -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]:
|
def get_navigation_items(self) -> List[dict]:
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user