diff --git a/resources/sql/autopatches/20170406.hmac.01.keystore.sql b/resources/sql/autopatches/20170406.hmac.01.keystore.sql new file mode 100644 index 0000000000..f7de1c9efa --- /dev/null +++ b/resources/sql/autopatches/20170406.hmac.01.keystore.sql @@ -0,0 +1,8 @@ +CREATE TABLE {$NAMESPACE}_auth.auth_hmackey ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + keyName VARCHAR(64) NOT NULL COLLATE {$COLLATE_TEXT}, + keyValue VARCHAR(128) NOT NULL COLLATE {$COLLATE_TEXT}, + dateCreated INT UNSIGNED NOT NULL, + dateModified INT UNSIGNED NOT NULL, + UNIQUE KEY `key_name` (keyName) +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/patches/20130530.sessionhash.php b/resources/sql/patches/20130530.sessionhash.php index 4efbe5feec..771dac61e3 100644 --- a/resources/sql/patches/20130530.sessionhash.php +++ b/resources/sql/patches/20130530.sessionhash.php @@ -14,7 +14,7 @@ foreach ($sessions as $session) { $conn, 'UPDATE %T SET sessionKey = %s WHERE userPHID = %s AND type = %s', PhabricatorUser::SESSION_TABLE, - PhabricatorHash::digest($session['sessionKey']), + PhabricatorHash::weakDigest($session['sessionKey']), $session['userPHID'], $session['type']); } diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 9ccc495e7a..b567e5a9e9 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -502,6 +502,7 @@ phutil_register_library_map(array( 'DifferentialReviewersCommitMessageField' => 'applications/differential/field/DifferentialReviewersCommitMessageField.php', 'DifferentialReviewersField' => 'applications/differential/customfield/DifferentialReviewersField.php', 'DifferentialReviewersHeraldAction' => 'applications/differential/herald/DifferentialReviewersHeraldAction.php', + 'DifferentialReviewersSearchEngineAttachment' => 'applications/differential/engineextension/DifferentialReviewersSearchEngineAttachment.php', 'DifferentialReviewersView' => 'applications/differential/view/DifferentialReviewersView.php', 'DifferentialRevision' => 'applications/differential/storage/DifferentialRevision.php', 'DifferentialRevisionAbandonTransaction' => 'applications/differential/xaction/DifferentialRevisionAbandonTransaction.php', @@ -1919,6 +1920,7 @@ phutil_register_library_map(array( 'PhabricatorAuthFactorConfig' => 'applications/auth/storage/PhabricatorAuthFactorConfig.php', 'PhabricatorAuthFactorTestCase' => 'applications/auth/factor/__tests__/PhabricatorAuthFactorTestCase.php', 'PhabricatorAuthFinishController' => 'applications/auth/controller/PhabricatorAuthFinishController.php', + 'PhabricatorAuthHMACKey' => 'applications/auth/storage/PhabricatorAuthHMACKey.php', 'PhabricatorAuthHighSecurityRequiredException' => 'applications/auth/exception/PhabricatorAuthHighSecurityRequiredException.php', 'PhabricatorAuthHighSecurityToken' => 'applications/auth/data/PhabricatorAuthHighSecurityToken.php', 'PhabricatorAuthInvite' => 'applications/auth/storage/PhabricatorAuthInvite.php', @@ -2743,7 +2745,6 @@ phutil_register_library_map(array( 'PhabricatorFileChunk' => 'applications/files/storage/PhabricatorFileChunk.php', 'PhabricatorFileChunkIterator' => 'applications/files/engine/PhabricatorFileChunkIterator.php', 'PhabricatorFileChunkQuery' => 'applications/files/query/PhabricatorFileChunkQuery.php', - 'PhabricatorFileCommentController' => 'applications/files/controller/PhabricatorFileCommentController.php', 'PhabricatorFileComposeController' => 'applications/files/controller/PhabricatorFileComposeController.php', 'PhabricatorFileController' => 'applications/files/controller/PhabricatorFileController.php', 'PhabricatorFileDAO' => 'applications/files/storage/PhabricatorFileDAO.php', @@ -2751,6 +2752,7 @@ phutil_register_library_map(array( 'PhabricatorFileDeleteController' => 'applications/files/controller/PhabricatorFileDeleteController.php', 'PhabricatorFileDropUploadController' => 'applications/files/controller/PhabricatorFileDropUploadController.php', 'PhabricatorFileEditController' => 'applications/files/controller/PhabricatorFileEditController.php', + 'PhabricatorFileEditEngine' => 'applications/files/editor/PhabricatorFileEditEngine.php', 'PhabricatorFileEditField' => 'applications/transactions/editfield/PhabricatorFileEditField.php', 'PhabricatorFileEditor' => 'applications/files/editor/PhabricatorFileEditor.php', 'PhabricatorFileExternalRequest' => 'applications/files/storage/PhabricatorFileExternalRequest.php', @@ -2762,13 +2764,16 @@ phutil_register_library_map(array( 'PhabricatorFileImageProxyController' => 'applications/files/controller/PhabricatorFileImageProxyController.php', 'PhabricatorFileImageTransform' => 'applications/files/transform/PhabricatorFileImageTransform.php', 'PhabricatorFileInfoController' => 'applications/files/controller/PhabricatorFileInfoController.php', + 'PhabricatorFileIntegrityException' => 'applications/files/exception/PhabricatorFileIntegrityException.php', 'PhabricatorFileLightboxController' => 'applications/files/controller/PhabricatorFileLightboxController.php', 'PhabricatorFileLinkView' => 'view/layout/PhabricatorFileLinkView.php', 'PhabricatorFileListController' => 'applications/files/controller/PhabricatorFileListController.php', + 'PhabricatorFileNameTransaction' => 'applications/files/xaction/PhabricatorFileNameTransaction.php', 'PhabricatorFileQuery' => 'applications/files/query/PhabricatorFileQuery.php', 'PhabricatorFileROT13StorageFormat' => 'applications/files/format/PhabricatorFileROT13StorageFormat.php', 'PhabricatorFileRawStorageFormat' => 'applications/files/format/PhabricatorFileRawStorageFormat.php', 'PhabricatorFileSchemaSpec' => 'applications/files/storage/PhabricatorFileSchemaSpec.php', + 'PhabricatorFileSearchConduitAPIMethod' => 'applications/files/conduit/PhabricatorFileSearchConduitAPIMethod.php', 'PhabricatorFileSearchEngine' => 'applications/files/query/PhabricatorFileSearchEngine.php', 'PhabricatorFileStorageBlob' => 'applications/files/storage/PhabricatorFileStorageBlob.php', 'PhabricatorFileStorageConfigurationException' => 'applications/files/exception/PhabricatorFileStorageConfigurationException.php', @@ -2783,6 +2788,7 @@ phutil_register_library_map(array( 'PhabricatorFileTransaction' => 'applications/files/storage/PhabricatorFileTransaction.php', 'PhabricatorFileTransactionComment' => 'applications/files/storage/PhabricatorFileTransactionComment.php', 'PhabricatorFileTransactionQuery' => 'applications/files/query/PhabricatorFileTransactionQuery.php', + 'PhabricatorFileTransactionType' => 'applications/files/xaction/PhabricatorFileTransactionType.php', 'PhabricatorFileTransform' => 'applications/files/transform/PhabricatorFileTransform.php', 'PhabricatorFileTransformController' => 'applications/files/controller/PhabricatorFileTransformController.php', 'PhabricatorFileTransformListController' => 'applications/files/controller/PhabricatorFileTransformListController.php', @@ -2805,6 +2811,7 @@ phutil_register_library_map(array( 'PhabricatorFilesManagementEncodeWorkflow' => 'applications/files/management/PhabricatorFilesManagementEncodeWorkflow.php', 'PhabricatorFilesManagementEnginesWorkflow' => 'applications/files/management/PhabricatorFilesManagementEnginesWorkflow.php', 'PhabricatorFilesManagementGenerateKeyWorkflow' => 'applications/files/management/PhabricatorFilesManagementGenerateKeyWorkflow.php', + 'PhabricatorFilesManagementIntegrityWorkflow' => 'applications/files/management/PhabricatorFilesManagementIntegrityWorkflow.php', 'PhabricatorFilesManagementMigrateWorkflow' => 'applications/files/management/PhabricatorFilesManagementMigrateWorkflow.php', 'PhabricatorFilesManagementPurgeWorkflow' => 'applications/files/management/PhabricatorFilesManagementPurgeWorkflow.php', 'PhabricatorFilesManagementRebuildWorkflow' => 'applications/files/management/PhabricatorFilesManagementRebuildWorkflow.php', @@ -2858,6 +2865,7 @@ phutil_register_library_map(array( 'PhabricatorGuideModule' => 'applications/guides/module/PhabricatorGuideModule.php', 'PhabricatorGuideModuleController' => 'applications/guides/controller/PhabricatorGuideModuleController.php', 'PhabricatorGuideQuickStartModule' => 'applications/guides/module/PhabricatorGuideQuickStartModule.php', + 'PhabricatorHMACTestCase' => 'infrastructure/util/__tests__/PhabricatorHMACTestCase.php', 'PhabricatorHTTPParameterTypeTableView' => 'applications/config/view/PhabricatorHTTPParameterTypeTableView.php', 'PhabricatorHandleList' => 'applications/phid/handle/pool/PhabricatorHandleList.php', 'PhabricatorHandleObjectSelectorDataView' => 'applications/phid/handle/view/PhabricatorHandleObjectSelectorDataView.php', @@ -5271,6 +5279,7 @@ phutil_register_library_map(array( 'DifferentialReviewersCommitMessageField' => 'DifferentialCommitMessageField', 'DifferentialReviewersField' => 'DifferentialCoreCustomField', 'DifferentialReviewersHeraldAction' => 'HeraldAction', + 'DifferentialReviewersSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment', 'DifferentialReviewersView' => 'AphrontView', 'DifferentialRevision' => array( 'DifferentialDAO', @@ -6893,6 +6902,7 @@ phutil_register_library_map(array( 'PhabricatorAuthFactorConfig' => 'PhabricatorAuthDAO', 'PhabricatorAuthFactorTestCase' => 'PhabricatorTestCase', 'PhabricatorAuthFinishController' => 'PhabricatorAuthController', + 'PhabricatorAuthHMACKey' => 'PhabricatorAuthDAO', 'PhabricatorAuthHighSecurityRequiredException' => 'Exception', 'PhabricatorAuthHighSecurityToken' => 'Phobject', 'PhabricatorAuthInvite' => array( @@ -7845,6 +7855,7 @@ phutil_register_library_map(array( 'PhabricatorFlaggableInterface', 'PhabricatorPolicyInterface', 'PhabricatorDestructibleInterface', + 'PhabricatorConduitResultInterface', ), 'PhabricatorFileAES256StorageFormat' => 'PhabricatorFileStorageFormat', 'PhabricatorFileBundleLoader' => 'Phobject', @@ -7858,7 +7869,6 @@ phutil_register_library_map(array( 'Iterator', ), 'PhabricatorFileChunkQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', - 'PhabricatorFileCommentController' => 'PhabricatorFileController', 'PhabricatorFileComposeController' => 'PhabricatorFileController', 'PhabricatorFileController' => 'PhabricatorController', 'PhabricatorFileDAO' => 'PhabricatorLiskDAO', @@ -7866,6 +7876,7 @@ phutil_register_library_map(array( 'PhabricatorFileDeleteController' => 'PhabricatorFileController', 'PhabricatorFileDropUploadController' => 'PhabricatorFileController', 'PhabricatorFileEditController' => 'PhabricatorFileController', + 'PhabricatorFileEditEngine' => 'PhabricatorEditEngine', 'PhabricatorFileEditField' => 'PhabricatorEditField', 'PhabricatorFileEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorFileExternalRequest' => array( @@ -7887,13 +7898,16 @@ phutil_register_library_map(array( 'PhabricatorFileImageProxyController' => 'PhabricatorFileController', 'PhabricatorFileImageTransform' => 'PhabricatorFileTransform', 'PhabricatorFileInfoController' => 'PhabricatorFileController', + 'PhabricatorFileIntegrityException' => 'Exception', 'PhabricatorFileLightboxController' => 'PhabricatorFileController', 'PhabricatorFileLinkView' => 'AphrontTagView', 'PhabricatorFileListController' => 'PhabricatorFileController', + 'PhabricatorFileNameTransaction' => 'PhabricatorFileTransactionType', 'PhabricatorFileQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorFileROT13StorageFormat' => 'PhabricatorFileStorageFormat', 'PhabricatorFileRawStorageFormat' => 'PhabricatorFileStorageFormat', 'PhabricatorFileSchemaSpec' => 'PhabricatorConfigSchemaSpec', + 'PhabricatorFileSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'PhabricatorFileSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorFileStorageBlob' => 'PhabricatorFileDAO', 'PhabricatorFileStorageConfigurationException' => 'Exception', @@ -7905,9 +7919,10 @@ phutil_register_library_map(array( 'PhabricatorFileTestCase' => 'PhabricatorTestCase', 'PhabricatorFileTestDataGenerator' => 'PhabricatorTestDataGenerator', 'PhabricatorFileThumbnailTransform' => 'PhabricatorFileImageTransform', - 'PhabricatorFileTransaction' => 'PhabricatorApplicationTransaction', + 'PhabricatorFileTransaction' => 'PhabricatorModularTransaction', 'PhabricatorFileTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PhabricatorFileTransactionQuery' => 'PhabricatorApplicationTransactionQuery', + 'PhabricatorFileTransactionType' => 'PhabricatorModularTransactionType', 'PhabricatorFileTransform' => 'Phobject', 'PhabricatorFileTransformController' => 'PhabricatorFileController', 'PhabricatorFileTransformListController' => 'PhabricatorFileController', @@ -7930,6 +7945,7 @@ phutil_register_library_map(array( 'PhabricatorFilesManagementEncodeWorkflow' => 'PhabricatorFilesManagementWorkflow', 'PhabricatorFilesManagementEnginesWorkflow' => 'PhabricatorFilesManagementWorkflow', 'PhabricatorFilesManagementGenerateKeyWorkflow' => 'PhabricatorFilesManagementWorkflow', + 'PhabricatorFilesManagementIntegrityWorkflow' => 'PhabricatorFilesManagementWorkflow', 'PhabricatorFilesManagementMigrateWorkflow' => 'PhabricatorFilesManagementWorkflow', 'PhabricatorFilesManagementPurgeWorkflow' => 'PhabricatorFilesManagementWorkflow', 'PhabricatorFilesManagementRebuildWorkflow' => 'PhabricatorFilesManagementWorkflow', @@ -7985,6 +8001,7 @@ phutil_register_library_map(array( 'PhabricatorGuideModule' => 'Phobject', 'PhabricatorGuideModuleController' => 'PhabricatorGuideController', 'PhabricatorGuideQuickStartModule' => 'PhabricatorGuideModule', + 'PhabricatorHMACTestCase' => 'PhabricatorTestCase', 'PhabricatorHTTPParameterTypeTableView' => 'AphrontView', 'PhabricatorHandleList' => array( 'Phobject', diff --git a/src/aphront/response/AphrontFileResponse.php b/src/aphront/response/AphrontFileResponse.php index a8f673d218..9699c49ad4 100644 --- a/src/aphront/response/AphrontFileResponse.php +++ b/src/aphront/response/AphrontFileResponse.php @@ -94,10 +94,15 @@ final class AphrontFileResponse extends AphrontResponse { array('Accept-Ranges', 'bytes'), ); - if ($this->rangeMin || $this->rangeMax) { + if ($this->rangeMin !== null || $this->rangeMax !== null) { $len = $this->getContentLength(); $min = $this->rangeMin; + $max = $this->rangeMax; + if ($max === null) { + $max = ($len - 1); + } + $headers[] = array('Content-Range', "bytes {$min}-{$max}/{$len}"); $content_len = ($max - $min) + 1; } else { @@ -105,7 +110,7 @@ final class AphrontFileResponse extends AphrontResponse { } if (!$this->shouldCompressResponse()) { - $headers[] = array('Content-Length', $this->getContentLength()); + $headers[] = array('Content-Length', $content_len); } if (strlen($this->getDownload())) { diff --git a/src/applications/auth/controller/PhabricatorAuthController.php b/src/applications/auth/controller/PhabricatorAuthController.php index 4a572edf22..c5b3c1ce99 100644 --- a/src/applications/auth/controller/PhabricatorAuthController.php +++ b/src/applications/auth/controller/PhabricatorAuthController.php @@ -194,7 +194,7 @@ abstract class PhabricatorAuthController extends PhabricatorController { // hijacking registration sessions. $actual = $account->getProperty('registrationKey'); - $expect = PhabricatorHash::digest($registration_key); + $expect = PhabricatorHash::weakDigest($registration_key); if (!phutil_hashes_are_identical($actual, $expect)) { $response = $this->renderError( pht( diff --git a/src/applications/auth/controller/PhabricatorAuthLoginController.php b/src/applications/auth/controller/PhabricatorAuthLoginController.php index b9b2a8d876..3264e61216 100644 --- a/src/applications/auth/controller/PhabricatorAuthLoginController.php +++ b/src/applications/auth/controller/PhabricatorAuthLoginController.php @@ -194,7 +194,7 @@ final class PhabricatorAuthLoginController $registration_key = Filesystem::readRandomCharacters(32); $account->setProperty( 'registrationKey', - PhabricatorHash::digest($registration_key)); + PhabricatorHash::weakDigest($registration_key)); $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $account->save(); diff --git a/src/applications/auth/controller/PhabricatorAuthOneTimeLoginController.php b/src/applications/auth/controller/PhabricatorAuthOneTimeLoginController.php index 627d1b43eb..ebfd07e7ac 100644 --- a/src/applications/auth/controller/PhabricatorAuthOneTimeLoginController.php +++ b/src/applications/auth/controller/PhabricatorAuthOneTimeLoginController.php @@ -135,7 +135,7 @@ final class PhabricatorAuthOneTimeLoginController ->setTokenResource($target_user->getPHID()) ->setTokenType($password_type) ->setTokenExpires(time() + phutil_units('1 hour in seconds')) - ->setTokenCode(PhabricatorHash::digest($key)) + ->setTokenCode(PhabricatorHash::weakDigest($key)) ->save(); unset($unguarded); diff --git a/src/applications/auth/controller/PhabricatorAuthSSHKeyGenerateController.php b/src/applications/auth/controller/PhabricatorAuthSSHKeyGenerateController.php index 69d93548e5..f39707618d 100644 --- a/src/applications/auth/controller/PhabricatorAuthSSHKeyGenerateController.php +++ b/src/applications/auth/controller/PhabricatorAuthSSHKeyGenerateController.php @@ -24,11 +24,11 @@ final class PhabricatorAuthSSHKeyGenerateController $keys = PhabricatorSSHKeyGenerator::generateKeypair(); list($public_key, $private_key) = $keys; - $file = PhabricatorFile::buildFromFileDataOrHash( + $file = PhabricatorFile::newFromFileData( $private_key, array( 'name' => $default_name.'.key', - 'ttl' => time() + (60 * 10), + 'ttl.relative' => phutil_units('10 minutes in seconds'), 'viewPolicy' => $viewer->getPHID(), )); diff --git a/src/applications/auth/controller/PhabricatorAuthTerminateSessionController.php b/src/applications/auth/controller/PhabricatorAuthTerminateSessionController.php index 43ac80bb70..fa58977c90 100644 --- a/src/applications/auth/controller/PhabricatorAuthTerminateSessionController.php +++ b/src/applications/auth/controller/PhabricatorAuthTerminateSessionController.php @@ -16,7 +16,7 @@ final class PhabricatorAuthTerminateSessionController $query->withIDs(array($id)); } - $current_key = PhabricatorHash::digest( + $current_key = PhabricatorHash::weakDigest( $request->getCookie(PhabricatorCookies::COOKIE_SESSION)); $sessions = $query->execute(); diff --git a/src/applications/auth/engine/PhabricatorAuthSessionEngine.php b/src/applications/auth/engine/PhabricatorAuthSessionEngine.php index 4e66d3c9f4..82303fff2b 100644 --- a/src/applications/auth/engine/PhabricatorAuthSessionEngine.php +++ b/src/applications/auth/engine/PhabricatorAuthSessionEngine.php @@ -110,7 +110,7 @@ final class PhabricatorAuthSessionEngine extends Phobject { $session_table = new PhabricatorAuthSession(); $user_table = new PhabricatorUser(); $conn_r = $session_table->establishConnection('r'); - $session_key = PhabricatorHash::digest($session_token); + $session_key = PhabricatorHash::weakDigest($session_token); $cache_parts = $this->getUserCacheQueryParts($conn_r); list($cache_selects, $cache_joins, $cache_map, $types_map) = $cache_parts; @@ -240,7 +240,7 @@ final class PhabricatorAuthSessionEngine extends Phobject { // This has a side effect of validating the session type. $session_ttl = PhabricatorAuthSession::getSessionTypeTTL($session_type); - $digest_key = PhabricatorHash::digest($session_key); + $digest_key = PhabricatorHash::weakDigest($session_key); // Logging-in users don't have CSRF stuff yet, so we have to unguard this // write. @@ -306,7 +306,7 @@ final class PhabricatorAuthSessionEngine extends Phobject { ->execute(); if ($except_session !== null) { - $except_session = PhabricatorHash::digest($except_session); + $except_session = PhabricatorHash::weakDigest($except_session); } foreach ($sessions as $key => $session) { @@ -755,7 +755,7 @@ final class PhabricatorAuthSessionEngine extends Phobject { $parts[] = $email->getVerificationCode(); } - return PhabricatorHash::digest(implode(':', $parts)); + return PhabricatorHash::weakDigest(implode(':', $parts)); } diff --git a/src/applications/auth/factor/PhabricatorTOTPAuthFactor.php b/src/applications/auth/factor/PhabricatorTOTPAuthFactor.php index 8875b960e2..10c44aaec0 100644 --- a/src/applications/auth/factor/PhabricatorTOTPAuthFactor.php +++ b/src/applications/auth/factor/PhabricatorTOTPAuthFactor.php @@ -39,7 +39,7 @@ final class PhabricatorTOTPAuthFactor extends PhabricatorAuthFactor { ->withTokenResources(array($user->getPHID())) ->withTokenTypes(array($totp_token_type)) ->withExpired(false) - ->withTokenCodes(array(PhabricatorHash::digest($key))) + ->withTokenCodes(array(PhabricatorHash::weakDigest($key))) ->executeOne(); if (!$temporary_token) { // If we don't have a matching token, regenerate the key below. @@ -58,7 +58,7 @@ final class PhabricatorTOTPAuthFactor extends PhabricatorAuthFactor { ->setTokenResource($user->getPHID()) ->setTokenType($totp_token_type) ->setTokenExpires(time() + phutil_units('1 hour in seconds')) - ->setTokenCode(PhabricatorHash::digest($key)) + ->setTokenCode(PhabricatorHash::weakDigest($key)) ->save(); unset($unguarded); } diff --git a/src/applications/auth/provider/PhabricatorAuthProvider.php b/src/applications/auth/provider/PhabricatorAuthProvider.php index a3f77618e4..4dd7f4da1b 100644 --- a/src/applications/auth/provider/PhabricatorAuthProvider.php +++ b/src/applications/auth/provider/PhabricatorAuthProvider.php @@ -474,7 +474,7 @@ abstract class PhabricatorAuthProvider extends Phobject { true); } - return PhabricatorHash::digest($phcid); + return PhabricatorHash::weakDigest($phcid); } protected function verifyAuthCSRFCode(AphrontRequest $request, $actual) { diff --git a/src/applications/auth/query/PhabricatorAuthSessionQuery.php b/src/applications/auth/query/PhabricatorAuthSessionQuery.php index 966bb946c4..dea95dd450 100644 --- a/src/applications/auth/query/PhabricatorAuthSessionQuery.php +++ b/src/applications/auth/query/PhabricatorAuthSessionQuery.php @@ -85,7 +85,7 @@ final class PhabricatorAuthSessionQuery if ($this->sessionKeys) { $hashes = array(); foreach ($this->sessionKeys as $session_key) { - $hashes[] = PhabricatorHash::digest($session_key); + $hashes[] = PhabricatorHash::weakDigest($session_key); } $where[] = qsprintf( $conn_r, diff --git a/src/applications/auth/storage/PhabricatorAuthHMACKey.php b/src/applications/auth/storage/PhabricatorAuthHMACKey.php new file mode 100644 index 0000000000..4d2aae4997 --- /dev/null +++ b/src/applications/auth/storage/PhabricatorAuthHMACKey.php @@ -0,0 +1,24 @@ + array( + 'keyName' => 'text64', + 'keyValue' => 'text128', + ), + self::CONFIG_KEY_SCHEMA => array( + 'key_name' => array( + 'columns' => array('keyName'), + 'unique' => true, + ), + ), + ) + parent::getConfiguration(); + } + +} diff --git a/src/applications/badges/xaction/PhabricatorBadgesBadgeNameTransaction.php b/src/applications/badges/xaction/PhabricatorBadgesBadgeNameTransaction.php index 1df7d89a70..3a609fedb2 100644 --- a/src/applications/badges/xaction/PhabricatorBadgesBadgeNameTransaction.php +++ b/src/applications/badges/xaction/PhabricatorBadgesBadgeNameTransaction.php @@ -43,7 +43,7 @@ final class PhabricatorBadgesBadgeNameTransaction $new_value = $xaction->getNewValue(); $new_length = strlen($new_value); if ($new_length > $max_length) { - $errors[] = $this->newRequiredError( + $errors[] = $this->newInvalidError( pht('The name can be no longer than %s characters.', new PhutilNumber($max_length))); } diff --git a/src/applications/base/controller/PhabricatorController.php b/src/applications/base/controller/PhabricatorController.php index f2b267b67f..58d8f6cf6f 100644 --- a/src/applications/base/controller/PhabricatorController.php +++ b/src/applications/base/controller/PhabricatorController.php @@ -98,7 +98,7 @@ abstract class PhabricatorController extends AphrontController { if (!$user->isLoggedIn()) { - $user->attachAlternateCSRFString(PhabricatorHash::digest($phsid)); + $user->attachAlternateCSRFString(PhabricatorHash::weakDigest($phsid)); } $request->setUser($user); diff --git a/src/applications/calendar/storage/PhabricatorCalendarEvent.php b/src/applications/calendar/storage/PhabricatorCalendarEvent.php index b2e81b0e8b..e566a77b76 100644 --- a/src/applications/calendar/storage/PhabricatorCalendarEvent.php +++ b/src/applications/calendar/storage/PhabricatorCalendarEvent.php @@ -1182,9 +1182,8 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO * @task markup */ public function getMarkupFieldKey($field) { - $hash = PhabricatorHash::digest($this->getMarkupText($field)); - $id = $this->getID(); - return "calendar:T{$id}:{$field}:{$hash}"; + $content = $this->getMarkupText($field); + return PhabricatorMarkupEngine::digestRemarkupContent($this, $content); } diff --git a/src/applications/celerity/resources/CelerityResources.php b/src/applications/celerity/resources/CelerityResources.php index 9536786a6a..e0b9191702 100644 --- a/src/applications/celerity/resources/CelerityResources.php +++ b/src/applications/celerity/resources/CelerityResources.php @@ -14,7 +14,7 @@ abstract class CelerityResources extends Phobject { public function getCelerityHash($data) { $tail = PhabricatorEnv::getEnvConfig('celerity.resource-hash'); - $hash = PhabricatorHash::digest($data, $tail); + $hash = PhabricatorHash::weakDigest($data, $tail); return substr($hash, 0, 8); } diff --git a/src/applications/config/application/PhabricatorConfigApplication.php b/src/applications/config/application/PhabricatorConfigApplication.php index 510cb6f76d..9789b7de9f 100644 --- a/src/applications/config/application/PhabricatorConfigApplication.php +++ b/src/applications/config/application/PhabricatorConfigApplication.php @@ -27,7 +27,7 @@ final class PhabricatorConfigApplication extends PhabricatorApplication { } public function getName() { - return 'Config'; + return pht('Config'); } public function getShortDescription() { diff --git a/src/applications/config/check/PhabricatorPathSetupCheck.php b/src/applications/config/check/PhabricatorPathSetupCheck.php index 9f5502e215..75c89d332a 100644 --- a/src/applications/config/check/PhabricatorPathSetupCheck.php +++ b/src/applications/config/check/PhabricatorPathSetupCheck.php @@ -107,7 +107,7 @@ final class PhabricatorPathSetupCheck extends PhabricatorSetupCheck { if ($bad_paths) { foreach ($bad_paths as $path_part => $message) { - $digest = substr(PhabricatorHash::digest($path_part), 0, 8); + $digest = substr(PhabricatorHash::weakDigest($path_part), 0, 8); $this ->newIssue('config.PATH.'.$digest) diff --git a/src/applications/config/option/PhabricatorSecurityConfigOptions.php b/src/applications/config/option/PhabricatorSecurityConfigOptions.php index 47fd1bb6f2..78f8e89e6a 100644 --- a/src/applications/config/option/PhabricatorSecurityConfigOptions.php +++ b/src/applications/config/option/PhabricatorSecurityConfigOptions.php @@ -109,7 +109,8 @@ EOTEXT 'Default key for HMAC digests where the key is not important '. '(i.e., the hash itself is secret). You can change this if you '. 'want (to any other string), but doing so will break existing '. - 'sessions and CSRF tokens.')), + 'sessions and CSRF tokens. This option is deprecated. Newer '. + 'code automatically manages HMAC keys.')), $this->newOption('security.require-https', 'bool', false) ->setLocked(true) ->setSummary( diff --git a/src/applications/differential/controller/DifferentialChangesetViewController.php b/src/applications/differential/controller/DifferentialChangesetViewController.php index b5bfe7464d..c2bd4bf8de 100644 --- a/src/applications/differential/controller/DifferentialChangesetViewController.php +++ b/src/applications/differential/controller/DifferentialChangesetViewController.php @@ -357,7 +357,7 @@ final class DifferentialChangesetViewController extends DifferentialController { array( 'name' => $changeset->getFilename(), 'mime-type' => 'text/plain', - 'ttl' => phutil_units('24 hours in seconds'), + 'ttl.relative' => phutil_units('24 hours in seconds'), 'viewPolicy' => PhabricatorPolicies::POLICY_NOONE, )); diff --git a/src/applications/differential/controller/DifferentialRevisionViewController.php b/src/applications/differential/controller/DifferentialRevisionViewController.php index e7d0a1cc87..6cb39c1510 100644 --- a/src/applications/differential/controller/DifferentialRevisionViewController.php +++ b/src/applications/differential/controller/DifferentialRevisionViewController.php @@ -889,15 +889,15 @@ final class DifferentialRevisionViewController extends DifferentialController { } $file_name .= 'diff'; - $file = PhabricatorFile::buildFromFileDataOrHash( - $raw_diff, - array( - 'name' => $file_name, - 'ttl' => (60 * 60 * 24), - 'viewPolicy' => PhabricatorPolicies::POLICY_NOONE, - )); - $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); + $file = PhabricatorFile::newFromFileData( + $raw_diff, + array( + 'name' => $file_name, + 'ttl.relative' => phutil_units('24 hours in seconds'), + 'viewPolicy' => PhabricatorPolicies::POLICY_NOONE, + )); + $file->attachToObject($revision->getPHID()); unset($unguarded); diff --git a/src/applications/differential/engineextension/DifferentialReviewersSearchEngineAttachment.php b/src/applications/differential/engineextension/DifferentialReviewersSearchEngineAttachment.php new file mode 100644 index 0000000000..33fb606a60 --- /dev/null +++ b/src/applications/differential/engineextension/DifferentialReviewersSearchEngineAttachment.php @@ -0,0 +1,41 @@ +needReviewers(true); + } + + public function getAttachmentForObject($object, $data, $spec) { + $reviewers = $object->getReviewers(); + + $status_blocking = DifferentialReviewerStatus::STATUS_BLOCKING; + + $list = array(); + foreach ($reviewers as $reviewer) { + $status = $reviewer->getReviewerStatus(); + $is_blocking = ($status == $status_blocking); + + $list[] = array( + 'reviewerPHID' => $reviewer->getReviewerPHID(), + 'status' => $status, + 'isBlocking' => $is_blocking, + 'actorPHID' => $reviewer->getLastActorPHID(), + ); + } + + return array( + 'reviewers' => $list, + ); + } + +} diff --git a/src/applications/differential/storage/DifferentialInlineComment.php b/src/applications/differential/storage/DifferentialInlineComment.php index c27d59bbe3..bdc231671f 100644 --- a/src/applications/differential/storage/DifferentialInlineComment.php +++ b/src/applications/differential/storage/DifferentialInlineComment.php @@ -260,8 +260,8 @@ final class DifferentialInlineComment public function getMarkupFieldKey($field) { - // We can't use ID because synthetic comments don't have it. - return 'DI:'.PhabricatorHash::digest($this->getContent()); + $content = $this->getMarkupText($field); + return PhabricatorMarkupEngine::digestRemarkupContent($this, $content); } public function newMarkupEngine($field) { diff --git a/src/applications/differential/storage/DifferentialRevision.php b/src/applications/differential/storage/DifferentialRevision.php index 72204256e5..0e968dccf4 100644 --- a/src/applications/differential/storage/DifferentialRevision.php +++ b/src/applications/differential/storage/DifferentialRevision.php @@ -907,7 +907,10 @@ final class DifferentialRevision extends DifferentialDAO } public function getConduitSearchAttachments() { - return array(); + return array( + id(new DifferentialReviewersSearchEngineAttachment()) + ->setAttachmentKey('reviewers'), + ); } diff --git a/src/applications/differential/xaction/DifferentialRevisionReviewTransaction.php b/src/applications/differential/xaction/DifferentialRevisionReviewTransaction.php index 019c4c036f..d44de8706c 100644 --- a/src/applications/differential/xaction/DifferentialRevisionReviewTransaction.php +++ b/src/applications/differential/xaction/DifferentialRevisionReviewTransaction.php @@ -183,8 +183,19 @@ abstract class DifferentialRevisionReviewTransaction // In all cases, you affect yourself. $map[$viewer->getPHID()] = $status; - // If the user has submitted a specific list of reviewers to act as (by - // unchecking some checkboxes under "Accept"), only affect those reviewers. + // If we're applying an "accept the defaults" transaction, and this + // transaction type uses checkboxes, replace the value with the list of + // defaults. + if (!is_array($value)) { + list($options, $default) = $this->getActionOptions($viewer, $revision); + if ($options) { + $value = $default; + } + } + + // If we have a specific list of reviewers to act on, usually because the + // user has submitted a specific list of reviewers to act as by + // unchecking some checkboxes under "Accept", only affect those reviewers. if (is_array($value)) { $map = array_select_keys($map, $value); } diff --git a/src/applications/diffusion/controller/DiffusionRepositoryListController.php b/src/applications/diffusion/controller/DiffusionRepositoryListController.php index d886209c89..5a21d2e3f1 100644 --- a/src/applications/diffusion/controller/DiffusionRepositoryListController.php +++ b/src/applications/diffusion/controller/DiffusionRepositoryListController.php @@ -14,7 +14,7 @@ final class DiffusionRepositoryListController extends DiffusionController { ->setName(pht('Commits')); $items[] = id(new PHUIListItemView()) - ->setName('Browse Commits') + ->setName(pht('Browse Commits')) ->setHref($this->getApplicationURI('commit/')); return id(new PhabricatorRepositorySearchEngine()) diff --git a/src/applications/diffusion/controller/DiffusionServeController.php b/src/applications/diffusion/controller/DiffusionServeController.php index 02ff23b15f..5e61ae3a7c 100644 --- a/src/applications/diffusion/controller/DiffusionServeController.php +++ b/src/applications/diffusion/controller/DiffusionServeController.php @@ -652,7 +652,7 @@ final class DiffusionServeController extends DiffusionController { } $lfs_pass = $password->openEnvelope(); - $lfs_hash = PhabricatorHash::digest($lfs_pass); + $lfs_hash = PhabricatorHash::weakDigest($lfs_pass); $token = id(new PhabricatorAuthTemporaryTokenQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) diff --git a/src/applications/diffusion/editor/DiffusionURIEditor.php b/src/applications/diffusion/editor/DiffusionURIEditor.php index 9219935d3a..674efbc158 100644 --- a/src/applications/diffusion/editor/DiffusionURIEditor.php +++ b/src/applications/diffusion/editor/DiffusionURIEditor.php @@ -507,6 +507,10 @@ final class DiffusionURIEditor ->synchronizeWorkingCopyAfterHostingChange(); } + $repository->writeStatusMessage( + PhabricatorRepositoryStatusMessage::TYPE_NEEDS_UPDATE, + null); + return $xactions; } diff --git a/src/applications/diffusion/gitlfs/DiffusionGitLFSTemporaryTokenType.php b/src/applications/diffusion/gitlfs/DiffusionGitLFSTemporaryTokenType.php index 0973072ba4..e5425b07e1 100644 --- a/src/applications/diffusion/gitlfs/DiffusionGitLFSTemporaryTokenType.php +++ b/src/applications/diffusion/gitlfs/DiffusionGitLFSTemporaryTokenType.php @@ -22,7 +22,7 @@ final class DiffusionGitLFSTemporaryTokenType $lfs_user = self::HTTP_USERNAME; $lfs_pass = Filesystem::readRandomCharacters(32); - $lfs_hash = PhabricatorHash::digest($lfs_pass); + $lfs_hash = PhabricatorHash::weakDigest($lfs_pass); $ttl = PhabricatorTime::getNow() + phutil_units('1 day in seconds'); diff --git a/src/applications/diffusion/query/DiffusionFileFutureQuery.php b/src/applications/diffusion/query/DiffusionFileFutureQuery.php index 8ce59028e2..250e4962da 100644 --- a/src/applications/diffusion/query/DiffusionFileFutureQuery.php +++ b/src/applications/diffusion/query/DiffusionFileFutureQuery.php @@ -93,7 +93,7 @@ abstract class DiffusionFileFutureQuery $drequest = $this->getRequest(); $name = basename($drequest->getPath()); - $ttl = PhabricatorTime::getNow() + phutil_units('48 hours in seconds'); + $relative_ttl = phutil_units('48 hours in seconds'); try { $threshold = PhabricatorFileStorageEngine::getChunkThreshold(); @@ -101,7 +101,7 @@ abstract class DiffusionFileFutureQuery $source = id(new PhabricatorExecFutureFileUploadSource()) ->setName($name) - ->setTTL($ttl) + ->setRelativeTTL($relative_ttl) ->setViewPolicy(PhabricatorPolicies::POLICY_NOONE) ->setExecFuture($future); diff --git a/src/applications/drydock/management/DrydockManagementLeaseWorkflow.php b/src/applications/drydock/management/DrydockManagementLeaseWorkflow.php index baffd7706f..4992833c50 100644 --- a/src/applications/drydock/management/DrydockManagementLeaseWorkflow.php +++ b/src/applications/drydock/management/DrydockManagementLeaseWorkflow.php @@ -22,7 +22,7 @@ final class DrydockManagementLeaseWorkflow array( 'name' => 'attributes', 'param' => 'name=value,...', - 'help' => pht('Resource specficiation.'), + 'help' => pht('Resource specification.'), ), )); } diff --git a/src/applications/files/PhabricatorImageTransformer.php b/src/applications/files/PhabricatorImageTransformer.php index 75e83c223d..df4243cfdd 100644 --- a/src/applications/files/PhabricatorImageTransformer.php +++ b/src/applications/files/PhabricatorImageTransformer.php @@ -15,7 +15,7 @@ final class PhabricatorImageTransformer extends Phobject { $image, array( 'name' => 'meme-'.$file->getName(), - 'ttl' => time() + 60 * 60 * 24, + 'ttl.relative' => phutil_units('24 hours in seconds'), 'canCDN' => true, )); } diff --git a/src/applications/files/application/PhabricatorFilesApplication.php b/src/applications/files/application/PhabricatorFilesApplication.php index 5733439fcf..1010818c19 100644 --- a/src/applications/files/application/PhabricatorFilesApplication.php +++ b/src/applications/files/application/PhabricatorFilesApplication.php @@ -78,7 +78,8 @@ final class PhabricatorFilesApplication extends PhabricatorApplication { 'comment/(?P[1-9]\d*)/' => 'PhabricatorFileCommentController', 'thread/(?P[^/]+)/' => 'PhabricatorFileLightboxController', 'delete/(?P[1-9]\d*)/' => 'PhabricatorFileDeleteController', - 'edit/(?P[1-9]\d*)/' => 'PhabricatorFileEditController', + $this->getEditRoutePattern('edit/') + => 'PhabricatorFileEditController', 'info/(?P[^/]+)/' => 'PhabricatorFileInfoController', 'imageproxy/' => 'PhabricatorFileImageProxyController', 'transforms/(?P[1-9]\d*)/' => diff --git a/src/applications/files/conduit/FileAllocateConduitAPIMethod.php b/src/applications/files/conduit/FileAllocateConduitAPIMethod.php index ff3a0c80da..c831eb2afe 100644 --- a/src/applications/files/conduit/FileAllocateConduitAPIMethod.php +++ b/src/applications/files/conduit/FileAllocateConduitAPIMethod.php @@ -36,23 +36,26 @@ final class FileAllocateConduitAPIMethod $properties = array( 'name' => $name, 'authorPHID' => $viewer->getPHID(), - 'viewPolicy' => $view_policy, 'isExplicitUpload' => true, ); + if ($view_policy !== null) { + $properties['viewPolicy'] = $view_policy; + } + $ttl = $request->getValue('deleteAfterEpoch'); if ($ttl) { - $properties['ttl'] = $ttl; + $properties['ttl.absolute'] = $ttl; } $file = null; - if ($hash) { + if ($hash !== null) { $file = PhabricatorFile::newFileFromContentHash( $hash, $properties); } - if ($hash && !$file) { + if ($hash !== null && !$file) { $chunked_hash = PhabricatorChunkedFileStorageEngine::getChunkedHash( $viewer, $hash); @@ -103,7 +106,7 @@ final class FileAllocateConduitAPIMethod if ($chunk_engines) { $chunk_properties = $properties; - if ($hash) { + if ($hash !== null) { $chunk_properties += array( 'chunkedHash' => $chunked_hash, ); diff --git a/src/applications/files/conduit/FileInfoConduitAPIMethod.php b/src/applications/files/conduit/FileInfoConduitAPIMethod.php index 5f1bb6e936..f1c8f5941a 100644 --- a/src/applications/files/conduit/FileInfoConduitAPIMethod.php +++ b/src/applications/files/conduit/FileInfoConduitAPIMethod.php @@ -10,6 +10,16 @@ final class FileInfoConduitAPIMethod extends FileConduitAPIMethod { return pht('Get information about a file.'); } + public function getMethodStatus() { + return self::METHOD_STATUS_FROZEN; + } + + public function getMethodStatusDescription() { + return pht( + 'This method is frozen and will eventually be deprecated. New code '. + 'should use "file.search" instead.'); + } + protected function defineParamTypes() { return array( 'phid' => 'optional phid', diff --git a/src/applications/files/conduit/FileUploadConduitAPIMethod.php b/src/applications/files/conduit/FileUploadConduitAPIMethod.php index ac93b7d39a..8b3b9faaaa 100644 --- a/src/applications/files/conduit/FileUploadConduitAPIMethod.php +++ b/src/applications/files/conduit/FileUploadConduitAPIMethod.php @@ -27,21 +27,27 @@ final class FileUploadConduitAPIMethod extends FileConduitAPIMethod { $viewer = $request->getUser(); $name = $request->getValue('name'); - $can_cdn = $request->getValue('canCDN'); + $can_cdn = (bool)$request->getValue('canCDN'); $view_policy = $request->getValue('viewPolicy'); $data = $request->getValue('data_base64'); $data = $this->decodeBase64($data); - $file = PhabricatorFile::newFromFileData( - $data, - array( - 'name' => $name, - 'authorPHID' => $viewer->getPHID(), - 'viewPolicy' => $view_policy, - 'canCDN' => $can_cdn, - 'isExplicitUpload' => true, - )); + $params = array( + 'authorPHID' => $viewer->getPHID(), + 'canCDN' => $can_cdn, + 'isExplicitUpload' => true, + ); + + if ($name !== null) { + $params['name'] = $name; + } + + if ($view_policy !== null) { + $params['viewPolicy'] = $view_policy; + } + + $file = PhabricatorFile::newFromFileData($data, $params); return $file->getPHID(); } diff --git a/src/applications/files/conduit/FileUploadHashConduitAPIMethod.php b/src/applications/files/conduit/FileUploadHashConduitAPIMethod.php index 135e018a2f..db7a6acecb 100644 --- a/src/applications/files/conduit/FileUploadHashConduitAPIMethod.php +++ b/src/applications/files/conduit/FileUploadHashConduitAPIMethod.php @@ -3,12 +3,21 @@ final class FileUploadHashConduitAPIMethod extends FileConduitAPIMethod { public function getAPIMethodName() { - // TODO: Deprecate this in favor of `file.allocate`. return 'file.uploadhash'; } + public function getMethodStatus() { + return self::METHOD_STATUS_DEPRECATED; + } + + public function getMethodStatusDescription() { + return pht( + 'This method is deprecated. Callers should use "file.allocate" '. + 'instead.'); + } + public function getMethodDescription() { - return pht('Upload a file to the server using content hash.'); + return pht('Obsolete. Has no effect.'); } protected function defineParamTypes() { @@ -19,25 +28,11 @@ final class FileUploadHashConduitAPIMethod extends FileConduitAPIMethod { } protected function defineReturnType() { - return 'phid or null'; + return 'null'; } protected function execute(ConduitAPIRequest $request) { - $hash = $request->getValue('hash'); - $name = $request->getValue('name'); - $user = $request->getUser(); - - $file = PhabricatorFile::newFileFromContentHash( - $hash, - array( - 'name' => $name, - 'authorPHID' => $user->getPHID(), - )); - - if ($file) { - return $file->getPHID(); - } - return $file; + return null; } } diff --git a/src/applications/files/conduit/PhabricatorFileSearchConduitAPIMethod.php b/src/applications/files/conduit/PhabricatorFileSearchConduitAPIMethod.php new file mode 100644 index 0000000000..0b6920d559 --- /dev/null +++ b/src/applications/files/conduit/PhabricatorFileSearchConduitAPIMethod.php @@ -0,0 +1,18 @@ +getViewer(); - $id = $request->getURIData('id'); - - if (!$request->isFormPost()) { - return new Aphront400Response(); - } - - $file = id(new PhabricatorFileQuery()) - ->setViewer($viewer) - ->withIDs(array($id)) - ->executeOne(); - if (!$file) { - return new Aphront404Response(); - } - - $is_preview = $request->isPreviewRequest(); - $draft = PhabricatorDraft::buildFromRequest($request); - - $view_uri = $file->getInfoURI(); - - $xactions = array(); - $xactions[] = id(new PhabricatorFileTransaction()) - ->setTransactionType(PhabricatorTransactions::TYPE_COMMENT) - ->attachComment( - id(new PhabricatorFileTransactionComment()) - ->setContent($request->getStr('comment'))); - - $editor = id(new PhabricatorFileEditor()) - ->setActor($viewer) - ->setContinueOnNoEffect($request->isContinueRequest()) - ->setContentSourceFromRequest($request) - ->setIsPreview($is_preview); - - try { - $xactions = $editor->applyTransactions($file, $xactions); - } catch (PhabricatorApplicationTransactionNoEffectException $ex) { - return id(new PhabricatorApplicationTransactionNoEffectResponse()) - ->setCancelURI($view_uri) - ->setException($ex); - } - - if ($draft) { - $draft->replaceOrDelete(); - } - - if ($request->isAjax() && $is_preview) { - return id(new PhabricatorApplicationTransactionResponse()) - ->setViewer($viewer) - ->setTransactions($xactions) - ->setIsPreview($is_preview); - } else { - return id(new AphrontRedirectResponse()) - ->setURI($view_uri); - } - } - -} diff --git a/src/applications/files/controller/PhabricatorFileDataController.php b/src/applications/files/controller/PhabricatorFileDataController.php index 5c2fc7bbda..31761d1244 100644 --- a/src/applications/files/controller/PhabricatorFileDataController.php +++ b/src/applications/files/controller/PhabricatorFileDataController.php @@ -64,14 +64,21 @@ final class PhabricatorFileDataController extends PhabricatorFileController { $range = $request->getHTTPHeader('range'); if ($range) { $matches = null; - if (preg_match('/^bytes=(\d+)-(\d+)$/', $range, $matches)) { + 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; + + // The "Range" may be "200-299" or "200-", meaning "until end of file". + if (strlen($matches[2])) { + $range_end = (int)$matches[2]; + $end = $range_end + 1; + } else { + $range_end = null; + } $response->setHTTPResponseCode(206); - $response->setRange($begin, ($end - 1)); + $response->setRange($begin, $range_end); } } @@ -84,18 +91,28 @@ final class PhabricatorFileDataController extends PhabricatorFileController { 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. + $is_public = !$viewer->isLoggedIn(); + $is_post = $request->isHTTPPost(); + // NOTE: Require POST to download files from the primary domain if the + // request includes credentials. The "Download File" links we generate + // in the web UI are forms which use POST to satisfy this requirement. + + // The intent is to make attacks based on tags like "