SafeAnchor.jsx (2229B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 import { actionCreators as ac, actionTypes as at } from "common/Actions.mjs"; 6 import React from "react"; 7 8 export class SafeAnchor extends React.PureComponent { 9 constructor(props) { 10 super(props); 11 this.onClick = this.onClick.bind(this); 12 } 13 14 onClick(event) { 15 // Use dispatch instead of normal link click behavior to include referrer 16 if (this.props.dispatch) { 17 event.preventDefault(); 18 const { altKey, button, ctrlKey, metaKey, shiftKey } = event; 19 this.props.dispatch( 20 ac.OnlyToMain({ 21 type: at.OPEN_LINK, 22 data: { 23 event: { altKey, button, ctrlKey, metaKey, shiftKey }, 24 referrer: 25 this.props.referrer || "https://getpocket.com/recommendations", 26 // Use the anchor's url, which could have been cleaned up 27 url: event.currentTarget.href, 28 is_sponsored: this.props.isSponsored, 29 }, 30 }) 31 ); 32 } 33 34 // Propagate event if there's a handler 35 if (this.props.onLinkClick) { 36 this.props.onLinkClick(event); 37 } 38 } 39 40 safeURI(url) { 41 let protocol = null; 42 try { 43 protocol = new URL(url).protocol; 44 } catch (e) { 45 return ""; 46 } 47 48 const isAllowed = ["http:", "https:"].includes(protocol); 49 if (!isAllowed) { 50 console.warn(`${url} is not allowed for anchor targets.`); // eslint-disable-line no-console 51 return ""; 52 } 53 return url; 54 } 55 56 render() { 57 const { url, className, title, isSponsored, onFocus } = this.props; 58 59 let anchor = ( 60 <a 61 href={this.safeURI(url)} 62 title={title} 63 className={className} 64 onClick={this.onClick} 65 data-is-sponsored-link={!!isSponsored} 66 {...(this.props.tabIndex === 0 || this.props.tabIndex 67 ? { 68 ref: this.props.setRef, 69 tabIndex: this.props.tabIndex, 70 } 71 : {})} 72 {...(onFocus ? { onFocus } : {})} 73 > 74 {this.props.children} 75 </a> 76 ); 77 78 return anchor; 79 } 80 }