protected function renderInput() { $name = $this->getName(); $values = nonempty($this->getValue(), array()); if ($this->getID()) { $id = $this->getID(); } else { $id = celerity_generate_unique_node_id(); } $placeholder = null; if (!$this->placeholder) { $placeholder = $this->getDefaultPlaceholder(); } $template = new AphrontTokenizerTemplateView(); $template->setName($name); $template->setID($id); $template->setValue($values); $username = null; if ($this->user) { $username = $this->user->getUsername(); } if (!$this->disableBehavior) { Javelin::initBehavior('aphront-basic-tokenizer', array('id' => $id, 'src' => $this->datasource, 'value' => $values, 'limit' => $this->limit, 'ondemand' => PhabricatorEnv::getEnvConfig('tokenizer.ondemand'), 'username' => $username, 'placeholder' => $placeholder)); } return $template->render(); }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $visible = $request->getStr('visible'); if (strlen($visible)) { $user->setConsoleVisible((int) $visible); $user->save(); return new AphrontAjaxResponse(); } $tab = $request->getStr('tab'); if (strlen($tab)) { $user->setConsoleTab($tab); $user->save(); return new AphrontAjaxResponse(); } if (PhabricatorEnv::getEnvConfig('darkconsole.enabled')) { $user->setConsoleEnabled(!$user->getConsoleEnabled()); if ($user->getConsoleEnabled()) { $user->setConsoleVisible(true); } $user->save(); if ($request->isAjax()) { return new AphrontRedirectResponse(); } else { return id(new AphrontRedirectResponse())->setURI('/'); } } }
public static function loadOneSkinSpecification($name) { // Only allow skins which we know to exist to load. This prevents loading // skins like "../../secrets/evil/". $all = self::loadAllSkinSpecifications(); if (empty($all[$name])) { throw new Exception(pht('Blog skin "%s" is not a valid skin!', $name)); } $paths = PhabricatorEnv::getEnvConfig('phame.skins'); $base = dirname(phutil_get_library_root('phabricator')); foreach ($paths as $path) { $path = Filesystem::resolvePath($path, $base); $skin_path = $path . DIRECTORY_SEPARATOR . $name; if (is_dir($skin_path)) { // Double check that the skin really lives in the skin directory. if (!Filesystem::isDescendant($skin_path, $path)) { throw new Exception(pht('Blog skin "%s" is not located in path "%s"!', $name, $path)); } $spec = self::loadSkinSpecification($skin_path); if ($spec) { $spec->setName($name); return $spec; } } } return null; }
public static function getLog() { if (!self::$log) { $path = PhabricatorEnv::getEnvConfig('log.ssh.path'); $format = PhabricatorEnv::getEnvConfig('log.ssh.format'); $format = nonempty($format, "[%D]\t%p\t%h\t%r\t%s\t%S\t%u\t%C\t%U\t%c\t%T\t%i\t%o"); // NOTE: Path may be null. We still create the log, it just won't write // anywhere. $data = array('D' => date('r'), 'h' => php_uname('n'), 'p' => getmypid(), 'e' => time()); $sudo_user = PhabricatorEnv::getEnvConfig('phd.user'); if (strlen($sudo_user)) { $data['S'] = $sudo_user; } if (function_exists('posix_geteuid')) { $system_uid = posix_geteuid(); $system_info = posix_getpwuid($system_uid); $data['s'] = idx($system_info, 'name'); } $client = getenv('SSH_CLIENT'); if (strlen($client)) { $remote_address = head(explode(' ', $client)); $data['r'] = $remote_address; } $log = id(new PhutilDeferredLog($path, $format))->setFailQuietly(true)->setData($data); self::$log = $log; } return self::$log; }
public function processRequest() { $request = $this->getRequest(); $chrono_key = $request->getStr('chronoKey'); $user = $request->getUser(); if ($request->isDialogFormPost()) { $table = new PhabricatorFeedStoryNotification(); queryfx($table->establishConnection('w'), 'UPDATE %T SET hasViewed = 1 ' . 'WHERE userPHID = %s AND hasViewed = 0 and chronologicalKey <= %s', $table->getTableName(), $user->getPHID(), $chrono_key); return id(new AphrontReloadResponse())->setURI('/notification/'); } $dialog = new AphrontDialogView(); $dialog->setUser($user); $dialog->addCancelButton('/notification/'); if ($chrono_key) { $dialog->setTitle(pht('Really mark all notifications as read?')); $dialog->addHiddenInput('chronoKey', $chrono_key); $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); if ($is_serious) { $dialog->appendChild(pht('All unread notifications will be marked as read. You can not ' . 'undo this action.')); } else { $dialog->appendChild(pht("You can't ignore your problems forever, you know.")); } $dialog->addSubmitButton(pht('Mark All Read')); } else { $dialog->setTitle(pht('No notifications to mark as read.')); $dialog->appendChild(pht('You have no unread notifications.')); } return id(new AphrontDialogResponse())->setDialog($dialog); }
/** * Select viable default storage engines according to configuration. We'll * select the MySQL and Local Disk storage engines if they are configured * to allow a given file. */ public function selectStorageEngines($data, array $params) { $length = strlen($data); $mysql_key = 'storage.mysql-engine.max-size'; $mysql_limit = PhabricatorEnv::getEnvConfig($mysql_key); $engines = array(); if ($mysql_limit && $length <= $mysql_limit) { $engines[] = new PhabricatorMySQLFileStorageEngine(); } $local_key = 'storage.local-disk.path'; $local_path = PhabricatorEnv::getEnvConfig($local_key); if ($local_path) { $engines[] = new PhabricatorLocalDiskFileStorageEngine(); } $s3_key = 'storage.s3.bucket'; if (PhabricatorEnv::getEnvConfig($s3_key)) { $engines[] = new PhabricatorS3FileStorageEngine(); } if ($mysql_limit && empty($engines)) { // If we return no engines, an exception will be thrown but it will be // a little vague ("No valid storage engines"). Since this is a default // case, throw a more specific exception. throw new Exception("This file exceeds the configured MySQL storage engine filesize " . "limit, but no other storage engines are configured. Increase the " . "MySQL storage engine limit or configure a storage engine suitable " . "for larger files."); } return $engines; }
/** * 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($custom_domain) { $example_domain = '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($custom_domain); if ($uri->getProtocol()) { return array($label, pht('The custom domain should not include a protocol. Just provide ' . 'the bare domain name (for example, "%s").', $example_domain)); } if ($uri->getPort()) { return array($label, pht('The custom domain should not include a port number. Just provide ' . 'the bare domain name (for example, "%s").', $example_domain)); } if (strpos($custom_domain, '/') !== false) { 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($custom_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 processRequest() { $request = $this->getRequest(); if (!PhabricatorEnv::getEnvConfig('auth.password-auth-enabled')) { return new Aphront400Response(); } if ($request->getUser()->getPHID()) { $view = new AphrontRequestFailureView(); $view->setHeader('Already Logged In'); $view->appendChild('<p>You are already logged in.</p>'); $view->appendChild('<div class="aphront-failure-continue">' . '<a class="button" href="/">Return Home</a>' . '</div>'); return $this->buildStandardPageResponse($view, array('title' => 'Already Logged In')); } $token = $this->token; $email = $request->getStr('email'); $target_user = id(new PhabricatorUser())->loadOneWhere('email = %s', $email); if (!$target_user || !$target_user->validateEmailToken($token)) { $view = new AphrontRequestFailureView(); $view->setHeader('Unable to Login'); $view->appendChild('<p>The authentication information in the link you clicked is ' . 'invalid or out of date. Make sure you are copy-and-pasting the ' . 'entire link into your browser. You can try again, or request ' . 'a new email.</p>'); $view->appendChild('<div class="aphront-failure-continue">' . '<a class="button" href="/login/email/">Send Another Email</a>' . '</div>'); return $this->buildStandardPageResponse($view, array('title' => 'Email Sent')); } $session_key = $target_user->establishSession('web'); $request->setCookie('phusr', $target_user->getUsername()); $request->setCookie('phsid', $session_key); if (PhabricatorEnv::getEnvConfig('account.editable')) { $next = '/settings/page/password/?token=' . $token; } else { $next = '/'; } $uri = new PhutilURI('/login/validate/'); $uri->setQueryParams(array('phusr' => $target_user->getUsername(), 'next' => $next)); return id(new AphrontRedirectResponse())->setURI((string) $uri); }
/** * @task config */ protected function establishLiveConnection($mode) { $namespace = self::getStorageNamespace(); $database = $namespace . '_' . $this->getApplicationName(); $is_readonly = PhabricatorEnv::isReadOnly(); if ($is_readonly && $mode != 'r') { $this->raiseImproperWrite($database); } $is_cluster = (bool) PhabricatorEnv::getEnvConfig('cluster.databases'); if ($is_cluster) { $connection = $this->newClusterConnection($database, $mode); } else { $connection = $this->newBasicConnection($database, $mode, $namespace); } // TODO: This should be testing if the mode is "r", but that would proably // break a lot of things. Perform a more narrow test for readonly mode // until we have greater certainty that this works correctly most of the // time. if ($is_readonly) { $connection->setReadOnly(true); } // Unless this is a script running from the CLI, prevent any query from // running for more than 30 seconds. See T10849 for discussion. if (php_sapi_name() != 'cli') { $connection->setQueryTimeout(30); } return $connection; }
protected function getHead() { $framebust = null; if (!$this->getFrameable()) { $framebust = '(top == self) || top.location.replace(self.location.href);'; } $viewport_tag = null; if ($this->getDeviceReady()) { $viewport_tag = phutil_tag('meta', array('name' => 'viewport', 'content' => 'width=device-width, ' . 'initial-scale=1, ' . 'maximum-scale=1')); } $mask_icon = phutil_tag('link', array('rel' => 'mask-icon', 'color' => '#3D4B67', 'href' => celerity_get_resource_uri('/rsrc/favicons/mask-icon.svg'))); $icon_tag_76 = phutil_tag('link', array('rel' => 'apple-touch-icon', 'href' => celerity_get_resource_uri('/rsrc/favicons/apple-touch-icon-76x76.png'))); $icon_tag_120 = phutil_tag('link', array('rel' => 'apple-touch-icon', 'sizes' => '120x120', 'href' => celerity_get_resource_uri('/rsrc/favicons/apple-touch-icon-120x120.png'))); $icon_tag_152 = phutil_tag('link', array('rel' => 'apple-touch-icon', 'sizes' => '152x152', 'href' => celerity_get_resource_uri('/rsrc/favicons/apple-touch-icon-152x152.png'))); $favicon_tag = phutil_tag('link', array('id' => 'favicon', 'rel' => 'shortcut icon', 'href' => celerity_get_resource_uri('/rsrc/favicons/favicon.ico'))); $referrer_tag = phutil_tag('meta', array('name' => 'referrer', 'content' => 'never')); $response = CelerityAPI::getStaticResourceResponse(); if ($this->getRequest()) { $viewer = $this->getRequest()->getViewer(); if ($viewer) { $postprocessor_key = $viewer->getUserSetting(PhabricatorAccessibilitySetting::SETTINGKEY); if (strlen($postprocessor_key)) { $response->setPostProcessorKey($postprocessor_key); } } } $developer = PhabricatorEnv::getEnvConfig('phabricator.developer-mode'); return hsprintf('%s%s%s%s%s%s%s%s%s', $viewport_tag, $mask_icon, $icon_tag_76, $icon_tag_120, $icon_tag_152, $favicon_tag, $referrer_tag, CelerityStaticResourceResponse::renderInlineScript($framebust . jsprintf('window.__DEV__=%d;', $developer ? 1 : 0)), $response->renderResourcesOfType('css')); }
/** * @phutil-external-symbol class PhabricatorStartup */ protected function executeChecks() { $upload_limit = PhabricatorEnv::getEnvConfig('storage.upload-size-limit'); if (!$upload_limit) { $message = pht('The Phabricator file upload limit is not configured. You may only ' . 'be able to upload very small files until you configure it, because ' . 'some PHP default limits are very low (as low as 2MB).'); $this->newIssue('config.storage.upload-size-limit')->setShortName(pht('Upload Limit'))->setName(pht('Upload Limit Not Yet Configured'))->setMessage($message)->addPhabricatorConfig('storage.upload-size-limit'); } else { $memory_limit = PhabricatorStartup::getOldMemoryLimit(); if ($memory_limit && (int) $memory_limit > 0) { $memory_limit_bytes = phutil_parse_bytes($memory_limit); $memory_usage_bytes = memory_get_usage(); $upload_limit_bytes = phutil_parse_bytes($upload_limit); $available_bytes = $memory_limit_bytes - $memory_usage_bytes; if ($upload_limit_bytes > $available_bytes) { $summary = pht('Your PHP memory limit is configured in a way that may prevent ' . 'you from uploading large files.'); $message = pht('When you upload a file via drag-and-drop or the API, the entire ' . 'file is buffered into memory before being written to permanent ' . 'storage. Phabricator needs memory available to store these ' . 'files while they are uploaded, but PHP is currently configured ' . 'to limit the available memory.' . "\n\n" . 'Your Phabricator %s is currently set to a larger value (%s) than ' . 'the amount of available memory (%s) that a PHP process has ' . 'available to use, so uploads via drag-and-drop and the API will ' . 'hit the memory limit before they hit other limits.' . "\n\n" . '(Note that the application itself must also fit in available ' . 'memory, so not all of the memory under the memory limit is ' . 'available for buffering file uploads.)' . "\n\n" . "The easiest way to resolve this issue is to set %s to %s in your " . "PHP configuration, to disable the memory limit. There is " . "usually little or no value to using this option to limit " . "Phabricator process memory." . "\n\n" . "You can also increase the limit, or decrease %s, or ignore this " . "issue and accept that these upload mechanisms will be limited " . "in the size of files they can handle.", phutil_tag('tt', array(), 'storage.upload-size-limit'), phutil_format_bytes($upload_limit_bytes), phutil_format_bytes($available_bytes), phutil_tag('tt', array(), 'memory_limit'), phutil_tag('tt', array(), '-1'), phutil_tag('tt', array(), 'storage.upload-size-limit')); $this->newIssue('php.memory_limit.upload')->setName(pht('Memory Limit Restricts File Uploads'))->setSummary($summary)->setMessage($message)->addPHPConfig('memory_limit')->addPHPConfigOriginalValue('memory_limit', $memory_limit)->addPhabricatorConfig('storage.upload-size-limit'); } } } $local_path = PhabricatorEnv::getEnvConfig('storage.local-disk.path'); if (!$local_path) { return; } if (!Filesystem::pathExists($local_path) || !is_readable($local_path) || !is_writable($local_path)) { $message = pht('Configured location for storing uploaded files on disk ("%s") does ' . 'not exist, or is not readable or writable. Verify the directory ' . 'exists and is readable and writable by the webserver.', $local_path); $this->newIssue('config.storage.local-disk.path')->setShortName(pht('Local Disk Storage'))->setName(pht('Local Disk Storage Not Readable/Writable'))->setMessage($message)->addPhabricatorConfig('storage.local-disk.path'); } }
protected function getProxyCommand() { $uri = new PhutilURI($this->proxyURI); $username = PhabricatorEnv::getEnvConfig('cluster.instance'); if (!strlen($username)) { $username = PhabricatorEnv::getEnvConfig('diffusion.ssh-user'); if (!strlen($username)) { 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 final function willBeginExecution() { $request = $this->getRequest(); $user = new PhabricatorUser(); $phusr = $request->getCookie('phusr'); $phsid = $request->getCookie('phsid'); if ($phusr && $phsid) { $info = queryfx_one($user->establishConnection('r'), 'SELECT u.* FROM %T u JOIN %T s ON u.phid = s.userPHID AND s.type LIKE %> AND s.sessionKey = %s', $user->getTableName(), 'phabricator_session', 'web-', $phsid); if ($info) { $user->loadFromArray($info); } } $request->setUser($user); if ($user->getIsDisabled() && $this->shouldRequireEnabledUser()) { $disabled_user_controller = newv('PhabricatorDisabledUserController', array($request)); return $this->delegateToController($disabled_user_controller); } if (PhabricatorEnv::getEnvConfig('darkconsole.enabled')) { if ($user->getConsoleEnabled() || PhabricatorEnv::getEnvConfig('darkconsole.always-on')) { $console = new DarkConsoleCore(); $request->getApplicationConfiguration()->setConsole($console); } } if ($this->shouldRequireLogin() && !$user->getPHID()) { $login_controller = newv('PhabricatorLoginController', array($request)); return $this->delegateToController($login_controller); } if ($this->shouldRequireAdmin() && !$user->getIsAdmin()) { return new Aphront403Response(); } }
public function render() { $data = $this->getData(); $lib_data = $data['libraries']; $lib_rows = array(); foreach ($lib_data as $key => $value) { $lib_rows[] = array(phutil_escape_html($key), phutil_escape_html($value)); } $lib_table = new AphrontTableView($lib_rows); $lib_table->setHeaders(array('Library', 'Loaded From')); $lib_table->setColumnClasses(array('header', 'wide wrap')); $config_data = $data['config']; ksort($config_data); $mask = PhabricatorEnv::getEnvConfig('darkconsole.config-mask'); $mask = array_fill_keys($mask, true); foreach ($mask as $masked_key => $ignored) { if (!PhabricatorEnv::envConfigExists($masked_key)) { throw new Exception("Configuration 'darkconsole.config-mask' masks unknown " . "configuration key '" . $masked_key . "'. If this key has been " . "renamed, you might be accidentally exposing information which you " . "don't intend to."); } } $rows = array(); foreach ($config_data as $key => $value) { if (empty($mask[$key])) { $display_value = is_array($value) ? json_encode($value) : $value; $display_value = phutil_escape_html($display_value); } else { $display_value = phutil_escape_html('<Masked>'); } $rows[] = array(phutil_escape_html($key), $display_value); } $table = new AphrontTableView($rows); $table->setHeaders(array('Key', 'Value')); $table->setColumnClasses(array('header', 'wide wrap')); return $lib_table->render() . $table->render(); }
public function handleException(Exception $ex) { // Always log the unhandled exception. phlog($ex); $class = phutil_escape_html(get_class($ex)); $message = phutil_escape_html($ex->getMessage()); if (PhabricatorEnv::getEnvConfig('phabricator.show-stack-traces')) { $trace = $this->renderStackTrace($ex->getTrace()); } else { $trace = null; } $content = '<div class="aphront-unhandled-exception">' . '<div class="exception-message">' . $message . '</div>' . $trace . '</div>'; $user = $this->getRequest()->getUser(); if (!$user) { // If we hit an exception very early, we won't have a user. $user = new PhabricatorUser(); } $dialog = new AphrontDialogView(); $dialog->setTitle('Unhandled Exception ("' . $class . '")')->setClass('aphront-exception-dialog')->setUser($user)->appendChild($content); if ($this->getRequest()->isAjax()) { $dialog->addCancelButton('/', 'Close'); } $response = new AphrontDialogResponse(); $response->setDialog($dialog); return $response; }
private function renderSearch() { $user = $this->user; $result = null; $keyboard_config = array('helpURI' => '/help/keyboardshortcut/'); if ($user->isLoggedIn()) { $show_search = $user->isUserActivated(); } else { $show_search = PhabricatorEnv::getEnvConfig('policy.allow-public'); } if ($show_search) { $search = new PhabricatorMainMenuSearchView(); $search->setUser($user); $result = $search; $pref_shortcut = PhabricatorUserPreferences::PREFERENCE_SEARCH_SHORTCUT; if ($user->loadPreferences()->getPreference($pref_shortcut, true)) { $keyboard_config['searchID'] = $search->getID(); } } Javelin::initBehavior('phabricator-keyboard-shortcuts', $keyboard_config); if ($result) { $result = id(new PHUIListItemView())->addClass('phabricator-main-menu-search')->appendChild($result); } return $result; }
protected function executeChecks() { $adapter = PhabricatorEnv::getEnvConfig('metamta.mail-adapter'); switch ($adapter) { case 'PhabricatorMailImplementationPHPMailerLiteAdapter': if (!Filesystem::pathExists('/usr/bin/sendmail') && !Filesystem::pathExists('/usr/sbin/sendmail')) { $message = pht('Mail is configured to send via sendmail, but this system has ' . 'no sendmail binary. Install sendmail or choose a different ' . 'mail adapter.'); $this->newIssue('config.metamta.mail-adapter')->setShortName(pht('Missing Sendmail'))->setName(pht('No Sendmail Binary Found'))->setMessage($message)->addRelatedPhabricatorConfig('metamta.mail-adapter'); } break; case 'PhabricatorMailImplementationAmazonSESAdapter': if (PhabricatorEnv::getEnvConfig('metamta.can-send-as-user')) { $message = pht('Amazon SES does not support sending email as users. Disable ' . 'send as user, or choose a different mail adapter.'); $this->newIssue('config.can-send-as-user')->setName(pht("SES Can't Send As User"))->setMessage($message)->addRelatedPhabricatorConfig('metamta.mail-adapter')->addPhabricatorConfig('metamta.can-send-as-user'); } if (!PhabricatorEnv::getEnvConfig('amazon-ses.access-key')) { $message = pht('Amazon SES is selected as the mail adapter, but no SES access ' . 'key is configured. Provide an SES access key, or choose a ' . 'different mail adapter.'); $this->newIssue('config.amazon-ses.access-key')->setName(pht('Amazon SES Access Key Not Set'))->setMessage($message)->addRelatedPhabricatorConfig('metamta.mail-adapter')->addPhabricatorConfig('amazon-ses.access-key'); } if (!PhabricatorEnv::getEnvConfig('amazon-ses.secret-key')) { $message = pht('Amazon SES is selected as the mail adapter, but no SES secret ' . 'key is configured. Provide an SES secret key, or choose a ' . 'different mail adapter.'); $this->newIssue('config.amazon-ses.secret-key')->setName(pht('Amazon SES Secret Key Not Set'))->setMessage($message)->addRelatedPhabricatorConfig('metamta.mail-adapter')->addPhabricatorConfig('amazon-ses.secret-key'); } $address_key = 'metamta.default-address'; $options = PhabricatorApplicationConfigOptions::loadAllOptions(); $default = $options[$address_key]->getDefault(); $value = PhabricatorEnv::getEnvConfig($address_key); if ($default === $value) { $message = pht('Amazon SES requires verification of the "From" address, but ' . 'you have not configured a "From" address. Configure and verify ' . 'a "From" address, or choose a different mail adapter.'); $this->newIssue('config.metamta.default-address')->setName(pht('No SES From Address Configured'))->setMessage($message)->addRelatedPhabricatorConfig('metamta.mail-adapter')->addPhabricatorConfig('metamta.default-address'); } break; } }
protected function executeChecks() { if (!extension_loaded('apc')) { $message = pht("Installing the PHP extension 'APC' (Alternative PHP Cache) will " . "dramatically improve performance. Note that APC versions 3.1.14 and " . "3.1.15 are broken; 3.1.13 is recommended instead."); $this->newIssue('extension.apc')->setShortName(pht('APC'))->setName(pht("PHP Extension 'APC' Not Installed"))->setMessage($message)->addPHPExtension('apc'); return; } if (!ini_get('apc.enabled')) { $summary = pht('Enabling APC will dramatically improve performance.'); $message = pht("The PHP extension 'APC' is installed, but not enabled in your PHP " . "configuration. Enabling it will dramatically improve Phabricator " . "performance. Edit the 'apc.enabled' setting to enable the extension."); $this->newIssue('extension.apc.enabled')->setShortName(pht('APC Disabled'))->setName(pht("PHP Extension 'APC' Not Enabled"))->setSummary($summary)->setMessage($message)->addPHPConfig('apc.enabled'); return; } $is_dev = PhabricatorEnv::getEnvConfig('phabricator.developer-mode'); $is_stat_enabled = ini_get('apc.stat'); $issue_key = null; if ($is_stat_enabled && !$is_dev) { $issue_key = 'extension.apc.stat-enabled'; $short = pht("'apc.stat' Enabled"); $long = pht("'apc.stat' Enabled in Production"); $summary = pht("'apc.stat' is currently enabled, but should probably be disabled."); $message = pht("'apc.stat' is currently enabled in your PHP configuration. For most " . "Phabricator installs, 'apc.stat' should be disabled. This will " . "slightly improve performance (PHP will do fewer disk reads) and make " . "updates safer (PHP won't read in the middle of a 'git pull').\n\n" . "(If you are developing for Phabricator, leave 'apc.stat' enabled but " . "enable 'phabricator.developer-mode'.)"); } else { if (!$is_stat_enabled && $is_dev) { $issue_key = 'extension.apc.stat-disabled'; $short = pht("'apc.stat' Disabled"); $long = pht("'apc.stat' Disabled in Development"); $summary = pht("'apc.stat' is currently disabled, but should probably be enabled " . "in development mode."); $message = pht("'apc.stat' is disabled in your PHP configuration, but Phabricator is " . "set to developer mode. Normally, you should enable 'apc.stat' for " . "development installs so you don't need to restart your webserver " . "after making changes to the code.\n\n" . "You can enable 'apc.stat', or disable 'phabricator.developer-mode', " . "or safely ignore this warning if you have some reasoning behind " . "your current configuration."); } } if ($issue_key !== null) { $this->newIssue($issue_key)->setShortName($short)->setName($long)->setSummary($summary)->setMessage($message)->addPHPConfig('apc.stat')->addPhabricatorConfig('phabricator.developer-mode'); } }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $query = id(new PhabricatorNotificationQuery())->setViewer($user)->withUserPHIDs(array($user->getPHID()))->setLimit(15); $stories = $query->execute(); $clear_ui_class = 'phabricator-notification-clear-all'; $clear_uri = id(new PhutilURI('/notification/clear/')); if ($stories) { $builder = new PhabricatorNotificationBuilder($stories); $notifications_view = $builder->buildView(); $content = $notifications_view->render(); $clear_uri->setQueryParam('chronoKey', head($stories)->getChronologicalKey()); } else { $content = phutil_tag_div('phabricator-notification no-notifications', pht('You have no notifications.')); $clear_ui_class .= ' disabled'; } $clear_ui = javelin_tag('a', array('sigil' => 'workflow', 'href' => (string) $clear_uri, 'class' => $clear_ui_class), pht('Mark All Read')); $notifications_link = phutil_tag('a', array('href' => '/notification/'), pht('Notifications')); if (PhabricatorEnv::getEnvConfig('notification.enabled')) { $connection_status = new PhabricatorNotificationStatusView(); } else { $connection_status = phutil_tag('a', array('href' => PhabricatorEnv::getDoclink('Notifications User Guide: Setup and Configuration')), pht('Notification Server not enabled.')); } $connection_ui = phutil_tag('div', array('class' => 'phabricator-notification-footer'), $connection_status); $header = phutil_tag('div', array('class' => 'phabricator-notification-header'), array($notifications_link, $clear_ui)); $content = hsprintf('%s%s%s', $header, $content, $connection_ui); $unread_count = id(new PhabricatorFeedStoryNotification())->countUnread($user); $json = array('content' => $content, 'number' => (int) $unread_count); return id(new AphrontAjaxResponse())->setContent($json); }
protected function buildAttachments() { $attachments = array(); if (PhabricatorEnv::getEnvConfig('metamta.differential.attach-patches')) { $revision = $this->getRevision(); $revision_id = $revision->getID(); $diffs = $revision->loadDiffs(); $diff_number = count($diffs); $diff = array_pop($diffs); $filename = "D{$revision_id}.{$diff_number}.patch"; $diff->attachChangesets($diff->loadChangesets()); // TODO: We could batch this to improve performance. foreach ($diff->getChangesets() as $changeset) { $changeset->attachHunks($changeset->loadHunks()); } $diff_dict = $diff->getDiffDict(); $changes = array(); foreach ($diff_dict['changes'] as $changedict) { $changes[] = ArcanistDiffChange::newFromDictionary($changedict); } $bundle = ArcanistBundle::newFromChanges($changes); $unified_diff = $bundle->toUnifiedDiff(); $attachments[] = new PhabricatorMetaMTAAttachment($unified_diff, $filename, 'text/x-patch; charset=utf-8'); } return $attachments; }
public function processRequest() { $alt = PhabricatorEnv::getEnvConfig('security.alternate-file-domain'); if (!$alt) { return new Aphront400Response(); } $request = $this->getRequest(); $alt_domain = id(new PhutilURI($alt))->getDomain(); if ($alt_domain != $request->getHost()) { return new Aphront400Response(); } $file = id(new PhabricatorFile())->loadOneWhere('phid = %s', $this->phid); if (!$file) { return new Aphront404Response(); } if (!$file->validateSecretKey($this->key)) { return new Aphront404Response(); } // It's safe to bypass view restrictions because we know we are being served // off an alternate domain which we will not set cookies on. $data = $file->loadFileData(); $response = new AphrontFileResponse(); $response->setContent($data); $response->setMimeType($file->getMimeType()); $response->setCacheDurationInSeconds(60 * 60 * 24 * 30); return $response; }
public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); $db_values = id(new PhabricatorConfigEntry())->loadAllWhere('namespace = %s', 'default'); $db_values = mpull($db_values, null, 'getConfigKey'); $rows = array(); $options = PhabricatorApplicationConfigOptions::loadAllOptions(); ksort($options); foreach ($options as $option) { $key = $option->getKey(); if ($option->getHidden()) { $value = phutil_tag('em', array(), pht('Hidden')); } else { $value = PhabricatorEnv::getEnvConfig($key); $value = PhabricatorConfigJSON::prettyPrintJSON($value); } $db_value = idx($db_values, $key); $rows[] = array(phutil_tag('a', array('href' => $this->getApplicationURI('edit/' . $key . '/')), $key), $value, $db_value && !$db_value->getIsDeleted() ? pht('Customized') : ''); } $table = id(new AphrontTableView($rows))->setColumnClasses(array('', 'wide'))->setHeaders(array(pht('Key'), pht('Value'), pht('Customized'))); $title = pht('Current Settings'); $crumbs = $this->buildApplicationCrumbs()->addTextCrumb($title); $panel = new PHUIObjectBoxView(); $panel->setHeaderText(pht('Current Settings')); $panel->setTable($table); $nav = $this->buildSideNavView(); $nav->selectFilter('all/'); $view = id(new PHUITwoColumnView())->setNavigation($nav)->setMainColumn(array($panel)); return $this->newPage()->setTitle($title)->setCrumbs($crumbs)->appendChild($view); }
protected function renderResultList(array $pastes, PhabricatorSavedQuery $query, array $handles) { assert_instances_of($pastes, 'PhabricatorPaste'); $viewer = $this->requireViewer(); $lang_map = PhabricatorEnv::getEnvConfig('pygments.dropdown-choices'); $list = new PHUIObjectItemListView(); $list->setUser($viewer); foreach ($pastes as $paste) { $created = phabricator_date($paste->getDateCreated(), $viewer); $author = $handles[$paste->getAuthorPHID()]->renderLink(); $snippet_type = $paste->getSnippet()->getType(); $lines = phutil_split_lines($paste->getSnippet()->getContent()); $preview = id(new PhabricatorSourceCodeView())->setLines($lines)->setTruncatedFirstBytes($snippet_type == PhabricatorPasteSnippet::FIRST_BYTES)->setTruncatedFirstLines($snippet_type == PhabricatorPasteSnippet::FIRST_LINES)->setURI(new PhutilURI($paste->getURI())); $source_code = phutil_tag('div', array('class' => 'phabricator-source-code-summary'), $preview); $created = phabricator_datetime($paste->getDateCreated(), $viewer); $line_count = count($lines); $line_count = pht('%s Line(s)', new PhutilNumber($line_count)); $title = nonempty($paste->getTitle(), pht('(An Untitled Masterwork)')); $item = id(new PHUIObjectItemView())->setObjectName('P' . $paste->getID())->setHeader($title)->setHref('/P' . $paste->getID())->setObject($paste)->addByline(pht('Author: %s', $author))->addIcon('none', $created)->addIcon('none', $line_count)->appendChild($source_code); if ($paste->isArchived()) { $item->setDisabled(true); } $lang_name = $paste->getLanguage(); if ($lang_name) { $lang_name = idx($lang_map, $lang_name, $lang_name); $item->addIcon('none', $lang_name); } $list->addItem($item); } $result = new PhabricatorApplicationSearchResultView(); $result->setObjectList($list); $result->setNoDataString(pht('No pastes found.')); return $result; }
protected function buildResourceTransformer() { $minify_on = PhabricatorEnv::getEnvConfig('celerity.minify'); $developer_on = PhabricatorEnv::getEnvConfig('phabricator.developer-mode'); $should_minify = $minify_on && !$developer_on; return id(new CelerityResourceTransformer())->setMinify($should_minify)->setCelerityMap($this->getCelerityResourceMap()); }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $editable = $this->getAccountEditable(); // There's no sense in showing a change password panel if the user // can't change their password if (!$editable || !PhabricatorEnv::getEnvConfig('auth.password-auth-enabled')) { return new Aphront400Response(); } $errors = array(); if ($request->isFormPost()) { if ($user->comparePassword($request->getStr('old_pw'))) { $pass = $request->getStr('new_pw'); $conf = $request->getStr('conf_pw'); if ($pass === $conf) { if (strlen($pass)) { $user->setPassword($pass); // This write is unguarded because the CSRF token has already // been checked in the call to $request->isFormPost() and // the CSRF token depends on the password hash, so when it // is changed here the CSRF token check will fail. $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $user->save(); unset($unguarded); return id(new AphrontRedirectResponse())->setURI('/settings/page/password/?saved=true'); } else { $errors[] = 'Your new password is too short.'; } } else { $errors[] = 'New password and confirmation do not match.'; } } else { $errors[] = 'The old password you entered is incorrect.'; } } $notice = null; if (!$errors) { if ($request->getStr('saved')) { $notice = new AphrontErrorView(); $notice->setSeverity(AphrontErrorView::SEVERITY_NOTICE); $notice->setTitle('Changes Saved'); $notice->appendChild('<p>Your password has been updated.</p>'); } } else { $notice = new AphrontErrorView(); $notice->setTitle('Error Changing Password'); $notice->setErrors($errors); } $form = new AphrontFormView(); $form->setUser($user)->appendChild(id(new AphrontFormPasswordControl())->setLabel('Old Password')->setName('old_pw')); $form->appendChild(id(new AphrontFormPasswordControl())->setLabel('New Password')->setName('new_pw')); $form->appendChild(id(new AphrontFormPasswordControl())->setLabel('Confirm Password')->setName('conf_pw')); $form->appendChild(id(new AphrontFormSubmitControl())->setValue('Save')); $panel = new AphrontPanelView(); $panel->setHeader('Change Password'); $panel->setWidth(AphrontPanelView::WIDTH_FORM); $panel->appendChild($form); return id(new AphrontNullView())->appendChild(array($notice, $panel)); }
/** * @phutil-external-symbol class PhabricatorStartup */ public function buildRequest() { $parser = new PhutilQueryStringParser(); $data = array(); // If the request has "multipart/form-data" content, we can't use // PhutilQueryStringParser to parse it, and the raw data supposedly is not // available anyway (according to the PHP documentation, "php://input" is // not available for "multipart/form-data" requests). However, it is // available at least some of the time (see T3673), so double check that // we aren't trying to parse data we won't be able to parse correctly by // examining the Content-Type header. $content_type = idx($_SERVER, 'CONTENT_TYPE'); $is_form_data = preg_match('@^multipart/form-data@i', $content_type); $raw_input = PhabricatorStartup::getRawInput(); if (strlen($raw_input) && !$is_form_data) { $data += $parser->parseQueryString($raw_input); } else { if ($_POST) { $data += $_POST; } } $data += $parser->parseQueryString(idx($_SERVER, 'QUERY_STRING', '')); $cookie_prefix = PhabricatorEnv::getEnvConfig('phabricator.cookie-prefix'); $request = new AphrontRequest($this->getHost(), $this->getPath()); $request->setRequestData($data); $request->setApplicationConfiguration($this); $request->setCookiePrefix($cookie_prefix); return $request; }
public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); $id = $request->getURIData('id'); $timeline = null; $url = id(new PhabricatorPhurlURLQuery())->setViewer($viewer)->withIDs(array($id))->executeOne(); if (!$url) { return new Aphront404Response(); } $title = $url->getMonogram(); $page_title = $title . ' ' . $url->getName(); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb($title, $url->getURI()); $timeline = $this->buildTransactionTimeline($url, new PhabricatorPhurlURLTransactionQuery()); $header = $this->buildHeaderView($url); $actions = $this->buildActionView($url); $properties = $this->buildPropertyView($url); $properties->setActionList($actions); $url_error = id(new PHUIInfoView())->setErrors(array(pht('This URL is invalid due to a bad protocol.')))->setIsHidden($url->isValid()); $box = id(new PHUIObjectBoxView())->setHeader($header)->addPropertyList($properties)->setInfoView($url_error); $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); $add_comment_header = $is_serious ? pht('Add Comment') : pht('More Cowbell'); $draft = PhabricatorDraft::newFromUserAndKey($viewer, $url->getPHID()); $comment_uri = $this->getApplicationURI('/phurl/comment/' . $url->getID() . '/'); $add_comment_form = id(new PhabricatorApplicationTransactionCommentView())->setUser($viewer)->setObjectPHID($url->getPHID())->setDraft($draft)->setHeaderText($add_comment_header)->setAction($comment_uri)->setSubmitButtonName(pht('Add Comment')); return $this->buildApplicationPage(array($crumbs, $box, $timeline, $add_comment_form), array('title' => $page_title, 'pageObjects' => array($url->getPHID()))); }
protected function getHead() { $framebust = null; if (!$this->getFrameable()) { $framebust = '(top == self) || top.location.replace(self.location.href);'; } $viewport_tag = null; if ($this->getDeviceReady()) { $viewport_tag = phutil_tag('meta', array('name' => 'viewport', 'content' => 'width=device-width, ' . 'initial-scale=1, ' . 'maximum-scale=1')); } $icon_tag_76 = phutil_tag('link', array('rel' => 'apple-touch-icon', 'href' => celerity_get_resource_uri('/rsrc/favicons/apple-touch-icon-76x76.png'))); $icon_tag_120 = phutil_tag('link', array('rel' => 'apple-touch-icon', 'sizes' => '120x120', 'href' => celerity_get_resource_uri('/rsrc/favicons/apple-touch-icon-120x120.png'))); $icon_tag_152 = phutil_tag('link', array('rel' => 'apple-touch-icon', 'sizes' => '152x152', 'href' => celerity_get_resource_uri('/rsrc/favicons/apple-touch-icon-152x152.png'))); $apple_tag = phutil_tag('meta', array('name' => 'apple-mobile-web-app-status-bar-style', 'content' => 'black-translucent')); $referrer_tag = phutil_tag('meta', array('name' => 'referrer', 'content' => 'never')); $response = CelerityAPI::getStaticResourceResponse(); if ($this->getRequest()) { $viewer = $this->getRequest()->getViewer(); if ($viewer) { $postprocessor_key = $viewer->getPreference(PhabricatorUserPreferences::PREFERENCE_RESOURCE_POSTPROCESSOR); if (strlen($postprocessor_key)) { $response->setPostProcessorKey($postprocessor_key); } } } $developer = PhabricatorEnv::getEnvConfig('phabricator.developer-mode'); return hsprintf('%s%s%s%s%s%s%s%s', $viewport_tag, $icon_tag_76, $icon_tag_120, $icon_tag_152, $apple_tag, $referrer_tag, CelerityStaticResourceResponse::renderInlineScript($framebust . jsprintf('window.__DEV__=%d;', $developer ? 1 : 0)), $response->renderResourcesOfType('css')); }
public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); $id = $request->getURIData('id'); $paste = id(new PhabricatorPasteQuery())->setViewer($viewer)->withIDs(array($id))->needContent(true)->executeOne(); if (!$paste) { return new Aphront404Response(); } $file = id(new PhabricatorFileQuery())->setViewer($viewer)->withPHIDs(array($paste->getFilePHID()))->executeOne(); if (!$file) { return new Aphront400Response(); } $forks = id(new PhabricatorPasteQuery())->setViewer($viewer)->withParentPHIDs(array($paste->getPHID()))->execute(); $fork_phids = mpull($forks, 'getPHID'); $header = $this->buildHeaderView($paste); $actions = $this->buildActionView($viewer, $paste, $file); $properties = $this->buildPropertyView($paste, $fork_phids, $actions); $object_box = id(new PHUIObjectBoxView())->setHeader($header)->addPropertyList($properties); $source_code = $this->buildSourceCodeView($paste, null, $this->highlightMap); $source_code = id(new PHUIBoxView())->appendChild($source_code)->addMargin(PHUI::MARGIN_LARGE_LEFT)->addMargin(PHUI::MARGIN_LARGE_RIGHT)->addMargin(PHUI::MARGIN_LARGE_TOP); $crumbs = $this->buildApplicationCrumbs($this->buildSideNavView())->addTextCrumb('P' . $paste->getID(), '/P' . $paste->getID()); $timeline = $this->buildTransactionTimeline($paste, new PhabricatorPasteTransactionQuery()); $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); $add_comment_header = $is_serious ? pht('Add Comment') : pht('Eat Paste'); $draft = PhabricatorDraft::newFromUserAndKey($viewer, $paste->getPHID()); $add_comment_form = id(new PhabricatorApplicationTransactionCommentView())->setUser($viewer)->setObjectPHID($paste->getPHID())->setDraft($draft)->setHeaderText($add_comment_header)->setAction($this->getApplicationURI('/comment/' . $paste->getID() . '/'))->setSubmitButtonName(pht('Add Comment')); return $this->buildApplicationPage(array($crumbs, $object_box, $source_code, $timeline, $add_comment_form), array('title' => $paste->getFullName(), 'pageObjects' => array($paste->getPHID()))); }
private function executeMethod() { $user = $this->getUser(); if (!$user) { $user = new PhabricatorUser(); } $this->request->setUser($user); if (!$this->shouldRequireAuthentication()) { // No auth requirement here. } else { $allow_public = $this->handler->shouldAllowPublic() && PhabricatorEnv::getEnvConfig('policy.allow-public'); if (!$allow_public) { if (!$user->isLoggedIn() && !$user->isOmnipotent()) { // TODO: As per below, this should get centralized and cleaned up. throw new ConduitException('ERR-INVALID-AUTH'); } } // TODO: This would be slightly cleaner by just using a Query, but the // Conduit auth workflow requires the Call and User be built separately. // Just do it this way for the moment. $application = $this->handler->getApplication(); if ($application) { $can_view = PhabricatorPolicyFilter::hasCapability($user, $application, PhabricatorPolicyCapability::CAN_VIEW); if (!$can_view) { throw new ConduitException(pht('You do not have access to the application which provides this ' . 'API method.')); } } } return $this->handler->executeMethod($this->request); }