Example #1
0
 protected function applyCustomInternalTransaction(PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction)
 {
     switch ($xaction->getTransactionType()) {
         case PhameBlogTransaction::TYPE_NAME:
             return $object->setName($xaction->getNewValue());
         case PhameBlogTransaction::TYPE_SUBTITLE:
             return $object->setSubtitle($xaction->getNewValue());
         case PhameBlogTransaction::TYPE_DESCRIPTION:
             return $object->setDescription($xaction->getNewValue());
         case PhameBlogTransaction::TYPE_FULLDOMAIN:
             $new_value = $xaction->getNewValue();
             if (strlen($new_value)) {
                 $uri = new PhutilURI($new_value);
                 $domain = $uri->getDomain();
                 $object->setDomain($domain);
             } else {
                 $object->setDomain(null);
             }
             $object->setDomainFullURI($new_value);
             return;
         case PhameBlogTransaction::TYPE_PROFILEIMAGE:
             return $object->setProfileImagePHID($xaction->getNewValue());
         case PhameBlogTransaction::TYPE_HEADERIMAGE:
             return $object->setHeaderImagePHID($xaction->getNewValue());
         case PhameBlogTransaction::TYPE_STATUS:
             return $object->setStatus($xaction->getNewValue());
         case PhameBlogTransaction::TYPE_PARENTSITE:
             return $object->setParentSite($xaction->getNewValue());
         case PhameBlogTransaction::TYPE_PARENTDOMAIN:
             return $object->setParentDomain($xaction->getNewValue());
     }
     return parent::applyCustomInternalTransaction($object, $xaction);
 }
 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'));
         }
     }
 }
