diff --git a/src/apps/legacy/routes/session/forgotPassword/index.tsx b/src/apps/legacy/routes/session/forgotPassword/index.tsx index 8861a288f3..3f4f7f9b37 100644 --- a/src/apps/legacy/routes/session/forgotPassword/index.tsx +++ b/src/apps/legacy/routes/session/forgotPassword/index.tsx @@ -10,6 +10,8 @@ import Input from 'elements/emby-input/Input'; import globalize from 'lib/globalize'; import ServerConnections from 'lib/jellyfin-apiclient/ServerConnections'; import { getAuthenticationApi } from 'utils/sdk/authentication-api'; +import { isValidUrl } from 'utils/url'; +import shell from 'scripts/shell'; export const ForgotPasswordPage = () => { const navigate = useNavigate(); @@ -41,13 +43,19 @@ export const ForgotPasswordPage = () => { msg = globalize.translate('MessageForgotPasswordInNetworkRequired'); break; case ForgotPasswordAction.PinCode: - msg = globalize.translate('MessageForgotPasswordFileCreated'); - msg += '

'; - msg += globalize.translate('MessageForgotPasswordPinReset'); - msg += '

'; - msg += result.PinFile; - msg += '
'; - callback = () => navigate('/forgotpasswordpin'); + if (result.PinFile && isValidUrl(result.PinFile)) { + msg = globalize.translate('MessageForgotPasswordRedirect'); + shell.openUrl(result.PinFile); + callback = () => navigate('/login'); + } else { + msg = globalize.translate('MessageForgotPasswordFileCreated'); + msg += '

'; + msg += globalize.translate('MessageForgotPasswordPinReset'); + msg += '

'; + msg += result.PinFile; + msg += '
'; + callback = () => navigate('/forgotpasswordpin'); + } break; default: return; diff --git a/src/strings/en-us.json b/src/strings/en-us.json index a6b093a5fd..358b318363 100755 --- a/src/strings/en-us.json +++ b/src/strings/en-us.json @@ -1186,6 +1186,7 @@ "MessageFileReadError": "There was an error reading the file. Please try again.", "MessageForgotPasswordFileCreated": "The following file has been created on your server and contains instructions on how to proceed", "MessageForgotPasswordPinReset": "Enter PIN here to finish Password reset", + "MessageForgotPasswordRedirect": "You have been redirected to an external provider for the password reset.", "MessageForgotPasswordInNetworkRequired": "Please try again within your home network to initiate the password reset process.", "MessageGetInstalledPluginsError": "An error occurred while getting the list of currently installed plugins.", "MessageImageFileTypeAllowed": "Only JPEG and PNG files are supported.", diff --git a/src/utils/url.ts b/src/utils/url.ts index 7e3f4a84c6..3798122200 100644 --- a/src/utils/url.ts +++ b/src/utils/url.ts @@ -53,3 +53,20 @@ export const safeDecodeURIComponent = (value: string) => { return value; } }; + +/** + * Test if a string is a valid http or https URL. + * @param value The value to test. + * @returns Whether the value is a URL or not. + */ +export const isValidUrl = (value: string) => { + let url; + + try { + url = new URL(value); + } catch { + return false; + } + + return url.protocol === 'http:' || url.protocol === 'https:'; +};