public function processRequest() { // No CSRF for SendGrid. $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $request = $this->getRequest(); $user = $request->getUser(); $raw_headers = $request->getStr('headers'); $raw_headers = explode("\n", rtrim($raw_headers)); $raw_dict = array(); foreach (array_filter($raw_headers) as $header) { list($name, $value) = explode(':', $header, 2); $raw_dict[$name] = ltrim($value); } $headers = array('to' => $request->getStr('to'), 'from' => $request->getStr('from'), 'subject' => $request->getStr('subject')) + $raw_dict; $received = new PhabricatorMetaMTAReceivedMail(); $received->setHeaders($headers); $received->setBodies(array('text' => $request->getStr('text'), 'html' => $request->getStr('from'))); $file_phids = array(); foreach ($_FILES as $file_raw) { try { $file = PhabricatorFile::newFromPHPUpload($file_raw, array('authorPHID' => $user->getPHID())); $file_phids[] = $file->getPHID(); } catch (Exception $ex) { phlog($ex); } } $received->setAttachments($file_phids); $received->save(); $received->processReceivedMail(); $response = new AphrontWebpageResponse(); $response->setContent("Got it! Thanks, SendGrid!\n"); return $response; }
public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); id(new PhabricatorAuthSessionEngine())->requireHighSecuritySession($viewer, $this->getRequest(), '/'); // Ideally we'd like to verify this, but it's fine to leave it unguarded // for now and verifying it would need some Ajax junk or for the user to // click a button or similar. $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $old_token = id(new PhabricatorConduitCertificateToken())->loadOneWhere('userPHID = %s', $viewer->getPHID()); if ($old_token) { $old_token->delete(); } $token = id(new PhabricatorConduitCertificateToken())->setUserPHID($viewer->getPHID())->setToken(Filesystem::readRandomCharacters(40))->save(); unset($unguarded); $pre_instructions = pht('Copy and paste this token into the prompt given to you by ' . '`arc install-certificate`'); $post_instructions = pht('After you copy and paste this token, `arc` will complete ' . 'the certificate install process for you.'); Javelin::initBehavior('select-on-click'); $form = id(new AphrontFormView())->setUser($viewer)->appendRemarkupInstructions($pre_instructions)->appendChild(id(new AphrontFormTextAreaControl())->setLabel(pht('Token'))->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_SHORT)->setReadonly(true)->setSigil('select-on-click')->setValue($token->getToken()))->appendRemarkupInstructions($post_instructions); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('Install Certificate')); $crumbs->setBorder(true); $object_box = id(new PHUIObjectBoxView())->setHeaderText(pht('Certificate Token'))->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)->setForm($form); $title = pht('Certificate Install Token'); $header = id(new PHUIHeaderView())->setHeader($title); $view = id(new PHUITwoColumnView())->setHeader($header)->setFooter($object_box); return $this->newPage()->setTitle($title)->setCrumbs($crumbs)->appendChild($view); }
public function processRequest() { if (!PhabricatorEnv::getEnvConfig('files.enable-proxy')) { return new Aphront400Response(); } $request = $this->getRequest(); $uri = $request->getStr('uri'); $proxy = id(new PhabricatorFileProxyImage())->loadOneWhere('uri = %s', $uri); if (!$proxy) { // This write is fine to skip CSRF checks for, we're just building a // cache of some remote image. $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $file = PhabricatorFile::newFromFileDownload($uri, nonempty(basename($uri), 'proxied-file')); if ($file) { $proxy = new PhabricatorFileProxyImage(); $proxy->setURI($uri); $proxy->setFilePHID($file->getPHID()); $proxy->save(); } unset($unguarded); } if ($proxy) { $file = id(new PhabricatorFile())->loadOneWhere('phid = %s', $proxy->getFilePHID()); if ($file) { $view_uri = $file->getBestURI(); } else { $bad_phid = $proxy->getFilePHID(); throw new Exception("Unable to load file with phid {$bad_phid}."); } return id(new AphrontRedirectResponse())->setURI($view_uri); } return new Aphront400Response(); }
public function setKeys(array $keys, $ttl = null) { if (PhabricatorEnv::isReadOnly()) { return; } if ($keys) { $map = $this->digestKeys(array_keys($keys)); $conn_w = $this->establishConnection('w'); $sql = array(); foreach ($map as $key => $hash) { $value = $keys[$key]; list($format, $storage_value) = $this->willWriteValue($key, $value); $sql[] = qsprintf($conn_w, '(%s, %s, %s, %B, %d, %nd)', $hash, $key, $format, $storage_value, time(), $ttl ? time() + $ttl : null); } $guard = AphrontWriteGuard::beginScopedUnguardedWrites(); foreach (PhabricatorLiskDAO::chunkSQL($sql) as $chunk) { queryfx($conn_w, 'INSERT INTO %T (cacheKeyHash, cacheKey, cacheFormat, cacheData, cacheCreated, cacheExpires) VALUES %Q ON DUPLICATE KEY UPDATE cacheKey = VALUES(cacheKey), cacheFormat = VALUES(cacheFormat), cacheData = VALUES(cacheData), cacheCreated = VALUES(cacheCreated), cacheExpires = VALUES(cacheExpires)', $this->getTableName(), $chunk); } unset($guard); } return $this; }
protected function getResult(ConduitAPIRequest $request) { $drequest = $this->getDiffusionRequest(); $file_query = DiffusionFileContentQuery::newFromDiffusionRequest($drequest); $timeout = $request->getValue('timeout'); if ($timeout) { $file_query->setTimeout($timeout); } $byte_limit = $request->getValue('byteLimit'); if ($byte_limit) { $file_query->setByteLimit($byte_limit); } $file = $file_query->execute(); $too_slow = (bool) $file_query->getExceededTimeLimit(); $too_huge = (bool) $file_query->getExceededByteLimit(); $file_phid = null; if (!$too_slow && !$too_huge) { $repository = $drequest->getRepository(); $repository_phid = $repository->getPHID(); $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $file->attachToObject($repository_phid); unset($unguarded); $file_phid = $file->getPHID(); } return array('tooSlow' => $too_slow, 'tooHuge' => $too_huge, 'filePHID' => $file_phid); }
public function handleRequest(AphrontRequest $request) { // No CSRF for Mailgun. $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); if (!$this->verifyMessage()) { throw new Exception(pht('Mail signature is not valid. Check your Mailgun API key.')); } $user = $request->getUser(); $raw_headers = $request->getStr('headers'); $raw_headers = explode("\n", rtrim($raw_headers)); $raw_dict = array(); foreach (array_filter($raw_headers) as $header) { list($name, $value) = explode(':', $header, 2); $raw_dict[$name] = ltrim($value); } $headers = array('to' => $request->getStr('recipient'), 'from' => $request->getStr('from'), 'subject' => $request->getStr('subject')) + $raw_dict; $received = new PhabricatorMetaMTAReceivedMail(); $received->setHeaders($headers); $received->setBodies(array('text' => $request->getStr('stripped-text'), 'html' => $request->getStr('stripped-html'))); $file_phids = array(); foreach ($_FILES as $file_raw) { try { $file = PhabricatorFile::newFromPHPUpload($file_raw, array('viewPolicy' => PhabricatorPolicies::POLICY_NOONE)); $file_phids[] = $file->getPHID(); } catch (Exception $ex) { phlog($ex); } } $received->setAttachments($file_phids); $received->save(); $received->processReceivedMail(); $response = new AphrontWebpageResponse(); $response->setContent(pht("Got it! Thanks, Mailgun!\n")); return $response; }
protected function loadPage() { $table = new PhortuneProduct(); $conn = $table->establishConnection('r'); $rows = queryfx_all($conn, 'SELECT * FROM %T %Q %Q %Q', $table->getTableName(), $this->buildWhereClause($conn), $this->buildOrderClause($conn), $this->buildLimitClause($conn)); $page = $table->loadAllFromArray($rows); // NOTE: We're loading product implementations here, but also creating any // products which do not yet exist. $class_map = mgroup($page, 'getProductClass'); if ($this->refMap) { $class_map += array_fill_keys(array_keys($this->refMap), array()); } foreach ($class_map as $class => $products) { $refs = mpull($products, null, 'getProductRef'); if (isset($this->refMap[$class])) { $refs += array_fill_keys($this->refMap[$class], null); } $implementations = newv($class, array())->loadImplementationsForRefs($this->getViewer(), array_keys($refs)); $implementations = mpull($implementations, null, 'getRef'); foreach ($implementations as $ref => $implementation) { $product = idx($refs, $ref); if ($product === null) { // If this product does not exist yet, create it and add it to the // result page. $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $product = PhortuneProduct::initializeNewProduct()->setProductClass($class)->setProductRef($ref)->save(); unset($unguarded); $page[] = $product; } $product->attachImplementation($implementation); } } return $page; }
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)); }
public static function generateMacro($viewer, $macro_name, $upper_text, $lower_text) { $macro = id(new PhabricatorMacroQuery())->setViewer($viewer)->withNames(array($macro_name))->needFiles(true)->executeOne(); if (!$macro) { return false; } $file = $macro->getFile(); $upper_text = strtoupper($upper_text); $lower_text = strtoupper($lower_text); $mixed_text = md5($upper_text) . ':' . md5($lower_text); $hash = 'meme' . hash('sha256', $mixed_text); $xform = id(new PhabricatorTransformedFile())->loadOneWhere('originalphid=%s and transform=%s', $file->getPHID(), $hash); if ($xform) { $memefile = id(new PhabricatorFileQuery())->setViewer($viewer)->withPHIDs(array($xform->getTransformedPHID()))->executeOne(); if ($memefile) { return $memefile->getBestURI(); } } $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $transformers = new PhabricatorImageTransformer(); $newfile = $transformers->executeMemeTransform($file, $upper_text, $lower_text); $xfile = new PhabricatorTransformedFile(); $xfile->setOriginalPHID($file->getPHID()); $xfile->setTransformedPHID($newfile->getPHID()); $xfile->setTransform($hash); $xfile->save(); return $newfile->getBestURI(); }
/** * @phutil-external-symbol class PhabricatorStartup */ public function handleRequest(AphrontRequest $request) { $raw_body = PhabricatorStartup::getRawInput(); $body = phutil_json_decode($raw_body); $payload = $body['payload']; $parameters = idx($payload, 'build_parameters'); if (!$parameters) { $parameters = array(); } $target_phid = idx($parameters, 'HARBORMASTER_BUILD_TARGET_PHID'); // NOTE: We'll get callbacks here for builds we triggered, but also for // arbitrary builds the system executes for other reasons. So it's normal // to get some notifications with no Build Target PHID. We just ignore // these under the assumption that they're routine builds caused by events // like branch updates. if ($target_phid) { $viewer = PhabricatorUser::getOmnipotentUser(); $target = id(new HarbormasterBuildTargetQuery())->setViewer($viewer)->withPHIDs(array($target_phid))->needBuildSteps(true)->executeOne(); if ($target) { $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $this->updateTarget($target, $payload); } } $response = new AphrontWebpageResponse(); $response->setContent(pht("Request OK\n")); return $response; }
/** * Deletes the file from local disk, if it exists. * @task impl */ public function deleteFile($handle) { $path = $this->getLocalDiskFileStorageFullPath($handle); if (Filesystem::pathExists($path)) { AphrontWriteGuard::willWrite(); Filesystem::remove($path); } }
public function processRequest() { $viewer = $this->getRequest()->getUser(); // NOTE: This is a public/CDN endpoint, and permission to see files is // controlled by knowing the secret key, not by authentication. $file = id(new PhabricatorFileQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withPHIDs(array($this->phid))->executeOne(); if (!$file) { return new Aphront404Response(); } if (!$file->validateSecretKey($this->key)) { return new Aphront403Response(); } $xform = id(new PhabricatorTransformedFile())->loadOneWhere('originalPHID = %s AND transform = %s', $this->phid, $this->transform); if ($xform) { return $this->buildTransformedFileResponse($xform); } $type = $file->getMimeType(); if (!$file->isViewableInBrowser() || !$file->isTransformableImage()) { return $this->buildDefaultTransformation($file); } // We're essentially just building a cache here and don't need CSRF // protection. $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); switch ($this->transform) { case 'thumb-profile': $xformed_file = $this->executeThumbTransform($file, 50, 50); break; case 'thumb-280x210': $xformed_file = $this->executeThumbTransform($file, 280, 210); break; case 'thumb-220x165': $xformed_file = $this->executeThumbTransform($file, 220, 165); break; case 'preview-100': $xformed_file = $this->executePreviewTransform($file, 100); break; case 'preview-220': $xformed_file = $this->executePreviewTransform($file, 220); break; case 'thumb-160x120': $xformed_file = $this->executeThumbTransform($file, 160, 120); break; case 'thumb-60x45': $xformed_file = $this->executeThumbTransform($file, 60, 45); break; default: return new Aphront400Response(); } if (!$xformed_file) { return new Aphront400Response(); } $xform = new PhabricatorTransformedFile(); $xform->setOriginalPHID($this->phid); $xform->setTransform($this->transform); $xform->setTransformedPHID($xformed_file->getPHID()); $xform->save(); return $this->buildTransformedFileResponse($xform); }
public function handleRequest(AphrontRequest $request) { $viewer = $this->getViewer(); if ($request->getStr('jump') != 'no') { $response = PhabricatorJumpNavHandler::getJumpResponse($viewer, $request->getStr('query')); if ($response) { return $response; } } $engine = new PhabricatorSearchApplicationSearchEngine(); $engine->setViewer($viewer); // If we're coming from primary search, do some special handling to // interpret the scope selector and query. if ($request->getBool('search:primary')) { // If there's no query, just take the user to advanced search. if (!strlen($request->getStr('query'))) { $advanced_uri = '/search/query/advanced/'; return id(new AphrontRedirectResponse())->setURI($advanced_uri); } // First, load or construct a template for the search by examining // the current search scope. $scope = $request->getStr('search:scope'); $saved = null; if ($scope == self::SCOPE_CURRENT_APPLICATION) { $application = id(new PhabricatorApplicationQuery())->setViewer($viewer)->withClasses(array($request->getStr('search:application')))->executeOne(); if ($application) { $types = $application->getApplicationSearchDocumentTypes(); if ($types) { $saved = id(new PhabricatorSavedQuery())->setEngineClassName(get_class($engine))->setParameter('types', $types)->setParameter('statuses', array('open')); } } } if (!$saved && !$engine->isBuiltinQuery($scope)) { $saved = id(new PhabricatorSavedQueryQuery())->setViewer($viewer)->withQueryKeys(array($scope))->executeOne(); } if (!$saved) { if (!$engine->isBuiltinQuery($scope)) { $scope = 'all'; } $saved = $engine->buildSavedQueryFromBuiltin($scope); } // Add the user's query, then save this as a new saved query and send // the user to the results page. $saved->setParameter('query', $request->getStr('query')); $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); try { $saved->setID(null)->save(); } catch (AphrontDuplicateKeyQueryException $ex) { // Ignore, this is just a repeated search. } unset($unguarded); $query_key = $saved->getQueryKey(); $results_uri = $engine->getQueryResultsPageURI($query_key) . '#R'; return id(new AphrontRedirectResponse())->setURI($results_uri); } $controller = id(new PhabricatorApplicationSearchController())->setQueryKey($request->getURIData('queryKey'))->setSearchEngine($engine)->setNavigation($this->buildSideNavView()); return $this->delegateToController($controller); }
/** * Delete a blob from Amazon S3. */ public function deleteFile($handle) { AphrontWriteGuard::willWrite(); $s3 = $this->newS3API(); $profiler = PhutilServiceProfiler::getInstance(); $call_id = $profiler->beginServiceCall(array('type' => 's3', 'method' => 'deleteObject')); $s3->deleteObject($this->getBucketName(), $handle); $profiler->endServiceCall($call_id, array()); }
/** * Delete a blob from Amazon S3. */ public function deleteFile($handle) { $s3 = $this->newS3API(); AphrontWriteGuard::willWrite(); $profiler = PhutilServiceProfiler::getInstance(); $call_id = $profiler->beginServiceCall(array('type' => 's3', 'method' => 'deleteObject')); $s3->setParametersForDeleteObject($handle)->resolve(); $profiler->endServiceCall($call_id, array()); }
public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); $aid = $request->getURIData('aid'); $bid = $request->getURIData('bid'); // If "aid" is "x", then it means the user wants to generate // a patch of an empty file to the version specified by "bid". $ids = array($aid, $bid); if ($aid === 'x') { $ids = array($bid); } $versions = id(new PhragmentFragmentVersionQuery())->setViewer($viewer)->withIDs($ids)->execute(); $version_a = null; if ($aid !== 'x') { $version_a = idx($versions, $aid, null); if ($version_a === null) { return new Aphront404Response(); } } $version_b = idx($versions, $bid, null); if ($version_b === null) { return new Aphront404Response(); } $file_phids = array(); if ($version_a !== null) { $file_phids[] = $version_a->getFilePHID(); } $file_phids[] = $version_b->getFilePHID(); $files = id(new PhabricatorFileQuery())->setViewer($viewer)->withPHIDs($file_phids)->execute(); $files = mpull($files, null, 'getPHID'); $file_a = null; if ($version_a != null) { $file_a = idx($files, $version_a->getFilePHID(), null); } $file_b = idx($files, $version_b->getFilePHID(), null); $patch = PhragmentPatchUtil::calculatePatch($file_a, $file_b); if ($patch === null) { // There are no differences between the two files, so we output // an empty patch. $patch = ''; } $a_sequence = 'x'; if ($version_a !== null) { $a_sequence = $version_a->getSequence(); } $name = $version_b->getFragment()->getName() . '.' . $a_sequence . '.' . $version_b->getSequence() . '.patch'; $return = $version_b->getURI(); if ($request->getExists('return')) { $return = $request->getStr('return'); } $result = PhabricatorFile::buildFromFileDataOrHash($patch, array('name' => $name, 'mime-type' => 'text/plain', 'ttl' => time() + 60 * 60 * 24)); $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $result->attachToObject($version_b->getFragmentPHID()); unset($unguarded); return id(new AphrontRedirectResponse())->setURI($result->getDownloadURI($return)); }
public static function updateObjectNotificationViews(PhabricatorUser $user, $object_phid) { if (PhabricatorEnv::getEnvConfig('notification.enabled')) { $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $notification_table = new PhabricatorFeedStoryNotification(); $conn = $notification_table->establishConnection('w'); queryfx($conn, "UPDATE %T\n SET hasViewed = 1\n WHERE userPHID = %s\n AND primaryObjectPHID = %s\n AND hasViewed = 0", $notification_table->getTableName(), $user->getPHID(), $object_phid); unset($unguarded); } }
public function render() { $rows = array(); if (!$this->user) { throw new Exception("Call setUser() before rendering!"); } foreach ($this->daemonLogs as $log) { $epoch = $log->getDateCreated(); $status = $log->getStatus(); if ($log->getHost() == php_uname('n') && $status != PhabricatorDaemonLog::STATUS_EXITED && $status != PhabricatorDaemonLog::STATUS_DEAD) { $pid = $log->getPID(); $is_running = PhabricatorDaemonReference::isProcessRunning($pid); if (!$is_running) { $guard = AphrontWriteGuard::beginScopedUnguardedWrites(); $log->setStatus(PhabricatorDaemonLog::STATUS_DEAD); $log->save(); unset($guard); $status = PhabricatorDaemonLog::STATUS_DEAD; } } $heartbeat_timeout = $log->getDateModified() + 3 * PhutilDaemonOverseer::HEARTBEAT_WAIT; if ($status == PhabricatorDaemonLog::STATUS_RUNNING && $heartbeat_timeout < time()) { $status = PhabricatorDaemonLog::STATUS_UNKNOWN; } switch ($status) { case PhabricatorDaemonLog::STATUS_RUNNING: $style = 'color: #00cc00'; $title = 'Running'; $symbol = '•'; break; case PhabricatorDaemonLog::STATUS_DEAD: $style = 'color: #cc0000'; $title = 'Died'; $symbol = '•'; break; case PhabricatorDaemonLog::STATUS_EXITED: $style = 'color: #000000'; $title = 'Exited'; $symbol = '•'; break; case PhabricatorDaemonLog::STATUS_UNKNOWN: default: // fallthrough $style = 'color: #888888'; $title = 'Unknown'; $symbol = '?'; } $running = phutil_render_tag('span', array('style' => $style, 'title' => $title), $symbol); $rows[] = array($running, phutil_escape_html($log->getDaemon()), phutil_escape_html($log->getHost()), $log->getPID(), phabricator_date($epoch, $this->user), phabricator_time($epoch, $this->user), phutil_render_tag('a', array('href' => '/daemon/log/' . $log->getID() . '/', 'class' => 'button small grey'), 'View Log')); } $daemon_table = new AphrontTableView($rows); $daemon_table->setHeaders(array('', 'Daemon', 'Host', 'PID', 'Date', 'Time', 'View')); $daemon_table->setColumnClasses(array('', 'wide wrap', '', '', '', 'right', 'action')); return $daemon_table->render(); }
public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); id(new PhabricatorAuthSessionEngine())->requireHighSecuritySession($viewer, $request, '/'); $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $token = PhabricatorConduitToken::initializeNewToken($viewer->getPHID(), PhabricatorConduitToken::TYPE_COMMANDLINE); $token->save(); unset($unguarded); $form = id(new AphrontFormView())->setUser($viewer)->appendRemarkupInstructions(pht('Copy-paste the API Token below to grant access to your account.'))->appendChild(id(new AphrontFormTextControl())->setLabel(pht('API Token'))->setValue($token->getToken()))->appendRemarkupInstructions(pht('This will authorize the requesting script to act on your behalf ' . 'permanently, like giving the script your account password.'))->appendRemarkupInstructions(pht('If you change your mind, you can revoke this token later in ' . '{nav icon=wrench,name=Settings > Conduit API Tokens}.')); return $this->newDialog()->setTitle(pht('Grant Account Access'))->setWidth(AphrontDialogView::WIDTH_FULL)->appendForm($form)->addCancelButton('/'); }
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 function saveQuery(PhabricatorSavedQuery $query) { $query->setEngineClassName(get_class($this)); $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); try { $query->save(); } catch (AphrontDuplicateKeyQueryException $ex) { // Ignore, this is just a repeated search. } unset($unguarded); }
public static function clearCacheForAllUsers($key) { if (PhabricatorEnv::isReadOnly()) { return; } $table = new self(); $conn_w = $table->establishConnection('w'); $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); queryfx($conn_w, 'DELETE FROM %T WHERE cacheIndex = %s', $table->getTableName(), PhabricatorHash::digestForIndex($key)); unset($unguarded); }
private function newFile(DiffusionRequest $drequest, $content) { $path = $drequest->getPath(); $name = basename($path); $repository = $drequest->getRepository(); $repository_phid = $repository->getPHID(); $file = PhabricatorFile::buildFromFileDataOrHash($content, array('name' => $name, 'ttl' => time() + phutil_units('48 hours in seconds'), 'viewPolicy' => PhabricatorPolicies::POLICY_NOONE)); $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $file->attachToObject($repository_phid); unset($unguarded); return $file; }
/** * Find locked services which are bound to this device, updating the device * lock flag if necessary. * * @return list<phid> List of locking service PHIDs. */ public function rebuildDeviceLocks() { $services = id(new AlmanacServiceQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withDevicePHIDs(array($this->getPHID()))->withLocked(true)->execute(); $locked = (bool) count($services); if ($locked != $this->getIsLocked()) { $this->setIsLocked((int) $locked); $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); queryfx($this->establishConnection('w'), 'UPDATE %T SET isLocked = %d WHERE id = %d', $this->getTableName(), $this->getIsLocked(), $this->getID()); unset($unguarded); } return $this; }
public function pullRefs(array $refs) { $token = $this->getGitHubAccessToken(); if (!strlen($token)) { return null; } $template = id(new PhutilGitHubFuture())->setAccessToken($token); $futures = array(); $id_map = mpull($refs, 'getObjectID', 'getObjectKey'); foreach ($id_map as $key => $id) { list($user, $repository, $number) = $this->parseGitHubIssueID($id); $uri = "/repos/{$user}/{$repository}/issues/{$number}"; $data = array(); $futures[$key] = id(clone $template)->setRawGitHubQuery($uri, $data); } $results = array(); $failed = array(); foreach (new FutureIterator($futures) as $key => $future) { try { $results[$key] = $future->resolve(); } catch (Exception $ex) { if ($ex instanceof HTTPFutureResponseStatus && $ex->getStatusCode() == 404) { // TODO: Do we end up here for deleted objects and invisible // objects? } else { phlog($ex); $failed[$key] = $ex; } } } $viewer = $this->getViewer(); foreach ($refs as $ref) { $ref->setAttribute('name', pht('GitHub Issue %s', $ref->getObjectID())); $did_fail = idx($failed, $ref->getObjectKey()); if ($did_fail) { $ref->setSyncFailed(true); continue; } $result = idx($results, $ref->getObjectKey()); if (!$result) { continue; } $body = $result->getBody(); $ref->setIsVisible(true); $ref->setAttribute('api.raw', $body); $ref->setAttribute('name', $body['title']); $obj = $ref->getExternalObject(); $this->fillObjectFromData($obj, $result); $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $obj->save(); unset($unguarded); } }
protected function willRun() { parent::willRun(); // This stores unbounded amounts of log data; make it discard instead so // that daemons do not require unbounded amounts of memory. DarkConsoleErrorLogPluginAPI::enableDiscardMode(); $phabricator = phutil_get_library_root('phabricator'); $root = dirname($phabricator); require_once $root . '/scripts/__init_env__.php'; // Daemons may perform writes. AphrontWriteGuard::allowDangerousUnguardedWrites(true); }
public function handleRequest(AphrontRequest $request) { $user = $request->getUser(); $latest_conpherences = array(); $latest_participant = id(new ConpherenceParticipantQuery())->withParticipantPHIDs(array($user->getPHID()))->setLimit(6)->execute(); if ($latest_participant) { $conpherence_phids = mpull($latest_participant, 'getConpherencePHID'); $latest_conpherences = id(new ConpherenceThreadQuery())->setViewer($user)->withPHIDs($conpherence_phids)->needCropPics(true)->needParticipantCache(true)->execute(); $latest_conpherences = mpull($latest_conpherences, null, 'getPHID'); $latest_conpherences = array_select_keys($latest_conpherences, $conpherence_phids); } $conpherence = null; $should_404 = false; if ($request->getInt('id')) { $conpherence = id(new ConpherenceThreadQuery())->setViewer($user)->withIDs(array($request->getInt('id')))->needCropPics(true)->needTransactions(true)->setTransactionLimit(ConpherenceThreadQuery::TRANSACTION_LIMIT)->executeOne(); $should_404 = true; } else { if ($latest_participant) { $participant = head($latest_participant); $conpherence = id(new ConpherenceThreadQuery())->setViewer($user)->withPHIDs(array($participant->getConpherencePHID()))->needCropPics(true)->needTransactions(true)->setTransactionLimit(ConpherenceThreadQuery::TRANSACTION_LIMIT)->executeOne(); $should_404 = true; } } $durable_column = id(new ConpherenceDurableColumnView())->setUser($user)->setVisible(true); if (!$conpherence) { if ($should_404) { return new Aphront404Response(); } $conpherence_id = null; $conpherence_phid = null; $latest_transaction_id = null; $can_edit = false; } else { $this->setConpherence($conpherence); $participant = $conpherence->getParticipant($user->getPHID()); $transactions = $conpherence->getTransactions(); $latest_transaction = head($transactions); $write_guard = AphrontWriteGuard::beginScopedUnguardedWrites(); $participant->markUpToDate($conpherence, $latest_transaction); unset($write_guard); $draft = PhabricatorDraft::newFromUserAndKey($user, $conpherence->getPHID()); $durable_column->setDraft($draft)->setSelectedConpherence($conpherence)->setConpherences($latest_conpherences); $conpherence_id = $conpherence->getID(); $conpherence_phid = $conpherence->getPHID(); $latest_transaction_id = $latest_transaction->getID(); $can_edit = PhabricatorPolicyFilter::hasCapability($user, $conpherence, PhabricatorPolicyCapability::CAN_EDIT); } $dropdown_query = id(new AphlictDropdownDataQuery())->setViewer($user); $dropdown_query->execute(); $response = array('content' => hsprintf('%s', $durable_column), 'threadID' => $conpherence_id, 'threadPHID' => $conpherence_phid, 'latestTransactionID' => $latest_transaction_id, 'canEdit' => $can_edit, 'aphlictDropdownData' => array($dropdown_query->getNotificationData(), $dropdown_query->getConpherenceData())); return id(new AphrontAjaxResponse())->setContent($response); }
public static function createNewAccount(PhabricatorUser $actor, PhabricatorContentSource $content_source) { $account = self::initializeNewAccount($actor); $xactions = array(); $xactions[] = id(new PhortuneAccountTransaction())->setTransactionType(PhortuneAccountTransaction::TYPE_NAME)->setNewValue(pht('Default Account')); $xactions[] = id(new PhortuneAccountTransaction())->setTransactionType(PhabricatorTransactions::TYPE_EDGE)->setMetadataValue('edge:type', PhortuneAccountHasMemberEdgeType::EDGECONST)->setNewValue(array('=' => array($actor->getPHID() => $actor->getPHID()))); $editor = id(new PhortuneAccountEditor())->setActor($actor)->setContentSource($content_source); // We create an account for you the first time you visit Phortune. $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $editor->applyTransactions($account, $xactions); unset($unguarded); return $account; }
public function handleRequest(AphrontRequest $request) { $show_prototypes = PhabricatorEnv::getEnvConfig('phabricator.show-prototypes'); if (!$show_prototypes) { throw new Exception(pht('Show prototypes is disabled. Set `phabricator.show-prototypes` to `true` to use the image proxy')); } $viewer = $request->getViewer(); $img_uri = $request->getStr('uri'); // Validate the URI before doing anything PhabricatorEnv::requireValidRemoteURIForLink($img_uri); $uri = new PhutilURI($img_uri); $proto = $uri->getProtocol(); if (!in_array($proto, array('http', 'https'))) { throw new Exception(pht('The provided image URI must be either http or https')); } // Check if we already have the specified image URI downloaded $cached_request = id(new PhabricatorFileExternalRequest())->loadOneWhere('uriIndex = %s', PhabricatorHash::digestForIndex($img_uri)); if ($cached_request) { return $this->getExternalResponse($cached_request); } $ttl = PhabricatorTime::getNow() + phutil_units('7 days in seconds'); $external_request = id(new PhabricatorFileExternalRequest())->setURI($img_uri)->setTTL($ttl); $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); // Cache missed so we'll need to validate and download the image try { // Rate limit outbound fetches to make this mechanism less useful for // scanning networks and ports. PhabricatorSystemActionEngine::willTakeAction(array($viewer->getPHID()), new PhabricatorFilesOutboundRequestAction(), 1); $file = PhabricatorFile::newFromFileDownload($uri, array('viewPolicy' => PhabricatorPolicies::POLICY_NOONE, 'canCDN' => true)); if (!$file->isViewableImage()) { $mime_type = $file->getMimeType(); $engine = new PhabricatorDestructionEngine(); $engine->destroyObject($file); $file = null; throw new Exception(pht('The URI "%s" does not correspond to a valid image file, got ' . 'a file with MIME type "%s". You must specify the URI of a ' . 'valid image file.', $uri, $mime_type)); } else { $file->save(); } $external_request->setIsSuccessful(true)->setFilePHID($file->getPHID())->save(); unset($unguarded); return $this->getExternalResponse($external_request); } catch (HTTPFutureHTTPResponseStatus $status) { $external_request->setIsSuccessful(false)->setResponseMessage($status->getMessage())->save(); return $this->getExternalResponse($external_request); } catch (Exception $ex) { // Not actually saving the request in this case $external_request->setResponseMessage($ex->getMessage()); return $this->getExternalResponse($external_request); } }
public static function initializeScriptEnvironment() { self::initializeCommonEnvironment(); // NOTE: This is dangerous in general, but we know we're in a script context // and are not vulnerable to CSRF. AphrontWriteGuard::allowDangerousUnguardedWrites(true); // There are several places where we log information (about errors, events, // service calls, etc.) for analysis via DarkConsole or similar. These are // useful for web requests, but grow unboundedly in long-running scripts and // daemons. Discard data as it arrives in these cases. PhutilServiceProfiler::getInstance()->enableDiscardMode(); DarkConsoleErrorLogPluginAPI::enableDiscardMode(); DarkConsoleEventPluginAPI::enableDiscardMode(); }