Example #1
0
 public function __toString()
 {
     $prefix = null;
     if ($this->protocol || $this->domain || $this->port) {
         $protocol = ValueAs::nonempty($this->protocol, 'http');
         $auth = '';
         if (strlen($this->user) && strlen($this->pass)) {
             $auth = SafeHtml::escapeUri($this->user) . ':' . SafeHtml::escapeUri($this->pass) . '@';
         } else {
             if (strlen($this->user)) {
                 $auth = SafeHtml::escapeUri($this->user) . '@';
             }
         }
         if ($protocol != 'javascript') {
             $prefix = $protocol . '://' . $auth . $this->domain;
         } else {
             $prefix = $protocol . ':';
         }
         if ($this->port) {
             $prefix .= ':' . $this->port;
         }
     }
     if ($this->query) {
         $query = '?' . http_build_query($this->query);
     } else {
         $query = null;
     }
     if (strlen($this->getFragment())) {
         $fragment = '#' . $this->getFragment();
     } else {
         $fragment = null;
     }
     return $prefix . $this->getPath() . $query . $fragment;
 }
Example #2
0
 public function testURIPathComponentEscape()
 {
     $this->assertEquals('a%252Fb', SafeHtml::escapeUriPathComponent('a/b'));
     $str = '';
     for ($ii = 0; $ii <= 255; $ii++) {
         $str .= chr($ii);
     }
     $this->assertEquals($str, SafeHtml::unescapeUriPathComponent(rawurldecode(SafeHtml::escapeUriPathComponent($str))));
 }
 public function testCollection()
 {
     $tags = Paragraph::collection(['a', 'b', 'c']);
     $this->assertEquals('<p>a</p><p>b</p><p>c</p>', SafeHtml::escape($tags, ''));
 }
Example #4
0
 /**
  * @return SafeHtml|SafeHtml[]
  * @throws \Exception
  */
 public function produceSafeHTML()
 {
     // If the `href` attribute is present:
     //   - make sure it is not a "javascript:" URI. We never permit these.
     //   - if the tag is an `<a>` and the link is to some foreign resource,
     //     add `rel="nofollow"` by default.
     if (!empty($this->_attributes['href'])) {
         // This might be a URI object, so cast it to a string.
         $href = (string) $this->_attributes['href'];
         if (isset($href[0])) {
             $isAnchorHref = $href[0] == '#';
             // Is this a link to a resource on the same domain? The second part of
             // this excludes "///evil.com/" protocol-relative hrefs.
             $isDomainHref = $href[0] == '/' && (!isset($href[1]) || $href[1] != '/');
             // Block 'javascript:' hrefs at the tag level: no well-designed
             // application should ever use them, and they are a potent attack vector.
             // This function is deep in the core and performance sensitive, so we're
             // doing a cheap version of this test first to avoid calling preg_match()
             // on URIs which begin with '/' or `#`. These cover essentially all URIs
             // in Phabricator.
             if (!$isAnchorHref && !$isDomainHref) {
                 // Chrome 33 and IE 11 both interpret "javascript\n:" as a Javascript
                 // URI, and all browsers interpret "  javascript:" as a Javascript URI,
                 // so be aggressive about looking for "javascript:" in the initial
                 // section of the string.
                 $normalizedHref = preg_replace('([^a-z0-9/:]+)i', '', $href);
                 if (preg_match('/^javascript:/i', $normalizedHref)) {
                     throw new \Exception("Attempting to render a tag with an 'href' attribute that " . "begins with 'javascript:'. This is either a serious security " . "concern or a serious architecture concern. Seek urgent " . "remedy.");
                 }
             }
         }
     }
     // For tags which can't self-close, treat null as the empty string -- for
     // example, always render `<div></div>`, never `<div />`.
     $selfClosingTags = ['area' => true, 'base' => true, 'br' => true, 'col' => true, 'command' => true, 'embed' => true, 'frame' => true, 'hr' => true, 'img' => true, 'input' => true, 'keygen' => true, 'link' => true, 'meta' => true, 'param' => true, 'source' => true, 'track' => true, 'wbr' => true];
     $attrString = '';
     foreach ($this->_attributes as $k => $v) {
         if ($v !== null) {
             $attrString .= ' ' . $k . '="' . SafeHtml::escape($v) . '"';
         } else {
             $attrString .= ' ' . $k;
         }
     }
     $content = $this->_getContentForRender();
     if ($content === null) {
         if (isset($selfClosingTags[$this->_tag])) {
             return new SafeHtml('<' . $this->_tag . $attrString . ' />');
         }
         $content = '';
     } else {
         $content = SafeHtml::escape($content, '');
     }
     return new SafeHtml('<' . $this->_tag . $attrString . '>' . $content . '</' . $this->_tag . '>');
 }