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')); } } }
/** * 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; }
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; }
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/'."); } }
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;
/** * 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; }
/** * 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; } }
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; }