SafeAnchor.jsx 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. import {actionCreators as ac, actionTypes as at} from "common/Actions.jsm";
  2. import React from "react";
  3. export class SafeAnchor extends React.PureComponent {
  4. constructor(props) {
  5. super(props);
  6. this.onClick = this.onClick.bind(this);
  7. }
  8. onClick(event) {
  9. // Use dispatch instead of normal link click behavior to include referrer
  10. if (this.props.dispatch) {
  11. event.preventDefault();
  12. const {altKey, button, ctrlKey, metaKey, shiftKey} = event;
  13. this.props.dispatch(ac.OnlyToMain({
  14. type: at.OPEN_LINK,
  15. data: {
  16. event: {altKey, button, ctrlKey, metaKey, shiftKey},
  17. referrer: "https://getpocket.com/recommendations",
  18. // Use the anchor's url, which could have been cleaned up
  19. url: event.currentTarget.href,
  20. },
  21. }));
  22. }
  23. // Propagate event if there's a handler
  24. if (this.props.onLinkClick) {
  25. this.props.onLinkClick(event);
  26. }
  27. }
  28. safeURI(url) {
  29. let protocol = null;
  30. try {
  31. protocol = new URL(url).protocol;
  32. } catch (e) { return ""; }
  33. const isAllowed = [
  34. "http:",
  35. "https:",
  36. ].includes(protocol);
  37. if (!isAllowed) {
  38. console.warn(`${url} is not allowed for anchor targets.`); // eslint-disable-line no-console
  39. return "";
  40. }
  41. return url;
  42. }
  43. render() {
  44. const {url, className} = this.props;
  45. return (
  46. <a href={this.safeURI(url)} className={className} onClick={this.onClick}>
  47. {this.props.children}
  48. </a>
  49. );
  50. }
  51. }