mirror of
https://github.com/sct/overseerr.git
synced 2025-09-17 17:24:35 +02:00
fix(ui): validate application url and service external urls
This commit is contained in:
@@ -1,6 +1,5 @@
|
|||||||
import axios, { AxiosInstance, AxiosRequestConfig } from 'axios';
|
import axios, { AxiosInstance, AxiosRequestConfig } from 'axios';
|
||||||
import NodeCache from 'node-cache';
|
import NodeCache from 'node-cache';
|
||||||
import logger from '../logger';
|
|
||||||
|
|
||||||
// 5 minute default TTL (in seconds)
|
// 5 minute default TTL (in seconds)
|
||||||
const DEFAULT_TTL = 300;
|
const DEFAULT_TTL = 300;
|
||||||
@@ -66,9 +65,6 @@ class ExternalAPI {
|
|||||||
|
|
||||||
if (cachedItem) {
|
if (cachedItem) {
|
||||||
const keyTtl = this.cache?.getTtl(cacheKey) ?? 0;
|
const keyTtl = this.cache?.getTtl(cacheKey) ?? 0;
|
||||||
logger.debug(`Loaded item from cache: ${cacheKey}`, {
|
|
||||||
keyTtl,
|
|
||||||
});
|
|
||||||
|
|
||||||
// If the item has passed our rolling check, fetch again in background
|
// If the item has passed our rolling check, fetch again in background
|
||||||
if (
|
if (
|
||||||
|
@@ -50,6 +50,8 @@ const messages = defineMessages({
|
|||||||
loadingrootfolders: 'Loading root folders…',
|
loadingrootfolders: 'Loading root folders…',
|
||||||
testFirstRootFolders: 'Test connection to load root folders',
|
testFirstRootFolders: 'Test connection to load root folders',
|
||||||
preventSearch: 'Disable Auto-Search',
|
preventSearch: 'Disable Auto-Search',
|
||||||
|
validationApplicationUrl: 'You must provide a valid URL',
|
||||||
|
validationApplicationUrlTrailingSlash: 'URL must not end in a trailing slash',
|
||||||
});
|
});
|
||||||
|
|
||||||
interface TestResponse {
|
interface TestResponse {
|
||||||
@@ -105,6 +107,18 @@ const RadarrModal: React.FC<RadarrModalProps> = ({
|
|||||||
minimumAvailability: Yup.string().required(
|
minimumAvailability: Yup.string().required(
|
||||||
intl.formatMessage(messages.validationMinimumAvailabilityRequired)
|
intl.formatMessage(messages.validationMinimumAvailabilityRequired)
|
||||||
),
|
),
|
||||||
|
externalUrl: Yup.string()
|
||||||
|
.url(intl.formatMessage(messages.validationApplicationUrl))
|
||||||
|
.test(
|
||||||
|
'no-trailing-slash',
|
||||||
|
intl.formatMessage(messages.validationApplicationUrlTrailingSlash),
|
||||||
|
(value) => {
|
||||||
|
if (value?.substr(value.length - 1) === '/') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
const testConnection = useCallback(
|
const testConnection = useCallback(
|
||||||
|
@@ -39,6 +39,8 @@ const messages = defineMessages({
|
|||||||
'Allows Overseerr to correctly register client IP addresses behind a proxy (Overseerr must be reloaded for changes to take effect)',
|
'Allows Overseerr to correctly register client IP addresses behind a proxy (Overseerr must be reloaded for changes to take effect)',
|
||||||
localLogin: 'Enable Local User Sign-In',
|
localLogin: 'Enable Local User Sign-In',
|
||||||
validationApplicationTitle: 'You must provide an application title',
|
validationApplicationTitle: 'You must provide an application title',
|
||||||
|
validationApplicationUrl: 'You must provide a valid URL',
|
||||||
|
validationApplicationUrlTrailingSlash: 'URL must not end in a trailing slash',
|
||||||
});
|
});
|
||||||
|
|
||||||
const SettingsMain: React.FC = () => {
|
const SettingsMain: React.FC = () => {
|
||||||
@@ -52,6 +54,18 @@ const SettingsMain: React.FC = () => {
|
|||||||
applicationTitle: Yup.string().required(
|
applicationTitle: Yup.string().required(
|
||||||
intl.formatMessage(messages.validationApplicationTitle)
|
intl.formatMessage(messages.validationApplicationTitle)
|
||||||
),
|
),
|
||||||
|
applicationUrl: Yup.string()
|
||||||
|
.url(intl.formatMessage(messages.validationApplicationUrl))
|
||||||
|
.test(
|
||||||
|
'no-trailing-slash',
|
||||||
|
intl.formatMessage(messages.validationApplicationUrlTrailingSlash),
|
||||||
|
(value) => {
|
||||||
|
if (value?.substr(value.length - 1) === '/') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
const regenerate = async () => {
|
const regenerate = async () => {
|
||||||
@@ -200,6 +214,9 @@ const SettingsMain: React.FC = () => {
|
|||||||
placeholder="https://os.example.com"
|
placeholder="https://os.example.com"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
{errors.applicationUrl && touched.applicationUrl && (
|
||||||
|
<div className="error">{errors.applicationUrl}</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="form-row">
|
<div className="form-row">
|
||||||
|
@@ -50,6 +50,8 @@ const messages = defineMessages({
|
|||||||
externalUrl: 'External URL',
|
externalUrl: 'External URL',
|
||||||
externalUrlPlaceholder: 'External URL pointing to your Sonarr server',
|
externalUrlPlaceholder: 'External URL pointing to your Sonarr server',
|
||||||
preventSearch: 'Disable Auto-Search',
|
preventSearch: 'Disable Auto-Search',
|
||||||
|
validationApplicationUrl: 'You must provide a valid URL',
|
||||||
|
validationApplicationUrlTrailingSlash: 'URL must not end in a trailing slash',
|
||||||
});
|
});
|
||||||
|
|
||||||
interface TestResponse {
|
interface TestResponse {
|
||||||
@@ -102,6 +104,18 @@ const SonarrModal: React.FC<SonarrModalProps> = ({
|
|||||||
activeProfileId: Yup.string().required(
|
activeProfileId: Yup.string().required(
|
||||||
intl.formatMessage(messages.validationProfileRequired)
|
intl.formatMessage(messages.validationProfileRequired)
|
||||||
),
|
),
|
||||||
|
externalUrl: Yup.string()
|
||||||
|
.url(intl.formatMessage(messages.validationApplicationUrl))
|
||||||
|
.test(
|
||||||
|
'no-trailing-slash',
|
||||||
|
intl.formatMessage(messages.validationApplicationUrlTrailingSlash),
|
||||||
|
(value) => {
|
||||||
|
if (value?.substr(value.length - 1) === '/') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
const testConnection = useCallback(
|
const testConnection = useCallback(
|
||||||
|
@@ -325,6 +325,8 @@
|
|||||||
"components.Settings.RadarrModal.toastRadarrTestFailure": "Failed to connect to Radarr.",
|
"components.Settings.RadarrModal.toastRadarrTestFailure": "Failed to connect to Radarr.",
|
||||||
"components.Settings.RadarrModal.toastRadarrTestSuccess": "Radarr connection established!",
|
"components.Settings.RadarrModal.toastRadarrTestSuccess": "Radarr connection established!",
|
||||||
"components.Settings.RadarrModal.validationApiKeyRequired": "You must provide an API key",
|
"components.Settings.RadarrModal.validationApiKeyRequired": "You must provide an API key",
|
||||||
|
"components.Settings.RadarrModal.validationApplicationUrl": "You must provide a valid URL",
|
||||||
|
"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash": "URL must not end in a trailing slash",
|
||||||
"components.Settings.RadarrModal.validationHostnameRequired": "You must provide a hostname/IP",
|
"components.Settings.RadarrModal.validationHostnameRequired": "You must provide a hostname/IP",
|
||||||
"components.Settings.RadarrModal.validationMinimumAvailabilityRequired": "You must select a minimum availability",
|
"components.Settings.RadarrModal.validationMinimumAvailabilityRequired": "You must select a minimum availability",
|
||||||
"components.Settings.RadarrModal.validationNameRequired": "You must provide a server name",
|
"components.Settings.RadarrModal.validationNameRequired": "You must provide a server name",
|
||||||
@@ -409,6 +411,8 @@
|
|||||||
"components.Settings.SonarrModal.toastSonarrTestFailure": "Failed to connect to Sonarr.",
|
"components.Settings.SonarrModal.toastSonarrTestFailure": "Failed to connect to Sonarr.",
|
||||||
"components.Settings.SonarrModal.toastSonarrTestSuccess": "Sonarr connection established!",
|
"components.Settings.SonarrModal.toastSonarrTestSuccess": "Sonarr connection established!",
|
||||||
"components.Settings.SonarrModal.validationApiKeyRequired": "You must provide an API key",
|
"components.Settings.SonarrModal.validationApiKeyRequired": "You must provide an API key",
|
||||||
|
"components.Settings.SonarrModal.validationApplicationUrl": "You must provide a valid URL",
|
||||||
|
"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash": "URL must not end in a trailing slash",
|
||||||
"components.Settings.SonarrModal.validationHostnameRequired": "You must provide a hostname/IP",
|
"components.Settings.SonarrModal.validationHostnameRequired": "You must provide a hostname/IP",
|
||||||
"components.Settings.SonarrModal.validationNameRequired": "You must provide a server name",
|
"components.Settings.SonarrModal.validationNameRequired": "You must provide a server name",
|
||||||
"components.Settings.SonarrModal.validationPortRequired": "You must provide a port",
|
"components.Settings.SonarrModal.validationPortRequired": "You must provide a port",
|
||||||
@@ -502,6 +506,8 @@
|
|||||||
"components.Settings.trustProxy": "Enable Proxy Support",
|
"components.Settings.trustProxy": "Enable Proxy Support",
|
||||||
"components.Settings.trustProxyTip": "Allows Overseerr to correctly register client IP addresses behind a proxy (Overseerr must be reloaded for changes to take effect)",
|
"components.Settings.trustProxyTip": "Allows Overseerr to correctly register client IP addresses behind a proxy (Overseerr must be reloaded for changes to take effect)",
|
||||||
"components.Settings.validationApplicationTitle": "You must provide an application title",
|
"components.Settings.validationApplicationTitle": "You must provide an application title",
|
||||||
|
"components.Settings.validationApplicationUrl": "You must provide a valid URL",
|
||||||
|
"components.Settings.validationApplicationUrlTrailingSlash": "URL must not end in a trailing slash",
|
||||||
"components.Settings.validationHostnameRequired": "You must provide a hostname/IP",
|
"components.Settings.validationHostnameRequired": "You must provide a hostname/IP",
|
||||||
"components.Settings.validationPortRequired": "You must provide a port",
|
"components.Settings.validationPortRequired": "You must provide a port",
|
||||||
"components.Setup.configureplex": "Configure Plex",
|
"components.Setup.configureplex": "Configure Plex",
|
||||||
|
Reference in New Issue
Block a user