@@ -48,6 +48,16 @@ function getButtonClasses(buttonVariant: ButtonVariant): string {
4848 return `${ base } bg-primary hover:bg-primary/90 text-black font-black py-4 transition-all active:scale-[0.98] shadow-lg shadow-primary/20` ;
4949}
5050
51+ // Helper function to validate URLs and prevent XSS through 'javascript:' protocol
52+ function validateUrl ( url ?: string ) : string | undefined {
53+ if ( ! url ) return undefined ;
54+ const lowerUrl = url . toLowerCase ( ) ;
55+ if ( lowerUrl . startsWith ( "http://" ) || lowerUrl . startsWith ( "https://" ) ) {
56+ return url ;
57+ }
58+ return undefined ;
59+ }
60+
5161// Main component function that renders the support us button, taking in various props for customization and rendering different sections such as hero, organization information, sponsors, and call-to-action based on the provided data and selected theme and button variant
5262function SupportUsButton ( {
5363 Theme = "AOSSIE" ,
@@ -70,6 +80,21 @@ function SupportUsButton({
7080 } ,
7181 buttonVariant = "AOSSIE" ,
7282} : supportUsButtonProps ) : React . JSX . Element {
83+ const validatedUrl = validateUrl ( organizationInformation ?. url ) ;
84+ const logoContent =
85+ typeof organizationInformation . logo === "string" ? (
86+ < span className = "block h-fit w-fit p-4 bg-black text-white rounded-2xl" >
87+ < b className = "text-2xl italic" > { organizationInformation . logo } </ b >
88+ </ span >
89+ ) : (
90+ < img
91+ className = "w-24 h-24 bg-white/80 select-none rounded-2xl object-cover object-center"
92+ src = { organizationInformation . logo ?. src }
93+ alt = { organizationInformation . logo ?. alt }
94+ title = { organizationInformation . logo ?. alt }
95+ draggable = { false }
96+ />
97+ ) ;
7398 return (
7499 // Container for the support us button, with dynamic classes based on the selected theme and custom class names
75100 < div
@@ -163,25 +188,22 @@ function SupportUsButton({
163188 ) }
164189
165190 { /* Organization logo */ }
166- < div >
167- { typeof organizationInformation . logo === "string" ? (
168- < span
169- className = "block h-fit w-fit p-4 bg-black text-white rounded-2xl"
170- title = { organizationInformation . logo }
171- >
172- < b className = "text-2xl italic" >
173- { organizationInformation . logo }
174- </ b >
175- </ span >
176- ) : (
177- < img
178- className = "w-24 h-24 bg-white/80 pointer-none:cursor-none select-none rounded-2xl object-cover object-center"
179- src = { organizationInformation . logo ?. src }
180- alt = { organizationInformation . logo ?. alt }
181- title = { organizationInformation . logo ?. alt }
182- draggable = { false }
183- />
184- ) }
191+
192+ < div >
193+ { organizationInformation ?. logo &&
194+ ( validatedUrl ? (
195+ < a
196+ href = { validatedUrl }
197+ target = "_blank"
198+ rel = "noopener noreferrer"
199+ title = { `Visit ${ organizationInformation . name } ` }
200+ className = "inline-block transition-transform duration-200 hover:scale-105 hover:shadow-lg cursor-pointer"
201+ >
202+ { logoContent }
203+ </ a >
204+ ) : (
205+ logoContent
206+ ) ) }
185207 </ div >
186208
187209 { /* Organization name and description */ }
@@ -456,4 +478,4 @@ function SupportUsButton({
456478 ) ;
457479}
458480
459- export default SupportUsButton ;
481+ export default SupportUsButton ;
0 commit comments