Example #3
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;
 }
 protected function getProxyCommand()
 {
     $uri = new PhutilURI($this->proxyURI);
     $username = AlmanacKeys::getClusterSSHUser();
     if ($username === null) {
         throw new Exception(pht('Unable to determine the username to connect with when trying ' . 'to proxy an SSH request within the Phabricator cluster.'));
     }
     $port = $uri->getPort();
     $host = $uri->getDomain();
     $key_path = AlmanacKeys::getKeyPath('device.key');
     if (!Filesystem::pathExists($key_path)) {
         throw new Exception(pht('Unable to proxy this SSH request within the cluster: this device ' . 'is not registered and has a missing device key (expected to ' . 'find key at "%s").', $key_path));
     }
     $options = array();
     $options[] = '-o';
     $options[] = 'StrictHostKeyChecking=no';
     $options[] = '-o';
     $options[] = 'UserKnownHostsFile=/dev/null';
     // This is suppressing "added <address> to the list of known hosts"
     // messages, which are confusing and irrelevant when they arise from
     // proxied requests. It might also be suppressing lots of useful errors,
     // of course. Ideally, we would enforce host keys eventually.
     $options[] = '-o';
     $options[] = 'LogLevel=quiet';
     // NOTE: We prefix the command with "@username", which the far end of the
     // connection will parse in order to act as the specified user. This
     // behavior is only available to cluster requests signed by a trusted
     // device key.
     return csprintf('ssh %Ls -l %s -i %s -p %s %s -- %s %Ls', $options, $username, $key_path, $port, $host, '@' . $this->getUser()->getUsername(), $this->getOriginalArguments());
 }
 public function processAddFactorForm(AphrontFormView $form, AphrontRequest $request, PhabricatorUser $user)
 {
     $totp_token_type = PhabricatorAuthTOTPKeyTemporaryTokenType::TOKENTYPE;
     $key = $request->getStr('totpkey');
     if (strlen($key)) {
         // If the user is providing a key, make sure it's a key we generated.
         // This raises the barrier to theoretical attacks where an attacker might
         // provide a known key (such attacks are already prevented by CSRF, but
         // this is a second barrier to overcome).
         // (We store and verify the hash of the key, not the key itself, to limit
         // how useful the data in the table is to an attacker.)
         $temporary_token = id(new PhabricatorAuthTemporaryTokenQuery())->setViewer($user)->withTokenResources(array($user->getPHID()))->withTokenTypes(array($totp_token_type))->withExpired(false)->withTokenCodes(array(PhabricatorHash::digest($key)))->executeOne();
         if (!$temporary_token) {
             // If we don't have a matching token, regenerate the key below.
             $key = null;
         }
     }
     if (!strlen($key)) {
         $key = self::generateNewTOTPKey();
         // Mark this key as one we generated, so the user is allowed to submit
         // a response for it.
         $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
         id(new PhabricatorAuthTemporaryToken())->setTokenResource($user->getPHID())->setTokenType($totp_token_type)->setTokenExpires(time() + phutil_units('1 hour in seconds'))->setTokenCode(PhabricatorHash::digest($key))->save();
         unset($unguarded);
     }
     $code = $request->getStr('totpcode');
     $e_code = true;
     if ($request->getExists('totp')) {
         $okay = self::verifyTOTPCode($user, new PhutilOpaqueEnvelope($key), $code);
         if ($okay) {
             $config = $this->newConfigForUser($user)->setFactorName(pht('Mobile App (TOTP)'))->setFactorSecret($key);
             return $config;
         } else {
             if (!strlen($code)) {
                 $e_code = pht('Required');
             } else {
                 $e_code = pht('Invalid');
             }
         }
     }
     $form->addHiddenInput('totp', true);
     $form->addHiddenInput('totpkey', $key);
     $form->appendRemarkupInstructions(pht('First, download an authenticator application on your phone. Two ' . 'applications which work well are **Authy** and **Google ' . 'Authenticator**, but any other TOTP application should also work.'));
     $form->appendInstructions(pht('Launch the application on your phone, and add a new entry for ' . 'this Phabricator install. When prompted, scan the QR code or ' . 'manually enter the key shown below into the application.'));
     $prod_uri = new PhutilURI(PhabricatorEnv::getProductionURI('/'));
     $issuer = $prod_uri->getDomain();
     $uri = urisprintf('otpauth://totp/%s:%s?secret=%s&issuer=%s', $issuer, $user->getUsername(), $key, $issuer);
     $qrcode = $this->renderQRCode($uri);
     $form->appendChild($qrcode);
     $form->appendChild(id(new AphrontFormStaticControl())->setLabel(pht('Key'))->setValue(phutil_tag('strong', array(), $key)));
     $form->appendInstructions(pht('(If given an option, select that this key is "Time Based", not ' . '"Counter Based".)'));
     $form->appendInstructions(pht('After entering the key, the application should display a numeric ' . 'code. Enter that code below to confirm that you have configured ' . 'the authenticator correctly:'));
     $form->appendChild(id(new PHUIFormNumberControl())->setLabel(pht('TOTP Code'))->setName('totpcode')->setValue($code)->setError($e_code));
 }
 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;
     }
 }
 private function getBareHostAndPort($host)
 {
     // Split out port information, since the command-line client requires a
     // separate flag for the port.
     $uri = new PhutilURI('mysql://' . $host);
     if ($uri->getPort()) {
         $port = $uri->getPort();
         $bare_hostname = $uri->getDomain();
     } else {
         $port = null;
         $bare_hostname = $host;
     }
     return array($bare_hostname, $port);
 }
 protected final function launch($debug = false)
 {
     $console = PhutilConsole::getConsole();
     if ($debug) {
         $console->writeOut(pht("Starting Aphlict server in foreground...\n"));
     } else {
         Filesystem::writeFile($this->getPIDPath(), getmypid());
     }
     $server_uri = PhabricatorEnv::getEnvConfig('notification.server-uri');
     $server_uri = new PhutilURI($server_uri);
     $client_uri = PhabricatorEnv::getEnvConfig('notification.client-uri');
     $client_uri = new PhutilURI($client_uri);
     $user = PhabricatorEnv::getEnvConfig('notification.user');
     $log = PhabricatorEnv::getEnvConfig('notification.log');
     $server_argv = array();
     $server_argv[] = csprintf('--port=%s', $client_uri->getPort());
     $server_argv[] = csprintf('--admin=%s', $server_uri->getPort());
     $server_argv[] = csprintf('--host=%s', $server_uri->getDomain());
     if ($user) {
         $server_argv[] = csprintf('--user=%s', $user);
     }
     if (!$debug) {
         $server_argv[] = csprintf('--log=%s', $log);
     }
     $command = csprintf('%s %s %C', $this->getNodeBinary(), dirname(__FILE__) . '/../../../../support/aphlict/server/aphlict_server.js', implode(' ', $server_argv));
     if (!$debug) {
         declare (ticks=1);
         pcntl_signal(SIGINT, array($this, 'cleanup'));
         pcntl_signal(SIGTERM, array($this, 'cleanup'));
     }
     register_shutdown_function(array($this, 'cleanup'));
     if ($debug) {
         $console->writeOut("Launching server:\n\n    \$ " . $command . "\n\n");
         $err = phutil_passthru('%C', $command);
         $console->writeOut(">>> Server exited!\n");
         exit($err);
     } else {
         while (true) {
             global $g_future;
             $g_future = new ExecFuture('exec %C', $command);
             $g_future->resolve();
             // If the server exited, wait a couple of seconds and restart it.
             unset($g_future);
             sleep(2);
         }
     }
 }
 public function isVCSRequest(AphrontRequest $request)
 {
     $identifier = $this->getRepositoryIdentifierFromRequest($request);
     if ($identifier === null) {
         return null;
     }
     $content_type = $request->getHTTPHeader('Content-Type');
     $user_agent = idx($_SERVER, 'HTTP_USER_AGENT');
     $vcs = null;
     if ($request->getExists('service')) {
         $service = $request->getStr('service');
         // We get this initially for `info/refs`.
         // Git also gives us a User-Agent like "git/1.8.2.3".
         $vcs = PhabricatorRepositoryType::REPOSITORY_TYPE_GIT;
     } else {
         if (strncmp($user_agent, 'git/', 4) === 0) {
             $vcs = PhabricatorRepositoryType::REPOSITORY_TYPE_GIT;
         } else {
             if ($content_type == 'application/x-git-upload-pack-request') {
                 // We get this for `git-upload-pack`.
                 $vcs = PhabricatorRepositoryType::REPOSITORY_TYPE_GIT;
             } else {
                 if ($content_type == 'application/x-git-receive-pack-request') {
                     // We get this for `git-receive-pack`.
                     $vcs = PhabricatorRepositoryType::REPOSITORY_TYPE_GIT;
                 } else {
                     if ($request->getExists('cmd')) {
                         // Mercurial also sends an Accept header like
                         // "application/mercurial-0.1", and a User-Agent like
                         // "mercurial/proto-1.0".
                         $vcs = PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL;
                     } else {
                         // Subversion also sends an initial OPTIONS request (vs GET/POST), and
                         // has a User-Agent like "SVN/1.8.3 (x86_64-apple-darwin11.4.2)
                         // serf/1.3.2".
                         $dav = $request->getHTTPHeader('DAV');
                         $dav = new PhutilURI($dav);
                         if ($dav->getDomain() === 'subversion.tigris.org') {
                             $vcs = PhabricatorRepositoryType::REPOSITORY_TYPE_SVN;
                         }
                     }
                 }
             }
         }
     }
     return $vcs;
 }
 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;
 }
 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 #13
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');
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $alt = PhabricatorEnv::getEnvConfig('security.alternate-file-domain');
     $uri = new PhutilURI($alt);
     $alt_domain = $uri->getDomain();
     if ($alt_domain && $alt_domain != $request->getHost()) {
         return id(new AphrontRedirectResponse())->setURI($uri->setPath($request->getPath()));
     }
     $file = id(new PhabricatorFile())->loadOneWhere('phid = %s', $this->phid);
     if (!$file) {
         return new Aphront404Response();
     }
     if (!$file->validateSecretKey($this->key)) {
         return new Aphront403Response();
     }
     $data = $file->loadFileData();
     $response = new AphrontFileResponse();
     $response->setContent($data);
     $response->setCacheDurationInSeconds(60 * 60 * 24 * 30);
     $is_view = $file->isViewableInBrowser();
     if ($is_view) {
         $response->setMimeType($file->getViewableMimeType());
     } else {
         if (!$request->isHTTPPost()) {
             // NOTE: Require POST to download files. We'd rather go full-bore and
             // do a real CSRF check, but can't currently authenticate users on the
             // file domain. This should blunt any attacks based on iframes, script
             // tags, applet tags, etc., at least. Send the user to the "info" page
             // if they're using some other method.
             return id(new AphrontRedirectResponse())->setURI(PhabricatorEnv::getProductionURI($file->getBestURI()));
         }
         $response->setMimeType($file->getMimeType());
         $response->setDownload($file->getName());
     }
     return $response;
 }
 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());
 }
 /**
  * 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 and (at least) the
  * same query parameters as the primary URI.
  */
 public function validateSecondaryRedirectURI(PhutilURI $secondary_uri, PhutilURI $primary_uri)
 {
     $valid = $this->validateRedirectURI($secondary_uri);
     if ($valid) {
         $valid_domain = $secondary_uri->getDomain() == $primary_uri->getDomain();
         $good_params = $primary_uri->getQueryParams();
         $test_params = $secondary_uri->getQueryParams();
         $missing_params = array_diff_key($good_params, $test_params);
         $valid = $valid_domain && empty($missing_params);
     }
     return $valid;
 }
