protected function didValidateOption(PhabricatorConfigOption $option, $value)
 {
     $key = $option->getKey();
     if ($key == 'phabricator.base-uri' || $key == 'phabricator.production-uri') {
         $uri = new PhutilURI($value);
         $protocol = $uri->getProtocol();
         if ($protocol !== 'http' && $protocol !== 'https') {
             throw new PhabricatorConfigValidationException(pht("Config option '%s' is invalid. The URI must start with " . "%s' or '%s'.", 'http://', 'https://', $key));
         }
         $domain = $uri->getDomain();
         if (strpos($domain, '.') === false) {
             throw new PhabricatorConfigValidationException(pht("Config option '%s' is invalid. The URI must contain a dot " . "('%s'), like '%s', not just a bare name like '%s'. Some web " . "browsers will not set cookies on domains with no TLD.", '.', 'http://example.com/', 'http://example/', $key));
         }
         $path = $uri->getPath();
         if ($path !== '' && $path !== '/') {
             throw new PhabricatorConfigValidationException(pht("Config option '%s' is invalid. The URI must NOT have a path, " . "e.g. '%s' is OK, but '%s' is not. Phabricator must be installed " . "on an entire domain; it can not be installed on a path.", $key, 'http://phabricator.example.com/', 'http://example.com/phabricator/'));
         }
     }
     if ($key === 'phabricator.timezone') {
         $old = date_default_timezone_get();
         $ok = @date_default_timezone_set($value);
         @date_default_timezone_set($old);
         if (!$ok) {
             throw new PhabricatorConfigValidationException(pht("Config option '%s' is invalid. The timezone identifier must " . "be a valid timezone identifier recognized by PHP, like '%s'. " . "\n            You can find a list of valid identifiers here: %s", $key, 'America/Los_Angeles', 'http://php.net/manual/timezones.php'));
         }
     }
 }
 public static function newFromRawCorpus($corpus)
 {
     $obj = new ArcanistDifferentialCommitMessage();
     $obj->rawCorpus = $corpus;
     // Parse older-style "123" fields, or newer-style full-URI fields.
     // TODO: Remove support for older-style fields.
     $match = null;
     if (preg_match('/^Differential Revision:\\s*(.*)/im', $corpus, $match)) {
         $revision_id = trim($match[1]);
         if (strlen($revision_id)) {
             if (preg_match('/^D?\\d+$/', $revision_id)) {
                 $obj->revisionID = (int) trim($revision_id, 'D');
             } else {
                 $uri = new PhutilURI($revision_id);
                 $path = $uri->getPath();
                 $path = trim($path, '/');
                 if (preg_match('/^D\\d+$/', $path)) {
                     $obj->revisionID = (int) trim($path, 'D');
                 } else {
                     throw new ArcanistUsageException("Invalid 'Differential Revision' field. The field should have a " . "Phabricator URI like 'http://phabricator.example.com/D123', " . "but has '{$match[1]}'.");
                 }
             }
         }
     }
     $pattern = '/^git-svn-id:\\s*([^@]+)@(\\d+)\\s+(.*)$/m';
     if (preg_match($pattern, $corpus, $match)) {
         $obj->gitSVNBaseRevision = $match[1] . '@' . $match[2];
         $obj->gitSVNBasePath = $match[1];
         $obj->gitSVNUUID = $match[3];
     }
     return $obj;
 }
 public function markupDocumentLink($matches)
 {
     $link = trim($matches[1]);
     $name = trim(idx($matches, 2, $link));
     if (empty($matches[2])) {
         $name = explode('/', trim($name, '/'));
         $name = end($name);
     }
     $uri = new PhutilURI($link);
     $slug = $uri->getPath();
     $fragment = $uri->getFragment();
     $slug = PhabricatorSlug::normalize($slug);
     $slug = PhrictionDocument::getSlugURI($slug);
     $href = (string) id(new PhutilURI($slug))->setFragment($fragment);
     if ($this->getEngine()->getState('toc')) {
         $text = $name;
     } else {
         if ($this->getEngine()->isTextMode()) {
             return PhabricatorEnv::getProductionURI($href);
         } else {
             $text = $this->newTag('a', array('href' => $href, 'class' => 'phriction-link'), $name);
         }
     }
     return $this->getEngine()->storeText($text);
 }
