Fix webhook pages in Settings (#10902)
## Context Some users were able to set an empty URL as webhook targetUrl, which was breaking the Webhook List and Detail pages ## Fix - Making sure to protect getHostNameOrThrow by isValidUrl - rework webhook form to prevent creation of invalid webhooks Fixes https://github.com/twentyhq/twenty/issues/10822
This commit is contained in:
@ -5,7 +5,7 @@ import { IconChevronRight } from 'twenty-ui';
|
|||||||
import { Webhook } from '@/settings/developers/types/webhook/Webhook';
|
import { Webhook } from '@/settings/developers/types/webhook/Webhook';
|
||||||
import { TableCell } from '@/ui/layout/table/components/TableCell';
|
import { TableCell } from '@/ui/layout/table/components/TableCell';
|
||||||
import { TableRow } from '@/ui/layout/table/components/TableRow';
|
import { TableRow } from '@/ui/layout/table/components/TableRow';
|
||||||
import { getUrlHostnameOrThrow } from 'twenty-shared';
|
import { getUrlHostnameOrThrow, isValidUrl } from 'twenty-shared';
|
||||||
|
|
||||||
export const StyledApisFieldTableRow = styled(TableRow)`
|
export const StyledApisFieldTableRow = styled(TableRow)`
|
||||||
grid-template-columns: 1fr 28px;
|
grid-template-columns: 1fr 28px;
|
||||||
@ -39,7 +39,9 @@ export const SettingsDevelopersWebhookTableRow = ({
|
|||||||
return (
|
return (
|
||||||
<StyledApisFieldTableRow to={to}>
|
<StyledApisFieldTableRow to={to}>
|
||||||
<StyledUrlTableCell>
|
<StyledUrlTableCell>
|
||||||
{getUrlHostnameOrThrow(fieldItem.targetUrl)}
|
{isValidUrl(fieldItem.targetUrl)
|
||||||
|
? getUrlHostnameOrThrow(fieldItem.targetUrl)
|
||||||
|
: fieldItem.targetUrl}
|
||||||
</StyledUrlTableCell>
|
</StyledUrlTableCell>
|
||||||
<StyledIconTableCell>
|
<StyledIconTableCell>
|
||||||
<StyledIconChevronRight
|
<StyledIconChevronRight
|
||||||
|
|||||||
@ -35,7 +35,12 @@ export const useWebhookUpdateForm = ({
|
|||||||
const [formData, setFormData] = useState<WebhookFormData>({
|
const [formData, setFormData] = useState<WebhookFormData>({
|
||||||
targetUrl: '',
|
targetUrl: '',
|
||||||
description: '',
|
description: '',
|
||||||
operations: [],
|
operations: [
|
||||||
|
{
|
||||||
|
object: '*',
|
||||||
|
action: '*',
|
||||||
|
},
|
||||||
|
],
|
||||||
secret: '',
|
secret: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -98,20 +103,35 @@ export const useWebhookUpdateForm = ({
|
|||||||
});
|
});
|
||||||
}, 300);
|
}, 300);
|
||||||
|
|
||||||
const validateData = (data: Partial<WebhookFormData>) => {
|
const isFormValidAndSetErrors = () => {
|
||||||
if (isDefined(data?.targetUrl)) {
|
const { targetUrl } = formData;
|
||||||
const trimmedUrl = data.targetUrl.trim();
|
|
||||||
const isTargetUrlValid = isValidUrl(trimmedUrl);
|
if (isDefined(targetUrl)) {
|
||||||
setIsTargetUrlValid(isTargetUrlValid);
|
const trimmedUrl = targetUrl.trim();
|
||||||
if (isTargetUrlValid) {
|
const isValid = isValidUrl(trimmedUrl);
|
||||||
setTitle(getUrlHostnameOrThrow(trimmedUrl) || 'New Webhook');
|
|
||||||
|
if (!isValid) {
|
||||||
|
setIsTargetUrlValid(false);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setIsTargetUrlValid(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateWebhook = async (data: Partial<WebhookFormData>) => {
|
const updateWebhook = async (data: Partial<WebhookFormData>) => {
|
||||||
validateData(data);
|
|
||||||
setFormData((prev) => ({ ...prev, ...data }));
|
setFormData((prev) => ({ ...prev, ...data }));
|
||||||
|
|
||||||
|
if (!isFormValidAndSetErrors()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDefined(data?.targetUrl)) {
|
||||||
|
setTitle(getUrlHostnameOrThrow(data.targetUrl) || 'New Webhook');
|
||||||
|
}
|
||||||
|
|
||||||
await handleSave();
|
await handleSave();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -173,7 +193,10 @@ export const useWebhookUpdateForm = ({
|
|||||||
operations,
|
operations,
|
||||||
secret: data.secret,
|
secret: data.secret,
|
||||||
});
|
});
|
||||||
setTitle(getUrlHostnameOrThrow(data.targetUrl) || 'New Webhook');
|
if (isValidUrl(data.targetUrl)) {
|
||||||
|
setTitle(getUrlHostnameOrThrow(data.targetUrl));
|
||||||
|
}
|
||||||
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user