@@ -15,42 +15,68 @@ import DOMPurify from "dompurify";
1515import { useEffect , useState } from "react" ;
1616
1717export const ContinuePage = ( ) => {
18- const { isLoggedIn } = useUserContext ( ) ;
19-
20- if ( ! isLoggedIn ) {
21- return < Navigate to = "/login" /> ;
22- }
23-
2418 const { rootDomain } = useAppContext ( ) ;
19+ const { isLoggedIn } = useUserContext ( ) ;
2520 const { search } = useLocation ( ) ;
21+ const { t } = useTranslation ( ) ;
22+ const navigate = useNavigate ( ) ;
23+
2624 const [ loading , setLoading ] = useState ( false ) ;
2725 const [ showRedirectButton , setShowRedirectButton ] = useState ( false ) ;
2826
2927 const searchParams = new URLSearchParams ( search ) ;
30- const redirectURI = searchParams . get ( "redirect_uri" ) ;
28+ const redirectUri = searchParams . get ( "redirect_uri" ) ;
3129
32- if ( ! redirectURI ) {
33- return < Navigate to = "/logout" /> ;
34- }
35-
36- if ( ! isValidUrl ( DOMPurify . sanitize ( redirectURI ) ) ) {
37- return < Navigate to = "/logout" /> ;
38- }
39-
40- const { t } = useTranslation ( ) ;
41- const navigate = useNavigate ( ) ;
30+ const isValidRedirectUri =
31+ redirectUri !== null ? isValidUrl ( DOMPurify . sanitize ( redirectUri ) ) : false ;
32+ const redirectUriObj = isValidRedirectUri
33+ ? new URL ( redirectUri as string )
34+ : null ;
35+ const isTrustedRedirectUri =
36+ redirectUriObj !== null
37+ ? redirectUriObj . hostname === rootDomain ||
38+ redirectUriObj . hostname . endsWith ( `.${ rootDomain } ` )
39+ : false ;
40+ const isHttpsDowngrade =
41+ redirectUriObj !== null
42+ ? redirectUriObj . protocol === "http:" &&
43+ window . location . protocol === "https:"
44+ : false ;
4245
4346 const handleRedirect = ( ) => {
4447 setLoading ( true ) ;
45- window . location . href = DOMPurify . sanitize ( redirectURI ) ;
48+ window . location . replace ( DOMPurify . sanitize ( redirectUriObj ! . toString ( ) ) ) ;
4649 } ;
4750
48- const redirectURLObj = new URL ( redirectURI ) ;
51+ useEffect ( ( ) => {
52+ if (
53+ ! isLoggedIn ||
54+ ! isValidRedirectUri ||
55+ ! isTrustedRedirectUri ||
56+ isHttpsDowngrade
57+ ) {
58+ return ;
59+ }
60+
61+ setTimeout ( ( ) => {
62+ handleRedirect ( ) ;
63+ } , 100 ) ;
64+
65+ setTimeout ( ( ) => {
66+ setLoading ( false ) ;
67+ setShowRedirectButton ( true ) ;
68+ } , 1000 ) ;
69+ } , [ ] ) ;
70+
71+ if ( ! isLoggedIn ) {
72+ return < Navigate to = "/login" /> ;
73+ }
4974
50- if (
51- ! ( redirectURLObj . hostname == rootDomain ) &&
52- ! redirectURLObj . hostname . endsWith ( `.${ rootDomain } ` )
53- ) {
75+ if ( ! isValidRedirectUri ) {
76+ return < Navigate to = "/logout" /> ;
77+ }
78+
79+ if ( ! isTrustedRedirectUri ) {
5480 return (
5581 < Card className = "min-w-xs sm:min-w-sm" >
5682 < CardHeader >
@@ -88,10 +114,7 @@ export const ContinuePage = () => {
88114 ) ;
89115 }
90116
91- if (
92- redirectURLObj . protocol === "http:" &&
93- window . location . protocol === "https:"
94- ) {
117+ if ( isHttpsDowngrade ) {
95118 return (
96119 < Card className = "min-w-xs sm:min-w-sm" >
97120 < CardHeader >
@@ -124,16 +147,6 @@ export const ContinuePage = () => {
124147 ) ;
125148 }
126149
127- useEffect ( ( ) => {
128- setTimeout ( ( ) => {
129- handleRedirect ( ) ;
130- } , 100 ) ;
131- setTimeout ( ( ) => {
132- setLoading ( false ) ;
133- setShowRedirectButton ( true ) ;
134- } , 1000 ) ;
135- } , [ ] ) ;
136-
137150 return (
138151 < Card className = "min-w-xs sm:min-w-sm" >
139152 < CardHeader >
0 commit comments