Example #4
0
 /**
  * Makes sure a given custom blog uri is properly configured in DNS
  * to point at this Phabricator instance. If there is an error in
  * the configuration, return a string describing the error and how
  * to fix it. If there is no error, return an empty string.
  *
  * @return string
  */
 public function validateCustomDomain($domain_full_uri)
 {
     $example_domain = 'http://blog.example.com/';
     $label = pht('Invalid');
     // note this "uri" should be pretty busted given the desired input
     // so just use it to test if there's a protocol specified
     $uri = new PhutilURI($domain_full_uri);
     $domain = $uri->getDomain();
     $protocol = $uri->getProtocol();
     $path = $uri->getPath();
     $supported_protocols = array('http', 'https');
     if (!in_array($protocol, $supported_protocols)) {
         return array($label, pht('The custom domain should include a valid protocol in the URI ' . '(for example, "%s"). Valid protocols are "http" or "https".', $example_domain));
     }
     if (strlen($path) && $path != '/') {
         return array($label, pht('The custom domain should not specify a path (hosting a Phame ' . 'blog at a path is currently not supported). Instead, just provide ' . 'the bare domain name (for example, "%s").', $example_domain));
     }
     if (strpos($domain, '.') === false) {
         return array($label, pht('The custom domain should contain at least one dot (.) because ' . 'some browsers fail to set cookies on domains without a dot. ' . 'Instead, use a normal looking domain name like "%s".', $example_domain));
     }
     if (!PhabricatorEnv::getEnvConfig('policy.allow-public')) {
         $href = PhabricatorEnv::getProductionURI('/config/edit/policy.allow-public/');
         return array(pht('Fix Configuration'), pht('For custom domains to work, this Phabricator instance must be ' . 'configured to allow the public access policy. Configure this ' . 'setting %s, or ask an administrator to configure this setting. ' . 'The domain can be specified later once this setting has been ' . 'changed.', phutil_tag('a', array('href' => $href), pht('here'))));
     }
     return null;
 }
 public function getWikiURI()
 {
     $config = $this->getProviderConfig();
     $uri = $config->getProperty(self::PROPERTY_MEDIAWIKI_URI);
     $uri = new PhutilURI($uri);
     $normalized = $uri->getProtocol() . '://' . $uri->getDomain();
     if ($uri->getPort() != 80 && $uri->getPort() != 443) {
         $normalized .= ':' . $uri->getPort();
     }
     if (strlen($uri->getPath()) > 0 && $uri->getPath() !== '/') {
         $normalized .= $uri->getPath();
     }
     if (substr($normalized, -1) == '/') {
         $normalized = substr($normalized, 0, -1);
     }
     return $normalized;
 }
 public static function getGitHubPath($uri)
 {
     $uri_object = new PhutilURI($uri);
     $domain = $uri_object->getDomain();
     $domain = phutil_utf8_strtolower($domain);
     switch ($domain) {
         case 'github.com':
         case 'www.github.com':
             return $uri_object->getPath();
         default:
             return null;
     }
 }
 /**
  * @task normal
  */
 public function getPath()
 {
     switch ($this->type) {
         case self::TYPE_GIT:
             $uri = new PhutilURI($this->uri);
             return $uri->getPath();
         case self::TYPE_SVN:
         case self::TYPE_MERCURIAL:
             $uri = new PhutilURI($this->uri);
             if ($uri->getProtocol()) {
                 return $uri->getPath();
             }
             return $this->uri;
     }
 }
 protected function didValidateOption(PhabricatorConfigOption $option, $value)
 {
     $key = $option->getKey();
     if ($key == 'security.alternate-file-domain') {
         $uri = new PhutilURI($value);
         $protocol = $uri->getProtocol();
         if ($protocol !== 'http' && $protocol !== 'https') {
             throw new PhabricatorConfigValidationException(pht("Config option '%s' is invalid. The URI must start with " . "'%s' or '%s'.", $key, 'http://', 'https://'));
         }
         $domain = $uri->getDomain();
         if (strpos($domain, '.') === false) {
             throw new PhabricatorConfigValidationException(pht("Config option '%s' is invalid. The URI must contain a dot ('.'), " . "like '%s', not just a bare name like '%s'. " . "Some web browsers will not set cookies on domains with no TLD.", $key, 'http://example.com/', 'http://example/'));
         }
         $path = $uri->getPath();
         if ($path !== '' && $path !== '/') {
             throw new PhabricatorConfigValidationException(pht("Config option '%s' is invalid. The URI must NOT have a path, " . "e.g. '%s' is OK, but '%s' is not. Phabricator must be installed " . "on an entire domain; it can not be installed on a path.", $key, 'http://phabricator.example.com/', 'http://example.com/phabricator/'));
         }
     }
 }
 private static function parseRevisionIDFromURI($uri_string)
 {
     $uri = new PhutilURI($uri_string);
     $path = $uri->getPath();
     $matches = null;
     if (preg_match('#^/D(\\d+)$#', $path, $matches)) {
         $id = (int) $matches[1];
         $prod_uri = new PhutilURI(PhabricatorEnv::getProductionURI('/D' . $id));
         // Make sure the URI is the same as our URI. Basically, we want to ignore
         // commits from other Phabricator installs.
         if ($uri->getDomain() == $prod_uri->getDomain()) {
             return $id;
         }
         $allowed_uris = PhabricatorEnv::getAllowedURIs('/D' . $id);
         foreach ($allowed_uris as $allowed_uri) {
             if ($uri_string == $allowed_uri) {
                 return $id;
             }
         }
     }
     return null;
 }
