fix(calendar): SSRF exception for Exchange + error messages + domain in edit
- SSRF check skipped for Exchange type (internal EWS servers are common)
- testConnectionFromConfig catches SSRF/validation errors, returns {success:false,error} instead of throwing 403
- updateSource reads existing.type to determine effective type for SSRF check
- Panel shows saveError/editSaveError on failed add/update
- Edit form initialValues now includes domain field
- i18n: calendar.saveError key added (de+en)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -37,6 +37,8 @@ export function CalendarSettingsPanel() {
|
||||
const [editingId, setEditingId] = useState<string | null>(null);
|
||||
const [deletingId, setDeletingId] = useState<string | null>(null);
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
const [saveError, setSaveError] = useState<string | null>(null);
|
||||
const [editSaveError, setEditSaveError] = useState<string | null>(null);
|
||||
const [testResults, setTestResults] = useState<Record<string, 'success' | 'error' | 'testing'>>({});
|
||||
|
||||
// Load sources on mount
|
||||
@@ -76,6 +78,7 @@ export function CalendarSettingsPanel() {
|
||||
// Add new source
|
||||
const handleAddSource = useCallback(async (payload: CreateSourcePayload) => {
|
||||
setIsSaving(true);
|
||||
setSaveError(null);
|
||||
try {
|
||||
const created = await addSource(payload);
|
||||
setSources((prev) => [...prev, created]);
|
||||
@@ -93,11 +96,11 @@ export function CalendarSettingsPanel() {
|
||||
setTestResults((prev) => ({ ...prev, [created.id]: 'error' }));
|
||||
}
|
||||
} catch {
|
||||
// Error handled silently
|
||||
setSaveError(t('calendar.saveError') || 'Fehler beim Speichern');
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
}
|
||||
}, []);
|
||||
}, [t]);
|
||||
|
||||
// Delete source
|
||||
const handleDeleteSource = useCallback(async (id: string) => {
|
||||
@@ -282,6 +285,9 @@ export function CalendarSettingsPanel() {
|
||||
{/* Edit form (below the source being edited) */}
|
||||
{editingId && (
|
||||
<div className="rounded-md border border-border bg-card p-4">
|
||||
{editSaveError && (
|
||||
<p className="mb-3 text-sm text-destructive">{editSaveError}</p>
|
||||
)}
|
||||
<h3 className="mb-3 text-sm font-semibold text-foreground">
|
||||
Edit Source
|
||||
</h3>
|
||||
@@ -296,12 +302,14 @@ export function CalendarSettingsPanel() {
|
||||
url: s.url,
|
||||
username: s.username ?? '',
|
||||
exchangeMode: s.exchangeMode ?? undefined,
|
||||
domain: s.domain ?? undefined,
|
||||
color: s.color ?? undefined,
|
||||
}
|
||||
: undefined;
|
||||
})()}
|
||||
onSave={async (payload) => {
|
||||
setIsSaving(true);
|
||||
setEditSaveError(null);
|
||||
try {
|
||||
const updated = await updateSource(editingId, payload);
|
||||
setSources((prev) =>
|
||||
@@ -309,7 +317,7 @@ export function CalendarSettingsPanel() {
|
||||
);
|
||||
setEditingId(null);
|
||||
} catch {
|
||||
// Error handled silently
|
||||
setEditSaveError(t('calendar.saveError') || 'Fehler beim Speichern');
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
}
|
||||
@@ -337,6 +345,9 @@ export function CalendarSettingsPanel() {
|
||||
<h3 className="mb-3 text-sm font-semibold text-foreground">
|
||||
{t('calendar.addSource')}
|
||||
</h3>
|
||||
{saveError && (
|
||||
<p className="mb-3 text-sm text-destructive">{saveError}</p>
|
||||
)}
|
||||
<CalendarSourceForm
|
||||
onSave={handleAddSource}
|
||||
onCancel={() => setShowAddForm(false)}
|
||||
|
||||
@@ -208,6 +208,7 @@
|
||||
"formTesting": "Teste...",
|
||||
"formTestSuccess": "Verbindung erfolgreich",
|
||||
"formTestFailed": "Verbindung fehlgeschlagen",
|
||||
"saveError": "Speichern fehlgeschlagen. Bitte Eingaben prüfen.",
|
||||
"formSave": "Speichern",
|
||||
"formSaving": "Wird gespeichert...",
|
||||
"formCancel": "Abbrechen",
|
||||
|
||||
@@ -208,6 +208,7 @@
|
||||
"formTesting": "Testing...",
|
||||
"formTestSuccess": "Connection successful",
|
||||
"formTestFailed": "Connection failed",
|
||||
"saveError": "Save failed. Please check your input.",
|
||||
"formSave": "Save",
|
||||
"formSaving": "Saving...",
|
||||
"formCancel": "Cancel",
|
||||
|
||||
Reference in New Issue
Block a user