generated from Nodarx/template
refactor: bunch of improvements
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
234
src/components/ImapProtocolPanel.vue
Normal file
234
src/components/ImapProtocolPanel.vue
Normal file
@@ -0,0 +1,234 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { LocationSocketSole } from '@KTXM/MailManager/models/location'
|
||||
import { ServiceObject } from '@KTXM/MailManager/models/service'
|
||||
import type {
|
||||
ServiceLocation,
|
||||
ServiceLocationSocketSole,
|
||||
} from '@KTXM/MailManager/types/service'
|
||||
import type {
|
||||
ProviderProtocolPanelProps,
|
||||
ProviderProtocolPanelEmits,
|
||||
} from '@KTXM/MailManager/types/integration'
|
||||
|
||||
type ImapEncryption = 'none' | 'ssl' | 'tls' | 'starttls'
|
||||
|
||||
const props = defineProps<ProviderProtocolPanelProps>()
|
||||
const emit = defineEmits<ProviderProtocolPanelEmits>()
|
||||
|
||||
const host = ref('')
|
||||
const encryption = ref<ImapEncryption>('ssl')
|
||||
const port = ref('993')
|
||||
const verifyPeer = ref(true)
|
||||
const verifyHost = ref(true)
|
||||
|
||||
const encryptionOptions = [
|
||||
{ title: 'Implicit TLS (SSL)', value: 'ssl' },
|
||||
{ title: 'TLS', value: 'tls' },
|
||||
{ title: 'STARTTLS', value: 'starttls' },
|
||||
{ title: 'None', value: 'none' },
|
||||
]
|
||||
|
||||
const rules = {
|
||||
required: (value: unknown) => !!value || 'This field is required',
|
||||
port: (value: string) => {
|
||||
const numericValue = Number(value)
|
||||
return Number.isInteger(numericValue) && numericValue >= 1 && numericValue <= 65535
|
||||
? true
|
||||
: 'Port must be between 1 and 65535'
|
||||
}
|
||||
}
|
||||
|
||||
const isValid = computed(() => !!host.value && rules.port(port.value) === true)
|
||||
|
||||
const currentLocation = computed((): ServiceLocationSocketSole | null => {
|
||||
if (!isValid.value) {
|
||||
return null
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'SOCKET_SOLE',
|
||||
host: host.value,
|
||||
port: Number(port.value),
|
||||
encryption: encryption.value,
|
||||
verifyPeer: verifyPeer.value,
|
||||
verifyHost: verifyHost.value,
|
||||
}
|
||||
})
|
||||
|
||||
watch(
|
||||
() => [props.service, props.discoveredLocation] as const,
|
||||
([service, discoveredLocation]) => {
|
||||
syncFromLocation(service?.location?.toJson() ?? discoveredLocation ?? null)
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
watch(
|
||||
currentLocation,
|
||||
location => {
|
||||
const existingLocation = props.service?.location?.toJson() ?? null
|
||||
if (sameLocation(existingLocation, location)) {
|
||||
return
|
||||
}
|
||||
|
||||
const nextService = createServiceObject(props.service)
|
||||
nextService.location = location ? LocationSocketSole.fromJson(location) : null
|
||||
emit('update:service', nextService)
|
||||
},
|
||||
{ immediate: true, deep: true }
|
||||
)
|
||||
|
||||
watch(encryption, (next, previous) => {
|
||||
const previousDefault = defaultPortFor(previous)
|
||||
if (!port.value || Number(port.value) === previousDefault) {
|
||||
port.value = String(defaultPortFor(next))
|
||||
}
|
||||
})
|
||||
|
||||
function syncFromLocation(location: ServiceLocation | null) {
|
||||
const socketLocation = getSocketLocation(location)
|
||||
|
||||
host.value = socketLocation?.host ?? ''
|
||||
encryption.value = socketLocation?.encryption ?? 'ssl'
|
||||
port.value = String(socketLocation?.port ?? defaultPortFor(encryption.value))
|
||||
verifyPeer.value = socketLocation?.verifyPeer ?? true
|
||||
verifyHost.value = socketLocation?.verifyHost ?? true
|
||||
}
|
||||
|
||||
function createServiceObject(service?: ServiceObject): ServiceObject {
|
||||
const nextService = new ServiceObject()
|
||||
|
||||
if (service) {
|
||||
nextService.fromJson(service.toJson())
|
||||
}
|
||||
|
||||
return nextService
|
||||
}
|
||||
|
||||
function getSocketLocation(location?: ServiceLocation | null): ServiceLocationSocketSole | null {
|
||||
return location?.type === 'SOCKET_SOLE' ? location : null
|
||||
}
|
||||
|
||||
function sameLocation(a: ServiceLocation | null, b: ServiceLocation | null): boolean {
|
||||
if (a === null || b === null) {
|
||||
return a === b
|
||||
}
|
||||
|
||||
if (a.type !== 'SOCKET_SOLE' || b.type !== 'SOCKET_SOLE') {
|
||||
return false
|
||||
}
|
||||
|
||||
return a.host === b.host
|
||||
&& a.port === b.port
|
||||
&& a.encryption === b.encryption
|
||||
&& (a.verifyPeer ?? true) === (b.verifyPeer ?? true)
|
||||
&& (a.verifyHost ?? true) === (b.verifyHost ?? true)
|
||||
}
|
||||
|
||||
function defaultPortFor(nextEncryption: ImapEncryption): number {
|
||||
return nextEncryption === 'ssl' || nextEncryption === 'tls' ? 993 : 143
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="imap-protocol-panel">
|
||||
<h3 class="text-h6 mb-4">IMAP Connection Settings</h3>
|
||||
<p class="text-body-2 mb-6">Configure the server address, transport security, and certificate verification for your IMAP mailbox.</p>
|
||||
|
||||
<v-text-field
|
||||
v-model="host"
|
||||
label="Server Host"
|
||||
hint="For example: imap.example.com"
|
||||
persistent-hint
|
||||
variant="outlined"
|
||||
prepend-inner-icon="mdi-server"
|
||||
class="mb-4"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
autocapitalize="none"
|
||||
:rules="[rules.required]"
|
||||
/>
|
||||
|
||||
<v-select
|
||||
v-model="encryption"
|
||||
:items="encryptionOptions"
|
||||
label="Security"
|
||||
variant="outlined"
|
||||
prepend-inner-icon="mdi-shield-lock"
|
||||
class="mb-4"
|
||||
/>
|
||||
|
||||
<v-text-field
|
||||
v-model="port"
|
||||
label="Port"
|
||||
hint="Defaults to 993 for TLS/SSL and 143 for plain or STARTTLS"
|
||||
persistent-hint
|
||||
variant="outlined"
|
||||
prepend-inner-icon="mdi-numeric"
|
||||
class="mb-4"
|
||||
type="number"
|
||||
min="1"
|
||||
max="65535"
|
||||
:rules="[rules.required, rules.port]"
|
||||
/>
|
||||
|
||||
<v-expansion-panels class="mt-4">
|
||||
<v-expansion-panel>
|
||||
<v-expansion-panel-title>
|
||||
<v-icon start>mdi-cog</v-icon>
|
||||
Security Options
|
||||
</v-expansion-panel-title>
|
||||
<v-expansion-panel-text>
|
||||
<v-switch
|
||||
v-model="verifyPeer"
|
||||
label="Verify TLS certificate"
|
||||
color="primary"
|
||||
hint="Disable only for trusted internal or test environments"
|
||||
persistent-hint
|
||||
class="mb-4"
|
||||
/>
|
||||
|
||||
<v-switch
|
||||
v-model="verifyHost"
|
||||
label="Verify certificate hostname"
|
||||
color="primary"
|
||||
hint="Checks that the certificate matches the IMAP host"
|
||||
persistent-hint
|
||||
class="mb-4"
|
||||
/>
|
||||
</v-expansion-panel-text>
|
||||
</v-expansion-panel>
|
||||
</v-expansion-panels>
|
||||
|
||||
<v-alert type="info" variant="tonal" density="compact" class="mt-4">
|
||||
<template #prepend>
|
||||
<v-icon>mdi-information</v-icon>
|
||||
</template>
|
||||
<div class="text-caption">
|
||||
STARTTLS is accepted for compatibility, but the current IMAP client transport does not perform STARTTLS negotiation. Prefer TLS on port 993 when available.
|
||||
</div>
|
||||
</v-alert>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.imap-protocol-panel {
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
.text-h6 {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 500;
|
||||
line-height: 2rem;
|
||||
letter-spacing: 0.0125em;
|
||||
}
|
||||
|
||||
.text-body-2 {
|
||||
font-size: 0.875rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.25rem;
|
||||
letter-spacing: 0.0178571429em;
|
||||
color: rgba(var(--v-theme-on-surface), 0.7);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user