Add a password-gated private instance mode for xaigen.

Keep Authentik on aigen, isolate library data per instance, and purge Comfy outputs from the desktop after they are saved on the server.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Towsty
2026-08-25 19:24:00 -05:00
co-authored by Cursor
parent e2db183a8e
commit bc0ea613c1
22 changed files with 426 additions and 15 deletions
+39
View File
@@ -10,6 +10,17 @@
<button type="button" class="rounded-full border border-white/10 px-3 py-1 text-sm text-zinc-400 hover:text-white" @click="emit('close')">Close</button>
</div>
<section v-if="authMode === 'password'" class="mt-6 space-y-3">
<h3 class="text-sm font-semibold uppercase tracking-wider text-zinc-500">Site login</h3>
<p class="text-sm text-zinc-400">Username and password are stored encrypted on this server. Changing them does not move the library.</p>
<form class="grid gap-2 sm:grid-cols-2" @submit.prevent="saveLogin">
<input v-model="loginUser" class="rounded-xl border border-white/10 bg-zinc-950 px-3 py-2 text-sm" placeholder="Username" autocomplete="username">
<input v-model="loginCurrent" type="password" class="rounded-xl border border-white/10 bg-zinc-950 px-3 py-2 text-sm" placeholder="Current password" autocomplete="current-password" required>
<input v-model="loginNext" type="password" class="rounded-xl border border-white/10 bg-zinc-950 px-3 py-2 text-sm sm:col-span-2" placeholder="New password (blank to keep)" autocomplete="new-password">
<button type="submit" class="rounded-xl bg-amber-400 px-4 py-2 text-sm font-semibold text-zinc-950 sm:col-span-2">Update login</button>
</form>
</section>
<section class="mt-6 space-y-3">
<div class="flex items-center justify-between gap-3">
<h3 class="text-sm font-semibold uppercase tracking-wider text-zinc-500">Folders</h3>
@@ -115,15 +126,21 @@ export interface SettingsFolder {
const props = defineProps<{
folders: SettingsFolder[]
authMode?: string
username?: string
}>()
const emit = defineEmits<{
close: []
updated: [payload: unknown]
error: [message: string]
renamed: [username: string]
}>()
const newName = ref('')
const loginUser = ref(props.username || '')
const loginCurrent = ref('')
const loginNext = ref('')
const drafts = reactive<Record<string, { name: string; protect: boolean; password: string; currentPassword: string }>>({})
function onKey(event: KeyboardEvent) {
@@ -148,6 +165,28 @@ watch(() => props.folders, (folders) => {
}
}, { immediate: true, deep: true })
watch(() => props.username, (value) => {
if (value) loginUser.value = value
})
async function saveLogin() {
try {
const data = await $fetch<{ username: string }>('/api/auth/credentials', {
method: 'PUT',
body: {
username: loginUser.value,
password: loginNext.value,
currentPassword: loginCurrent.value
}
})
loginCurrent.value = ''
loginNext.value = ''
emit('renamed', data.username)
} catch (error: any) {
emit('error', error?.data?.statusMessage || 'Could not update site login')
}
}
async function addFolder() {
const name = newName.value.trim()
if (!name) return