fix: Client-Upload akzeptiert SECRET_KEY oder JWT_SECRET_KEY + Download in Settings
Upload-Auth: - Akzeptiert jetzt sowohl SECRET_KEY als auch JWT_SECRET_KEY (BUILD_UPLOAD_TOKEN in Entwicklungs-.env kann einer von beiden sein) Settings-View: - Zeigt verfuegbare Desktop/Mobile Clients zum Download an (nur wenn mindestens ein Client vorhanden) - Pro Client: Name, Dateiname, Download-Button .env.example: - Klarere Kommentare: "SECRET_KEY oder JWT_SECRET_KEY des Zielservers" Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9391a58683
commit
29cc00e284
11
.env.example
11
.env.example
|
|
@ -37,11 +37,12 @@ MAX_UPLOAD_SIZE_MB=500
|
||||||
ONLYOFFICE_URL=
|
ONLYOFFICE_URL=
|
||||||
|
|
||||||
# =============================================
|
# =============================================
|
||||||
# Client-Build Upload (NUR auf der Entwicklungsmaschine!)
|
# Client-Build Upload (NUR auf der ENTWICKLUNGSMASCHINE!)
|
||||||
# Diese Werte gehoeren NICHT auf den Produktionsserver,
|
# NICHT auf dem Produktionsserver setzen!
|
||||||
# sondern in die .env der Maschine auf der ./build.sh laeuft.
|
# Diese Werte braucht nur die Maschine auf der ./build.sh laeuft.
|
||||||
# =============================================
|
# =============================================
|
||||||
# Oeffentliche URL der Cloud-Instanz wohin die Builds hochgeladen werden
|
# URL der Cloud-Instanz wohin die Builds hochgeladen werden
|
||||||
CLOUD_URL=https://cloud.example.com
|
CLOUD_URL=https://cloud.example.com
|
||||||
# SECRET_KEY des Zielservers (identisch mit SECRET_KEY oben auf dem Server)
|
# SECRET_KEY oder JWT_SECRET_KEY des Zielservers
|
||||||
|
# (den gleichen Wert hier reinkopieren der auf dem Server steht)
|
||||||
BUILD_UPLOAD_TOKEN=
|
BUILD_UPLOAD_TOKEN=
|
||||||
|
|
|
||||||
|
|
@ -26,11 +26,13 @@ def _clients_dir():
|
||||||
|
|
||||||
def _verify_build_token():
|
def _verify_build_token():
|
||||||
"""Verify the build upload token from header or query param."""
|
"""Verify the build upload token from header or query param."""
|
||||||
expected = os.environ.get('SECRET_KEY', '')
|
|
||||||
if not expected:
|
|
||||||
return False
|
|
||||||
token = request.headers.get('X-Build-Token', '') or request.args.get('build_token', '')
|
token = request.headers.get('X-Build-Token', '') or request.args.get('build_token', '')
|
||||||
return token == expected
|
if not token:
|
||||||
|
return False
|
||||||
|
# Accept SECRET_KEY or JWT_SECRET_KEY
|
||||||
|
secret = os.environ.get('SECRET_KEY', '')
|
||||||
|
jwt_secret = os.environ.get('JWT_SECRET_KEY', '')
|
||||||
|
return token == secret or token == jwt_secret
|
||||||
|
|
||||||
|
|
||||||
# --- Public: list available clients ---
|
# --- Public: list available clients ---
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,24 @@
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Client Downloads -->
|
||||||
|
<div v-if="availableClients.length" class="settings-section">
|
||||||
|
<h3>Desktop & Mobile Clients</h3>
|
||||||
|
<div class="client-list">
|
||||||
|
<div v-for="client in availableClients" :key="client.platform" class="client-item">
|
||||||
|
<div class="client-info">
|
||||||
|
<i :class="'pi ' + (client.platform === 'linux' || client.platform === 'windows' || client.platform === 'mac' ? 'pi-desktop' : 'pi-mobile')"></i>
|
||||||
|
<div>
|
||||||
|
<strong>{{ client.name }}</strong>
|
||||||
|
<span class="client-meta">{{ client.filename }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Button icon="pi pi-download" :label="'Download'" size="small" outlined
|
||||||
|
@click="downloadClient(client)" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Email Accounts -->
|
<!-- Email Accounts -->
|
||||||
<div class="settings-section">
|
<div class="settings-section">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
|
|
@ -167,6 +185,13 @@ import InputSwitch from 'primevue/inputswitch'
|
||||||
const auth = useAuthStore()
|
const auth = useAuthStore()
|
||||||
const toast = useToast()
|
const toast = useToast()
|
||||||
|
|
||||||
|
// Client downloads
|
||||||
|
const availableClients = ref([])
|
||||||
|
|
||||||
|
function downloadClient(client) {
|
||||||
|
window.location.href = `/api/clients/${client.platform}/download`
|
||||||
|
}
|
||||||
|
|
||||||
// --- Password change ---
|
// --- Password change ---
|
||||||
const currentPassword = ref('')
|
const currentPassword = ref('')
|
||||||
const newPassword = ref('')
|
const newPassword = ref('')
|
||||||
|
|
@ -307,7 +332,13 @@ async function doDeleteAccount() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(loadAccounts)
|
onMounted(async () => {
|
||||||
|
loadAccounts()
|
||||||
|
try {
|
||||||
|
const res = await apiClient.get('/clients')
|
||||||
|
availableClients.value = res.data.clients
|
||||||
|
} catch { availableClients.value = [] }
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
@ -346,4 +377,12 @@ onMounted(loadAccounts)
|
||||||
.field label { display: block; margin-bottom: 0.5rem; font-weight: 500; font-size: 0.875rem; }
|
.field label { display: block; margin-bottom: 0.5rem; font-weight: 500; font-size: 0.875rem; }
|
||||||
.field-row { display: flex; gap: 0.75rem; align-items: flex-end; }
|
.field-row { display: flex; gap: 0.75rem; align-items: flex-end; }
|
||||||
.flex-grow { flex: 1; }
|
.flex-grow { flex: 1; }
|
||||||
|
.client-list { display: flex; flex-direction: column; gap: 0.5rem; }
|
||||||
|
.client-item {
|
||||||
|
display: flex; align-items: center; justify-content: space-between;
|
||||||
|
padding: 0.75rem; border: 1px solid var(--p-surface-200); border-radius: 8px;
|
||||||
|
}
|
||||||
|
.client-info { display: flex; align-items: center; gap: 0.75rem; }
|
||||||
|
.client-info i { font-size: 1.25rem; color: var(--p-primary-color); }
|
||||||
|
.client-meta { display: block; font-size: 0.8rem; color: var(--p-text-muted-color); }
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue