public function testRequestDataAccess() { $r = new AphrontRequest('http://example.com/', '/'); $r->setRequestData(array('str_empty' => '', 'str' => 'derp', 'str_true' => 'true', 'str_false' => 'false', 'zero' => '0', 'one' => '1', 'arr_empty' => array(), 'arr_num' => array(1, 2, 3), 'comma' => ',', 'comma_1' => 'a, b', 'comma_2' => ' ,a ,, b ,,,, ,, ', 'comma_3' => '0', 'comma_4' => 'a, a, b, a', 'comma_5' => "a\nb, c\n\nd\n\n\n,\n")); $this->assertEqual(1, $r->getInt('one')); $this->assertEqual(0, $r->getInt('zero')); $this->assertEqual(null, $r->getInt('does-not-exist')); $this->assertEqual(0, $r->getInt('str_empty')); $this->assertEqual(true, $r->getBool('one')); $this->assertEqual(false, $r->getBool('zero')); $this->assertEqual(true, $r->getBool('str_true')); $this->assertEqual(false, $r->getBool('str_false')); $this->assertEqual(true, $r->getBool('str')); $this->assertEqual(null, $r->getBool('does-not-exist')); $this->assertEqual(false, $r->getBool('str_empty')); $this->assertEqual('derp', $r->getStr('str')); $this->assertEqual('', $r->getStr('str_empty')); $this->assertEqual(null, $r->getStr('does-not-exist')); $this->assertEqual(array(), $r->getArr('arr_empty')); $this->assertEqual(array(1, 2, 3), $r->getArr('arr_num')); $this->assertEqual(null, $r->getArr('str_empty', null)); $this->assertEqual(null, $r->getArr('str_true', null)); $this->assertEqual(null, $r->getArr('does-not-exist', null)); $this->assertEqual(array(), $r->getArr('does-not-exist')); $this->assertEqual(array(), $r->getStrList('comma')); $this->assertEqual(array('a', 'b'), $r->getStrList('comma_1')); $this->assertEqual(array('a', 'b'), $r->getStrList('comma_2')); $this->assertEqual(array('0'), $r->getStrList('comma_3')); $this->assertEqual(array('a', 'a', 'b', 'a'), $r->getStrList('comma_4')); $this->assertEqual(array('a', 'b', 'c', 'd'), $r->getStrList('comma_5')); $this->assertEqual(array(), $r->getStrList('does-not-exist')); $this->assertEqual(null, $r->getStrList('does-not-exist', null)); $this->assertEqual(true, $r->getExists('str')); $this->assertEqual(false, $r->getExists('does-not-exist')); }
protected function getParameterExists(AphrontRequest $request, $key) { if ($request->getExists($key)) { return true; } $checkbox_key = $this->getCheckboxKey($key); if ($request->getExists($checkbox_key)) { return true; } return false; }
protected function getValueExistsInRequest(AphrontRequest $request, $key) { // The control doesn't actually submit a value with the same name as the // key, so look for the "_d" value instead, which has the date part of the // control value. return $request->getExists($key . '_d'); }
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 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 processRequest(AphrontRequest $request) { if ($request->getExists('new')) { return $this->processNew($request); } if ($request->getExists('edit')) { return $this->processEdit($request); } if ($request->getExists('delete')) { return $this->processDelete($request); } $user = $this->getUser(); $viewer = $request->getUser(); $factors = id(new PhabricatorAuthFactorConfig())->loadAllWhere('userPHID = %s', $user->getPHID()); $rows = array(); $rowc = array(); $highlight_id = $request->getInt('id'); foreach ($factors as $factor) { $impl = $factor->getImplementation(); if ($impl) { $type = $impl->getFactorName(); } else { $type = $factor->getFactorKey(); } if ($factor->getID() == $highlight_id) { $rowc[] = 'highlighted'; } else { $rowc[] = null; } $rows[] = array(javelin_tag('a', array('href' => $this->getPanelURI('?edit=' . $factor->getID()), 'sigil' => 'workflow'), $factor->getFactorName()), $type, phabricator_datetime($factor->getDateCreated(), $viewer), javelin_tag('a', array('href' => $this->getPanelURI('?delete=' . $factor->getID()), 'sigil' => 'workflow', 'class' => 'small grey button'), pht('Remove'))); } $table = new AphrontTableView($rows); $table->setNoDataString(pht("You haven't added any authentication factors to your account yet.")); $table->setHeaders(array(pht('Name'), pht('Type'), pht('Created'), '')); $table->setColumnClasses(array('wide pri', '', 'right', 'action')); $table->setRowClasses($rowc); $table->setDeviceVisibility(array(true, false, false, true)); $panel = new PHUIObjectBoxView(); $header = new PHUIHeaderView(); $help_uri = PhabricatorEnv::getDoclink('User Guide: Multi-Factor Authentication'); $help_icon = id(new PHUIIconView())->setIconFont('fa-info-circle'); $help_button = id(new PHUIButtonView())->setText(pht('Help'))->setHref($help_uri)->setTag('a')->setIcon($help_icon); $create_icon = id(new PHUIIconView())->setIconFont('fa-plus'); $create_button = id(new PHUIButtonView())->setText(pht('Add Authentication Factor'))->setHref($this->getPanelURI('?new=true'))->setTag('a')->setWorkflow(true)->setIcon($create_icon); $header->setHeader(pht('Authentication Factors')); $header->addActionLink($help_button); $header->addActionLink($create_button); $panel->setHeader($header); $panel->setTable($table); return $panel; }
public function handleRequest(AphrontRequest $request) { $viewer = $this->getViewer(); $phid = $request->getURIData('phid'); $xaction = id(new PhabricatorObjectQuery())->withPHIDs(array($phid))->setViewer($viewer)->executeOne(); if (!$xaction) { return new Aphront404Response(); } if (!$xaction->getComment()) { // You can't view a raw comment if there is no comment. return new Aphront404Response(); } if ($xaction->getComment()->getIsRemoved()) { // You can't view a raw comment if the comment is deleted. return new Aphront400Response(); } $obj_phid = $xaction->getObjectPHID(); $obj_handle = id(new PhabricatorHandleQuery())->setViewer($viewer)->withPHIDs(array($obj_phid))->executeOne(); $title = pht('Raw Comment'); $body = $xaction->getComment()->getContent(); $addendum = null; if ($request->getExists('email')) { $content_source = $xaction->getContentSource(); $source_email = PhabricatorContentSource::SOURCE_EMAIL; if ($content_source->getSource() == $source_email) { $source_id = $content_source->getParam('id'); if ($source_id) { $message = id(new PhabricatorMetaMTAReceivedMail())->loadOneWhere('id = %d', $source_id); if ($message) { $title = pht('Email Body Text'); $body = $message->getRawTextBody(); $details_text = pht('For full details, run `/bin/mail show-outbound --id %d`', $source_id); $addendum = PhabricatorMarkupEngine::renderOneObject(id(new PhabricatorMarkupOneOff())->setContent($details_text), 'default', $viewer); } } } } $dialog = id(new AphrontDialogView())->setUser($viewer)->addCancelButton($obj_handle->getURI())->setTitle($title); $dialog->addHiddenInput('anchor', $request->getStr('anchor'))->appendChild(id(new PHUIFormLayoutView())->setFullWidth(true)->appendChild(id(new AphrontFormTextAreaControl())->setReadOnly(true)->setValue($body))); if ($addendum) { $dialog->appendParagraph($addendum); } return id(new AphrontDialogResponse())->setDialog($dialog); }
/** * Require high security, or prompt the user to enter high security. * * If the user's session is in high security, this method will return a * token. Otherwise, it will throw an exception which will eventually * be converted into a multi-factor authentication workflow. * * @param PhabricatorUser User whose session needs to be in high security. * @param AphrontReqeust Current request. * @param string URI to return the user to if they cancel. * @param bool True to jump partial sessions directly into high * security instead of just upgrading them to full * sessions. * @return PhabricatorAuthHighSecurityToken Security token. * @task hisec */ public function requireHighSecuritySession(PhabricatorUser $viewer, AphrontRequest $request, $cancel_uri, $jump_into_hisec = false) { if (!$viewer->hasSession()) { throw new Exception(pht('Requiring a high-security session from a user with no session!')); } $session = $viewer->getSession(); // Check if the session is already in high security mode. $token = $this->issueHighSecurityToken($session); if ($token) { return $token; } // Load the multi-factor auth sources attached to this account. $factors = id(new PhabricatorAuthFactorConfig())->loadAllWhere('userPHID = %s', $viewer->getPHID()); // If the account has no associated multi-factor auth, just issue a token // without putting the session into high security mode. This is generally // easier for users. A minor but desirable side effect is that when a user // adds an auth factor, existing sessions won't get a free pass into hisec, // since they never actually got marked as hisec. if (!$factors) { return $this->issueHighSecurityToken($session, true); } // Check for a rate limit without awarding points, so the user doesn't // get partway through the workflow only to get blocked. PhabricatorSystemActionEngine::willTakeAction(array($viewer->getPHID()), new PhabricatorAuthTryFactorAction(), 0); $validation_results = array(); if ($request->isHTTPPost()) { $request->validateCSRF(); if ($request->getExists(AphrontRequest::TYPE_HISEC)) { // Limit factor verification rates to prevent brute force attacks. PhabricatorSystemActionEngine::willTakeAction(array($viewer->getPHID()), new PhabricatorAuthTryFactorAction(), 1); $ok = true; foreach ($factors as $factor) { $id = $factor->getID(); $impl = $factor->requireImplementation(); $validation_results[$id] = $impl->processValidateFactorForm($factor, $viewer, $request); if (!$impl->isFactorValid($factor, $validation_results[$id])) { $ok = false; } } if ($ok) { // Give the user a credit back for a successful factor verification. PhabricatorSystemActionEngine::willTakeAction(array($viewer->getPHID()), new PhabricatorAuthTryFactorAction(), -1); if ($session->getIsPartial() && !$jump_into_hisec) { // If we have a partial session and are not jumping directly into // hisec, just issue a token without putting it in high security // mode. return $this->issueHighSecurityToken($session, true); } $until = time() + phutil_units('15 minutes in seconds'); $session->setHighSecurityUntil($until); queryfx($session->establishConnection('w'), 'UPDATE %T SET highSecurityUntil = %d WHERE id = %d', $session->getTableName(), $until, $session->getID()); $log = PhabricatorUserLog::initializeNewLog($viewer, $viewer->getPHID(), PhabricatorUserLog::ACTION_ENTER_HISEC); $log->save(); } else { $log = PhabricatorUserLog::initializeNewLog($viewer, $viewer->getPHID(), PhabricatorUserLog::ACTION_FAIL_HISEC); $log->save(); } } } $token = $this->issueHighSecurityToken($session); if ($token) { return $token; } throw id(new PhabricatorAuthHighSecurityRequiredException())->setCancelURI($cancel_uri)->setFactors($factors)->setFactorValidationResults($validation_results); }
public function handleRequest(AphrontRequest $request) { $viewer = $this->getViewer(); $this->revisionID = $request->getURIData('id'); $viewer_is_anonymous = !$viewer->isLoggedIn(); $revision = id(new DifferentialRevisionQuery())->withIDs(array($this->revisionID))->setViewer($request->getUser())->needRelationships(true)->needReviewerStatus(true)->needReviewerAuthority(true)->executeOne(); if (!$revision) { return new Aphront404Response(); } $diffs = id(new DifferentialDiffQuery())->setViewer($request->getUser())->withRevisionIDs(array($this->revisionID))->execute(); $diffs = array_reverse($diffs, $preserve_keys = true); if (!$diffs) { throw new Exception(pht('This revision has no diffs. Something has gone quite wrong.')); } $revision->attachActiveDiff(last($diffs)); $diff_vs = $request->getInt('vs'); $target_id = $request->getInt('id'); $target = idx($diffs, $target_id, end($diffs)); $target_manual = $target; if (!$target_id) { foreach ($diffs as $diff) { if ($diff->getCreationMethod() != 'commit') { $target_manual = $diff; } } } if (empty($diffs[$diff_vs])) { $diff_vs = null; } $repository = null; $repository_phid = $target->getRepositoryPHID(); if ($repository_phid) { if ($repository_phid == $revision->getRepositoryPHID()) { $repository = $revision->getRepository(); } else { $repository = id(new PhabricatorRepositoryQuery())->setViewer($viewer)->withPHIDs(array($repository_phid))->executeOne(); } } list($changesets, $vs_map, $vs_changesets, $rendering_references) = $this->loadChangesetsAndVsMap($target, idx($diffs, $diff_vs), $repository); if ($request->getExists('download')) { return $this->buildRawDiffResponse($revision, $changesets, $vs_changesets, $vs_map, $repository); } $map = $vs_map; if (!$map) { $map = array_fill_keys(array_keys($changesets), 0); } $old_ids = array(); $new_ids = array(); foreach ($map as $id => $vs) { if ($vs <= 0) { $old_ids[] = $id; $new_ids[] = $id; } else { $new_ids[] = $id; $new_ids[] = $vs; } } $props = id(new DifferentialDiffProperty())->loadAllWhere('diffID = %d', $target_manual->getID()); $props = mpull($props, 'getData', 'getName'); $object_phids = array_merge($revision->getReviewers(), $revision->getCCPHIDs(), $revision->loadCommitPHIDs(), array($revision->getAuthorPHID(), $viewer->getPHID())); foreach ($revision->getAttached() as $type => $phids) { foreach ($phids as $phid => $info) { $object_phids[] = $phid; } } $field_list = PhabricatorCustomField::getObjectFields($revision, PhabricatorCustomField::ROLE_VIEW); $field_list->setViewer($viewer); $field_list->readFieldsFromStorage($revision); $warning_handle_map = array(); foreach ($field_list->getFields() as $key => $field) { $req = $field->getRequiredHandlePHIDsForRevisionHeaderWarnings(); foreach ($req as $phid) { $warning_handle_map[$key][] = $phid; $object_phids[] = $phid; } } $handles = $this->loadViewerHandles($object_phids); $request_uri = $request->getRequestURI(); $limit = 100; $large = $request->getStr('large'); if (count($changesets) > $limit && !$large) { $count = count($changesets); $warning = new PHUIInfoView(); $warning->setTitle(pht('Very Large Diff')); $warning->setSeverity(PHUIInfoView::SEVERITY_WARNING); $warning->appendChild(hsprintf('%s <strong>%s</strong>', pht('This diff is very large and affects %s files. ' . 'You may load each file individually or ', new PhutilNumber($count)), phutil_tag('a', array('class' => 'button grey', 'href' => $request_uri->alter('large', 'true')->setFragment('toc')), pht('Show All Files Inline')))); $warning = $warning->render(); $old = array_select_keys($changesets, $old_ids); $new = array_select_keys($changesets, $new_ids); $query = id(new DifferentialInlineCommentQuery())->setViewer($viewer)->needHidden(true)->withRevisionPHIDs(array($revision->getPHID())); $inlines = $query->execute(); $inlines = $query->adjustInlinesForChangesets($inlines, $old, $new, $revision); $visible_changesets = array(); foreach ($inlines as $inline) { $changeset_id = $inline->getChangesetID(); if (isset($changesets[$changeset_id])) { $visible_changesets[$changeset_id] = $changesets[$changeset_id]; } } } else { $warning = null; $visible_changesets = $changesets; } $commit_hashes = mpull($diffs, 'getSourceControlBaseRevision'); $local_commits = idx($props, 'local:commits', array()); foreach ($local_commits as $local_commit) { $commit_hashes[] = idx($local_commit, 'tree'); $commit_hashes[] = idx($local_commit, 'local'); } $commit_hashes = array_unique(array_filter($commit_hashes)); if ($commit_hashes) { $commits_for_links = id(new DiffusionCommitQuery())->setViewer($viewer)->withIdentifiers($commit_hashes)->execute(); $commits_for_links = mpull($commits_for_links, null, 'getCommitIdentifier'); } else { $commits_for_links = array(); } $revision_detail = id(new DifferentialRevisionDetailView())->setUser($viewer)->setRevision($revision)->setDiff(end($diffs))->setCustomFields($field_list)->setURI($request->getRequestURI()); $actions = $this->getRevisionActions($revision); $whitespace = $request->getStr('whitespace', DifferentialChangesetParser::WHITESPACE_IGNORE_MOST); $repository = $revision->getRepository(); if ($repository) { $symbol_indexes = $this->buildSymbolIndexes($repository, $visible_changesets); } else { $symbol_indexes = array(); } $revision_detail->setActions($actions); $revision_detail->setUser($viewer); $revision_detail_box = $revision_detail->render(); $revision_warnings = $this->buildRevisionWarnings($revision, $field_list, $warning_handle_map, $handles); if ($revision_warnings) { $revision_warnings = id(new PHUIInfoView())->setSeverity(PHUIInfoView::SEVERITY_WARNING)->setErrors($revision_warnings); $revision_detail_box->setInfoView($revision_warnings); } $detail_diffs = array_select_keys($diffs, array($diff_vs, $target->getID())); $detail_diffs = mpull($detail_diffs, null, 'getPHID'); $buildables = id(new HarbormasterBuildableQuery())->setViewer($viewer)->withBuildablePHIDs(array_keys($detail_diffs))->withManualBuildables(false)->needBuilds(true)->needTargets(true)->execute(); $buildables = mpull($buildables, null, 'getBuildablePHID'); foreach ($detail_diffs as $diff_phid => $detail_diff) { $detail_diff->attachBuildable(idx($buildables, $diff_phid)); } $diff_detail_box = $this->buildDiffDetailView($detail_diffs, $revision, $field_list); $comment_view = $this->buildTransactions($revision, $diff_vs ? $diffs[$diff_vs] : $target, $target, $old_ids, $new_ids); if (!$viewer_is_anonymous) { $comment_view->setQuoteRef('D' . $revision->getID()); $comment_view->setQuoteTargetID('comment-content'); } $wrap_id = celerity_generate_unique_node_id(); $comment_view = phutil_tag('div', array('id' => $wrap_id), $comment_view); $changeset_view = new DifferentialChangesetListView(); $changeset_view->setChangesets($changesets); $changeset_view->setVisibleChangesets($visible_changesets); if (!$viewer_is_anonymous) { $changeset_view->setInlineCommentControllerURI('/differential/comment/inline/edit/' . $revision->getID() . '/'); } $changeset_view->setStandaloneURI('/differential/changeset/'); $changeset_view->setRawFileURIs('/differential/changeset/?view=old', '/differential/changeset/?view=new'); $changeset_view->setUser($viewer); $changeset_view->setDiff($target); $changeset_view->setRenderingReferences($rendering_references); $changeset_view->setVsMap($vs_map); $changeset_view->setWhitespace($whitespace); if ($repository) { $changeset_view->setRepository($repository); } $changeset_view->setSymbolIndexes($symbol_indexes); $changeset_view->setTitle(pht('Diff %s', $target->getID())); $diff_history = id(new DifferentialRevisionUpdateHistoryView())->setUser($viewer)->setDiffs($diffs)->setSelectedVersusDiffID($diff_vs)->setSelectedDiffID($target->getID())->setSelectedWhitespace($whitespace)->setCommitsForLinks($commits_for_links); $local_view = id(new DifferentialLocalCommitsView())->setUser($viewer)->setLocalCommits(idx($props, 'local:commits'))->setCommitsForLinks($commits_for_links); if ($repository) { $other_revisions = $this->loadOtherRevisions($changesets, $target, $repository); } else { $other_revisions = array(); } $other_view = null; if ($other_revisions) { $other_view = $this->renderOtherRevisions($other_revisions); } $toc_view = $this->buildTableOfContents($changesets, $visible_changesets, $target->loadCoverageMap($viewer)); $comment_form = null; if (!$viewer_is_anonymous) { $draft = id(new PhabricatorDraft())->loadOneWhere('authorPHID = %s AND draftKey = %s', $viewer->getPHID(), 'differential-comment-' . $revision->getID()); $reviewers = array(); $ccs = array(); if ($draft) { $reviewers = idx($draft->getMetadata(), 'reviewers', array()); $ccs = idx($draft->getMetadata(), 'ccs', array()); if ($reviewers || $ccs) { $handles = $this->loadViewerHandles(array_merge($reviewers, $ccs)); $reviewers = array_select_keys($handles, $reviewers); $ccs = array_select_keys($handles, $ccs); } } $comment_form = new DifferentialAddCommentView(); $comment_form->setRevision($revision); $review_warnings = array(); foreach ($field_list->getFields() as $field) { $review_warnings[] = $field->getWarningsForDetailView(); } $review_warnings = array_mergev($review_warnings); if ($review_warnings) { $review_warnings_panel = id(new PHUIInfoView())->setSeverity(PHUIInfoView::SEVERITY_WARNING)->setErrors($review_warnings); $comment_form->setInfoView($review_warnings_panel); } $comment_form->setActions($this->getRevisionCommentActions($revision)); $action_uri = $this->getApplicationURI('comment/save/' . $revision->getID() . '/'); $comment_form->setActionURI($action_uri); $comment_form->setUser($viewer); $comment_form->setDraft($draft); $comment_form->setReviewers(mpull($reviewers, 'getFullName', 'getPHID')); $comment_form->setCCs(mpull($ccs, 'getFullName', 'getPHID')); // TODO: This just makes the "Z" key work. Generalize this and remove // it at some point. $comment_form = phutil_tag('div', array('class' => 'differential-add-comment-panel'), $comment_form); } $pane_id = celerity_generate_unique_node_id(); Javelin::initBehavior('differential-keyboard-navigation', array('haunt' => $pane_id)); Javelin::initBehavior('differential-user-select'); $page_pane = id(new DifferentialPrimaryPaneView())->setID($pane_id)->appendChild($comment_view); $signatures = DifferentialRequiredSignaturesField::loadForRevision($revision); $missing_signatures = false; foreach ($signatures as $phid => $signed) { if (!$signed) { $missing_signatures = true; } } if ($missing_signatures) { $signature_message = id(new PHUIInfoView())->setErrors(array(array(phutil_tag('strong', array(), pht('Content Hidden:')), ' ', pht('The content of this revision is hidden until the author has ' . 'signed all of the required legal agreements.')))); $page_pane->appendChild($signature_message); } else { $page_pane->appendChild(array($diff_history, $warning, $local_view, $toc_view, $other_view, $changeset_view)); } if ($comment_form) { $page_pane->appendChild($comment_form); } else { // TODO: For now, just use this to get "Login to Comment". $page_pane->appendChild(id(new PhabricatorApplicationTransactionCommentView())->setUser($viewer)->setRequestURI($request->getRequestURI())); } $object_id = 'D' . $revision->getID(); $operations_box = $this->buildOperationsBox($revision); $content = array($operations_box, $revision_detail_box, $diff_detail_box, $page_pane); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb($object_id, '/' . $object_id); $prefs = $viewer->loadPreferences(); $pref_filetree = PhabricatorUserPreferences::PREFERENCE_DIFF_FILETREE; if ($prefs->getPreference($pref_filetree)) { $collapsed = $prefs->getPreference(PhabricatorUserPreferences::PREFERENCE_NAV_COLLAPSED, false); $nav = id(new DifferentialChangesetFileTreeSideNavBuilder())->setTitle('D' . $revision->getID())->setBaseURI(new PhutilURI('/D' . $revision->getID()))->setCollapsed((bool) $collapsed)->build($changesets); $nav->appendChild($content); $nav->setCrumbs($crumbs); $content = $nav; } else { array_unshift($content, $crumbs); } return $this->buildApplicationPage($content, array('title' => $object_id . ' ' . $revision->getTitle(), 'pageObjects' => array($revision->getPHID()))); }
public function handleRequest(AphrontRequest $request) { $viewer = $this->getViewer(); $this->revisionID = $request->getURIData('id'); $viewer_is_anonymous = !$viewer->isLoggedIn(); $revision = id(new DifferentialRevisionQuery())->withIDs(array($this->revisionID))->setViewer($request->getUser())->needRelationships(true)->needReviewerStatus(true)->needReviewerAuthority(true)->executeOne(); if (!$revision) { return new Aphront404Response(); } $diffs = id(new DifferentialDiffQuery())->setViewer($request->getUser())->withRevisionIDs(array($this->revisionID))->execute(); $diffs = array_reverse($diffs, $preserve_keys = true); if (!$diffs) { throw new Exception(pht('This revision has no diffs. Something has gone quite wrong.')); } $revision->attachActiveDiff(last($diffs)); $diff_vs = $request->getInt('vs'); $target_id = $request->getInt('id'); $target = idx($diffs, $target_id, end($diffs)); $target_manual = $target; if (!$target_id) { foreach ($diffs as $diff) { if ($diff->getCreationMethod() != 'commit') { $target_manual = $diff; } } } if (empty($diffs[$diff_vs])) { $diff_vs = null; } $repository = null; $repository_phid = $target->getRepositoryPHID(); if ($repository_phid) { if ($repository_phid == $revision->getRepositoryPHID()) { $repository = $revision->getRepository(); } else { $repository = id(new PhabricatorRepositoryQuery())->setViewer($viewer)->withPHIDs(array($repository_phid))->executeOne(); } } list($changesets, $vs_map, $vs_changesets, $rendering_references) = $this->loadChangesetsAndVsMap($target, idx($diffs, $diff_vs), $repository); if ($request->getExists('download')) { return $this->buildRawDiffResponse($revision, $changesets, $vs_changesets, $vs_map, $repository); } $map = $vs_map; if (!$map) { $map = array_fill_keys(array_keys($changesets), 0); } $old_ids = array(); $new_ids = array(); foreach ($map as $id => $vs) { if ($vs <= 0) { $old_ids[] = $id; $new_ids[] = $id; } else { $new_ids[] = $id; $new_ids[] = $vs; } } $this->loadDiffProperties($diffs); $props = $target_manual->getDiffProperties(); $object_phids = array_merge($revision->getReviewers(), $revision->getCCPHIDs(), $revision->loadCommitPHIDs(), array($revision->getAuthorPHID(), $viewer->getPHID())); foreach ($revision->getAttached() as $type => $phids) { foreach ($phids as $phid => $info) { $object_phids[] = $phid; } } $field_list = PhabricatorCustomField::getObjectFields($revision, PhabricatorCustomField::ROLE_VIEW); $field_list->setViewer($viewer); $field_list->readFieldsFromStorage($revision); $warning_handle_map = array(); foreach ($field_list->getFields() as $key => $field) { $req = $field->getRequiredHandlePHIDsForRevisionHeaderWarnings(); foreach ($req as $phid) { $warning_handle_map[$key][] = $phid; $object_phids[] = $phid; } } $handles = $this->loadViewerHandles($object_phids); $request_uri = $request->getRequestURI(); $limit = 100; $large = $request->getStr('large'); if (count($changesets) > $limit && !$large) { $count = count($changesets); $warning = new PHUIInfoView(); $warning->setTitle(pht('Very Large Diff')); $warning->setSeverity(PHUIInfoView::SEVERITY_WARNING); $warning->appendChild(hsprintf('%s <strong>%s</strong>', pht('This diff is very large and affects %s files. ' . 'You may load each file individually or ', new PhutilNumber($count)), phutil_tag('a', array('class' => 'button grey', 'href' => $request_uri->alter('large', 'true')->setFragment('toc')), pht('Show All Files Inline')))); $warning = $warning->render(); $old = array_select_keys($changesets, $old_ids); $new = array_select_keys($changesets, $new_ids); $query = id(new DifferentialInlineCommentQuery())->setViewer($viewer)->needHidden(true)->withRevisionPHIDs(array($revision->getPHID())); $inlines = $query->execute(); $inlines = $query->adjustInlinesForChangesets($inlines, $old, $new, $revision); $visible_changesets = array(); foreach ($inlines as $inline) { $changeset_id = $inline->getChangesetID(); if (isset($changesets[$changeset_id])) { $visible_changesets[$changeset_id] = $changesets[$changeset_id]; } } } else { $warning = null; $visible_changesets = $changesets; } $commit_hashes = mpull($diffs, 'getSourceControlBaseRevision'); $local_commits = idx($props, 'local:commits', array()); foreach ($local_commits as $local_commit) { $commit_hashes[] = idx($local_commit, 'tree'); $commit_hashes[] = idx($local_commit, 'local'); } $commit_hashes = array_unique(array_filter($commit_hashes)); if ($commit_hashes) { $commits_for_links = id(new DiffusionCommitQuery())->setViewer($viewer)->withIdentifiers($commit_hashes)->execute(); $commits_for_links = mpull($commits_for_links, null, 'getCommitIdentifier'); } else { $commits_for_links = array(); } $header = $this->buildHeader($revision); $subheader = $this->buildSubheaderView($revision); $details = $this->buildDetails($revision, $field_list); $curtain = $this->buildCurtain($revision); $whitespace = $request->getStr('whitespace', DifferentialChangesetParser::WHITESPACE_IGNORE_MOST); $repository = $revision->getRepository(); if ($repository) { $symbol_indexes = $this->buildSymbolIndexes($repository, $visible_changesets); } else { $symbol_indexes = array(); } $revision_warnings = $this->buildRevisionWarnings($revision, $field_list, $warning_handle_map, $handles); $info_view = null; if ($revision_warnings) { $info_view = id(new PHUIInfoView())->setSeverity(PHUIInfoView::SEVERITY_WARNING)->setErrors($revision_warnings); } $detail_diffs = array_select_keys($diffs, array($diff_vs, $target->getID())); $detail_diffs = mpull($detail_diffs, null, 'getPHID'); $this->loadHarbormasterData($detail_diffs); $diff_detail_box = $this->buildDiffDetailView($detail_diffs, $revision, $field_list); $unit_box = $this->buildUnitMessagesView($target, $revision); $comment_view = $this->buildTransactions($revision, $diff_vs ? $diffs[$diff_vs] : $target, $target, $old_ids, $new_ids); if (!$viewer_is_anonymous) { $comment_view->setQuoteRef('D' . $revision->getID()); $comment_view->setQuoteTargetID('comment-content'); } $changeset_view = id(new DifferentialChangesetListView())->setChangesets($changesets)->setVisibleChangesets($visible_changesets)->setStandaloneURI('/differential/changeset/')->setRawFileURIs('/differential/changeset/?view=old', '/differential/changeset/?view=new')->setUser($viewer)->setDiff($target)->setRenderingReferences($rendering_references)->setVsMap($vs_map)->setWhitespace($whitespace)->setSymbolIndexes($symbol_indexes)->setTitle(pht('Diff %s', $target->getID()))->setBackground(PHUIObjectBoxView::BLUE_PROPERTY); if ($repository) { $changeset_view->setRepository($repository); } if (!$viewer_is_anonymous) { $changeset_view->setInlineCommentControllerURI('/differential/comment/inline/edit/' . $revision->getID() . '/'); } $history = id(new DifferentialRevisionUpdateHistoryView())->setUser($viewer)->setDiffs($diffs)->setSelectedVersusDiffID($diff_vs)->setSelectedDiffID($target->getID())->setSelectedWhitespace($whitespace)->setCommitsForLinks($commits_for_links); $local_table = id(new DifferentialLocalCommitsView())->setUser($viewer)->setLocalCommits(idx($props, 'local:commits'))->setCommitsForLinks($commits_for_links); if ($repository) { $other_revisions = $this->loadOtherRevisions($changesets, $target, $repository); } else { $other_revisions = array(); } $other_view = null; if ($other_revisions) { $other_view = $this->renderOtherRevisions($other_revisions); } $toc_view = $this->buildTableOfContents($changesets, $visible_changesets, $target->loadCoverageMap($viewer)); $tab_group = id(new PHUITabGroupView())->addTab(id(new PHUITabView())->setName(pht('Files'))->setKey('files')->appendChild($toc_view))->addTab(id(new PHUITabView())->setName(pht('History'))->setKey('history')->appendChild($history))->addTab(id(new PHUITabView())->setName(pht('Commits'))->setKey('commits')->appendChild($local_table)); $stack_graph = id(new DifferentialRevisionGraph())->setViewer($viewer)->setSeedPHID($revision->getPHID())->setLoadEntireGraph(true)->loadGraph(); if (!$stack_graph->isEmpty()) { $stack_table = $stack_graph->newGraphTable(); $parent_type = DifferentialRevisionDependsOnRevisionEdgeType::EDGECONST; $reachable = $stack_graph->getReachableObjects($parent_type); foreach ($reachable as $key => $reachable_revision) { if ($reachable_revision->isClosed()) { unset($reachable[$key]); } } if ($reachable) { $stack_name = pht('Stack (%s Open)', phutil_count($reachable)); $stack_color = PHUIListItemView::STATUS_FAIL; } else { $stack_name = pht('Stack'); $stack_color = null; } $tab_group->addTab(id(new PHUITabView())->setName($stack_name)->setKey('stack')->setColor($stack_color)->appendChild($stack_table)); } if ($other_view) { $tab_group->addTab(id(new PHUITabView())->setName(pht('Similar'))->setKey('similar')->appendChild($other_view)); } $tab_view = id(new PHUIObjectBoxView())->setHeaderText(pht('Revision Contents'))->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)->addTabGroup($tab_group); $comment_form = null; if (!$viewer_is_anonymous) { $comment_form = $this->buildCommentForm($revision, $field_list); } $signatures = DifferentialRequiredSignaturesField::loadForRevision($revision); $missing_signatures = false; foreach ($signatures as $phid => $signed) { if (!$signed) { $missing_signatures = true; } } $footer = array(); $signature_message = null; if ($missing_signatures) { $signature_message = id(new PHUIInfoView())->setTitle(pht('Content Hidden'))->appendChild(pht('The content of this revision is hidden until the author has ' . 'signed all of the required legal agreements.')); } else { $anchor = id(new PhabricatorAnchorView())->setAnchorName('toc')->setNavigationMarker(true); $footer[] = array($anchor, $warning, $tab_view, $changeset_view); } if ($comment_form) { $footer[] = $comment_form; } else { // TODO: For now, just use this to get "Login to Comment". $footer[] = id(new PhabricatorApplicationTransactionCommentView())->setUser($viewer)->setRequestURI($request->getRequestURI()); } $object_id = 'D' . $revision->getID(); $operations_box = $this->buildOperationsBox($revision); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb($object_id, '/' . $object_id); $crumbs->setBorder(true); $filetree_on = $viewer->compareUserSetting(PhabricatorShowFiletreeSetting::SETTINGKEY, PhabricatorShowFiletreeSetting::VALUE_ENABLE_FILETREE); $nav = null; if ($filetree_on) { $collapsed_key = PhabricatorFiletreeVisibleSetting::SETTINGKEY; $collapsed_value = $viewer->getUserSetting($collapsed_key); $nav = id(new DifferentialChangesetFileTreeSideNavBuilder())->setTitle('D' . $revision->getID())->setBaseURI(new PhutilURI('/D' . $revision->getID()))->setCollapsed((bool) $collapsed_value)->build($changesets); } // Haunt Mode $pane_id = celerity_generate_unique_node_id(); Javelin::initBehavior('differential-keyboard-navigation', array('haunt' => $pane_id)); Javelin::initBehavior('differential-user-select'); $view = id(new PHUITwoColumnView())->setHeader($header)->setSubheader($subheader)->setCurtain($curtain)->setID($pane_id)->setMainColumn(array($operations_box, $info_view, $details, $diff_detail_box, $unit_box, $comment_view, $signature_message))->setFooter($footer); $page = $this->newPage()->setTitle($object_id . ' ' . $revision->getTitle())->setCrumbs($crumbs)->setPageObjectPHIDs(array($revision->getPHID()))->appendChild($view); if ($nav) { $page->setNavigation($nav); } return $page; }
public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); $dblob = $request->getURIData('dblob'); $snapshot = $request->getURIData('snapshot'); $parents = $this->loadParentFragments($dblob); if ($parents === null) { return new Aphront404Response(); } $fragment = idx($parents, count($parents) - 1, null); if ($snapshot !== null) { $snapshot = id(new PhragmentSnapshotQuery())->setViewer($viewer)->withPrimaryFragmentPHIDs(array($fragment->getPHID()))->withNames(array($snapshot))->executeOne(); if ($snapshot === null) { return new Aphront404Response(); } $cache = id(new PhragmentSnapshotChildQuery())->setViewer($viewer)->needFragmentVersions(true)->withSnapshotPHIDs(array($snapshot->getPHID()))->execute(); $this->snapshotCache = mpull($cache, 'getFragmentVersion', 'getFragmentPHID'); } $temp = new TempFile(); $zip = null; try { $zip = new ZipArchive(); } catch (Exception $e) { $dialog = new AphrontDialogView(); $dialog->setUser($viewer); $inst = pht('This system does not have the ZIP PHP extension installed. This ' . 'is required to download ZIPs from Phragment.'); $dialog->setTitle(pht('ZIP Extension Not Installed')); $dialog->appendParagraph($inst); $dialog->addCancelButton('/phragment/browse/' . $dblob); return id(new AphrontDialogResponse())->setDialog($dialog); } if (!$zip->open((string) $temp, ZipArchive::CREATE)) { throw new Exception(pht('Unable to create ZIP archive!')); } $mappings = $this->getFragmentMappings($fragment, $fragment->getPath(), $snapshot); $phids = array(); foreach ($mappings as $path => $file_phid) { $phids[] = $file_phid; } $files = id(new PhabricatorFileQuery())->setViewer($viewer)->withPHIDs($phids)->execute(); $files = mpull($files, null, 'getPHID'); foreach ($mappings as $path => $file_phid) { if (!isset($files[$file_phid])) { // The path is most likely pointing to a deleted fragment, which // hence no longer has a file associated with it. unset($mappings[$path]); continue; } $mappings[$path] = $files[$file_phid]; } foreach ($mappings as $path => $file) { if ($file !== null) { $zip->addFromString($path, $file->loadFileData()); } } $zip->close(); $zip_name = $fragment->getName(); if (substr($zip_name, -4) !== '.zip') { $zip_name .= '.zip'; } $data = Filesystem::readFile((string) $temp); $file = PhabricatorFile::buildFromFileDataOrHash($data, array('name' => $zip_name, 'ttl' => time() + 60 * 60 * 24)); $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $file->attachToObject($fragment->getPHID()); unset($unguarded); $return = $fragment->getURI(); if ($request->getExists('return')) { $return = $request->getStr('return'); } return id(new AphrontRedirectResponse())->setIsExternal(true)->setURI($file->getDownloadURI($return)); }
protected function getParameterExists(AphrontRequest $request, $key) { $file_key = $this->getFileKey($key); return $request->getExists($key) || $request->getFileExists($file_key); }
public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); $this->phid = $request->getURIData('phid'); $this->key = $request->getURIData('key'); $this->token = $request->getURIData('token'); $alt = PhabricatorEnv::getEnvConfig('security.alternate-file-domain'); $base_uri = PhabricatorEnv::getEnvConfig('phabricator.base-uri'); $alt_uri = new PhutilURI($alt); $alt_domain = $alt_uri->getDomain(); $req_domain = $request->getHost(); $main_domain = id(new PhutilURI($base_uri))->getDomain(); $cache_response = true; if (empty($alt) || $main_domain == $alt_domain) { // Alternate files domain isn't configured or it's set // to the same as the default domain $response = $this->loadFile($viewer); if ($response) { return $response; } $file = $this->getFile(); // when the file is not CDNable, don't allow cache $cache_response = $file->getCanCDN(); } else { if ($req_domain != $alt_domain) { // Alternate domain is configured but this request isn't using it $response = $this->loadFile($viewer); if ($response) { return $response; } $file = $this->getFile(); // if the user can see the file, generate a token; // redirect to the alt domain with the token; $token_uri = $file->getCDNURIWithToken(); $token_uri = new PhutilURI($token_uri); $token_uri = $this->addURIParameters($token_uri); return id(new AphrontRedirectResponse())->setIsExternal(true)->setURI($token_uri); } else { // We are using the alternate domain. We don't have authentication // on this domain, so we bypass policy checks when loading the file. $bypass_policies = PhabricatorUser::getOmnipotentUser(); $response = $this->loadFile($bypass_policies); if ($response) { return $response; } $file = $this->getFile(); $acquire_token_uri = id(new PhutilURI($file->getViewURI()))->setDomain($main_domain); $acquire_token_uri = $this->addURIParameters($acquire_token_uri); if ($this->token) { // validate the token, if it is valid, continue $validated_token = $file->validateOneTimeToken($this->token); if (!$validated_token) { $dialog = $this->newDialog()->setShortTitle(pht('Expired File'))->setTitle(pht('File Link Has Expired'))->appendParagraph(pht('The link you followed to view this file is invalid or ' . 'expired.'))->appendParagraph(pht('Continue to generate a new link to the file. You may be ' . 'required to log in.'))->addCancelButton($acquire_token_uri, pht('Continue')); // Build an explicit response so we can respond with HTTP/403 instead // of HTTP/200. $response = id(new AphrontDialogResponse())->setDialog($dialog)->setHTTPResponseCode(403); return $response; } // return the file data without cache headers $cache_response = false; } else { if (!$file->getCanCDN()) { // file cannot be served via cdn, and no token given // redirect to the main domain to aquire a token // This is marked as an "external" URI because it is fully qualified. return id(new AphrontRedirectResponse())->setIsExternal(true)->setURI($acquire_token_uri); } } } } $response = new AphrontFileResponse(); if ($cache_response) { $response->setCacheDurationInSeconds(60 * 60 * 24 * 30); } $begin = null; $end = null; // NOTE: It's important to accept "Range" requests when playing audio. // If we don't, Safari has difficulty figuring out how long sounds are // and glitches when trying to loop them. In particular, Safari sends // an initial request for bytes 0-1 of the audio file, and things go south // if we can't respond with a 206 Partial Content. $range = $request->getHTTPHeader('range'); if ($range) { $matches = null; if (preg_match('/^bytes=(\\d+)-(\\d+)$/', $range, $matches)) { // Note that the "Range" header specifies bytes differently than // we do internally: the range 0-1 has 2 bytes (byte 0 and byte 1). $begin = (int) $matches[1]; $end = (int) $matches[2] + 1; $response->setHTTPResponseCode(206); $response->setRange($begin, $end - 1); } } else { if (isset($validated_token)) { // We set this on the response, and the response deletes it after the // transfer completes. This allows transfers to be resumed, in theory. $response->setTemporaryFileToken($validated_token); } } $is_viewable = $file->isViewableInBrowser(); $force_download = $request->getExists('download'); if ($is_viewable && !$force_download) { $response->setMimeType($file->getViewableMimeType()); } else { if (!$request->isHTTPPost() && !$alt_domain) { // NOTE: Require POST to download files from the primary domain. 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. // This is marked as "external" because it is fully qualified. return id(new AphrontRedirectResponse())->setIsExternal(true)->setURI(PhabricatorEnv::getProductionURI($file->getBestURI())); } $response->setMimeType($file->getMimeType()); $response->setDownload($file->getName()); } $iterator = $file->getFileDataIterator($begin, $end); $response->setContentLength($file->getByteSize()); $response->setContentIterator($iterator); return $response; }
public function processRequest(AphrontRequest $request) { $user = $request->getUser(); $profile = id(new PhabricatorUserProfile())->loadOneWhere('userPHID = %s', $user->getPHID()); if (!$profile) { $profile = new PhabricatorUserProfile(); $profile->setUserPHID($user->getPHID()); } $supported_formats = PhabricatorFile::getTransformableImageFormats(); $e_image = null; $errors = array(); if ($request->isFormPost()) { $profile->setTitle($request->getStr('title')); $profile->setBlurb($request->getStr('blurb')); $sex = $request->getStr('sex'); $sexes = array(PhutilPerson::SEX_MALE, PhutilPerson::SEX_FEMALE); if (in_array($sex, $sexes)) { $user->setSex($sex); } else { $user->setSex(null); } // Checked in runtime. $user->setTranslation($request->getStr('translation')); $default_image = $request->getExists('default_image'); if ($default_image) { $profile->setProfileImagePHID(null); $user->setProfileImagePHID(null); } else { if (!empty($_FILES['image'])) { $err = idx($_FILES['image'], 'error'); if ($err != UPLOAD_ERR_NO_FILE) { $file = PhabricatorFile::newFromPHPUpload($_FILES['image'], array('authorPHID' => $user->getPHID())); $okay = $file->isTransformableImage(); if ($okay) { $xformer = new PhabricatorImageTransformer(); // Generate the large picture for the profile page. $large_xformed = $xformer->executeProfileTransform($file, $width = 280, $min_height = 140, $max_height = 420); $profile->setProfileImagePHID($large_xformed->getPHID()); // Generate the small picture for comments, etc. $small_xformed = $xformer->executeProfileTransform($file, $width = 50, $min_height = 50, $max_height = 50); $user->setProfileImagePHID($small_xformed->getPHID()); } else { $e_image = 'Not Supported'; $errors[] = 'This server only supports these image formats: ' . implode(', ', $supported_formats) . '.'; } } } } if (!$errors) { $user->save(); $profile->save(); $response = id(new AphrontRedirectResponse())->setURI($this->getPanelURI('?saved=true')); return $response; } } $error_view = null; if ($errors) { $error_view = new AphrontErrorView(); $error_view->setTitle('Form Errors'); $error_view->setErrors($errors); } else { if ($request->getStr('saved')) { $error_view = new AphrontErrorView(); $error_view->setSeverity(AphrontErrorView::SEVERITY_NOTICE); $error_view->setTitle('Changes Saved'); $error_view->appendChild('<p>Your changes have been saved.</p>'); $error_view = $error_view->render(); } } $img_src = $user->loadProfileImageURI(); $profile_uri = PhabricatorEnv::getURI('/p/' . $user->getUsername() . '/'); $sexes = array(PhutilPerson::SEX_UNKNOWN => 'Unknown', PhutilPerson::SEX_MALE => 'Male', PhutilPerson::SEX_FEMALE => 'Female'); $translations = array(); $symbols = id(new PhutilSymbolLoader())->setType('class')->setAncestorClass('PhabricatorTranslation')->setConcreteOnly(true)->selectAndLoadSymbols(); foreach ($symbols as $symbol) { $class = $symbol['name']; $translations[$class] = newv($class, array())->getName(); } asort($translations); $default = PhabricatorEnv::newObjectFromConfig('translation.provider'); $translations = array('' => 'Server Default (' . $default->getName() . ')') + $translations; $form = new AphrontFormView(); $form->setUser($request->getUser())->setEncType('multipart/form-data')->appendChild(id(new AphrontFormTextControl())->setLabel('Title')->setName('title')->setValue($profile->getTitle())->setCaption('Serious business title.'))->appendChild(id(new AphrontFormSelectControl())->setOptions($sexes)->setLabel('Sex')->setName('sex')->setValue($user->getSex()))->appendChild(id(new AphrontFormSelectControl())->setOptions($translations)->setLabel('Translation')->setName('translation')->setValue($user->getTranslation()))->appendChild(id(new AphrontFormMarkupControl())->setLabel('Profile URI')->setValue(phutil_render_tag('a', array('href' => $profile_uri), phutil_escape_html($profile_uri))))->appendChild('<p class="aphront-form-instructions">Write something about yourself! ' . 'Make sure to include <strong>important information</strong> like ' . 'your favorite Pokemon and which Starcraft race you play.</p>')->appendChild(id(new AphrontFormTextAreaControl())->setLabel('Blurb')->setName('blurb')->setValue($profile->getBlurb()))->appendChild(id(new AphrontFormMarkupControl())->setLabel('Profile Image')->setValue(phutil_render_tag('img', array('src' => $img_src))))->appendChild(id(new AphrontFormImageControl())->setLabel('Change Image')->setName('image')->setError($e_image)->setCaption('Supported formats: ' . implode(', ', $supported_formats)))->appendChild(id(new AphrontFormSubmitControl())->setValue('Save')->addCancelButton('/p/' . $user->getUsername() . '/')); $panel = new AphrontPanelView(); $panel->setHeader('Edit Profile Details'); $panel->appendChild($form); $panel->setWidth(AphrontPanelView::WIDTH_FORM); return array($error_view, $panel); }
protected function getValueExistsInRequest(AphrontRequest $request, $key) { return $request->getExists($key); }
protected function getParameterExists(AphrontRequest $request, $key) { return $request->getExists($key) || $request->getExists($key . '_d'); }
public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); $this->phid = $request->getURIData('phid'); $this->key = $request->getURIData('key'); $alt = PhabricatorEnv::getEnvConfig('security.alternate-file-domain'); $base_uri = PhabricatorEnv::getEnvConfig('phabricator.base-uri'); $alt_uri = new PhutilURI($alt); $alt_domain = $alt_uri->getDomain(); $req_domain = $request->getHost(); $main_domain = id(new PhutilURI($base_uri))->getDomain(); if (!strlen($alt) || $main_domain == $alt_domain) { // No alternate domain. $should_redirect = false; $is_alternate_domain = false; } else { if ($req_domain != $alt_domain) { // Alternate domain, but this request is on the main domain. $should_redirect = true; $is_alternate_domain = false; } else { // Alternate domain, and on the alternate domain. $should_redirect = false; $is_alternate_domain = true; } } $response = $this->loadFile(); if ($response) { return $response; } $file = $this->getFile(); if ($should_redirect) { return id(new AphrontRedirectResponse())->setIsExternal(true)->setURI($file->getCDNURI()); } $response = new AphrontFileResponse(); $response->setCacheDurationInSeconds(60 * 60 * 24 * 30); $response->setCanCDN($file->getCanCDN()); $begin = null; $end = null; // NOTE: It's important to accept "Range" requests when playing audio. // If we don't, Safari has difficulty figuring out how long sounds are // and glitches when trying to loop them. In particular, Safari sends // an initial request for bytes 0-1 of the audio file, and things go south // if we can't respond with a 206 Partial Content. $range = $request->getHTTPHeader('range'); if ($range) { $matches = null; if (preg_match('/^bytes=(\\d+)-(\\d+)$/', $range, $matches)) { // Note that the "Range" header specifies bytes differently than // we do internally: the range 0-1 has 2 bytes (byte 0 and byte 1). $begin = (int) $matches[1]; $end = (int) $matches[2] + 1; $response->setHTTPResponseCode(206); $response->setRange($begin, $end - 1); } } $is_viewable = $file->isViewableInBrowser(); $force_download = $request->getExists('download'); $request_type = $request->getHTTPHeader('X-Phabricator-Request-Type'); $is_lfs = $request_type == 'git-lfs'; if ($is_viewable && !$force_download) { $response->setMimeType($file->getViewableMimeType()); } else { if (!$request->isHTTPPost() && !$is_alternate_domain && !$is_lfs) { // NOTE: Require POST to download files from the primary domain. 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. // This is marked as "external" because it is fully qualified. return id(new AphrontRedirectResponse())->setIsExternal(true)->setURI(PhabricatorEnv::getProductionURI($file->getBestURI())); } $response->setMimeType($file->getMimeType()); $response->setDownload($file->getName()); } $iterator = $file->getFileDataIterator($begin, $end); $response->setContentLength($file->getByteSize()); $response->setContentIterator($iterator); return $response; }