290 lines
9.8 KiB
Vue
290 lines
9.8 KiB
Vue
<script setup lang="ts">
|
|
import { ref, watch } from 'vue'
|
|
import type { VaultServer, VaultCredentials } from '../types'
|
|
import { useSweetAlert } from '../composables/useSweetAlert'
|
|
|
|
interface Props {
|
|
server: VaultServer
|
|
}
|
|
|
|
const props = defineProps<Props>()
|
|
const emit = defineEmits<{
|
|
login: [credentials: VaultCredentials, saveCredentials: boolean]
|
|
clearCredentials: [serverId: string]
|
|
}>()
|
|
|
|
const { confirm, error } = useSweetAlert()
|
|
|
|
const authMethod = ref<'token' | 'userpass' | 'ldap'>('token')
|
|
const token = ref('')
|
|
const username = ref('')
|
|
const password = ref('')
|
|
const isLoading = ref(false)
|
|
const saveCredentials = ref(false)
|
|
const showSecurityWarning = ref(false)
|
|
|
|
// Function to load credentials from server
|
|
const loadCredentialsFromServer = (server: VaultServer) => {
|
|
if (server.savedCredentials) {
|
|
// Load saved credentials
|
|
authMethod.value = server.savedCredentials.authMethod
|
|
token.value = server.savedCredentials.token || ''
|
|
username.value = server.savedCredentials.username || ''
|
|
password.value = server.savedCredentials.password || ''
|
|
saveCredentials.value = true
|
|
} else {
|
|
// Clear form when no saved credentials
|
|
authMethod.value = 'token'
|
|
token.value = ''
|
|
username.value = ''
|
|
password.value = ''
|
|
saveCredentials.value = false
|
|
}
|
|
}
|
|
|
|
// Load credentials on initial mount
|
|
loadCredentialsFromServer(props.server)
|
|
|
|
// Watch for server changes and reload credentials
|
|
watch(
|
|
() => props.server,
|
|
newServer => {
|
|
loadCredentialsFromServer(newServer)
|
|
showSecurityWarning.value = false // Close any open warning modal
|
|
},
|
|
{ immediate: false }
|
|
)
|
|
|
|
const handleSubmit = async () => {
|
|
// Show warning if user is trying to save credentials for the first time
|
|
if (saveCredentials.value && !props.server.savedCredentials) {
|
|
showSecurityWarning.value = true
|
|
return
|
|
}
|
|
|
|
await performLogin()
|
|
}
|
|
|
|
const performLogin = async () => {
|
|
isLoading.value = true
|
|
|
|
const credentials: VaultCredentials = {
|
|
serverId: props.server.id,
|
|
authMethod: authMethod.value,
|
|
token: authMethod.value === 'token' ? token.value : undefined,
|
|
username: authMethod.value !== 'token' ? username.value : undefined,
|
|
password: authMethod.value !== 'token' ? password.value : undefined,
|
|
}
|
|
|
|
try {
|
|
await emit('login', credentials, saveCredentials.value)
|
|
} catch (err) {
|
|
console.error('Login error:', err)
|
|
error('Login failed. Please check your credentials.')
|
|
} finally {
|
|
isLoading.value = false
|
|
}
|
|
}
|
|
|
|
const confirmSaveCredentials = () => {
|
|
showSecurityWarning.value = false
|
|
performLogin()
|
|
}
|
|
|
|
const handleClearCredentials = async (serverId: string, serverName: string) => {
|
|
const result = await confirm(`Clear saved credentials for "${serverName}"?`, 'Clear Credentials')
|
|
if (result.isConfirmed) {
|
|
emit('clearCredentials', serverId)
|
|
token.value = ''
|
|
username.value = ''
|
|
password.value = ''
|
|
saveCredentials.value = false
|
|
}
|
|
}
|
|
|
|
const cancelSaveCredentials = () => {
|
|
showSecurityWarning.value = false
|
|
saveCredentials.value = false
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="card bg-base-100 shadow-xl">
|
|
<div class="card-body">
|
|
<!-- Header -->
|
|
<div class="mb-4">
|
|
<h2 class="card-title text-2xl mb-2">Connect to {{ server.name }}</h2>
|
|
<p class="text-sm font-mono opacity-70">
|
|
{{ server.url }}
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Form -->
|
|
<form class="space-y-4" @submit.prevent="handleSubmit">
|
|
<!-- Auth Method -->
|
|
<div class="form-control">
|
|
<label class="label">
|
|
<span class="label-text">Authentication Method</span>
|
|
</label>
|
|
<select v-model="authMethod" class="select select-bordered w-full">
|
|
<option value="token">Token</option>
|
|
<option value="userpass">Username & Password</option>
|
|
<option value="ldap">LDAP</option>
|
|
</select>
|
|
</div>
|
|
|
|
<!-- Token Auth -->
|
|
<div v-if="authMethod === 'token'" class="form-control">
|
|
<label class="label">
|
|
<span class="label-text">Vault Token *</span>
|
|
</label>
|
|
<input
|
|
v-model="token"
|
|
type="password"
|
|
placeholder="Enter your vault token"
|
|
class="input input-bordered w-full"
|
|
autocomplete="off"
|
|
required
|
|
/>
|
|
<label class="label">
|
|
<span class="label-text-alt">Your token will be used to authenticate with the vault server</span>
|
|
</label>
|
|
</div>
|
|
|
|
<!-- Username/Password or LDAP -->
|
|
<template v-else>
|
|
<div class="form-control">
|
|
<label class="label">
|
|
<span class="label-text">Username *</span>
|
|
</label>
|
|
<input
|
|
v-model="username"
|
|
type="text"
|
|
placeholder="Enter your username"
|
|
class="input input-bordered w-full"
|
|
autocomplete="username"
|
|
required
|
|
/>
|
|
</div>
|
|
|
|
<div class="form-control">
|
|
<label class="label">
|
|
<span class="label-text">Password *</span>
|
|
</label>
|
|
<input
|
|
v-model="password"
|
|
type="password"
|
|
placeholder="Enter your password"
|
|
class="input input-bordered w-full"
|
|
autocomplete="current-password"
|
|
required
|
|
/>
|
|
</div>
|
|
</template>
|
|
|
|
<!-- Save Credentials Option -->
|
|
<div class="form-control">
|
|
<label class="label cursor-pointer justify-start gap-3">
|
|
<input v-model="saveCredentials" type="checkbox" class="checkbox checkbox-warning" />
|
|
<span class="label-text">
|
|
<span class="font-semibold text-warning flex items-center gap-2">
|
|
<i class="mdi mdi-alert text-warning" />
|
|
Save credentials locally
|
|
</span>
|
|
</span>
|
|
</label>
|
|
<label class="label">
|
|
<span class="label-text-alt text-warning"> Not recommended! Credentials will be stored in plain text in localStorage </span>
|
|
</label>
|
|
</div>
|
|
|
|
<!-- Submit Button -->
|
|
<button type="submit" class="btn btn-primary w-full" :class="{ loading: isLoading }" :disabled="isLoading">
|
|
{{ isLoading ? 'Connecting...' : 'Connect' }}
|
|
</button>
|
|
|
|
<button v-if="server.savedCredentials" class="btn btn-warning btn-sm" @click.prevent.stop="handleClearCredentials(server.id, server.name)">
|
|
<i class="mdi mdi-key-remove mr-1" />
|
|
Clear Credentials
|
|
</button>
|
|
</form>
|
|
|
|
<!-- Security Warning Modal -->
|
|
<div v-if="showSecurityWarning" class="modal modal-open">
|
|
<div class="modal-box border-2 border-error">
|
|
<h3 class="font-bold text-lg text-error mb-4 flex items-center gap-2">
|
|
<i class="mdi mdi-alert-circle text-error" />
|
|
Security Warning
|
|
</h3>
|
|
<div class="space-y-4">
|
|
<div class="alert alert-error">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="stroke-current shrink-0 h-6 w-6" fill="none" viewBox="0 0 24 24">
|
|
<path
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
stroke-width="2"
|
|
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"
|
|
/>
|
|
</svg>
|
|
<span class="font-semibold">This is NOT recommended for security reasons!</span>
|
|
</div>
|
|
|
|
<div class="text-sm space-y-2">
|
|
<p class="font-semibold">If you save credentials:</p>
|
|
<ul class="list-disc list-inside space-y-1 ml-2">
|
|
<li>
|
|
Your token/password will be stored in
|
|
<strong>plain text</strong>
|
|
</li>
|
|
<li>Anyone with access to your browser can read them</li>
|
|
<li>Browser extensions can access localStorage</li>
|
|
<li>If your computer is compromised, credentials are exposed</li>
|
|
<li>This violates most security policies</li>
|
|
</ul>
|
|
|
|
<p class="font-semibold mt-4">Only use this if:</p>
|
|
<ul class="list-disc list-inside space-y-1 ml-2">
|
|
<li>You're on a personal, secure device</li>
|
|
<li>You understand the security risks</li>
|
|
<li>You're using a development/test Vault server</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="bg-base-300 p-3 rounded text-xs">
|
|
<p class="font-mono">
|
|
<strong>Better alternatives:</strong><br />
|
|
• Use short-lived tokens<br />
|
|
• Re-login each session<br />
|
|
• Use a password manager<br />
|
|
• Enable auto-logout timeout
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="modal-action">
|
|
<button class="btn btn-ghost" @click="cancelSaveCredentials">Cancel</button>
|
|
<button class="btn btn-error" @click="confirmSaveCredentials">I Understand the Risks - Save Anyway</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Security Notice -->
|
|
<div class="alert mt-4">
|
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" class="stroke-info shrink-0 w-6 h-6">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
</svg>
|
|
<div class="text-xs">
|
|
<p class="font-semibold flex items-center gap-2">
|
|
<i class="mdi mdi-shield-alert text-warning" />
|
|
Security Notice:
|
|
</p>
|
|
<p>
|
|
This application connects directly to your Vault server. Credentials are not stored permanently and are only kept in memory during your
|
|
session.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|