Example #10
0
 public function testURIParsing()
 {
     $uri = new PhutilURI('http://*****:*****@host:99/path/?query=value#fragment');
     $this->assertEqual('http', $uri->getProtocol(), 'protocol');
     $this->assertEqual('user', $uri->getUser(), 'user');
     $this->assertEqual('pass', $uri->getPass(), 'pass');
     $this->assertEqual('host', $uri->getDomain(), 'domain');
     $this->assertEqual('99', $uri->getPort(), 'port');
     $this->assertEqual('/path/', $uri->getPath(), 'path');
     $this->assertEqual(array('query' => 'value'), $uri->getQueryParams(), 'query params');
     $this->assertEqual('fragment', $uri->getFragment(), 'fragment');
     $this->assertEqual('http://*****:*****@host:99/path/?query=value#fragment', (string) $uri, 'uri');
     $uri = new PhutilURI('ssh://git@example.com/example/example.git');
     $this->assertEqual('ssh', $uri->getProtocol(), 'protocol');
     $this->assertEqual('git', $uri->getUser(), 'user');
     $this->assertEqual('', $uri->getPass(), 'pass');
     $this->assertEqual('example.com', $uri->getDomain(), 'domain');
     $this->assertEqual('', $uri->getPort(), 'port');
     $this->assertEqual('/example/example.git', $uri->getPath(), 'path');
     $this->assertEqual(array(), $uri->getQueryParams(), 'query params');
     $this->assertEqual('', $uri->getFragment(), 'fragment');
     $this->assertEqual('ssh://git@example.com/example/example.git', (string) $uri, 'uri');
     $uri = new PhutilURI('http://0@domain.com/');
     $this->assertEqual('0', $uri->getUser());
     $this->assertEqual('http://0@domain.com/', (string) $uri);
     $uri = new PhutilURI('http://*****:*****@domain.com/');
     $this->assertEqual('0', $uri->getUser());
     $this->assertEqual('0', $uri->getPass());
     $this->assertEqual('http://*****:*****@domain.com/', (string) $uri);
     $uri = new PhutilURI('http://%20:%20@domain.com/');
     $this->assertEqual(' ', $uri->getUser());
     $this->assertEqual(' ', $uri->getPass());
     $this->assertEqual('http://%20:%20@domain.com/', (string) $uri);
     $uri = new PhutilURI('http://%40:%40@domain.com/');
     $this->assertEqual('@', $uri->getUser());
     $this->assertEqual('@', $uri->getPass());
     $this->assertEqual('http://%40:%40@domain.com/', (string) $uri);
 }
 public function processRequest()
 {
     $provider = $this->getOAuthProvider();
     $oauth_info = $this->getOAuthInfo();
     $request = $this->getRequest();
     $errors = array();
     $e_username = true;
     $e_email = true;
     $e_realname = true;
     $user = new PhabricatorUser();
     $user->setUsername($provider->retrieveUserAccountName());
     $user->setRealName($provider->retrieveUserRealName());
     $user->setEmail($provider->retrieveUserEmail());
     if ($request->isFormPost()) {
         $user->setUsername($request->getStr('username'));
         $username = $user->getUsername();
         if (!strlen($user->getUsername())) {
             $e_username = '******';
             $errors[] = 'Username is required.';
         } else {
             if (!PhabricatorUser::validateUsername($username)) {
                 $e_username = '******';
                 $errors[] = 'Username must consist of only numbers and letters.';
             } else {
                 $e_username = null;
             }
         }
         if ($user->getEmail() === null) {
             $user->setEmail($request->getStr('email'));
             if (!strlen($user->getEmail())) {
                 $e_email = 'Required';
                 $errors[] = 'Email is required.';
             } else {
                 $e_email = null;
             }
         }
         if (!strlen($user->getRealName())) {
             $user->setRealName($request->getStr('realname'));
             if (!strlen($user->getRealName())) {
                 $e_realname = 'Required';
                 $errors[] = 'Real name is required.';
             } else {
                 $e_realname = null;
             }
         }
         if (!$errors) {
             $image = $provider->retrieveUserProfileImage();
             if ($image) {
                 $file = PhabricatorFile::newFromFileData($image, array('name' => $provider->getProviderKey() . '-profile.jpg', 'authorPHID' => $user->getPHID()));
                 $user->setProfileImagePHID($file->getPHID());
             }
             try {
                 $user->save();
                 $oauth_info->setUserID($user->getID());
                 $oauth_info->save();
                 $session_key = $user->establishSession('web');
                 $request->setCookie('phusr', $user->getUsername());
                 $request->setCookie('phsid', $session_key);
                 return id(new AphrontRedirectResponse())->setURI('/');
             } catch (AphrontQueryDuplicateKeyException $exception) {
                 $same_username = id(new PhabricatorUser())->loadOneWhere('userName = %s', $user->getUserName());
                 $same_email = id(new PhabricatorUser())->loadOneWhere('email = %s', $user->getEmail());
                 if ($same_username) {
                     $e_username = '******';
                     $errors[] = 'That username or email is not unique.';
                 } else {
                     if ($same_email) {
                         $e_email = 'Duplicate';
                         $errors[] = 'That email is not unique.';
                     } else {
                         throw $exception;
                     }
                 }
             }
         }
     }
     $error_view = null;
     if ($errors) {
         $error_view = new AphrontErrorView();
         $error_view->setTitle('Registration Failed');
         $error_view->setErrors($errors);
     }
     // Strip the URI down to the path, because otherwise we'll trigger
     // external CSRF protection (by having a protocol in the form "action")
     // and generate a form with no CSRF token.
     $action_uri = new PhutilURI($provider->getRedirectURI());
     $action_path = $action_uri->getPath();
     $form = new AphrontFormView();
     $form->addHiddenInput('token', $provider->getAccessToken())->addHiddenInput('expires', $oauth_info->getTokenExpires())->addHiddenInput('state', $this->getOAuthState())->setUser($request->getUser())->setAction($action_path)->appendChild(id(new AphrontFormTextControl())->setLabel('Username')->setName('username')->setValue($user->getUsername())->setError($e_username));
     if ($provider->retrieveUserEmail() === null) {
         $form->appendChild(id(new AphrontFormTextControl())->setLabel('Email')->setName('email')->setValue($request->getStr('email'))->setError($e_email));
     }
     if ($provider->retrieveUserRealName() === null) {
         $form->appendChild(id(new AphrontFormTextControl())->setLabel('Real Name')->setName('realname')->setValue($request->getStr('realname'))->setError($e_realname));
     }
     $form->appendChild(id(new AphrontFormSubmitControl())->setValue('Create Account'));
     $panel = new AphrontPanelView();
     $panel->setHeader('Create New Account');
     $panel->setWidth(AphrontPanelView::WIDTH_FORM);
     $panel->appendChild($form);
     return $this->buildStandardPageResponse(array($error_view, $panel), array('title' => 'Create New Account'));
 }
 private function getPathFromSubversionURI($uri_string)
 {
     $uri = new PhutilURI($uri_string);
     $proto = $uri->getProtocol();
     if ($proto !== 'svn+ssh') {
         throw new Exception(pht('Protocol for URI "%s" MUST be "%s".', $uri_string, 'svn+ssh'));
     }
     $path = $uri->getPath();
     // Subversion presumably deals with this, but make sure there's nothing
     // sketchy going on with the URI.
     if (preg_match('(/\\.\\./)', $path)) {
         throw new Exception(pht('String "%s" is invalid in path specification "%s".', '/../', $uri_string));
     }
     $path = $this->normalizeSVNPath($path);
     return $path;
 }
 public function processRequest()
 {
     $provider = $this->getLDAProvider();
     $ldap_info = $this->getLDAPInfo();
     $request = $this->getRequest();
     $errors = array();
     $e_username = true;
     $e_email = true;
     $e_realname = true;
     $user = new PhabricatorUser();
     $user->setUsername();
     $user->setRealname($provider->retrieveUserRealName());
     $new_email = $provider->retrieveUserEmail();
     if ($new_email) {
         // If the user's LDAP provider account has an email address but the
         // email address domain is not allowed by the Phabricator configuration,
         // we just pretend the provider did not supply an address.
         //
         // For instance, if the user uses LDAP Auth and their email address
         // is "*****@*****.**" but Phabricator is configured to require users
         // use "@company.com" addresses, we show a prompt below and tell the user
         // to provide their "@company.com" address. They can still use the LDAP
         // account to login, they just need to associate their account with an
         // allowed address.
         //
         // If the email address is fine, we just use it and don't prompt the user.
         if (!PhabricatorUserEmail::isAllowedAddress($new_email)) {
             $new_email = null;
         }
     }
     $show_email_input = $new_email === null;
     if ($request->isFormPost()) {
         $user->setUsername($request->getStr('username'));
         $username = $user->getUsername();
         if (!strlen($user->getUsername())) {
             $e_username = '******';
             $errors[] = 'Username is required.';
         } else {
             if (!PhabricatorUser::validateUsername($username)) {
                 $e_username = '******';
                 $errors[] = PhabricatorUser::describeValidUsername();
             } else {
                 $e_username = null;
             }
         }
         if (!$new_email) {
             $new_email = trim($request->getStr('email'));
             if (!$new_email) {
                 $e_email = 'Required';
                 $errors[] = 'Email is required.';
             } else {
                 $e_email = null;
             }
         }
         if ($new_email) {
             if (!PhabricatorUserEmail::isAllowedAddress($new_email)) {
                 $e_email = 'Invalid';
                 $errors[] = PhabricatorUserEmail::describeAllowedAddresses();
             }
         }
         if (!strlen($user->getRealName())) {
             $user->setRealName($request->getStr('realname'));
             if (!strlen($user->getRealName())) {
                 $e_realname = 'Required';
                 $errors[] = 'Real name is required.';
             } else {
                 $e_realname = null;
             }
         }
         if (!$errors) {
             try {
                 // NOTE: We don't verify LDAP email addresses by default because
                 // LDAP providers might associate email addresses with accounts that
                 // haven't actually verified they own them. We could selectively
                 // auto-verify some providers that we trust here, but the stakes for
                 // verifying an email address are high because having a corporate
                 // address at a company is sometimes the key to the castle.
                 $email_obj = id(new PhabricatorUserEmail())->setAddress($new_email)->setIsVerified(0);
                 id(new PhabricatorUserEditor())->setActor($user)->createNewUser($user, $email_obj);
                 $ldap_info->setUserID($user->getID());
                 $ldap_info->save();
                 $session_key = $user->establishSession('web');
                 $request->setCookie('phusr', $user->getUsername());
                 $request->setCookie('phsid', $session_key);
                 $email_obj->sendVerificationEmail($user);
                 return id(new AphrontRedirectResponse())->setURI('/');
             } catch (AphrontQueryDuplicateKeyException $exception) {
                 $same_username = id(new PhabricatorUser())->loadOneWhere('userName = %s', $user->getUserName());
                 $same_email = id(new PhabricatorUserEmail())->loadOneWhere('address = %s', $new_email);
                 if ($same_username) {
                     $e_username = '******';
                     $errors[] = 'That username or email is not unique.';
                 } else {
                     if ($same_email) {
                         $e_email = 'Duplicate';
                         $errors[] = 'That email is not unique.';
                     } else {
                         throw $exception;
                     }
                 }
             }
         }
     }
     $error_view = null;
     if ($errors) {
         $error_view = new AphrontErrorView();
         $error_view->setTitle('Registration Failed');
         $error_view->setErrors($errors);
     }
     // Strip the URI down to the path, because otherwise we'll trigger
     // external CSRF protection (by having a protocol in the form "action")
     // and generate a form with no CSRF token.
     $action_uri = new PhutilURI('/ldap/login/');
     $action_path = $action_uri->getPath();
     $form = new AphrontFormView();
     $form->setUser($request->getUser())->setAction($action_path)->appendChild(id(new AphrontFormTextControl())->setLabel('Username')->setName('username')->setValue($user->getUsername())->setError($e_username));
     $form->appendChild(id(new AphrontFormPasswordControl())->setLabel('Password')->setName('password'));
     if ($show_email_input) {
         $form->appendChild(id(new AphrontFormTextControl())->setLabel('Email')->setName('email')->setValue($request->getStr('email'))->setError($e_email));
     }
     if ($provider->retrieveUserRealName() === null) {
         $form->appendChild(id(new AphrontFormTextControl())->setLabel('Real Name')->setName('realname')->setValue($request->getStr('realname'))->setError($e_realname));
     }
     $form->appendChild(id(new AphrontFormSubmitControl())->setValue('Create Account'));
     $panel = new AphrontPanelView();
     $panel->setHeader('Create New Account');
     $panel->setWidth(AphrontPanelView::WIDTH_FORM);
     $panel->appendChild($form);
     return $this->buildStandardPageResponse(array($error_view, $panel), array('title' => 'Create New Account'));
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $uri = $request->getStr('uri');
     $id = $request->getStr('id');
     $repositories = id(new PhabricatorRepository())->loadAll();
     if ($uri) {
         $uri_path = id(new PhutilURI($uri))->getPath();
         $matches = array();
         // Try to figure out which tracked repository this external lives in by
         // comparing repository metadata. We look for an exact match, but accept
         // a partial match.
         foreach ($repositories as $key => $repository) {
             $remote_uri = new PhutilURI($repository->getRemoteURI());
             if ($remote_uri->getPath() == $uri_path) {
                 $matches[$key] = 1;
             }
             if ($repository->getPublicRemoteURI() == $uri) {
                 $matches[$key] = 2;
             }
             if ($repository->getRemoteURI() == $uri) {
                 $matches[$key] = 3;
             }
         }
         arsort($matches);
         $best_match = head_key($matches);
         if ($best_match) {
             $repository = $repositories[$best_match];
             $redirect = DiffusionRequest::generateDiffusionURI(array('action' => 'browse', 'callsign' => $repository->getCallsign(), 'branch' => $repository->getDefaultBranch(), 'commit' => $id));
             return id(new AphrontRedirectResponse())->setURI($redirect);
         }
     }
     // TODO: This is a rare query but does a table scan, add a key?
     $commits = id(new PhabricatorRepositoryCommit())->loadAllWhere('commitIdentifier = %s', $id);
     if (empty($commits)) {
         $desc = null;
         if ($uri) {
             $desc = phutil_escape_html($uri) . ', at ';
         }
         $desc .= phutil_escape_html($id);
         $content = id(new AphrontErrorView())->setTitle('Unknown External')->setSeverity(AphrontErrorView::SEVERITY_WARNING)->appendChild("<p>This external ({$desc}) does not appear in any tracked " . "repository. It may exist in an untracked repository that " . "Diffusion does not know about.</p>");
     } else {
         if (count($commits) == 1) {
             $commit = head($commits);
             $repo = $repositories[$commit->getRepositoryID()];
             $redirect = DiffusionRequest::generateDiffusionURI(array('action' => 'browse', 'callsign' => $repo->getCallsign(), 'branch' => $repo->getDefaultBranch(), 'commit' => $commit->getCommitIdentifier()));
             return id(new AphrontRedirectResponse())->setURI($redirect);
         } else {
             $rows = array();
             foreach ($commits as $commit) {
                 $repo = $repositories[$commit->getRepositoryID()];
                 $href = DiffusionRequest::generateDiffusionURI(array('action' => 'browse', 'callsign' => $repo->getCallsign(), 'branch' => $repo->getDefaultBranch(), 'commit' => $commit->getCommitIdentifier()));
                 $rows[] = array(phutil_render_tag('a', array('href' => $href), phutil_escape_html('r' . $repo->getCallsign() . $commit->getCommitIdentifier())), phutil_escape_html($commit->loadCommitData()->getSummary()));
             }
             $table = new AphrontTableView($rows);
             $table->setHeaders(array('Commit', 'Description'));
             $table->setColumnClasses(array('pri', 'wide'));
             $content = new AphrontPanelView();
             $content->setHeader('Multiple Matching Commits');
             $content->setCaption('This external reference matches multiple known commits.');
             $content->appendChild($table);
         }
     }
     return $this->buildStandardPageResponse($content, array('title' => 'Unresolvable External'));
 }
 /**
  * Extract the revision ID from a commit message.
  *
  * @param string Raw commit message.
  * @return int|null Revision ID, if the commit message contains one.
  */
 private function parseRevisionIDFromRawCorpus($corpus)
 {
     $match = null;
     if (!preg_match('/^Differential Revision:\\s*(.+)/im', $corpus, $match)) {
         return null;
     }
     $revision_value = trim($match[1]);
     $revision_pattern = '/^[dD]([1-9]\\d*)\\z/';
     // Accept a bare revision ID like "D123".
     if (preg_match($revision_pattern, $revision_value, $match)) {
         return (int) $match[1];
     }
     // Otherwise, try to find a full URI.
     $uri = new PhutilURI($revision_value);
     $path = $uri->getPath();
     $path = trim($path, '/');
     if (preg_match($revision_pattern, $path, $match)) {
         return (int) $match[1];
     }
     throw new ArcanistUsageException(pht('Invalid "Differential Revision" field in commit message. This field ' . 'should have a revision identifier like "%s" or a Phabricator URI ' . 'like "%s", but has "%s".', 'D123', 'https://phabricator.example.com/D123', $revision_value));
 }
 private static function getPathFromGitURI($raw_uri)
 {
     $uri = new PhutilURI($raw_uri);
     if ($uri->getProtocol()) {
         return $uri->getPath();
     }
     $uri = new PhutilGitURI($raw_uri);
     if ($uri->getDomain()) {
         return $uri->getPath();
     }
     return $raw_uri;
 }
 private function makeInternalURI($uri_string)
 {
     $uri = new PhutilURI($uri_string);
     $proto = $uri->getProtocol();
     if ($proto !== 'svn+ssh') {
         throw new Exception(pht('Protocol for URI "%s" MUST be "svn+ssh".', $uri_string));
     }
     $path = $uri->getPath();
     // Subversion presumably deals with this, but make sure there's nothing
     // skethcy going on with the URI.
     if (preg_match('(/\\.\\./)', $path)) {
         throw new Exception(pht('String "/../" is invalid in path specification "%s".', $uri_string));
     }
     $repository = $this->loadRepository($path);
     $path = preg_replace('(^/diffusion/[A-Z]+)', rtrim($repository->getLocalPath(), '/'), $path);
     if (preg_match('(^/diffusion/[A-Z]+/\\z)', $path)) {
         $path = rtrim($path, '/');
     }
     $uri->setPath($path);
     // If this is happening during the handshake, these are the base URIs for
     // the request.
     if ($this->externalBaseURI === null) {
         $pre = (string) id(clone $uri)->setPath('');
         $this->externalBaseURI = $pre . '/diffusion/' . $repository->getCallsign();
         $this->internalBaseURI = $pre . rtrim($repository->getLocalPath(), '/');
     }
     return (string) $uri;
 }
 private function getRawHTTPCloneURIObject()
 {
     $uri = PhabricatorEnv::getProductionURI($this->getURI());
     $uri = new PhutilURI($uri);
     if ($this->isGit()) {
         $uri->setPath($uri->getPath() . $this->getCloneName() . '.git');
     } else {
         if ($this->isHg()) {
             $uri->setPath($uri->getPath() . $this->getCloneName() . '/');
         }
     }
     return $uri;
 }
 public function handleRequest(AphrontRequest $request)
 {
     $uri = $request->getStr('uri');
     $id = $request->getStr('id');
     $repositories = id(new PhabricatorRepositoryQuery())->setViewer($request->getUser())->execute();
     if ($uri) {
         $uri_path = id(new PhutilURI($uri))->getPath();
         $matches = array();
         // Try to figure out which tracked repository this external lives in by
         // comparing repository metadata. We look for an exact match, but accept
         // a partial match.
         foreach ($repositories as $key => $repository) {
             $remote_uri = new PhutilURI($repository->getRemoteURI());
             if ($remote_uri->getPath() == $uri_path) {
                 $matches[$key] = 1;
             }
             if ($repository->getPublicCloneURI() == $uri) {
                 $matches[$key] = 2;
             }
             if ($repository->getRemoteURI() == $uri) {
                 $matches[$key] = 3;
             }
         }
         arsort($matches);
         $best_match = head_key($matches);
         if ($best_match) {
             $repository = $repositories[$best_match];
             $redirect = $repository->generateURI(array('action' => 'browse', 'branch' => $repository->getDefaultBranch(), 'commit' => $id));
             return id(new AphrontRedirectResponse())->setURI($redirect);
         }
     }
     // TODO: This is a rare query but does a table scan, add a key?
     $commits = id(new PhabricatorRepositoryCommit())->loadAllWhere('commitIdentifier = %s', $id);
     if (empty($commits)) {
         $desc = null;
         if (strlen($uri)) {
             $desc = pht('"%s", at "%s"', $uri, $id);
         } else {
             $desc = pht('"%s"', $id);
         }
         $content = id(new PHUIInfoView())->setTitle(pht('Unknown External'))->setSeverity(PHUIInfoView::SEVERITY_WARNING)->appendChild(phutil_tag('p', array(), pht('This external (%s) does not appear in any tracked ' . 'repository. It may exist in an untracked repository that ' . 'Diffusion does not know about.', $desc)));
     } else {
         if (count($commits) == 1) {
             $commit = head($commits);
             $repo = $repositories[$commit->getRepositoryID()];
             $redirect = $repo->generateURI(array('action' => 'browse', 'branch' => $repo->getDefaultBranch(), 'commit' => $commit->getCommitIdentifier()));
             return id(new AphrontRedirectResponse())->setURI($redirect);
         } else {
             $rows = array();
             foreach ($commits as $commit) {
                 $repo = $repositories[$commit->getRepositoryID()];
                 $href = $repo->generateURI(array('action' => 'browse', 'branch' => $repo->getDefaultBranch(), 'commit' => $commit->getCommitIdentifier()));
                 $rows[] = array(phutil_tag('a', array('href' => $href), $commit->getURI()), $commit->loadCommitData()->getSummary());
             }
             $table = new AphrontTableView($rows);
             $table->setHeaders(array(pht('Commit'), pht('Description')));
             $table->setColumnClasses(array('pri', 'wide'));
             $caption = id(new PHUIInfoView())->setSeverity(PHUIInfoView::SEVERITY_NOTICE)->appendChild(pht('This external reference matches multiple known commits.'));
             $content = new PHUIObjectBoxView();
             $content->setHeaderText(pht('Multiple Matching Commits'));
             $content->setInfoView($caption);
             $content->setTable($table);
         }
     }
     $crumbs = $this->buildApplicationCrumbs();
     $crumbs->addTextCrumb(pht('External'));
     return $this->newPage()->setTitle(pht('Unresolvable External'))->setCrumbs($crumbs)->appendChild($content);
 }
 /**
  * If there's a URI specified in an OAuth request, it must be validated in
  * its own right. Further, it must have the same domain, the same path, the
  * same port, and (at least) the same query parameters as the primary URI.
  */
 public function validateSecondaryRedirectURI(PhutilURI $secondary_uri, PhutilURI $primary_uri)
 {
     // The secondary URI must be valid.
     if (!$this->validateRedirectURI($secondary_uri)) {
         return false;
     }
     // Both URIs must point at the same domain.
     if ($secondary_uri->getDomain() != $primary_uri->getDomain()) {
         return false;
     }
     // Both URIs must have the same path
     if ($secondary_uri->getPath() != $primary_uri->getPath()) {
         return false;
     }
     // Both URIs must have the same port
     if ($secondary_uri->getPort() != $primary_uri->getPort()) {
         return false;
     }
     // Any query parameters present in the first URI must be exactly present
     // in the second URI.
     $need_params = $primary_uri->getQueryParams();
     $have_params = $secondary_uri->getQueryParams();
     foreach ($need_params as $key => $value) {
         if (!array_key_exists($key, $have_params)) {
             return false;
         }
         if ((string) $have_params[$key] != (string) $value) {
             return false;
         }
     }
     // If the first URI is HTTPS, the second URI must also be HTTPS. This
     // defuses an attack where a third party with control over the network
     // tricks you into using HTTP to authenticate over a link which is supposed
     // to be HTTPS only and sniffs all your token cookies.
     if (strtolower($primary_uri->getProtocol()) == 'https') {
         if (strtolower($secondary_uri->getProtocol()) != 'https') {
             return false;
         }
     }
     return true;
 }
 public static function getJIRAIssueBrowseURIFromJIRARestURI($uri, $object_id)
 {
     $uri = new PhutilURI($uri);
     // The JIRA install might not be at the domain root, so we may need to
     // keep an initial part of the path, like "/jira/". Find the API specific
     // part of the URI, strip it off, then replace it with the web version.
     $path = $uri->getPath();
     $pos = strrpos($path, 'rest/api/2/issue/');
     if ($pos === false) {
         return null;
     }
     $path = substr($path, 0, $pos);
     $path = $path . 'browse/' . $object_id;
     $uri->setPath($path);
     return (string) $uri;
 }
 private function getPath(HTTPSFuture $future)
 {
     $uri = new PhutilURI($future->getURI());
     return $uri->getPath();
 }
 public function testUnusualURIs()
 {
     $uri = new PhutilURI('file:///path/to/file');
     $this->assertEqual('file', $uri->getProtocol(), pht('protocol'));
     $this->assertEqual('', $uri->getDomain(), pht('domain'));
     $this->assertEqual('/path/to/file', $uri->getPath(), pht('path'));
     $uri = new PhutilURI('idea://open?x=/');
     $this->assertEqual('idea', $uri->getProtocol(), pht('protocol'));
     $this->assertEqual('open', $uri->getDomain(), pht('domain'));
     $this->assertEqual('', $uri->getPath(), pht('path'));
     $this->assertEqual(array('x' => '/'), $uri->getQueryParams());
 }