Example #17
0
function phabricator_detect_bad_base_uri()
{
    $conf = PhabricatorEnv::getEnvConfig('phabricator.base-uri');
    $uri = new PhutilURI($conf);
    switch ($uri->getProtocol()) {
        case 'http':
        case 'https':
            break;
        default:
            return phabricator_fatal_config_error("'phabricator.base-uri' is set to '{$conf}', which is invalid. " . "The URI must start with 'http://' or 'https://'.");
    }
    if (strpos($uri->getDomain(), '.') === false) {
        phabricator_fatal_config_error("'phabricator.base-uri' is set to '{$conf}', which is invalid. The URI " . "must contain a dot ('.'), like 'http://example.com/', not just " . "'http://example/'. Some web browsers will not set cookies on domains " . "with no TLD, and Phabricator requires cookies for login. " . "If you are using localhost, create an entry in the hosts file like " . "'127.0.0.1 example.com', and access the localhost with " . "'http://example.com/'.");
    }
}
Example #18
0
 public function testStrictURIParsingOfLeadingWhitespace()
 {
     $uri = new PhutilURI(' http://example.com/');
     $this->assertEqual('', $uri->getDomain());
 }
$next_version = isset($options['v']) ? (int) $options['v'] : null;
$conf = DatabaseConfigurationProvider::getConfiguration();
if ($options['u']) {
    $conn_user = $options['u'];
    $conn_pass = $options['p'];
} else {
    $conn_user = $conf->getUser();
    $conn_pass = $conf->getPassword();
}
$conn_host = $conf->getHost();
// Split out port information, since the command-line client requires a
// separate flag for the port.
$uri = new PhutilURI('mysql://' . $conn_host);
if ($uri->getPort()) {
    $conn_port = $uri->getPort();
    $conn_bare_hostname = $uri->getDomain();
} else {
    $conn_port = null;
    $conn_bare_hostname = $conn_host;
}
$conn = new AphrontMySQLDatabaseConnection(array('user' => $conn_user, 'pass' => $conn_pass, 'host' => $conn_host, 'database' => null));
try {
    $create_sql = <<<END
  CREATE DATABASE IF NOT EXISTS `phabricator_meta_data`;
END;
    queryfx($conn, $create_sql);
    $create_sql = <<<END
  CREATE TABLE IF NOT EXISTS phabricator_meta_data.`schema_version` (
    `version` INTEGER not null
  );
END;
Example #20
0
 /**
  * Get the fully-qualified production URI for a path.
  *
  * @task read
  */
 public static function getProductionURI($path)
 {
     // If we're passed a URI which already has a domain, simply return it
     // unmodified. In particular, files may have URIs which point to a CDN
     // domain.
     $uri = new PhutilURI($path);
     if ($uri->getDomain()) {
         return $path;
     }
     $production_domain = self::getEnvConfig('phabricator.production-uri');
     if (!$production_domain) {
         $production_domain = self::getEnvConfig('phabricator.base-uri');
     }
     return rtrim($production_domain, '/') . $path;
 }
Example #21
0
 /**
  * Build a new @{class:HTTPSFuture} which proxies this request to another
  * node in the cluster.
  *
  * IMPORTANT: This is very dangerous!
  *
  * The future forwards authentication information present in the request.
  * Proxied requests must only be sent to trusted hosts. (We attempt to
  * enforce this.)
  *
  * This is not a general-purpose proxying method; it is a specialized
  * method with niche applications and severe security implications.
  *
  * @param string URI identifying the host we are proxying the request to.
  * @return HTTPSFuture New proxy future.
  *
  * @phutil-external-symbol class PhabricatorStartup
  */
 public function newClusterProxyFuture($uri)
 {
     $uri = new PhutilURI($uri);
     $domain = $uri->getDomain();
     $ip = gethostbyname($domain);
     if (!$ip) {
         throw new Exception(pht('Unable to resolve domain "%s"!', $domain));
     }
     if (!PhabricatorEnv::isClusterAddress($ip)) {
         throw new Exception(pht('Refusing to proxy a request to IP address ("%s") which is not ' . 'in the cluster address block (this address was derived by ' . 'resolving the domain "%s").', $ip, $domain));
     }
     $uri->setPath($this->getPath());
     $uri->setQueryParams(self::flattenData($_GET));
     $input = PhabricatorStartup::getRawInput();
     $future = id(new HTTPSFuture($uri))->addHeader('Host', self::getHost())->addHeader('X-Phabricator-Cluster', true)->setMethod($_SERVER['REQUEST_METHOD'])->write($input);
     if (isset($_SERVER['PHP_AUTH_USER'])) {
         $future->setHTTPBasicAuthCredentials($_SERVER['PHP_AUTH_USER'], new PhutilOpaqueEnvelope(idx($_SERVER, 'PHP_AUTH_PW', '')));
     }
     $headers = array();
     $seen = array();
     // NOTE: apache_request_headers() might provide a nicer way to do this,
     // but isn't available under FCGI until PHP 5.4.0.
     foreach ($_SERVER as $key => $value) {
         if (preg_match('/^HTTP_/', $key)) {
             // Unmangle the header as best we can.
             $key = str_replace('_', ' ', $key);
             $key = strtolower($key);
             $key = ucwords($key);
             $key = str_replace(' ', '-', $key);
             $headers[] = array($key, $value);
             $seen[$key] = true;
         }
     }
     // In some situations, this may not be mapped into the HTTP_X constants.
     // CONTENT_LENGTH is similarly affected, but we trust cURL to take care
     // of that if it matters, since we're handing off a request body.
     if (empty($seen['Content-Type'])) {
         if (isset($_SERVER['CONTENT_TYPE'])) {
             $headers[] = array('Content-Type', $_SERVER['CONTENT_TYPE']);
         }
     }
     foreach ($headers as $header) {
         list($key, $value) = $header;
         switch ($key) {
             case 'Host':
             case 'Authorization':
                 // Don't forward these headers, we've already handled them elsewhere.
                 unset($headers[$key]);
                 break;
             default:
                 break;
         }
     }
     foreach ($headers as $header) {
         list($key, $value) = $header;
         $future->addHeader($key, $value);
     }
     return $future;
 }
 /**
  * MediaWiki uses a signed JWT to assert the user's identity
  * here we verify the identity, not just the jwt signature.
  */
 private function decodeAndVerifyJWT($jwt, $nonce)
 {
     $userinfo = array();
     $identity = $this->decodeJWT($jwt);
     $iss_uri = new PhutilURI($identity->iss);
     $expected_uri = new PhutilURI($this->mediaWikiBaseURI);
     $now = time();
     if ($iss_uri->getDomain() !== $expected_uri->getDomain()) {
         throw new Exception(pht('OAuth JWT iss didn\'t match expected server name'));
     }
     if ($identity->aud !== $this->getConsumerKey()) {
         throw new Exception(pht('OAuth JWT aud didn\'t match expected consumer key'));
     }
     if ($identity->iat > $now || $identity->exp < $now) {
         throw new Exception(pht('OAuth JWT wasn\'t valid at this time'));
     }
     if ($identity->nonce !== $nonce) {
         throw new Exception(pht('OAuth JWT nonce didn\'t match what we sent.'));
     }
     $userinfo['userid'] = $identity->sub;
     $userinfo['username'] = $identity->username;
     $userinfo['groups'] = $identity->groups;
     $userinfo['blocked'] = $identity->blocked;
     $userinfo['editcount'] = $identity->editcount;
     return $userinfo;
 }
 private function determineConduitURI()
 {
     $uri = $this->getArgument('uri');
     if (count($uri) > 1) {
         throw new ArcanistUsageException(pht('Specify at most one URI.'));
     } else {
         if (count($uri) == 1) {
             $uri = reset($uri);
         } else {
             $conduit_uri = $this->getConduitURI();
             if (!$conduit_uri) {
                 throw new ArcanistUsageException(pht('Specify an explicit URI or run this command from within a ' . 'project which is configured with a %s.', '.arcconfig'));
             }
             $uri = $conduit_uri;
         }
     }
     $uri_object = new PhutilURI($uri);
     if (!$uri_object->getProtocol() || !$uri_object->getDomain()) {
         throw new ArcanistUsageException(pht('Server URI "%s" must include a protocol and domain. It should be ' . 'in the form "%s".', $uri, 'https://phabricator.example.com/'));
     }
     $uri_object->setPath('/api/');
     return (string) $uri_object;
 }
 private function getForcedHost()
 {
     $phabricator_uri = PhabricatorEnv::getURI('/');
     $phabricator_uri = new PhutilURI($phabricator_uri);
     $phabricator_host = $phabricator_uri->getDomain();
     switch ($this->getBuiltinProtocol()) {
         case self::BUILTIN_PROTOCOL_SSH:
             $ssh_host = PhabricatorEnv::getEnvConfig('diffusion.ssh-host');
             if ($ssh_host !== null) {
                 return $ssh_host;
             }
             return $phabricator_host;
         case self::BUILTIN_PROTOCOL_HTTP:
         case self::BUILTIN_PROTOCOL_HTTPS:
             return $phabricator_host;
         default:
             return null;
     }
 }
Example #25
0
 public final function setCookie($name, $value, $expire = null)
 {
     // Ensure cookies are only set on the configured domain.
     $base_uri = PhabricatorEnv::getEnvConfig('phabricator.base-uri');
     $base_uri = new PhutilURI($base_uri);
     $base_domain = $base_uri->getDomain();
     $base_protocol = $base_uri->getProtocol();
     // The "Host" header may include a port number; if so, ignore it. We can't
     // use PhutilURI since there's no URI scheme.
     list($actual_host) = explode(':', $this->getHost(), 2);
     if ($base_domain != $actual_host) {
         throw new Exception("This install of Phabricator is configured as '{$base_domain}' but " . "you are accessing it via '{$actual_host}'. Access Phabricator via " . "the primary configured domain.");
     }
     if ($expire === null) {
         $expire = time() + 60 * 60 * 24 * 365 * 5;
     }
     $is_secure = $base_protocol == 'https';
     setcookie($name, $value, $expire, $path = '/', $base_domain, $is_secure, $http_only = true);
     return $this;
 }
 private function getServerArgv()
 {
     $ssl_key = PhabricatorEnv::getEnvConfig('notification.ssl-key');
     $ssl_cert = PhabricatorEnv::getEnvConfig('notification.ssl-cert');
     $server_uri = PhabricatorEnv::getEnvConfig('notification.server-uri');
     $server_uri = new PhutilURI($server_uri);
     $client_uri = PhabricatorEnv::getEnvConfig('notification.client-uri');
     $client_uri = new PhutilURI($client_uri);
     $log = $this->getLogPath();
     $server_argv = array();
     $server_argv[] = '--client-port=' . coalesce($this->clientPort, $client_uri->getPort());
     $server_argv[] = '--admin-port=' . $server_uri->getPort();
     $server_argv[] = '--admin-host=' . $server_uri->getDomain();
     if ($ssl_key) {
         $server_argv[] = '--ssl-key=' . $ssl_key;
     }
     if ($ssl_cert) {
         $server_argv[] = '--ssl-cert=' . $ssl_cert;
     }
     $server_argv[] = '--log=' . $log;
     if ($this->clientHost) {
         $server_argv[] = '--client-host=' . $this->clientHost;
     }
     return $server_argv;
 }
 public function getNormalizedDomain()
 {
     $domain = null;
     $uri = new PhutilURI($this->uri);
     $domain = $uri->getDomain();
     if (!strlen($domain)) {
         $domain = '<void>';
     }
     return phutil_utf8_strtolower($domain);
 }
 public static function getAllowedURIs($path)
 {
     $uri = new PhutilURI($path);
     if ($uri->getDomain()) {
         return $path;
     }
     $allowed_uris = self::getEnvConfig('phabricator.allowed-uris');
     $return = array();
     foreach ($allowed_uris as $allowed_uri) {
         $return[] = rtrim($allowed_uri, '/') . $path;
     }
     return $return;
 }
 /**
  * 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;
 }
 protected function getTail()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $tail = array(parent::getTail());
     $response = CelerityAPI::getStaticResourceResponse();
     if (PhabricatorEnv::getEnvConfig('notification.enabled')) {
         if ($user && $user->isLoggedIn()) {
             $client_uri = PhabricatorEnv::getEnvConfig('notification.client-uri');
             $client_uri = new PhutilURI($client_uri);
             if ($client_uri->getDomain() == 'localhost') {
                 $this_host = $this->getRequest()->getHost();
                 $this_host = new PhutilURI('http://' . $this_host . '/');
                 $client_uri->setDomain($this_host->getDomain());
             }
             if ($request->isHTTPS()) {
                 $client_uri->setProtocol('wss');
             } else {
                 $client_uri->setProtocol('ws');
             }
             Javelin::initBehavior('aphlict-listen', array('websocketURI' => (string) $client_uri) + $this->buildAphlictListenConfigData());
         }
     }
     $tail[] = $response->renderHTMLFooter();
     return $tail;
 }