Example #24
0
 public function testGitURIParsing()
 {
     $uri = new PhutilURI('git@host.com:path/to/something');
     $this->assertEqual('ssh', $uri->getProtocol());
     $this->assertEqual('git', $uri->getUser());
     $this->assertEqual('host.com', $uri->getDomain());
     $this->assertEqual('path/to/something', $uri->getPath());
     $this->assertEqual('git@host.com:path/to/something', (string) $uri);
     $uri = new PhutilURI('host.com:path/to/something');
     $this->assertEqual('ssh', $uri->getProtocol());
     $this->assertEqual('', $uri->getUser());
     $this->assertEqual('host.com', $uri->getDomain());
     $this->assertEqual('path/to/something', $uri->getPath());
     $this->assertEqual('host.com:path/to/something', (string) $uri);
     $uri_1 = new PhutilURI('host.com:path/to/something');
     $uri_2 = new PhutilURI($uri_1);
     $this->assertEqual((string) $uri_1, (string) $uri_2);
 }
 /**
  * Get the repository's HTTP clone/checkout URI, if one exists.
  */
 public function getHTTPCloneURIObject()
 {
     if (!$this->isHosted()) {
         if ($this->shouldUseHTTP()) {
             return $this->getRemoteURIObject();
         } else {
             return null;
         }
     }
     $serve_http = $this->getServeOverHTTP();
     if ($serve_http === self::SERVE_OFF) {
         return null;
     }
     $uri = PhabricatorEnv::getProductionURI($this->getURI());
     $uri = new PhutilURI($uri);
     if ($this->isGit()) {
         $uri->setPath($uri->getPath() . $this->getCloneName() . '.git');
     } else {
         if ($this->isHg()) {
             $uri->setPath($uri->getPath() . $this->getCloneName() . '/');
         }
     }
     return $uri;
 }
 public function didMarkupText()
 {
     $engine = $this->getEngine();
     $metadata = $engine->getTextMetadata(self::KEY_RULE_PHRICTION_LINK, array());
     if (!$metadata) {
         return;
     }
     $slugs = ipull($metadata, 'link');
     foreach ($slugs as $key => $slug) {
         $slugs[$key] = PhabricatorSlug::normalize($slug);
     }
     // We have to make two queries here to distinguish between
     // documents the user can't see, and documents that don't
     // exist.
     $visible_documents = id(new PhrictionDocumentQuery())->setViewer($engine->getConfig('viewer'))->withSlugs($slugs)->needContent(true)->execute();
     $existant_documents = id(new PhrictionDocumentQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withSlugs($slugs)->execute();
     $visible_documents = mpull($visible_documents, null, 'getSlug');
     $existant_documents = mpull($existant_documents, null, 'getSlug');
     foreach ($metadata as $spec) {
         $link = $spec['link'];
         $slug = PhabricatorSlug::normalize($link);
         $name = $spec['explicitName'];
         $class = 'phriction-link';
         // If the name is something meaningful to humans, we'll render this
         // in text as: "Title" <link>. Otherwise, we'll just render: <link>.
         $is_interesting_name = (bool) strlen($name);
         if (idx($existant_documents, $slug) === null) {
             // The target document doesn't exist.
             if ($name === null) {
                 $name = explode('/', trim($link, '/'));
                 $name = end($name);
             }
             $class = 'phriction-link-missing';
         } else {
             if (idx($visible_documents, $slug) === null) {
                 // The document exists, but the user can't see it.
                 if ($name === null) {
                     $name = explode('/', trim($link, '/'));
                     $name = end($name);
                 }
                 $class = 'phriction-link-lock';
             } else {
                 if ($name === null) {
                     // Use the title of the document if no name is set.
                     $name = $visible_documents[$slug]->getContent()->getTitle();
                     $is_interesting_name = true;
                 }
             }
         }
         $uri = new PhutilURI($link);
         $slug = $uri->getPath();
         $slug = PhabricatorSlug::normalize($slug);
         $slug = PhrictionDocument::getSlugURI($slug);
         $anchor = idx($spec, 'anchor');
         $href = (string) id(new PhutilURI($slug))->setFragment($anchor);
         $text_mode = $this->getEngine()->isTextMode();
         $mail_mode = $this->getEngine()->isHTMLMailMode();
         if ($this->getEngine()->getState('toc')) {
             $text = $name;
         } else {
             if ($text_mode || $mail_mode) {
                 $href = PhabricatorEnv::getProductionURI($href);
                 if ($is_interesting_name) {
                     $text = pht('"%s" <%s>', $name, $href);
                 } else {
                     $text = pht('<%s>', $href);
                 }
             } else {
                 if ($class === 'phriction-link-lock') {
                     $name = array($this->newTag('i', array('class' => 'phui-icon-view phui-font-fa fa-lock'), ''), ' ', $name);
                 }
                 $text = $this->newTag('a', array('href' => $href, 'class' => $class), $name);
             }
         }
         $this->getEngine()->overwriteStoredText($spec['token'], $text);
     }
 }