mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-15 01:50:55 +01:00
(stable) Promote 2018 Week 4
This commit is contained in:
commit
4bf1bc2563
203 changed files with 6006 additions and 1673 deletions
1
bin/bulk
Symbolic link
1
bin/bulk
Symbolic link
|
@ -0,0 +1 @@
|
|||
../scripts/setup/manage_bulk.php
|
|
@ -9,16 +9,16 @@ return array(
|
|||
'names' => array(
|
||||
'conpherence.pkg.css' => 'e68cf1fa',
|
||||
'conpherence.pkg.js' => '15191c65',
|
||||
'core.pkg.css' => 'fdb27ef9',
|
||||
'core.pkg.css' => '075f9867',
|
||||
'core.pkg.js' => '4c79d74f',
|
||||
'darkconsole.pkg.js' => '1f9a31bc',
|
||||
'differential.pkg.css' => '45951e9e',
|
||||
'differential.pkg.js' => '500a75c5',
|
||||
'differential.pkg.js' => '19ee9979',
|
||||
'diffusion.pkg.css' => 'a2d17c7d',
|
||||
'diffusion.pkg.js' => '6134c5a1',
|
||||
'favicon.ico' => '30672e08',
|
||||
'maniphest.pkg.css' => '4845691a',
|
||||
'maniphest.pkg.js' => '5ab2753f',
|
||||
'maniphest.pkg.js' => '4d7e79c8',
|
||||
'rsrc/audio/basic/alert.mp3' => '98461568',
|
||||
'rsrc/audio/basic/bing.mp3' => 'ab8603a5',
|
||||
'rsrc/audio/basic/pock.mp3' => '0cc772f5',
|
||||
|
@ -81,7 +81,6 @@ return array(
|
|||
'rsrc/css/application/harbormaster/harbormaster.css' => 'f491c9f4',
|
||||
'rsrc/css/application/herald/herald-test.css' => 'a52e323e',
|
||||
'rsrc/css/application/herald/herald.css' => 'cd8d0134',
|
||||
'rsrc/css/application/maniphest/batch-editor.css' => 'b0f0b6d5',
|
||||
'rsrc/css/application/maniphest/report.css' => '9b9580b7',
|
||||
'rsrc/css/application/maniphest/task-edit.css' => 'fda62a9b',
|
||||
'rsrc/css/application/maniphest/task-summary.css' => '11cc5344',
|
||||
|
@ -135,14 +134,15 @@ return array(
|
|||
'rsrc/css/phui/object-item/phui-oi-color.css' => 'cd2b9b77',
|
||||
'rsrc/css/phui/object-item/phui-oi-drag-ui.css' => '08f4ccc3',
|
||||
'rsrc/css/phui/object-item/phui-oi-flush-ui.css' => '9d9685d6',
|
||||
'rsrc/css/phui/object-item/phui-oi-list-view.css' => 'bf094950',
|
||||
'rsrc/css/phui/object-item/phui-oi-list-view.css' => '6ae18df0',
|
||||
'rsrc/css/phui/object-item/phui-oi-simple-ui.css' => 'a8beebea',
|
||||
'rsrc/css/phui/phui-action-list.css' => 'f7f61a34',
|
||||
'rsrc/css/phui/phui-action-panel.css' => 'b4798122',
|
||||
'rsrc/css/phui/phui-badge.css' => '22c0cf4f',
|
||||
'rsrc/css/phui/phui-basic-nav-view.css' => '98c11ab3',
|
||||
'rsrc/css/phui/phui-big-info-view.css' => 'acc3492c',
|
||||
'rsrc/css/phui/phui-box.css' => '9f3745fb',
|
||||
'rsrc/css/phui/phui-box.css' => '4bd6cdb9',
|
||||
'rsrc/css/phui/phui-bulk-editor.css' => '9a81e5d5',
|
||||
'rsrc/css/phui/phui-chart.css' => '6bf6f78e',
|
||||
'rsrc/css/phui/phui-cms.css' => '504b4b23',
|
||||
'rsrc/css/phui/phui-comment-form.css' => 'ac68149f',
|
||||
|
@ -416,11 +416,10 @@ return array(
|
|||
'rsrc/js/application/drydock/drydock-live-operation-status.js' => '901935ef',
|
||||
'rsrc/js/application/files/behavior-icon-composer.js' => '8499b6ab',
|
||||
'rsrc/js/application/files/behavior-launch-icon-composer.js' => '48086888',
|
||||
'rsrc/js/application/herald/HeraldRuleEditor.js' => '2dff5579',
|
||||
'rsrc/js/application/herald/HeraldRuleEditor.js' => 'dca75c0e',
|
||||
'rsrc/js/application/herald/PathTypeahead.js' => 'f7fc67ec',
|
||||
'rsrc/js/application/herald/herald-rule-editor.js' => '7ebaeed3',
|
||||
'rsrc/js/application/maniphest/behavior-batch-editor.js' => '782ab6e7',
|
||||
'rsrc/js/application/maniphest/behavior-batch-selector.js' => '0825c27a',
|
||||
'rsrc/js/application/maniphest/behavior-batch-selector.js' => 'ad54037e',
|
||||
'rsrc/js/application/maniphest/behavior-line-chart.js' => 'e4232876',
|
||||
'rsrc/js/application/maniphest/behavior-list-edit.js' => 'a9f88de2',
|
||||
'rsrc/js/application/maniphest/behavior-subpriorityeditor.js' => '71237763',
|
||||
|
@ -444,7 +443,7 @@ return array(
|
|||
'rsrc/js/application/releeph/releeph-preview-branch.js' => 'b2b4fbaf',
|
||||
'rsrc/js/application/releeph/releeph-request-state-change.js' => 'a0b57eb8',
|
||||
'rsrc/js/application/releeph/releeph-request-typeahead.js' => 'de2e896f',
|
||||
'rsrc/js/application/repository/repository-crossreference.js' => '7fe9bc12',
|
||||
'rsrc/js/application/repository/repository-crossreference.js' => '2ab10a76',
|
||||
'rsrc/js/application/search/behavior-reorder-profile-menu-items.js' => 'e2e0a072',
|
||||
'rsrc/js/application/search/behavior-reorder-queries.js' => 'e9581f08',
|
||||
'rsrc/js/application/slowvote/behavior-slowvote-embed.js' => '887ad43f',
|
||||
|
@ -477,6 +476,7 @@ return array(
|
|||
'rsrc/js/core/behavior-audio-source.js' => '59b251eb',
|
||||
'rsrc/js/core/behavior-autofocus.js' => '7319e029',
|
||||
'rsrc/js/core/behavior-badge-view.js' => '8ff5e24c',
|
||||
'rsrc/js/core/behavior-bulk-editor.js' => '66a6def1',
|
||||
'rsrc/js/core/behavior-choose-control.js' => '327a00d1',
|
||||
'rsrc/js/core/behavior-copy.js' => 'b0b8f86d',
|
||||
'rsrc/js/core/behavior-detect-timezone.js' => '4c193c96',
|
||||
|
@ -523,6 +523,7 @@ return array(
|
|||
'rsrc/js/core/phtize.js' => 'd254d646',
|
||||
'rsrc/js/phui/behavior-phui-dropdown-menu.js' => 'b95d6f7d',
|
||||
'rsrc/js/phui/behavior-phui-file-upload.js' => 'b003d4fb',
|
||||
'rsrc/js/phui/behavior-phui-selectable-list.js' => '464259a2',
|
||||
'rsrc/js/phui/behavior-phui-submenu.js' => 'a6f7a73b',
|
||||
'rsrc/js/phui/behavior-phui-tab-group.js' => '0a0b10e9',
|
||||
'rsrc/js/phuix/PHUIXActionListView.js' => 'b5c256b8',
|
||||
|
@ -531,7 +532,7 @@ return array(
|
|||
'rsrc/js/phuix/PHUIXButtonView.js' => '8a91e1ac',
|
||||
'rsrc/js/phuix/PHUIXDropdownMenu.js' => '04b2ae03',
|
||||
'rsrc/js/phuix/PHUIXExample.js' => '68af71ca',
|
||||
'rsrc/js/phuix/PHUIXFormControl.js' => '83e03671',
|
||||
'rsrc/js/phuix/PHUIXFormControl.js' => '1dd0870c',
|
||||
'rsrc/js/phuix/PHUIXIconView.js' => 'bff6884b',
|
||||
),
|
||||
'symbols' => array(
|
||||
|
@ -579,7 +580,7 @@ return array(
|
|||
'global-drag-and-drop-css' => 'b556a948',
|
||||
'harbormaster-css' => 'f491c9f4',
|
||||
'herald-css' => 'cd8d0134',
|
||||
'herald-rule-editor' => '2dff5579',
|
||||
'herald-rule-editor' => 'dca75c0e',
|
||||
'herald-test-css' => 'a52e323e',
|
||||
'inline-comment-summary-css' => 'f23d4e8f',
|
||||
'javelin-aphlict' => 'e1d4b11a',
|
||||
|
@ -594,6 +595,7 @@ return array(
|
|||
'javelin-behavior-audio-source' => '59b251eb',
|
||||
'javelin-behavior-audit-preview' => 'd835b03a',
|
||||
'javelin-behavior-badge-view' => '8ff5e24c',
|
||||
'javelin-behavior-bulk-editor' => '66a6def1',
|
||||
'javelin-behavior-bulk-job-reload' => 'edf8a145',
|
||||
'javelin-behavior-calendar-month-view' => 'fe33e256',
|
||||
'javelin-behavior-choose-control' => '327a00d1',
|
||||
|
@ -641,8 +643,7 @@ return array(
|
|||
'javelin-behavior-lightbox-attachments' => '560f41da',
|
||||
'javelin-behavior-line-chart' => 'e4232876',
|
||||
'javelin-behavior-load-blame' => '42126667',
|
||||
'javelin-behavior-maniphest-batch-editor' => '782ab6e7',
|
||||
'javelin-behavior-maniphest-batch-selector' => '0825c27a',
|
||||
'javelin-behavior-maniphest-batch-selector' => 'ad54037e',
|
||||
'javelin-behavior-maniphest-list-editor' => 'a9f88de2',
|
||||
'javelin-behavior-maniphest-subpriority-editor' => '71237763',
|
||||
'javelin-behavior-owners-path-editor' => '7a68dda3',
|
||||
|
@ -673,6 +674,7 @@ return array(
|
|||
'javelin-behavior-phui-dropdown-menu' => 'b95d6f7d',
|
||||
'javelin-behavior-phui-file-upload' => 'b003d4fb',
|
||||
'javelin-behavior-phui-hovercards' => 'bcaccd64',
|
||||
'javelin-behavior-phui-selectable-list' => '464259a2',
|
||||
'javelin-behavior-phui-submenu' => 'a6f7a73b',
|
||||
'javelin-behavior-phui-tab-group' => '0a0b10e9',
|
||||
'javelin-behavior-phuix-example' => '68af71ca',
|
||||
|
@ -690,7 +692,7 @@ return array(
|
|||
'javelin-behavior-reorder-applications' => '76b9fc3e',
|
||||
'javelin-behavior-reorder-columns' => 'e1d25dfb',
|
||||
'javelin-behavior-reorder-profile-menu-items' => 'e2e0a072',
|
||||
'javelin-behavior-repository-crossreference' => '7fe9bc12',
|
||||
'javelin-behavior-repository-crossreference' => '2ab10a76',
|
||||
'javelin-behavior-scrollbar' => '834a1173',
|
||||
'javelin-behavior-search-reorder-queries' => 'e9581f08',
|
||||
'javelin-behavior-select-content' => 'bf5374ef',
|
||||
|
@ -754,7 +756,6 @@ return array(
|
|||
'javelin-workboard-column' => '758b4758',
|
||||
'javelin-workboard-controller' => '26167537',
|
||||
'javelin-workflow' => '1e911d0f',
|
||||
'maniphest-batch-editor' => 'b0f0b6d5',
|
||||
'maniphest-report-css' => '9b9580b7',
|
||||
'maniphest-task-edit-css' => 'fda62a9b',
|
||||
'maniphest-task-summary-css' => '11cc5344',
|
||||
|
@ -820,7 +821,8 @@ return array(
|
|||
'phui-badge-view-css' => '22c0cf4f',
|
||||
'phui-basic-nav-view-css' => '98c11ab3',
|
||||
'phui-big-info-view-css' => 'acc3492c',
|
||||
'phui-box-css' => '9f3745fb',
|
||||
'phui-box-css' => '4bd6cdb9',
|
||||
'phui-bulk-editor-css' => '9a81e5d5',
|
||||
'phui-button-bar-css' => 'f1ff5494',
|
||||
'phui-button-css' => '1863cc6e',
|
||||
'phui-button-simple-css' => '8e1baf68',
|
||||
|
@ -860,7 +862,7 @@ return array(
|
|||
'phui-oi-color-css' => 'cd2b9b77',
|
||||
'phui-oi-drag-ui-css' => '08f4ccc3',
|
||||
'phui-oi-flush-ui-css' => '9d9685d6',
|
||||
'phui-oi-list-view-css' => 'bf094950',
|
||||
'phui-oi-list-view-css' => '6ae18df0',
|
||||
'phui-oi-simple-ui-css' => 'a8beebea',
|
||||
'phui-pager-css' => 'edcbc226',
|
||||
'phui-pinboard-view-css' => '2495140e',
|
||||
|
@ -882,7 +884,7 @@ return array(
|
|||
'phuix-autocomplete' => 'e0731603',
|
||||
'phuix-button-view' => '8a91e1ac',
|
||||
'phuix-dropdown-menu' => '04b2ae03',
|
||||
'phuix-form-control-view' => '83e03671',
|
||||
'phuix-form-control-view' => '1dd0870c',
|
||||
'phuix-icon-view' => 'bff6884b',
|
||||
'policy-css' => '957ea14c',
|
||||
'policy-edit-css' => '815c66f7',
|
||||
|
@ -958,12 +960,6 @@ return array(
|
|||
'javelin-stratcom',
|
||||
'javelin-workflow',
|
||||
),
|
||||
'0825c27a' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
'javelin-stratcom',
|
||||
'javelin-util',
|
||||
),
|
||||
'08f4ccc3' => array(
|
||||
'phui-oi-list-view-css',
|
||||
),
|
||||
|
@ -1033,6 +1029,10 @@ return array(
|
|||
'javelin-request',
|
||||
'javelin-uri',
|
||||
),
|
||||
'1dd0870c' => array(
|
||||
'javelin-install',
|
||||
'javelin-dom',
|
||||
),
|
||||
'1e911d0f' => array(
|
||||
'javelin-stratcom',
|
||||
'javelin-request',
|
||||
|
@ -1088,6 +1088,12 @@ return array(
|
|||
'javelin-install',
|
||||
'javelin-util',
|
||||
),
|
||||
'2ab10a76' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
'javelin-stratcom',
|
||||
'javelin-uri',
|
||||
),
|
||||
'2ae077e1' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
|
@ -1106,15 +1112,6 @@ return array(
|
|||
'javelin-install',
|
||||
'javelin-event',
|
||||
),
|
||||
'2dff5579' => array(
|
||||
'multirow-row-manager',
|
||||
'javelin-install',
|
||||
'javelin-util',
|
||||
'javelin-dom',
|
||||
'javelin-stratcom',
|
||||
'javelin-json',
|
||||
'phabricator-prefab',
|
||||
),
|
||||
'2ee659ce' => array(
|
||||
'javelin-install',
|
||||
),
|
||||
|
@ -1226,6 +1223,11 @@ return array(
|
|||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
),
|
||||
'464259a2' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
'javelin-dom',
|
||||
),
|
||||
'469c0d9e' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
|
@ -1422,6 +1424,14 @@ return array(
|
|||
'javelin-workflow',
|
||||
'javelin-dom',
|
||||
),
|
||||
'66a6def1' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
'javelin-util',
|
||||
'multirow-row-manager',
|
||||
'javelin-json',
|
||||
'phuix-form-control-view',
|
||||
),
|
||||
'680ea2c8' => array(
|
||||
'javelin-install',
|
||||
'javelin-dom',
|
||||
|
@ -1523,14 +1533,6 @@ return array(
|
|||
'javelin-request',
|
||||
'javelin-util',
|
||||
),
|
||||
'782ab6e7' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
'javelin-util',
|
||||
'phabricator-prefab',
|
||||
'multirow-row-manager',
|
||||
'javelin-json',
|
||||
),
|
||||
'7927a7d3' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-quicksand',
|
||||
|
@ -1559,20 +1561,10 @@ return array(
|
|||
'7f243deb' => array(
|
||||
'javelin-install',
|
||||
),
|
||||
'7fe9bc12' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
'javelin-stratcom',
|
||||
'javelin-uri',
|
||||
),
|
||||
'834a1173' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-scrollbar',
|
||||
),
|
||||
'83e03671' => array(
|
||||
'javelin-install',
|
||||
'javelin-dom',
|
||||
),
|
||||
'8499b6ab' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
|
@ -1808,6 +1800,12 @@ return array(
|
|||
'phuix-autocomplete',
|
||||
'javelin-mask',
|
||||
),
|
||||
'ad54037e' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
'javelin-stratcom',
|
||||
'javelin-util',
|
||||
),
|
||||
'b003d4fb' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
|
@ -2023,6 +2021,15 @@ return array(
|
|||
'javelin-util',
|
||||
'phabricator-shaped-request',
|
||||
),
|
||||
'dca75c0e' => array(
|
||||
'multirow-row-manager',
|
||||
'javelin-install',
|
||||
'javelin-util',
|
||||
'javelin-dom',
|
||||
'javelin-stratcom',
|
||||
'javelin-json',
|
||||
'phabricator-prefab',
|
||||
),
|
||||
'de2e896f' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
|
|
|
@ -1,27 +1,13 @@
|
|||
<?php
|
||||
|
||||
$table = new PhabricatorRepositoryVCSPassword();
|
||||
$conn_w = $table->establishConnection('w');
|
||||
// This migration once upgraded VCS password hashing, but the table was
|
||||
// later removed in 2018 (see T13043).
|
||||
|
||||
echo pht('Upgrading password hashing for VCS passwords.')."\n";
|
||||
// Since almost four years have passed since this migration, the cost of
|
||||
// losing this data is very small (users just need to reset their passwords),
|
||||
// and a version of this migration against the modern schema isn't easy to
|
||||
// implement or test, just skip the migration.
|
||||
|
||||
$best_hasher = PhabricatorPasswordHasher::getBestHasher();
|
||||
foreach (new LiskMigrationIterator($table) as $password) {
|
||||
$id = $password->getID();
|
||||
|
||||
echo pht('Migrating VCS password %d...', $id)."\n";
|
||||
|
||||
$input_hash = $password->getPasswordHash();
|
||||
$input_envelope = new PhutilOpaqueEnvelope($input_hash);
|
||||
|
||||
$storage_hash = $best_hasher->getPasswordHashForStorage($input_envelope);
|
||||
|
||||
queryfx(
|
||||
$conn_w,
|
||||
'UPDATE %T SET passwordHash = %s WHERE id = %d',
|
||||
$table->getTableName(),
|
||||
$storage_hash->openEnvelope(),
|
||||
$id);
|
||||
}
|
||||
|
||||
echo pht('Done.')."\n";
|
||||
// This means that installs which upgrade from a version of Phabricator
|
||||
// released prior to Feb 2014 to a version of Phabricator relased after
|
||||
// Jan 2018 will need to have users reset VCS passwords.
|
||||
|
|
2
resources/sql/autopatches/20180119.bulk.01.silent.sql
Normal file
2
resources/sql/autopatches/20180119.bulk.01.silent.sql
Normal file
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_worker.worker_bulkjob
|
||||
ADD isSilent BOOL NOT NULL;
|
10
resources/sql/autopatches/20180120.auth.01.password.sql
Normal file
10
resources/sql/autopatches/20180120.auth.01.password.sql
Normal file
|
@ -0,0 +1,10 @@
|
|||
CREATE TABLE {$NAMESPACE}_auth.auth_password (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
phid VARBINARY(64) NOT NULL,
|
||||
objectPHID VARBINARY(64) NOT NULL,
|
||||
passwordType VARCHAR(64) NOT NULL COLLATE {$COLLATE_TEXT},
|
||||
passwordHash VARCHAR(128) NOT NULL COLLATE {$COLLATE_TEXT},
|
||||
isRevoked BOOL NOT NULL,
|
||||
dateCreated INT UNSIGNED NOT NULL,
|
||||
dateModified INT UNSIGNED NOT NULL
|
||||
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
|
|
@ -0,0 +1,19 @@
|
|||
CREATE TABLE {$NAMESPACE}_auth.auth_passwordtransaction (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
phid VARBINARY(64) NOT NULL,
|
||||
authorPHID VARBINARY(64) NOT NULL,
|
||||
objectPHID VARBINARY(64) NOT NULL,
|
||||
viewPolicy VARBINARY(64) NOT NULL,
|
||||
editPolicy VARBINARY(64) NOT NULL,
|
||||
commentPHID VARBINARY(64) DEFAULT NULL,
|
||||
commentVersion INT UNSIGNED NOT NULL,
|
||||
transactionType VARCHAR(32) COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||
oldValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||
newValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||
contentSource LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||
metadata LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||
dateCreated INT UNSIGNED NOT NULL,
|
||||
dateModified INT UNSIGNED NOT NULL,
|
||||
UNIQUE KEY `key_phid` (`phid`),
|
||||
KEY `key_object` (`objectPHID`)
|
||||
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
|
6
resources/sql/autopatches/20180120.auth.03.vcsdata.sql
Normal file
6
resources/sql/autopatches/20180120.auth.03.vcsdata.sql
Normal file
|
@ -0,0 +1,6 @@
|
|||
INSERT INTO {$NAMESPACE}_auth.auth_password
|
||||
(objectPHID, phid, passwordType, passwordHash, isRevoked,
|
||||
dateCreated, dateModified)
|
||||
SELECT userPHID, CONCAT('XVCS', id), 'vcs', passwordHash, 0,
|
||||
dateCreated, dateModified
|
||||
FROM {$NAMESPACE}_repository.repository_vcspassword;
|
24
resources/sql/autopatches/20180120.auth.04.vcsphid.php
Normal file
24
resources/sql/autopatches/20180120.auth.04.vcsphid.php
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
// Populate VCS passwords (which we copied from the old "VCS Password" table
|
||||
// in the last migration) with new PHIDs.
|
||||
|
||||
$table = new PhabricatorAuthPassword();
|
||||
$conn = $table->establishConnection('w');
|
||||
|
||||
$password_type = PhabricatorAuthPasswordPHIDType::TYPECONST;
|
||||
|
||||
foreach (new LiskMigrationIterator($table) as $row) {
|
||||
if (phid_get_type($row->getPHID()) == $password_type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$new_phid = $row->generatePHID();
|
||||
|
||||
queryfx(
|
||||
$conn,
|
||||
'UPDATE %T SET phid = %s WHERE id = %d',
|
||||
$table->getTableName(),
|
||||
$new_phid,
|
||||
$row->getID());
|
||||
}
|
1
resources/sql/autopatches/20180121.auth.01.vcsnuke.sql
Normal file
1
resources/sql/autopatches/20180121.auth.01.vcsnuke.sql
Normal file
|
@ -0,0 +1 @@
|
|||
DROP TABLE {$NAMESPACE}_repository.repository_vcspassword;
|
2
resources/sql/autopatches/20180121.auth.02.passsalt.sql
Normal file
2
resources/sql/autopatches/20180121.auth.02.passsalt.sql
Normal file
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_auth.auth_password
|
||||
ADD passwordSalt VARCHAR(64) NOT NULL COLLATE {$COLLATE_TEXT};
|
|
@ -0,0 +1,7 @@
|
|||
INSERT INTO {$NAMESPACE}_auth.auth_password
|
||||
(objectPHID, phid, passwordType, passwordHash, passwordSalt, isRevoked,
|
||||
dateCreated, dateModified)
|
||||
SELECT phid, CONCAT('XACCOUNT', id), 'account', passwordHash, passwordSalt, 0,
|
||||
dateCreated, dateModified
|
||||
FROM {$NAMESPACE}_user.user
|
||||
WHERE passwordHash != '';
|
24
resources/sql/autopatches/20180121.auth.04.accountphid.php
Normal file
24
resources/sql/autopatches/20180121.auth.04.accountphid.php
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
// Populate account passwords (which we copied from the user table in the last
|
||||
// migration) with new PHIDs.
|
||||
|
||||
$table = new PhabricatorAuthPassword();
|
||||
$conn = $table->establishConnection('w');
|
||||
|
||||
$password_type = PhabricatorAuthPasswordPHIDType::TYPECONST;
|
||||
|
||||
foreach (new LiskMigrationIterator($table) as $row) {
|
||||
if (phid_get_type($row->getPHID()) == $password_type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$new_phid = $row->generatePHID();
|
||||
|
||||
queryfx(
|
||||
$conn,
|
||||
'UPDATE %T SET phid = %s WHERE id = %d',
|
||||
$table->getTableName(),
|
||||
$new_phid,
|
||||
$row->getID());
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
ALTER TABLE {$NAMESPACE}_user.user
|
||||
DROP passwordSalt;
|
||||
|
||||
ALTER TABLE {$NAMESPACE}_user.user
|
||||
DROP passwordHash;
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_auth.auth_password
|
||||
ADD legacyDigestFormat VARCHAR(32) COLLATE {$COLLATE_TEXT};
|
|
@ -0,0 +1,4 @@
|
|||
UPDATE {$NAMESPACE}_auth.auth_password
|
||||
SET legacyDigestFormat = 'v1'
|
||||
WHERE passwordType IN ('vcs', 'account')
|
||||
AND legacyDigestFormat IS NULL;
|
26
resources/sql/autopatches/20180124.herald.01.repetition.sql
Normal file
26
resources/sql/autopatches/20180124.herald.01.repetition.sql
Normal file
|
@ -0,0 +1,26 @@
|
|||
/* This column was previously "uint32?" with these values:
|
||||
|
||||
1: run every time
|
||||
0: run only the first time
|
||||
|
||||
*/
|
||||
|
||||
UPDATE {$NAMESPACE}_herald.herald_rule
|
||||
SET repetitionPolicy = '1'
|
||||
WHERE repetitionPolicy IS NULL;
|
||||
|
||||
ALTER TABLE {$NAMESPACE}_herald.herald_rule
|
||||
CHANGE repetitionPolicy
|
||||
repetitionPolicy VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT};
|
||||
|
||||
/* If the old value was "0", the new value is "first". */
|
||||
|
||||
UPDATE {$NAMESPACE}_herald.herald_rule
|
||||
SET repetitionPolicy = 'first'
|
||||
WHERE repetitionPolicy = '0';
|
||||
|
||||
/* If the old value was anything else, the new value is "every". */
|
||||
|
||||
UPDATE {$NAMESPACE}_herald.herald_rule
|
||||
SET repetitionPolicy = 'every'
|
||||
WHERE repetitionPolicy NOT IN ('first', '0');
|
|
@ -1,39 +1,8 @@
|
|||
<?php
|
||||
|
||||
echo pht('Cleaning up old Herald rule applied rows...')."\n";
|
||||
$table = new HeraldRule();
|
||||
$table->openTransaction();
|
||||
$table->beginReadLocking();
|
||||
// Once, this migration deleted some unnecessary rows written by Herald before
|
||||
// January 2012. These rows don't hurt anything, they just cluttered up the
|
||||
// database a bit.
|
||||
|
||||
$rules = $table->loadAll();
|
||||
foreach ($rules as $key => $rule) {
|
||||
$first_policy = HeraldRepetitionPolicyConfig::toInt(
|
||||
HeraldRepetitionPolicyConfig::FIRST);
|
||||
if ($rule->getRepetitionPolicy() != $first_policy) {
|
||||
unset($rules[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$conn_w = $table->establishConnection('w');
|
||||
|
||||
$clause = '';
|
||||
if ($rules) {
|
||||
$clause = qsprintf(
|
||||
$conn_w,
|
||||
'WHERE ruleID NOT IN (%Ld)',
|
||||
mpull($rules, 'getID'));
|
||||
}
|
||||
|
||||
echo pht('This may take a moment')."\n";
|
||||
do {
|
||||
queryfx(
|
||||
$conn_w,
|
||||
'DELETE FROM %T %Q LIMIT 1000',
|
||||
HeraldRule::TABLE_RULE_APPLIED,
|
||||
$clause);
|
||||
echo '.';
|
||||
} while ($conn_w->getAffectedRows());
|
||||
|
||||
$table->endReadLocking();
|
||||
$table->saveTransaction();
|
||||
echo "\n".pht('Done.')."\n";
|
||||
// The migration was removed in January 2018 to make maintenance on rule
|
||||
// repetition policies easier.
|
||||
|
|
1
scripts/manage_bulk.php
Symbolic link
1
scripts/manage_bulk.php
Symbolic link
|
@ -0,0 +1 @@
|
|||
../scripts/setup/manage_bulk.php
|
21
scripts/setup/manage_bulk.php
Executable file
21
scripts/setup/manage_bulk.php
Executable file
|
@ -0,0 +1,21 @@
|
|||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
$root = dirname(dirname(dirname(__FILE__)));
|
||||
require_once $root.'/scripts/__init_script__.php';
|
||||
|
||||
$args = new PhutilArgumentParser($argv);
|
||||
$args->setTagline(pht('manage bulk jobs'));
|
||||
$args->setSynopsis(<<<EOSYNOPSIS
|
||||
**bulk** __command__ [__options__]
|
||||
Manage and debug bulk jobs.
|
||||
|
||||
EOSYNOPSIS
|
||||
);
|
||||
$args->parseStandardArguments();
|
||||
|
||||
$workflows = id(new PhutilClassMapQuery())
|
||||
->setAncestorClass('PhabricatorBulkManagementWorkflow')
|
||||
->execute();
|
||||
$workflows[] = new PhutilHelpArgumentWorkflow();
|
||||
$args->parseWorkflows($workflows);
|
|
@ -245,7 +245,7 @@ try {
|
|||
}
|
||||
|
||||
$workflow = $parsed_args->parseWorkflows($workflows);
|
||||
$workflow->setUser($user);
|
||||
$workflow->setSSHUser($user);
|
||||
$workflow->setOriginalArguments($original_argv);
|
||||
$workflow->setIsClusterRequest($is_cluster_request);
|
||||
|
||||
|
|
|
@ -112,17 +112,6 @@ if ($is_new) {
|
|||
$create_email = $email;
|
||||
}
|
||||
|
||||
$changed_pass = false;
|
||||
// This disables local echo, so the user's password is not shown as they type
|
||||
// it.
|
||||
phutil_passthru('stty -echo');
|
||||
$password = phutil_console_prompt(
|
||||
pht('Enter a password for this user [blank to leave unchanged]:'));
|
||||
phutil_passthru('stty echo');
|
||||
if (strlen($password)) {
|
||||
$changed_pass = $password;
|
||||
}
|
||||
|
||||
$is_system_agent = $user->getIsSystemAgent();
|
||||
$set_system_agent = phutil_console_confirm(
|
||||
pht('Is this user a bot?'),
|
||||
|
@ -158,10 +147,6 @@ printf($tpl, pht('Real Name'), $original->getRealName(), $user->getRealName());
|
|||
if ($is_new) {
|
||||
printf($tpl, pht('Email'), '', $create_email);
|
||||
}
|
||||
printf($tpl, pht('Password'), null,
|
||||
($changed_pass !== false)
|
||||
? pht('Updated')
|
||||
: pht('Unchanged'));
|
||||
|
||||
printf(
|
||||
$tpl,
|
||||
|
@ -218,11 +203,6 @@ $user->openTransaction();
|
|||
$editor->makeAdminUser($user, $set_admin);
|
||||
$editor->makeSystemAgentUser($user, $set_system_agent);
|
||||
|
||||
if ($changed_pass !== false) {
|
||||
$envelope = new PhutilOpaqueEnvelope($changed_pass);
|
||||
$editor->changePassword($user, $envelope);
|
||||
}
|
||||
|
||||
$user->saveTransaction();
|
||||
|
||||
echo pht('Saved changes.')."\n";
|
||||
|
|
|
@ -222,6 +222,12 @@ phutil_register_library_map(array(
|
|||
'AuditConduitAPIMethod' => 'applications/audit/conduit/AuditConduitAPIMethod.php',
|
||||
'AuditQueryConduitAPIMethod' => 'applications/audit/conduit/AuditQueryConduitAPIMethod.php',
|
||||
'AuthManageProvidersCapability' => 'applications/auth/capability/AuthManageProvidersCapability.php',
|
||||
'BulkParameterType' => 'applications/transactions/bulk/type/BulkParameterType.php',
|
||||
'BulkPointsParameterType' => 'applications/transactions/bulk/type/BulkPointsParameterType.php',
|
||||
'BulkRemarkupParameterType' => 'applications/transactions/bulk/type/BulkRemarkupParameterType.php',
|
||||
'BulkSelectParameterType' => 'applications/transactions/bulk/type/BulkSelectParameterType.php',
|
||||
'BulkStringParameterType' => 'applications/transactions/bulk/type/BulkStringParameterType.php',
|
||||
'BulkTokenizerParameterType' => 'applications/transactions/bulk/type/BulkTokenizerParameterType.php',
|
||||
'CalendarTimeUtil' => 'applications/calendar/util/CalendarTimeUtil.php',
|
||||
'CalendarTimeUtilTestCase' => 'applications/calendar/__tests__/CalendarTimeUtilTestCase.php',
|
||||
'CelerityAPI' => 'applications/celerity/CelerityAPI.php',
|
||||
|
@ -584,6 +590,7 @@ phutil_register_library_map(array(
|
|||
'DifferentialRevisionStatus' => 'applications/differential/constants/DifferentialRevisionStatus.php',
|
||||
'DifferentialRevisionStatusDatasource' => 'applications/differential/typeahead/DifferentialRevisionStatusDatasource.php',
|
||||
'DifferentialRevisionStatusFunctionDatasource' => 'applications/differential/typeahead/DifferentialRevisionStatusFunctionDatasource.php',
|
||||
'DifferentialRevisionStatusHeraldField' => 'applications/differential/herald/DifferentialRevisionStatusHeraldField.php',
|
||||
'DifferentialRevisionStatusTransaction' => 'applications/differential/xaction/DifferentialRevisionStatusTransaction.php',
|
||||
'DifferentialRevisionSummaryHeraldField' => 'applications/differential/herald/DifferentialRevisionSummaryHeraldField.php',
|
||||
'DifferentialRevisionSummaryTransaction' => 'applications/differential/xaction/DifferentialRevisionSummaryTransaction.php',
|
||||
|
@ -758,6 +765,7 @@ phutil_register_library_map(array(
|
|||
'DiffusionLintCountQuery' => 'applications/diffusion/query/DiffusionLintCountQuery.php',
|
||||
'DiffusionLintSaveRunner' => 'applications/diffusion/DiffusionLintSaveRunner.php',
|
||||
'DiffusionLocalRepositoryFilter' => 'applications/diffusion/data/DiffusionLocalRepositoryFilter.php',
|
||||
'DiffusionLogController' => 'applications/diffusion/controller/DiffusionLogController.php',
|
||||
'DiffusionLookSoonConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionLookSoonConduitAPIMethod.php',
|
||||
'DiffusionLowLevelCommitFieldsQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelCommitFieldsQuery.php',
|
||||
'DiffusionLowLevelCommitQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelCommitQuery.php',
|
||||
|
@ -825,9 +833,11 @@ phutil_register_library_map(array(
|
|||
'DiffusionPreCommitRefTypeHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitRefTypeHeraldField.php',
|
||||
'DiffusionPreCommitUsesGitLFSHeraldField' => 'applications/diffusion/herald/DiffusionPreCommitUsesGitLFSHeraldField.php',
|
||||
'DiffusionPullEventGarbageCollector' => 'applications/diffusion/garbagecollector/DiffusionPullEventGarbageCollector.php',
|
||||
'DiffusionPullLogListController' => 'applications/diffusion/controller/DiffusionPullLogListController.php',
|
||||
'DiffusionPullLogListView' => 'applications/diffusion/view/DiffusionPullLogListView.php',
|
||||
'DiffusionPullLogSearchEngine' => 'applications/diffusion/query/DiffusionPullLogSearchEngine.php',
|
||||
'DiffusionPushCapability' => 'applications/diffusion/capability/DiffusionPushCapability.php',
|
||||
'DiffusionPushEventViewController' => 'applications/diffusion/controller/DiffusionPushEventViewController.php',
|
||||
'DiffusionPushLogController' => 'applications/diffusion/controller/DiffusionPushLogController.php',
|
||||
'DiffusionPushLogListController' => 'applications/diffusion/controller/DiffusionPushLogListController.php',
|
||||
'DiffusionPushLogListView' => 'applications/diffusion/view/DiffusionPushLogListView.php',
|
||||
'DiffusionPythonExternalSymbolsSource' => 'applications/diffusion/symbol/DiffusionPythonExternalSymbolsSource.php',
|
||||
|
@ -1351,7 +1361,9 @@ phutil_register_library_map(array(
|
|||
'HeraldConditionTranscript' => 'applications/herald/storage/transcript/HeraldConditionTranscript.php',
|
||||
'HeraldContentSourceField' => 'applications/herald/field/HeraldContentSourceField.php',
|
||||
'HeraldController' => 'applications/herald/controller/HeraldController.php',
|
||||
'HeraldCoreStateReasons' => 'applications/herald/state/HeraldCoreStateReasons.php',
|
||||
'HeraldDAO' => 'applications/herald/storage/HeraldDAO.php',
|
||||
'HeraldDeprecatedFieldGroup' => 'applications/herald/field/HeraldDeprecatedFieldGroup.php',
|
||||
'HeraldDifferentialAdapter' => 'applications/differential/herald/HeraldDifferentialAdapter.php',
|
||||
'HeraldDifferentialDiffAdapter' => 'applications/differential/herald/HeraldDifferentialDiffAdapter.php',
|
||||
'HeraldDifferentialRevisionAdapter' => 'applications/differential/herald/HeraldDifferentialRevisionAdapter.php',
|
||||
|
@ -1389,7 +1401,6 @@ phutil_register_library_map(array(
|
|||
'HeraldRelatedFieldGroup' => 'applications/herald/field/HeraldRelatedFieldGroup.php',
|
||||
'HeraldRemarkupFieldValue' => 'applications/herald/value/HeraldRemarkupFieldValue.php',
|
||||
'HeraldRemarkupRule' => 'applications/herald/remarkup/HeraldRemarkupRule.php',
|
||||
'HeraldRepetitionPolicyConfig' => 'applications/herald/config/HeraldRepetitionPolicyConfig.php',
|
||||
'HeraldRule' => 'applications/herald/storage/HeraldRule.php',
|
||||
'HeraldRuleController' => 'applications/herald/controller/HeraldRuleController.php',
|
||||
'HeraldRuleDatasource' => 'applications/herald/typeahead/HeraldRuleDatasource.php',
|
||||
|
@ -1487,8 +1498,8 @@ phutil_register_library_map(array(
|
|||
'MacroQueryConduitAPIMethod' => 'applications/macro/conduit/MacroQueryConduitAPIMethod.php',
|
||||
'ManiphestAssignEmailCommand' => 'applications/maniphest/command/ManiphestAssignEmailCommand.php',
|
||||
'ManiphestAssigneeDatasource' => 'applications/maniphest/typeahead/ManiphestAssigneeDatasource.php',
|
||||
'ManiphestBatchEditController' => 'applications/maniphest/controller/ManiphestBatchEditController.php',
|
||||
'ManiphestBulkEditCapability' => 'applications/maniphest/capability/ManiphestBulkEditCapability.php',
|
||||
'ManiphestBulkEditController' => 'applications/maniphest/controller/ManiphestBulkEditController.php',
|
||||
'ManiphestClaimEmailCommand' => 'applications/maniphest/command/ManiphestClaimEmailCommand.php',
|
||||
'ManiphestCloseEmailCommand' => 'applications/maniphest/command/ManiphestCloseEmailCommand.php',
|
||||
'ManiphestConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestConduitAPIMethod.php',
|
||||
|
@ -1547,6 +1558,7 @@ phutil_register_library_map(array(
|
|||
'ManiphestTaskAttachTransaction' => 'applications/maniphest/xaction/ManiphestTaskAttachTransaction.php',
|
||||
'ManiphestTaskAuthorHeraldField' => 'applications/maniphest/herald/ManiphestTaskAuthorHeraldField.php',
|
||||
'ManiphestTaskAuthorPolicyRule' => 'applications/maniphest/policyrule/ManiphestTaskAuthorPolicyRule.php',
|
||||
'ManiphestTaskBulkEngine' => 'applications/maniphest/bulk/ManiphestTaskBulkEngine.php',
|
||||
'ManiphestTaskCloseAsDuplicateRelationship' => 'applications/maniphest/relationship/ManiphestTaskCloseAsDuplicateRelationship.php',
|
||||
'ManiphestTaskClosedStatusDatasource' => 'applications/maniphest/typeahead/ManiphestTaskClosedStatusDatasource.php',
|
||||
'ManiphestTaskCoverImageTransaction' => 'applications/maniphest/xaction/ManiphestTaskCoverImageTransaction.php',
|
||||
|
@ -1556,7 +1568,6 @@ phutil_register_library_map(array(
|
|||
'ManiphestTaskDescriptionTransaction' => 'applications/maniphest/xaction/ManiphestTaskDescriptionTransaction.php',
|
||||
'ManiphestTaskDetailController' => 'applications/maniphest/controller/ManiphestTaskDetailController.php',
|
||||
'ManiphestTaskEdgeTransaction' => 'applications/maniphest/xaction/ManiphestTaskEdgeTransaction.php',
|
||||
'ManiphestTaskEditBulkJobType' => 'applications/maniphest/bulk/ManiphestTaskEditBulkJobType.php',
|
||||
'ManiphestTaskEditController' => 'applications/maniphest/controller/ManiphestTaskEditController.php',
|
||||
'ManiphestTaskEditEngineLock' => 'applications/maniphest/editor/ManiphestTaskEditEngineLock.php',
|
||||
'ManiphestTaskFerretEngine' => 'applications/maniphest/search/ManiphestTaskFerretEngine.php',
|
||||
|
@ -2026,6 +2037,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorAuthApplication' => 'applications/auth/application/PhabricatorAuthApplication.php',
|
||||
'PhabricatorAuthAuthFactorPHIDType' => 'applications/auth/phid/PhabricatorAuthAuthFactorPHIDType.php',
|
||||
'PhabricatorAuthAuthProviderPHIDType' => 'applications/auth/phid/PhabricatorAuthAuthProviderPHIDType.php',
|
||||
'PhabricatorAuthChangePasswordAction' => 'applications/auth/action/PhabricatorAuthChangePasswordAction.php',
|
||||
'PhabricatorAuthConduitAPIMethod' => 'applications/auth/conduit/PhabricatorAuthConduitAPIMethod.php',
|
||||
'PhabricatorAuthConduitTokenRevoker' => 'applications/auth/revoker/PhabricatorAuthConduitTokenRevoker.php',
|
||||
'PhabricatorAuthConfirmLinkController' => 'applications/auth/controller/PhabricatorAuthConfirmLinkController.php',
|
||||
|
@ -2082,7 +2094,21 @@ phutil_register_library_map(array(
|
|||
'PhabricatorAuthOldOAuthRedirectController' => 'applications/auth/controller/PhabricatorAuthOldOAuthRedirectController.php',
|
||||
'PhabricatorAuthOneTimeLoginController' => 'applications/auth/controller/PhabricatorAuthOneTimeLoginController.php',
|
||||
'PhabricatorAuthOneTimeLoginTemporaryTokenType' => 'applications/auth/tokentype/PhabricatorAuthOneTimeLoginTemporaryTokenType.php',
|
||||
'PhabricatorAuthPassword' => 'applications/auth/storage/PhabricatorAuthPassword.php',
|
||||
'PhabricatorAuthPasswordEditor' => 'applications/auth/editor/PhabricatorAuthPasswordEditor.php',
|
||||
'PhabricatorAuthPasswordEngine' => 'applications/auth/engine/PhabricatorAuthPasswordEngine.php',
|
||||
'PhabricatorAuthPasswordException' => 'applications/auth/password/PhabricatorAuthPasswordException.php',
|
||||
'PhabricatorAuthPasswordHashInterface' => 'applications/auth/password/PhabricatorAuthPasswordHashInterface.php',
|
||||
'PhabricatorAuthPasswordPHIDType' => 'applications/auth/phid/PhabricatorAuthPasswordPHIDType.php',
|
||||
'PhabricatorAuthPasswordQuery' => 'applications/auth/query/PhabricatorAuthPasswordQuery.php',
|
||||
'PhabricatorAuthPasswordResetTemporaryTokenType' => 'applications/auth/tokentype/PhabricatorAuthPasswordResetTemporaryTokenType.php',
|
||||
'PhabricatorAuthPasswordRevokeTransaction' => 'applications/auth/xaction/PhabricatorAuthPasswordRevokeTransaction.php',
|
||||
'PhabricatorAuthPasswordRevoker' => 'applications/auth/revoker/PhabricatorAuthPasswordRevoker.php',
|
||||
'PhabricatorAuthPasswordTestCase' => 'applications/auth/__tests__/PhabricatorAuthPasswordTestCase.php',
|
||||
'PhabricatorAuthPasswordTransaction' => 'applications/auth/storage/PhabricatorAuthPasswordTransaction.php',
|
||||
'PhabricatorAuthPasswordTransactionQuery' => 'applications/auth/query/PhabricatorAuthPasswordTransactionQuery.php',
|
||||
'PhabricatorAuthPasswordTransactionType' => 'applications/auth/xaction/PhabricatorAuthPasswordTransactionType.php',
|
||||
'PhabricatorAuthPasswordUpgradeTransaction' => 'applications/auth/xaction/PhabricatorAuthPasswordUpgradeTransaction.php',
|
||||
'PhabricatorAuthProvider' => 'applications/auth/provider/PhabricatorAuthProvider.php',
|
||||
'PhabricatorAuthProviderConfig' => 'applications/auth/storage/PhabricatorAuthProviderConfig.php',
|
||||
'PhabricatorAuthProviderConfigController' => 'applications/auth/controller/config/PhabricatorAuthProviderConfigController.php',
|
||||
|
@ -2098,7 +2124,6 @@ phutil_register_library_map(array(
|
|||
'PhabricatorAuthRevoker' => 'applications/auth/revoker/PhabricatorAuthRevoker.php',
|
||||
'PhabricatorAuthSSHKey' => 'applications/auth/storage/PhabricatorAuthSSHKey.php',
|
||||
'PhabricatorAuthSSHKeyController' => 'applications/auth/controller/PhabricatorAuthSSHKeyController.php',
|
||||
'PhabricatorAuthSSHKeyDeactivateController' => 'applications/auth/controller/PhabricatorAuthSSHKeyDeactivateController.php',
|
||||
'PhabricatorAuthSSHKeyEditController' => 'applications/auth/controller/PhabricatorAuthSSHKeyEditController.php',
|
||||
'PhabricatorAuthSSHKeyEditor' => 'applications/auth/editor/PhabricatorAuthSSHKeyEditor.php',
|
||||
'PhabricatorAuthSSHKeyGenerateController' => 'applications/auth/controller/PhabricatorAuthSSHKeyGenerateController.php',
|
||||
|
@ -2106,12 +2131,15 @@ phutil_register_library_map(array(
|
|||
'PhabricatorAuthSSHKeyPHIDType' => 'applications/auth/phid/PhabricatorAuthSSHKeyPHIDType.php',
|
||||
'PhabricatorAuthSSHKeyQuery' => 'applications/auth/query/PhabricatorAuthSSHKeyQuery.php',
|
||||
'PhabricatorAuthSSHKeyReplyHandler' => 'applications/auth/mail/PhabricatorAuthSSHKeyReplyHandler.php',
|
||||
'PhabricatorAuthSSHKeyRevokeController' => 'applications/auth/controller/PhabricatorAuthSSHKeyRevokeController.php',
|
||||
'PhabricatorAuthSSHKeySearchEngine' => 'applications/auth/query/PhabricatorAuthSSHKeySearchEngine.php',
|
||||
'PhabricatorAuthSSHKeyTableView' => 'applications/auth/view/PhabricatorAuthSSHKeyTableView.php',
|
||||
'PhabricatorAuthSSHKeyTestCase' => 'applications/auth/__tests__/PhabricatorAuthSSHKeyTestCase.php',
|
||||
'PhabricatorAuthSSHKeyTransaction' => 'applications/auth/storage/PhabricatorAuthSSHKeyTransaction.php',
|
||||
'PhabricatorAuthSSHKeyTransactionQuery' => 'applications/auth/query/PhabricatorAuthSSHKeyTransactionQuery.php',
|
||||
'PhabricatorAuthSSHKeyViewController' => 'applications/auth/controller/PhabricatorAuthSSHKeyViewController.php',
|
||||
'PhabricatorAuthSSHPublicKey' => 'applications/auth/sshkey/PhabricatorAuthSSHPublicKey.php',
|
||||
'PhabricatorAuthSSHRevoker' => 'applications/auth/revoker/PhabricatorAuthSSHRevoker.php',
|
||||
'PhabricatorAuthSession' => 'applications/auth/storage/PhabricatorAuthSession.php',
|
||||
'PhabricatorAuthSessionEngine' => 'applications/auth/engine/PhabricatorAuthSessionEngine.php',
|
||||
'PhabricatorAuthSessionEngineExtension' => 'applications/auth/engine/PhabricatorAuthSessionEngineExtension.php',
|
||||
|
@ -2119,6 +2147,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorAuthSessionGarbageCollector' => 'applications/auth/garbagecollector/PhabricatorAuthSessionGarbageCollector.php',
|
||||
'PhabricatorAuthSessionInfo' => 'applications/auth/data/PhabricatorAuthSessionInfo.php',
|
||||
'PhabricatorAuthSessionQuery' => 'applications/auth/query/PhabricatorAuthSessionQuery.php',
|
||||
'PhabricatorAuthSessionRevoker' => 'applications/auth/revoker/PhabricatorAuthSessionRevoker.php',
|
||||
'PhabricatorAuthSetPasswordController' => 'applications/auth/controller/PhabricatorAuthSetPasswordController.php',
|
||||
'PhabricatorAuthSetupCheck' => 'applications/config/check/PhabricatorAuthSetupCheck.php',
|
||||
'PhabricatorAuthStartController' => 'applications/auth/controller/PhabricatorAuthStartController.php',
|
||||
|
@ -2126,6 +2155,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorAuthTemporaryToken' => 'applications/auth/storage/PhabricatorAuthTemporaryToken.php',
|
||||
'PhabricatorAuthTemporaryTokenGarbageCollector' => 'applications/auth/garbagecollector/PhabricatorAuthTemporaryTokenGarbageCollector.php',
|
||||
'PhabricatorAuthTemporaryTokenQuery' => 'applications/auth/query/PhabricatorAuthTemporaryTokenQuery.php',
|
||||
'PhabricatorAuthTemporaryTokenRevoker' => 'applications/auth/revoker/PhabricatorAuthTemporaryTokenRevoker.php',
|
||||
'PhabricatorAuthTemporaryTokenType' => 'applications/auth/tokentype/PhabricatorAuthTemporaryTokenType.php',
|
||||
'PhabricatorAuthTemporaryTokenTypeModule' => 'applications/auth/tokentype/PhabricatorAuthTemporaryTokenTypeModule.php',
|
||||
'PhabricatorAuthTerminateSessionController' => 'applications/auth/controller/PhabricatorAuthTerminateSessionController.php',
|
||||
|
@ -2198,6 +2228,11 @@ phutil_register_library_map(array(
|
|||
'PhabricatorBuiltinFileCachePurger' => 'applications/cache/purger/PhabricatorBuiltinFileCachePurger.php',
|
||||
'PhabricatorBuiltinPatchList' => 'infrastructure/storage/patch/PhabricatorBuiltinPatchList.php',
|
||||
'PhabricatorBulkContentSource' => 'infrastructure/daemon/contentsource/PhabricatorBulkContentSource.php',
|
||||
'PhabricatorBulkEditGroup' => 'applications/transactions/bulk/PhabricatorBulkEditGroup.php',
|
||||
'PhabricatorBulkEngine' => 'applications/transactions/bulk/PhabricatorBulkEngine.php',
|
||||
'PhabricatorBulkManagementMakeSilentWorkflow' => 'applications/transactions/bulk/management/PhabricatorBulkManagementMakeSilentWorkflow.php',
|
||||
'PhabricatorBulkManagementWorkflow' => 'applications/transactions/bulk/management/PhabricatorBulkManagementWorkflow.php',
|
||||
'PhabricatorCSVExportFormat' => 'infrastructure/export/PhabricatorCSVExportFormat.php',
|
||||
'PhabricatorCacheDAO' => 'applications/cache/storage/PhabricatorCacheDAO.php',
|
||||
'PhabricatorCacheEngine' => 'applications/system/engine/PhabricatorCacheEngine.php',
|
||||
'PhabricatorCacheEngineExtension' => 'applications/system/engine/PhabricatorCacheEngineExtension.php',
|
||||
|
@ -2727,6 +2762,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorEdgesDestructionEngineExtension' => 'infrastructure/edges/engineextension/PhabricatorEdgesDestructionEngineExtension.php',
|
||||
'PhabricatorEditEngine' => 'applications/transactions/editengine/PhabricatorEditEngine.php',
|
||||
'PhabricatorEditEngineAPIMethod' => 'applications/transactions/editengine/PhabricatorEditEngineAPIMethod.php',
|
||||
'PhabricatorEditEngineBulkJobType' => 'applications/transactions/bulk/PhabricatorEditEngineBulkJobType.php',
|
||||
'PhabricatorEditEngineCheckboxesCommentAction' => 'applications/transactions/commentaction/PhabricatorEditEngineCheckboxesCommentAction.php',
|
||||
'PhabricatorEditEngineColumnsCommentAction' => 'applications/transactions/commentaction/PhabricatorEditEngineColumnsCommentAction.php',
|
||||
'PhabricatorEditEngineCommentAction' => 'applications/transactions/commentaction/PhabricatorEditEngineCommentAction.php',
|
||||
|
@ -2802,12 +2838,15 @@ phutil_register_library_map(array(
|
|||
'PhabricatorEnv' => 'infrastructure/env/PhabricatorEnv.php',
|
||||
'PhabricatorEnvTestCase' => 'infrastructure/env/__tests__/PhabricatorEnvTestCase.php',
|
||||
'PhabricatorEpochEditField' => 'applications/transactions/editfield/PhabricatorEpochEditField.php',
|
||||
'PhabricatorEpochExportField' => 'infrastructure/export/PhabricatorEpochExportField.php',
|
||||
'PhabricatorEvent' => 'infrastructure/events/PhabricatorEvent.php',
|
||||
'PhabricatorEventEngine' => 'infrastructure/events/PhabricatorEventEngine.php',
|
||||
'PhabricatorEventListener' => 'infrastructure/events/PhabricatorEventListener.php',
|
||||
'PhabricatorEventType' => 'infrastructure/events/constant/PhabricatorEventType.php',
|
||||
'PhabricatorExampleEventListener' => 'infrastructure/events/PhabricatorExampleEventListener.php',
|
||||
'PhabricatorExecFutureFileUploadSource' => 'applications/files/uploadsource/PhabricatorExecFutureFileUploadSource.php',
|
||||
'PhabricatorExportField' => 'infrastructure/export/PhabricatorExportField.php',
|
||||
'PhabricatorExportFormat' => 'infrastructure/export/PhabricatorExportFormat.php',
|
||||
'PhabricatorExtendedPolicyInterface' => 'applications/policy/interface/PhabricatorExtendedPolicyInterface.php',
|
||||
'PhabricatorExtendingPhabricatorConfigOptions' => 'applications/config/option/PhabricatorExtendingPhabricatorConfigOptions.php',
|
||||
'PhabricatorExtensionsSetupCheck' => 'applications/config/check/PhabricatorExtensionsSetupCheck.php',
|
||||
|
@ -2927,6 +2966,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorFileUploadDialogController' => 'applications/files/controller/PhabricatorFileUploadDialogController.php',
|
||||
'PhabricatorFileUploadException' => 'applications/files/exception/PhabricatorFileUploadException.php',
|
||||
'PhabricatorFileUploadSource' => 'applications/files/uploadsource/PhabricatorFileUploadSource.php',
|
||||
'PhabricatorFileUploadSourceByteLimitException' => 'applications/files/uploadsource/PhabricatorFileUploadSourceByteLimitException.php',
|
||||
'PhabricatorFileinfoSetupCheck' => 'applications/config/check/PhabricatorFileinfoSetupCheck.php',
|
||||
'PhabricatorFilesApplication' => 'applications/files/application/PhabricatorFilesApplication.php',
|
||||
'PhabricatorFilesApplicationStorageEnginePanel' => 'applications/files/applicationpanel/PhabricatorFilesApplicationStorageEnginePanel.php',
|
||||
|
@ -3026,6 +3066,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorHomeProfileMenuItem' => 'applications/home/menuitem/PhabricatorHomeProfileMenuItem.php',
|
||||
'PhabricatorHovercardEngineExtension' => 'applications/search/engineextension/PhabricatorHovercardEngineExtension.php',
|
||||
'PhabricatorHovercardEngineExtensionModule' => 'applications/search/engineextension/PhabricatorHovercardEngineExtensionModule.php',
|
||||
'PhabricatorIDExportField' => 'infrastructure/export/PhabricatorIDExportField.php',
|
||||
'PhabricatorIDsSearchEngineExtension' => 'applications/search/engineextension/PhabricatorIDsSearchEngineExtension.php',
|
||||
'PhabricatorIDsSearchField' => 'applications/search/field/PhabricatorIDsSearchField.php',
|
||||
'PhabricatorIconDatasource' => 'applications/files/typeahead/PhabricatorIconDatasource.php',
|
||||
|
@ -3049,6 +3090,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorInlineSummaryView' => 'infrastructure/diff/view/PhabricatorInlineSummaryView.php',
|
||||
'PhabricatorInstructionsEditField' => 'applications/transactions/editfield/PhabricatorInstructionsEditField.php',
|
||||
'PhabricatorIntConfigType' => 'applications/config/type/PhabricatorIntConfigType.php',
|
||||
'PhabricatorIntExportField' => 'infrastructure/export/PhabricatorIntExportField.php',
|
||||
'PhabricatorInternalSetting' => 'applications/settings/setting/PhabricatorInternalSetting.php',
|
||||
'PhabricatorInternationalizationManagementExtractWorkflow' => 'infrastructure/internationalization/management/PhabricatorInternationalizationManagementExtractWorkflow.php',
|
||||
'PhabricatorInternationalizationManagementWorkflow' => 'infrastructure/internationalization/management/PhabricatorInternationalizationManagementWorkflow.php',
|
||||
|
@ -3058,6 +3100,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorIteratorFileUploadSource' => 'applications/files/uploadsource/PhabricatorIteratorFileUploadSource.php',
|
||||
'PhabricatorJIRAAuthProvider' => 'applications/auth/provider/PhabricatorJIRAAuthProvider.php',
|
||||
'PhabricatorJSONConfigType' => 'applications/config/type/PhabricatorJSONConfigType.php',
|
||||
'PhabricatorJSONExportFormat' => 'infrastructure/export/PhabricatorJSONExportFormat.php',
|
||||
'PhabricatorJavelinLinter' => 'infrastructure/lint/linter/PhabricatorJavelinLinter.php',
|
||||
'PhabricatorJiraIssueHasObjectEdgeType' => 'applications/doorkeeper/edge/PhabricatorJiraIssueHasObjectEdgeType.php',
|
||||
'PhabricatorJumpNavHandler' => 'applications/search/engine/PhabricatorJumpNavHandler.php',
|
||||
|
@ -3377,6 +3420,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorPHDConfigOptions' => 'applications/config/option/PhabricatorPHDConfigOptions.php',
|
||||
'PhabricatorPHID' => 'applications/phid/storage/PhabricatorPHID.php',
|
||||
'PhabricatorPHIDConstants' => 'applications/phid/PhabricatorPHIDConstants.php',
|
||||
'PhabricatorPHIDExportField' => 'infrastructure/export/PhabricatorPHIDExportField.php',
|
||||
'PhabricatorPHIDInterface' => 'applications/phid/interface/PhabricatorPHIDInterface.php',
|
||||
'PhabricatorPHIDListEditField' => 'applications/transactions/editfield/PhabricatorPHIDListEditField.php',
|
||||
'PhabricatorPHIDListEditType' => 'applications/transactions/edittype/PhabricatorPHIDListEditType.php',
|
||||
|
@ -3465,6 +3509,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorPagerUIExample' => 'applications/uiexample/examples/PhabricatorPagerUIExample.php',
|
||||
'PhabricatorPassphraseApplication' => 'applications/passphrase/application/PhabricatorPassphraseApplication.php',
|
||||
'PhabricatorPasswordAuthProvider' => 'applications/auth/provider/PhabricatorPasswordAuthProvider.php',
|
||||
'PhabricatorPasswordDestructionEngineExtension' => 'applications/auth/extension/PhabricatorPasswordDestructionEngineExtension.php',
|
||||
'PhabricatorPasswordHasher' => 'infrastructure/util/password/PhabricatorPasswordHasher.php',
|
||||
'PhabricatorPasswordHasherTestCase' => 'infrastructure/util/password/__tests__/PhabricatorPasswordHasherTestCase.php',
|
||||
'PhabricatorPasswordHasherUnavailableException' => 'infrastructure/util/password/PhabricatorPasswordHasherUnavailableException.php',
|
||||
|
@ -3915,7 +3960,6 @@ phutil_register_library_map(array(
|
|||
'PhabricatorRepositoryURITestCase' => 'applications/repository/storage/__tests__/PhabricatorRepositoryURITestCase.php',
|
||||
'PhabricatorRepositoryURITransaction' => 'applications/repository/storage/PhabricatorRepositoryURITransaction.php',
|
||||
'PhabricatorRepositoryURITransactionQuery' => 'applications/repository/query/PhabricatorRepositoryURITransactionQuery.php',
|
||||
'PhabricatorRepositoryVCSPassword' => 'applications/repository/storage/PhabricatorRepositoryVCSPassword.php',
|
||||
'PhabricatorRepositoryWorkingCopyVersion' => 'applications/repository/storage/PhabricatorRepositoryWorkingCopyVersion.php',
|
||||
'PhabricatorRequestExceptionHandler' => 'aphront/handler/PhabricatorRequestExceptionHandler.php',
|
||||
'PhabricatorResourceSite' => 'aphront/site/PhabricatorResourceSite.php',
|
||||
|
@ -4142,6 +4186,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorStorageSchemaSpec' => 'infrastructure/storage/schema/PhabricatorStorageSchemaSpec.php',
|
||||
'PhabricatorStorageSetupCheck' => 'applications/config/check/PhabricatorStorageSetupCheck.php',
|
||||
'PhabricatorStringConfigType' => 'applications/config/type/PhabricatorStringConfigType.php',
|
||||
'PhabricatorStringExportField' => 'infrastructure/export/PhabricatorStringExportField.php',
|
||||
'PhabricatorStringListConfigType' => 'applications/config/type/PhabricatorStringListConfigType.php',
|
||||
'PhabricatorStringListEditField' => 'applications/transactions/editfield/PhabricatorStringListEditField.php',
|
||||
'PhabricatorStringSetting' => 'applications/settings/setting/PhabricatorStringSetting.php',
|
||||
|
@ -4205,6 +4250,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorTextAreaEditField' => 'applications/transactions/editfield/PhabricatorTextAreaEditField.php',
|
||||
'PhabricatorTextConfigType' => 'applications/config/type/PhabricatorTextConfigType.php',
|
||||
'PhabricatorTextEditField' => 'applications/transactions/editfield/PhabricatorTextEditField.php',
|
||||
'PhabricatorTextExportFormat' => 'infrastructure/export/PhabricatorTextExportFormat.php',
|
||||
'PhabricatorTextListConfigType' => 'applications/config/type/PhabricatorTextListConfigType.php',
|
||||
'PhabricatorTime' => 'infrastructure/time/PhabricatorTime.php',
|
||||
'PhabricatorTimeFormatSetting' => 'applications/settings/setting/PhabricatorTimeFormatSetting.php',
|
||||
|
@ -5239,6 +5285,12 @@ phutil_register_library_map(array(
|
|||
'AuditConduitAPIMethod' => 'ConduitAPIMethod',
|
||||
'AuditQueryConduitAPIMethod' => 'AuditConduitAPIMethod',
|
||||
'AuthManageProvidersCapability' => 'PhabricatorPolicyCapability',
|
||||
'BulkParameterType' => 'Phobject',
|
||||
'BulkPointsParameterType' => 'BulkParameterType',
|
||||
'BulkRemarkupParameterType' => 'BulkParameterType',
|
||||
'BulkSelectParameterType' => 'BulkParameterType',
|
||||
'BulkStringParameterType' => 'BulkParameterType',
|
||||
'BulkTokenizerParameterType' => 'BulkParameterType',
|
||||
'CalendarTimeUtil' => 'Phobject',
|
||||
'CalendarTimeUtilTestCase' => 'PhabricatorTestCase',
|
||||
'CelerityAPI' => 'Phobject',
|
||||
|
@ -5650,6 +5702,7 @@ phutil_register_library_map(array(
|
|||
'DifferentialRevisionStatus' => 'Phobject',
|
||||
'DifferentialRevisionStatusDatasource' => 'PhabricatorTypeaheadDatasource',
|
||||
'DifferentialRevisionStatusFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
||||
'DifferentialRevisionStatusHeraldField' => 'DifferentialRevisionHeraldField',
|
||||
'DifferentialRevisionStatusTransaction' => 'DifferentialRevisionTransactionType',
|
||||
'DifferentialRevisionSummaryHeraldField' => 'DifferentialRevisionHeraldField',
|
||||
'DifferentialRevisionSummaryTransaction' => 'DifferentialRevisionTransactionType',
|
||||
|
@ -5827,6 +5880,7 @@ phutil_register_library_map(array(
|
|||
'DiffusionLintCountQuery' => 'PhabricatorQuery',
|
||||
'DiffusionLintSaveRunner' => 'Phobject',
|
||||
'DiffusionLocalRepositoryFilter' => 'Phobject',
|
||||
'DiffusionLogController' => 'DiffusionController',
|
||||
'DiffusionLookSoonConduitAPIMethod' => 'DiffusionConduitAPIMethod',
|
||||
'DiffusionLowLevelCommitFieldsQuery' => 'DiffusionLowLevelQuery',
|
||||
'DiffusionLowLevelCommitQuery' => 'DiffusionLowLevelQuery',
|
||||
|
@ -5894,10 +5948,12 @@ phutil_register_library_map(array(
|
|||
'DiffusionPreCommitRefTypeHeraldField' => 'DiffusionPreCommitRefHeraldField',
|
||||
'DiffusionPreCommitUsesGitLFSHeraldField' => 'DiffusionPreCommitContentHeraldField',
|
||||
'DiffusionPullEventGarbageCollector' => 'PhabricatorGarbageCollector',
|
||||
'DiffusionPullLogListController' => 'DiffusionLogController',
|
||||
'DiffusionPullLogListView' => 'AphrontView',
|
||||
'DiffusionPullLogSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||
'DiffusionPushCapability' => 'PhabricatorPolicyCapability',
|
||||
'DiffusionPushEventViewController' => 'DiffusionPushLogController',
|
||||
'DiffusionPushLogController' => 'DiffusionController',
|
||||
'DiffusionPushLogListController' => 'DiffusionPushLogController',
|
||||
'DiffusionPushEventViewController' => 'DiffusionLogController',
|
||||
'DiffusionPushLogListController' => 'DiffusionLogController',
|
||||
'DiffusionPushLogListView' => 'AphrontView',
|
||||
'DiffusionPythonExternalSymbolsSource' => 'DiffusionExternalSymbolsSource',
|
||||
'DiffusionQuery' => 'PhabricatorQuery',
|
||||
|
@ -6516,7 +6572,9 @@ phutil_register_library_map(array(
|
|||
'HeraldConditionTranscript' => 'Phobject',
|
||||
'HeraldContentSourceField' => 'HeraldField',
|
||||
'HeraldController' => 'PhabricatorController',
|
||||
'HeraldCoreStateReasons' => 'HeraldStateReasons',
|
||||
'HeraldDAO' => 'PhabricatorLiskDAO',
|
||||
'HeraldDeprecatedFieldGroup' => 'HeraldFieldGroup',
|
||||
'HeraldDifferentialAdapter' => 'HeraldAdapter',
|
||||
'HeraldDifferentialDiffAdapter' => 'HeraldDifferentialAdapter',
|
||||
'HeraldDifferentialRevisionAdapter' => array(
|
||||
|
@ -6557,7 +6615,6 @@ phutil_register_library_map(array(
|
|||
'HeraldRelatedFieldGroup' => 'HeraldFieldGroup',
|
||||
'HeraldRemarkupFieldValue' => 'HeraldFieldValue',
|
||||
'HeraldRemarkupRule' => 'PhabricatorObjectRemarkupRule',
|
||||
'HeraldRepetitionPolicyConfig' => 'Phobject',
|
||||
'HeraldRule' => array(
|
||||
'HeraldDAO',
|
||||
'PhabricatorApplicationTransactionInterface',
|
||||
|
@ -6678,8 +6735,8 @@ phutil_register_library_map(array(
|
|||
'MacroQueryConduitAPIMethod' => 'MacroConduitAPIMethod',
|
||||
'ManiphestAssignEmailCommand' => 'ManiphestEmailCommand',
|
||||
'ManiphestAssigneeDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
||||
'ManiphestBatchEditController' => 'ManiphestController',
|
||||
'ManiphestBulkEditCapability' => 'PhabricatorPolicyCapability',
|
||||
'ManiphestBulkEditController' => 'ManiphestController',
|
||||
'ManiphestClaimEmailCommand' => 'ManiphestEmailCommand',
|
||||
'ManiphestCloseEmailCommand' => 'ManiphestEmailCommand',
|
||||
'ManiphestConduitAPIMethod' => 'ConduitAPIMethod',
|
||||
|
@ -6761,6 +6818,7 @@ phutil_register_library_map(array(
|
|||
'ManiphestTaskAttachTransaction' => 'ManiphestTaskTransactionType',
|
||||
'ManiphestTaskAuthorHeraldField' => 'ManiphestTaskHeraldField',
|
||||
'ManiphestTaskAuthorPolicyRule' => 'PhabricatorPolicyRule',
|
||||
'ManiphestTaskBulkEngine' => 'PhabricatorBulkEngine',
|
||||
'ManiphestTaskCloseAsDuplicateRelationship' => 'ManiphestTaskRelationship',
|
||||
'ManiphestTaskClosedStatusDatasource' => 'PhabricatorTypeaheadDatasource',
|
||||
'ManiphestTaskCoverImageTransaction' => 'ManiphestTaskTransactionType',
|
||||
|
@ -6770,7 +6828,6 @@ phutil_register_library_map(array(
|
|||
'ManiphestTaskDescriptionTransaction' => 'ManiphestTaskTransactionType',
|
||||
'ManiphestTaskDetailController' => 'ManiphestController',
|
||||
'ManiphestTaskEdgeTransaction' => 'ManiphestTaskTransactionType',
|
||||
'ManiphestTaskEditBulkJobType' => 'PhabricatorWorkerBulkJobType',
|
||||
'ManiphestTaskEditController' => 'ManiphestController',
|
||||
'ManiphestTaskEditEngineLock' => 'PhabricatorEditEngineLock',
|
||||
'ManiphestTaskFerretEngine' => 'PhabricatorFerretEngine',
|
||||
|
@ -7284,6 +7341,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorAuthApplication' => 'PhabricatorApplication',
|
||||
'PhabricatorAuthAuthFactorPHIDType' => 'PhabricatorPHIDType',
|
||||
'PhabricatorAuthAuthProviderPHIDType' => 'PhabricatorPHIDType',
|
||||
'PhabricatorAuthChangePasswordAction' => 'PhabricatorSystemAction',
|
||||
'PhabricatorAuthConduitAPIMethod' => 'ConduitAPIMethod',
|
||||
'PhabricatorAuthConduitTokenRevoker' => 'PhabricatorAuthRevoker',
|
||||
'PhabricatorAuthConfirmLinkController' => 'PhabricatorAuthController',
|
||||
|
@ -7343,7 +7401,25 @@ phutil_register_library_map(array(
|
|||
'PhabricatorAuthOldOAuthRedirectController' => 'PhabricatorAuthController',
|
||||
'PhabricatorAuthOneTimeLoginController' => 'PhabricatorAuthController',
|
||||
'PhabricatorAuthOneTimeLoginTemporaryTokenType' => 'PhabricatorAuthTemporaryTokenType',
|
||||
'PhabricatorAuthPassword' => array(
|
||||
'PhabricatorAuthDAO',
|
||||
'PhabricatorPolicyInterface',
|
||||
'PhabricatorDestructibleInterface',
|
||||
'PhabricatorApplicationTransactionInterface',
|
||||
),
|
||||
'PhabricatorAuthPasswordEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||
'PhabricatorAuthPasswordEngine' => 'Phobject',
|
||||
'PhabricatorAuthPasswordException' => 'Exception',
|
||||
'PhabricatorAuthPasswordPHIDType' => 'PhabricatorPHIDType',
|
||||
'PhabricatorAuthPasswordQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
'PhabricatorAuthPasswordResetTemporaryTokenType' => 'PhabricatorAuthTemporaryTokenType',
|
||||
'PhabricatorAuthPasswordRevokeTransaction' => 'PhabricatorAuthPasswordTransactionType',
|
||||
'PhabricatorAuthPasswordRevoker' => 'PhabricatorAuthRevoker',
|
||||
'PhabricatorAuthPasswordTestCase' => 'PhabricatorTestCase',
|
||||
'PhabricatorAuthPasswordTransaction' => 'PhabricatorModularTransaction',
|
||||
'PhabricatorAuthPasswordTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||
'PhabricatorAuthPasswordTransactionType' => 'PhabricatorModularTransactionType',
|
||||
'PhabricatorAuthPasswordUpgradeTransaction' => 'PhabricatorAuthPasswordTransactionType',
|
||||
'PhabricatorAuthProvider' => 'Phobject',
|
||||
'PhabricatorAuthProviderConfig' => array(
|
||||
'PhabricatorAuthDAO',
|
||||
|
@ -7368,7 +7444,6 @@ phutil_register_library_map(array(
|
|||
'PhabricatorApplicationTransactionInterface',
|
||||
),
|
||||
'PhabricatorAuthSSHKeyController' => 'PhabricatorAuthController',
|
||||
'PhabricatorAuthSSHKeyDeactivateController' => 'PhabricatorAuthSSHKeyController',
|
||||
'PhabricatorAuthSSHKeyEditController' => 'PhabricatorAuthSSHKeyController',
|
||||
'PhabricatorAuthSSHKeyEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||
'PhabricatorAuthSSHKeyGenerateController' => 'PhabricatorAuthSSHKeyController',
|
||||
|
@ -7376,12 +7451,15 @@ phutil_register_library_map(array(
|
|||
'PhabricatorAuthSSHKeyPHIDType' => 'PhabricatorPHIDType',
|
||||
'PhabricatorAuthSSHKeyQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
'PhabricatorAuthSSHKeyReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler',
|
||||
'PhabricatorAuthSSHKeyRevokeController' => 'PhabricatorAuthSSHKeyController',
|
||||
'PhabricatorAuthSSHKeySearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||
'PhabricatorAuthSSHKeyTableView' => 'AphrontView',
|
||||
'PhabricatorAuthSSHKeyTestCase' => 'PhabricatorTestCase',
|
||||
'PhabricatorAuthSSHKeyTransaction' => 'PhabricatorApplicationTransaction',
|
||||
'PhabricatorAuthSSHKeyTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||
'PhabricatorAuthSSHKeyViewController' => 'PhabricatorAuthSSHKeyController',
|
||||
'PhabricatorAuthSSHPublicKey' => 'Phobject',
|
||||
'PhabricatorAuthSSHRevoker' => 'PhabricatorAuthRevoker',
|
||||
'PhabricatorAuthSession' => array(
|
||||
'PhabricatorAuthDAO',
|
||||
'PhabricatorPolicyInterface',
|
||||
|
@ -7392,6 +7470,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorAuthSessionGarbageCollector' => 'PhabricatorGarbageCollector',
|
||||
'PhabricatorAuthSessionInfo' => 'Phobject',
|
||||
'PhabricatorAuthSessionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
'PhabricatorAuthSessionRevoker' => 'PhabricatorAuthRevoker',
|
||||
'PhabricatorAuthSetPasswordController' => 'PhabricatorAuthController',
|
||||
'PhabricatorAuthSetupCheck' => 'PhabricatorSetupCheck',
|
||||
'PhabricatorAuthStartController' => 'PhabricatorAuthController',
|
||||
|
@ -7402,6 +7481,7 @@ phutil_register_library_map(array(
|
|||
),
|
||||
'PhabricatorAuthTemporaryTokenGarbageCollector' => 'PhabricatorGarbageCollector',
|
||||
'PhabricatorAuthTemporaryTokenQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
'PhabricatorAuthTemporaryTokenRevoker' => 'PhabricatorAuthRevoker',
|
||||
'PhabricatorAuthTemporaryTokenType' => 'Phobject',
|
||||
'PhabricatorAuthTemporaryTokenTypeModule' => 'PhabricatorConfigModule',
|
||||
'PhabricatorAuthTerminateSessionController' => 'PhabricatorAuthController',
|
||||
|
@ -7487,6 +7567,11 @@ phutil_register_library_map(array(
|
|||
'PhabricatorBuiltinFileCachePurger' => 'PhabricatorCachePurger',
|
||||
'PhabricatorBuiltinPatchList' => 'PhabricatorSQLPatchList',
|
||||
'PhabricatorBulkContentSource' => 'PhabricatorContentSource',
|
||||
'PhabricatorBulkEditGroup' => 'Phobject',
|
||||
'PhabricatorBulkEngine' => 'Phobject',
|
||||
'PhabricatorBulkManagementMakeSilentWorkflow' => 'PhabricatorBulkManagementWorkflow',
|
||||
'PhabricatorBulkManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
||||
'PhabricatorCSVExportFormat' => 'PhabricatorExportFormat',
|
||||
'PhabricatorCacheDAO' => 'PhabricatorLiskDAO',
|
||||
'PhabricatorCacheEngine' => 'Phobject',
|
||||
'PhabricatorCacheEngineExtension' => 'Phobject',
|
||||
|
@ -8106,6 +8191,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorPolicyInterface',
|
||||
),
|
||||
'PhabricatorEditEngineAPIMethod' => 'ConduitAPIMethod',
|
||||
'PhabricatorEditEngineBulkJobType' => 'PhabricatorWorkerBulkJobType',
|
||||
'PhabricatorEditEngineCheckboxesCommentAction' => 'PhabricatorEditEngineCommentAction',
|
||||
'PhabricatorEditEngineColumnsCommentAction' => 'PhabricatorEditEngineCommentAction',
|
||||
'PhabricatorEditEngineCommentAction' => 'Phobject',
|
||||
|
@ -8182,12 +8268,15 @@ phutil_register_library_map(array(
|
|||
'PhabricatorEnv' => 'Phobject',
|
||||
'PhabricatorEnvTestCase' => 'PhabricatorTestCase',
|
||||
'PhabricatorEpochEditField' => 'PhabricatorEditField',
|
||||
'PhabricatorEpochExportField' => 'PhabricatorExportField',
|
||||
'PhabricatorEvent' => 'PhutilEvent',
|
||||
'PhabricatorEventEngine' => 'Phobject',
|
||||
'PhabricatorEventListener' => 'PhutilEventListener',
|
||||
'PhabricatorEventType' => 'PhutilEventType',
|
||||
'PhabricatorExampleEventListener' => 'PhabricatorEventListener',
|
||||
'PhabricatorExecFutureFileUploadSource' => 'PhabricatorFileUploadSource',
|
||||
'PhabricatorExportField' => 'Phobject',
|
||||
'PhabricatorExportFormat' => 'Phobject',
|
||||
'PhabricatorExtendingPhabricatorConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||
'PhabricatorExtensionsSetupCheck' => 'PhabricatorSetupCheck',
|
||||
'PhabricatorExternalAccount' => array(
|
||||
|
@ -8340,6 +8429,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorFileUploadDialogController' => 'PhabricatorFileController',
|
||||
'PhabricatorFileUploadException' => 'Exception',
|
||||
'PhabricatorFileUploadSource' => 'Phobject',
|
||||
'PhabricatorFileUploadSourceByteLimitException' => 'Exception',
|
||||
'PhabricatorFileinfoSetupCheck' => 'PhabricatorSetupCheck',
|
||||
'PhabricatorFilesApplication' => 'PhabricatorApplication',
|
||||
'PhabricatorFilesApplicationStorageEnginePanel' => 'PhabricatorApplicationConfigurationPanel',
|
||||
|
@ -8447,6 +8537,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorHomeProfileMenuItem' => 'PhabricatorProfileMenuItem',
|
||||
'PhabricatorHovercardEngineExtension' => 'Phobject',
|
||||
'PhabricatorHovercardEngineExtensionModule' => 'PhabricatorConfigModule',
|
||||
'PhabricatorIDExportField' => 'PhabricatorExportField',
|
||||
'PhabricatorIDsSearchEngineExtension' => 'PhabricatorSearchEngineExtension',
|
||||
'PhabricatorIDsSearchField' => 'PhabricatorSearchField',
|
||||
'PhabricatorIconDatasource' => 'PhabricatorTypeaheadDatasource',
|
||||
|
@ -8469,6 +8560,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorInlineSummaryView' => 'AphrontView',
|
||||
'PhabricatorInstructionsEditField' => 'PhabricatorEditField',
|
||||
'PhabricatorIntConfigType' => 'PhabricatorTextConfigType',
|
||||
'PhabricatorIntExportField' => 'PhabricatorExportField',
|
||||
'PhabricatorInternalSetting' => 'PhabricatorSetting',
|
||||
'PhabricatorInternationalizationManagementExtractWorkflow' => 'PhabricatorInternationalizationManagementWorkflow',
|
||||
'PhabricatorInternationalizationManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
||||
|
@ -8478,6 +8570,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorIteratorFileUploadSource' => 'PhabricatorFileUploadSource',
|
||||
'PhabricatorJIRAAuthProvider' => 'PhabricatorOAuth1AuthProvider',
|
||||
'PhabricatorJSONConfigType' => 'PhabricatorTextConfigType',
|
||||
'PhabricatorJSONExportFormat' => 'PhabricatorExportFormat',
|
||||
'PhabricatorJavelinLinter' => 'ArcanistLinter',
|
||||
'PhabricatorJiraIssueHasObjectEdgeType' => 'PhabricatorEdgeType',
|
||||
'PhabricatorJumpNavHandler' => 'Phobject',
|
||||
|
@ -8837,6 +8930,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorPHDConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||
'PhabricatorPHID' => 'Phobject',
|
||||
'PhabricatorPHIDConstants' => 'Phobject',
|
||||
'PhabricatorPHIDExportField' => 'PhabricatorExportField',
|
||||
'PhabricatorPHIDListEditField' => 'PhabricatorEditField',
|
||||
'PhabricatorPHIDListEditType' => 'PhabricatorEditType',
|
||||
'PhabricatorPHIDResolver' => 'Phobject',
|
||||
|
@ -8952,6 +9046,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorPagerUIExample' => 'PhabricatorUIExample',
|
||||
'PhabricatorPassphraseApplication' => 'PhabricatorApplication',
|
||||
'PhabricatorPasswordAuthProvider' => 'PhabricatorAuthProvider',
|
||||
'PhabricatorPasswordDestructionEngineExtension' => 'PhabricatorDestructionEngineExtension',
|
||||
'PhabricatorPasswordHasher' => 'Phobject',
|
||||
'PhabricatorPasswordHasherTestCase' => 'PhabricatorTestCase',
|
||||
'PhabricatorPasswordHasherUnavailableException' => 'Exception',
|
||||
|
@ -9530,7 +9625,6 @@ phutil_register_library_map(array(
|
|||
'PhabricatorRepositoryURITestCase' => 'PhabricatorTestCase',
|
||||
'PhabricatorRepositoryURITransaction' => 'PhabricatorApplicationTransaction',
|
||||
'PhabricatorRepositoryURITransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||
'PhabricatorRepositoryVCSPassword' => 'PhabricatorRepositoryDAO',
|
||||
'PhabricatorRepositoryWorkingCopyVersion' => 'PhabricatorRepositoryDAO',
|
||||
'PhabricatorRequestExceptionHandler' => 'AphrontRequestExceptionHandler',
|
||||
'PhabricatorResourceSite' => 'PhabricatorSite',
|
||||
|
@ -9554,7 +9648,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorSSHKeysSettingsPanel' => 'PhabricatorSettingsPanel',
|
||||
'PhabricatorSSHLog' => 'Phobject',
|
||||
'PhabricatorSSHPassthruCommand' => 'Phobject',
|
||||
'PhabricatorSSHWorkflow' => 'PhabricatorManagementWorkflow',
|
||||
'PhabricatorSSHWorkflow' => 'PhutilArgumentWorkflow',
|
||||
'PhabricatorSavedQuery' => array(
|
||||
'PhabricatorSearchDAO',
|
||||
'PhabricatorPolicyInterface',
|
||||
|
@ -9776,6 +9870,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorStorageSchemaSpec' => 'PhabricatorConfigSchemaSpec',
|
||||
'PhabricatorStorageSetupCheck' => 'PhabricatorSetupCheck',
|
||||
'PhabricatorStringConfigType' => 'PhabricatorTextConfigType',
|
||||
'PhabricatorStringExportField' => 'PhabricatorExportField',
|
||||
'PhabricatorStringListConfigType' => 'PhabricatorTextListConfigType',
|
||||
'PhabricatorStringListEditField' => 'PhabricatorEditField',
|
||||
'PhabricatorStringSetting' => 'PhabricatorSetting',
|
||||
|
@ -9838,6 +9933,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorTextAreaEditField' => 'PhabricatorEditField',
|
||||
'PhabricatorTextConfigType' => 'PhabricatorConfigType',
|
||||
'PhabricatorTextEditField' => 'PhabricatorEditField',
|
||||
'PhabricatorTextExportFormat' => 'PhabricatorExportFormat',
|
||||
'PhabricatorTextListConfigType' => 'PhabricatorTextConfigType',
|
||||
'PhabricatorTime' => 'Phobject',
|
||||
'PhabricatorTimeFormatSetting' => 'PhabricatorSelectSetting',
|
||||
|
@ -9931,6 +10027,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorFulltextInterface',
|
||||
'PhabricatorFerretInterface',
|
||||
'PhabricatorConduitResultInterface',
|
||||
'PhabricatorAuthPasswordHashInterface',
|
||||
),
|
||||
'PhabricatorUserBadgesCacheType' => 'PhabricatorUserCacheType',
|
||||
'PhabricatorUserBlurbField' => 'PhabricatorUserCustomField',
|
||||
|
|
|
@ -0,0 +1,208 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorAuthPasswordTestCase extends PhabricatorTestCase {
|
||||
|
||||
protected function getPhabricatorTestCaseConfiguration() {
|
||||
return array(
|
||||
self::PHABRICATOR_TESTCONFIG_BUILD_STORAGE_FIXTURES => true,
|
||||
);
|
||||
}
|
||||
|
||||
public function testCompare() {
|
||||
$password1 = new PhutilOpaqueEnvelope('hunter2');
|
||||
$password2 = new PhutilOpaqueEnvelope('hunter3');
|
||||
|
||||
$user = $this->generateNewTestUser();
|
||||
$type = PhabricatorAuthPassword::PASSWORD_TYPE_TEST;
|
||||
|
||||
$pass = PhabricatorAuthPassword::initializeNewPassword($user, $type)
|
||||
->setPassword($password1, $user)
|
||||
->save();
|
||||
|
||||
$this->assertTrue(
|
||||
$pass->comparePassword($password1, $user),
|
||||
pht('Good password should match.'));
|
||||
|
||||
$this->assertFalse(
|
||||
$pass->comparePassword($password2, $user),
|
||||
pht('Bad password should not match.'));
|
||||
}
|
||||
|
||||
public function testPasswordEngine() {
|
||||
$password1 = new PhutilOpaqueEnvelope('the quick');
|
||||
$password2 = new PhutilOpaqueEnvelope('brown fox');
|
||||
|
||||
$user = $this->generateNewTestUser();
|
||||
$test_type = PhabricatorAuthPassword::PASSWORD_TYPE_TEST;
|
||||
$account_type = PhabricatorAuthPassword::PASSWORD_TYPE_ACCOUNT;
|
||||
$content_source = $this->newContentSource();
|
||||
|
||||
$engine = id(new PhabricatorAuthPasswordEngine())
|
||||
->setViewer($user)
|
||||
->setContentSource($content_source)
|
||||
->setPasswordType($test_type)
|
||||
->setObject($user);
|
||||
|
||||
$account_engine = id(new PhabricatorAuthPasswordEngine())
|
||||
->setViewer($user)
|
||||
->setContentSource($content_source)
|
||||
->setPasswordType($account_type)
|
||||
->setObject($user);
|
||||
|
||||
// We haven't set any passwords yet, so both passwords should be
|
||||
// invalid.
|
||||
$this->assertFalse($engine->isValidPassword($password1));
|
||||
$this->assertFalse($engine->isValidPassword($password2));
|
||||
|
||||
$pass = PhabricatorAuthPassword::initializeNewPassword($user, $test_type)
|
||||
->setPassword($password1, $user)
|
||||
->save();
|
||||
|
||||
// The password should now be valid.
|
||||
$this->assertTrue($engine->isValidPassword($password1));
|
||||
$this->assertFalse($engine->isValidPassword($password2));
|
||||
|
||||
// But, since the password is a "test" password, it should not be a valid
|
||||
// "account" password.
|
||||
$this->assertFalse($account_engine->isValidPassword($password1));
|
||||
$this->assertFalse($account_engine->isValidPassword($password2));
|
||||
|
||||
// Both passwords are unique for the "test" engine, since an active
|
||||
// password of a given type doesn't collide with itself.
|
||||
$this->assertTrue($engine->isUniquePassword($password1));
|
||||
$this->assertTrue($engine->isUniquePassword($password2));
|
||||
|
||||
// The "test" password is no longer unique for the "account" engine.
|
||||
$this->assertFalse($account_engine->isUniquePassword($password1));
|
||||
$this->assertTrue($account_engine->isUniquePassword($password2));
|
||||
|
||||
$this->revokePassword($user, $pass);
|
||||
|
||||
// Now that we've revoked the password, it should no longer be valid.
|
||||
$this->assertFalse($engine->isValidPassword($password1));
|
||||
$this->assertFalse($engine->isValidPassword($password2));
|
||||
|
||||
// But it should be a revoked password.
|
||||
$this->assertTrue($engine->isRevokedPassword($password1));
|
||||
$this->assertFalse($engine->isRevokedPassword($password2));
|
||||
|
||||
// It should be revoked for both roles: revoking a "test" password also
|
||||
// prevents you from choosing it as a new "account" password.
|
||||
$this->assertTrue($account_engine->isRevokedPassword($password1));
|
||||
$this->assertFalse($account_engine->isValidPassword($password2));
|
||||
|
||||
// The revoked password makes this password non-unique for all account
|
||||
// types.
|
||||
$this->assertFalse($engine->isUniquePassword($password1));
|
||||
$this->assertTrue($engine->isUniquePassword($password2));
|
||||
$this->assertFalse($account_engine->isUniquePassword($password1));
|
||||
$this->assertTrue($account_engine->isUniquePassword($password2));
|
||||
}
|
||||
|
||||
public function testPasswordUpgrade() {
|
||||
$weak_hasher = new PhabricatorIteratedMD5PasswordHasher();
|
||||
|
||||
// Make sure we have two different hashers, and that the second one is
|
||||
// stronger than iterated MD5. The most common reason this would fail is
|
||||
// if an install does not have bcrypt available.
|
||||
$strong_hasher = PhabricatorPasswordHasher::getBestHasher();
|
||||
if ($strong_hasher->getStrength() <= $weak_hasher->getStrength()) {
|
||||
$this->assertSkipped(
|
||||
pht(
|
||||
'Multiple password hashers of different strengths are not '.
|
||||
'available, so hash upgrading can not be tested.'));
|
||||
}
|
||||
|
||||
$envelope = new PhutilOpaqueEnvelope('lunar1997');
|
||||
|
||||
$user = $this->generateNewTestUser();
|
||||
$type = PhabricatorAuthPassword::PASSWORD_TYPE_TEST;
|
||||
$content_source = $this->newContentSource();
|
||||
|
||||
$engine = id(new PhabricatorAuthPasswordEngine())
|
||||
->setViewer($user)
|
||||
->setContentSource($content_source)
|
||||
->setPasswordType($type)
|
||||
->setObject($user);
|
||||
|
||||
$password = PhabricatorAuthPassword::initializeNewPassword($user, $type)
|
||||
->setPasswordWithHasher($envelope, $user, $weak_hasher)
|
||||
->save();
|
||||
|
||||
$weak_name = $weak_hasher->getHashName();
|
||||
$strong_name = $strong_hasher->getHashName();
|
||||
|
||||
// Since we explicitly used the weak hasher, the password should have
|
||||
// been hashed with it.
|
||||
$actual_hasher = $password->getHasher();
|
||||
$this->assertEqual($weak_name, $actual_hasher->getHashName());
|
||||
|
||||
$is_valid = $engine
|
||||
->setUpgradeHashers(false)
|
||||
->isValidPassword($envelope, $user);
|
||||
$password->reload();
|
||||
|
||||
// Since we disabled hasher upgrading, the password should not have been
|
||||
// rehashed.
|
||||
$this->assertTrue($is_valid);
|
||||
$actual_hasher = $password->getHasher();
|
||||
$this->assertEqual($weak_name, $actual_hasher->getHashName());
|
||||
|
||||
$is_valid = $engine
|
||||
->setUpgradeHashers(true)
|
||||
->isValidPassword($envelope, $user);
|
||||
$password->reload();
|
||||
|
||||
// Now that we enabled hasher upgrading, the password should have been
|
||||
// automatically rehashed into the stronger format.
|
||||
$this->assertTrue($is_valid);
|
||||
$actual_hasher = $password->getHasher();
|
||||
$this->assertEqual($strong_name, $actual_hasher->getHashName());
|
||||
|
||||
// We should also have an "upgrade" transaction in the transaction record
|
||||
// now which records the two hasher names.
|
||||
$xactions = id(new PhabricatorAuthPasswordTransactionQuery())
|
||||
->setViewer($user)
|
||||
->withObjectPHIDs(array($password->getPHID()))
|
||||
->withTransactionTypes(
|
||||
array(
|
||||
PhabricatorAuthPasswordUpgradeTransaction::TRANSACTIONTYPE,
|
||||
))
|
||||
->execute();
|
||||
|
||||
$this->assertEqual(1, count($xactions));
|
||||
$xaction = head($xactions);
|
||||
|
||||
$this->assertEqual($weak_name, $xaction->getOldValue());
|
||||
$this->assertEqual($strong_name, $xaction->getNewValue());
|
||||
|
||||
$is_valid = $engine
|
||||
->isValidPassword($envelope, $user);
|
||||
|
||||
// Finally, the password should still be valid after all the dust has
|
||||
// settled.
|
||||
$this->assertTrue($is_valid);
|
||||
}
|
||||
|
||||
private function revokePassword(
|
||||
PhabricatorUser $actor,
|
||||
PhabricatorAuthPassword $password) {
|
||||
|
||||
$content_source = $this->newContentSource();
|
||||
$revoke_type = PhabricatorAuthPasswordRevokeTransaction::TRANSACTIONTYPE;
|
||||
|
||||
$xactions = array();
|
||||
|
||||
$xactions[] = $password->getApplicationTransactionTemplate()
|
||||
->setTransactionType($revoke_type)
|
||||
->setNewValue(true);
|
||||
|
||||
$editor = $password->getApplicationTransactionEditor()
|
||||
->setActor($actor)
|
||||
->setContinueOnNoEffect(true)
|
||||
->setContinueOnMissingFields(true)
|
||||
->setContentSource($content_source)
|
||||
->applyTransactions($password, $xactions);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorAuthSSHKeyTestCase extends PhabricatorTestCase {
|
||||
|
||||
protected function getPhabricatorTestCaseConfiguration() {
|
||||
return array(
|
||||
self::PHABRICATOR_TESTCONFIG_BUILD_STORAGE_FIXTURES => true,
|
||||
);
|
||||
}
|
||||
|
||||
public function testRevokeSSHKey() {
|
||||
$user = $this->generateNewTestUser();
|
||||
$raw_key = 'ssh-rsa hunter2';
|
||||
|
||||
$ssh_key = PhabricatorAuthSSHKey::initializeNewSSHKey($user, $user);
|
||||
|
||||
// Add the key to the user's account.
|
||||
$xactions = array();
|
||||
$xactions[] = $ssh_key->getApplicationTransactionTemplate()
|
||||
->setTransactionType(PhabricatorAuthSSHKeyTransaction::TYPE_NAME)
|
||||
->setNewValue('key1');
|
||||
$xactions[] = $ssh_key->getApplicationTransactionTemplate()
|
||||
->setTransactionType(PhabricatorAuthSSHKeyTransaction::TYPE_KEY)
|
||||
->setNewValue($raw_key);
|
||||
$this->applyTransactions($user, $ssh_key, $xactions);
|
||||
|
||||
$ssh_key->reload();
|
||||
$this->assertTrue((bool)$ssh_key->getIsActive());
|
||||
|
||||
// Revoke it.
|
||||
$xactions = array();
|
||||
$xactions[] = $ssh_key->getApplicationTransactionTemplate()
|
||||
->setTransactionType(PhabricatorAuthSSHKeyTransaction::TYPE_DEACTIVATE)
|
||||
->setNewValue(true);
|
||||
$this->applyTransactions($user, $ssh_key, $xactions);
|
||||
|
||||
$ssh_key->reload();
|
||||
$this->assertFalse((bool)$ssh_key->getIsActive());
|
||||
|
||||
// Try to add the revoked key back. This should fail with a validation
|
||||
// error because the key was previously revoked by the user.
|
||||
$revoked_key = PhabricatorAuthSSHKey::initializeNewSSHKey($user, $user);
|
||||
$xactions = array();
|
||||
$xactions[] = $ssh_key->getApplicationTransactionTemplate()
|
||||
->setTransactionType(PhabricatorAuthSSHKeyTransaction::TYPE_NAME)
|
||||
->setNewValue('key2');
|
||||
$xactions[] = $ssh_key->getApplicationTransactionTemplate()
|
||||
->setTransactionType(PhabricatorAuthSSHKeyTransaction::TYPE_KEY)
|
||||
->setNewValue($raw_key);
|
||||
|
||||
$caught = null;
|
||||
try {
|
||||
$this->applyTransactions($user, $ssh_key, $xactions);
|
||||
} catch (PhabricatorApplicationTransactionValidationException $ex) {
|
||||
$errors = $ex->getErrors();
|
||||
$this->assertEqual(1, count($errors));
|
||||
$caught = head($errors)->getType();
|
||||
}
|
||||
|
||||
$this->assertEqual(PhabricatorAuthSSHKeyTransaction::TYPE_KEY, $caught);
|
||||
}
|
||||
|
||||
private function applyTransactions(
|
||||
PhabricatorUser $actor,
|
||||
PhabricatorAuthSSHKey $key,
|
||||
array $xactions) {
|
||||
|
||||
$content_source = $this->newContentSource();
|
||||
|
||||
$editor = $key->getApplicationTransactionEditor()
|
||||
->setActor($actor)
|
||||
->setContinueOnNoEffect(true)
|
||||
->setContinueOnMissingFields(true)
|
||||
->setContentSource($content_source)
|
||||
->applyTransactions($key, $xactions);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorAuthChangePasswordAction
|
||||
extends PhabricatorSystemAction {
|
||||
|
||||
const TYPECONST = 'auth.password';
|
||||
|
||||
public function getActionConstant() {
|
||||
return self::TYPECONST;
|
||||
}
|
||||
|
||||
public function getScoreThreshold() {
|
||||
return 20 / phutil_units('1 hour in seconds');
|
||||
}
|
||||
|
||||
public function getLimitExplanation() {
|
||||
return pht(
|
||||
'You have failed to enter the correct account password too often in '.
|
||||
'a short period of time.');
|
||||
}
|
||||
|
||||
}
|
|
@ -80,8 +80,8 @@ final class PhabricatorAuthApplication extends PhabricatorApplication {
|
|||
'generate/' => 'PhabricatorAuthSSHKeyGenerateController',
|
||||
'upload/' => 'PhabricatorAuthSSHKeyEditController',
|
||||
'edit/(?P<id>\d+)/' => 'PhabricatorAuthSSHKeyEditController',
|
||||
'deactivate/(?P<id>\d+)/'
|
||||
=> 'PhabricatorAuthSSHKeyDeactivateController',
|
||||
'revoke/(?P<id>\d+)/'
|
||||
=> 'PhabricatorAuthSSHKeyRevokeController',
|
||||
'view/(?P<id>\d+)/' => 'PhabricatorAuthSSHKeyViewController',
|
||||
),
|
||||
'password/' => 'PhabricatorAuthSetPasswordController',
|
||||
|
|
|
@ -61,6 +61,9 @@ final class PhabricatorAuthRegisterController
|
|||
$default_username = $account->getUsername();
|
||||
$default_realname = $account->getRealName();
|
||||
|
||||
$account_type = PhabricatorAuthPassword::PASSWORD_TYPE_ACCOUNT;
|
||||
$content_source = PhabricatorContentSource::newFromRequest($request);
|
||||
|
||||
$default_email = $account->getEmail();
|
||||
|
||||
if ($invite) {
|
||||
|
@ -285,27 +288,22 @@ final class PhabricatorAuthRegisterController
|
|||
if ($must_set_password) {
|
||||
$value_password = $request->getStr('password');
|
||||
$value_confirm = $request->getStr('confirm');
|
||||
if (!strlen($value_password)) {
|
||||
$e_password = pht('Required');
|
||||
$errors[] = pht('You must choose a password.');
|
||||
} else if ($value_password !== $value_confirm) {
|
||||
$e_password = pht('No Match');
|
||||
$errors[] = pht('Password and confirmation must match.');
|
||||
} else if (strlen($value_password) < $min_len) {
|
||||
$e_password = pht('Too Short');
|
||||
$errors[] = pht(
|
||||
'Password is too short (must be at least %d characters long).',
|
||||
$min_len);
|
||||
} else if (
|
||||
PhabricatorCommonPasswords::isCommonPassword($value_password)) {
|
||||
|
||||
$e_password = pht('Very Weak');
|
||||
$errors[] = pht(
|
||||
'Password is pathologically weak. This password is one of the '.
|
||||
'most common passwords in use, and is extremely easy for '.
|
||||
'attackers to guess. You must choose a stronger password.');
|
||||
} else {
|
||||
$password_envelope = new PhutilOpaqueEnvelope($value_password);
|
||||
$confirm_envelope = new PhutilOpaqueEnvelope($value_confirm);
|
||||
|
||||
$engine = id(new PhabricatorAuthPasswordEngine())
|
||||
->setViewer($user)
|
||||
->setContentSource($content_source)
|
||||
->setPasswordType($account_type)
|
||||
->setObject($user);
|
||||
|
||||
try {
|
||||
$engine->checkNewPassword($password_envelope, $confirm_envelope);
|
||||
$e_password = null;
|
||||
} catch (PhabricatorAuthPasswordException $ex) {
|
||||
$errors[] = $ex->getMessage();
|
||||
$e_password = $ex->getPasswordError();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -408,8 +406,13 @@ final class PhabricatorAuthRegisterController
|
|||
|
||||
$editor->createNewUser($user, $email_obj, $allow_reassign_email);
|
||||
if ($must_set_password) {
|
||||
$envelope = new PhutilOpaqueEnvelope($value_password);
|
||||
$editor->changePassword($user, $envelope);
|
||||
$password_object = PhabricatorAuthPassword::initializeNewPassword(
|
||||
$user,
|
||||
$account_type);
|
||||
|
||||
$password_object
|
||||
->setPassword($password_envelope, $user)
|
||||
->save();
|
||||
}
|
||||
|
||||
if ($is_setup) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorAuthSSHKeyDeactivateController
|
||||
final class PhabricatorAuthSSHKeyRevokeController
|
||||
extends PhabricatorAuthSSHKeyController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
|
@ -46,14 +46,14 @@ final class PhabricatorAuthSSHKeyDeactivateController
|
|||
$name = phutil_tag('strong', array(), $key->getName());
|
||||
|
||||
return $this->newDialog()
|
||||
->setTitle(pht('Deactivate SSH Public Key'))
|
||||
->setTitle(pht('Revoke SSH Public Key'))
|
||||
->appendParagraph(
|
||||
pht(
|
||||
'The key "%s" will be permanently deactivated, and you will no '.
|
||||
'The key "%s" will be permanently revoked, and you will no '.
|
||||
'longer be able to use the corresponding private key to '.
|
||||
'authenticate.',
|
||||
$name))
|
||||
->addSubmitButton(pht('Deactivate Public Key'))
|
||||
->addSubmitButton(pht('Revoke Public Key'))
|
||||
->addCancelButton($cancel_uri);
|
||||
}
|
||||
|
|
@ -35,7 +35,7 @@ final class PhabricatorAuthSSHKeyViewController
|
|||
if ($ssh_key->getIsActive()) {
|
||||
$header->setStatus('fa-check', 'bluegrey', pht('Active'));
|
||||
} else {
|
||||
$header->setStatus('fa-ban', 'dark', pht('Deactivated'));
|
||||
$header->setStatus('fa-ban', 'dark', pht('Revoked'));
|
||||
}
|
||||
|
||||
$header->addActionLink(
|
||||
|
@ -80,7 +80,7 @@ final class PhabricatorAuthSSHKeyViewController
|
|||
$id = $ssh_key->getID();
|
||||
|
||||
$edit_uri = $this->getApplicationURI("sshkey/edit/{$id}/");
|
||||
$deactivate_uri = $this->getApplicationURI("sshkey/deactivate/{$id}/");
|
||||
$revoke_uri = $this->getApplicationURI("sshkey/revoke/{$id}/");
|
||||
|
||||
$curtain = $this->newCurtainView($ssh_key);
|
||||
|
||||
|
@ -95,8 +95,8 @@ final class PhabricatorAuthSSHKeyViewController
|
|||
$curtain->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setIcon('fa-times')
|
||||
->setName(pht('Deactivate SSH Key'))
|
||||
->setHref($deactivate_uri)
|
||||
->setName(pht('Revoke SSH Key'))
|
||||
->setHref($revoke_uri)
|
||||
->setWorkflow(true)
|
||||
->setDisabled(!$can_edit));
|
||||
|
||||
|
|
|
@ -40,8 +40,30 @@ final class PhabricatorAuthSetPasswordController
|
|||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$min_len = PhabricatorEnv::getEnvConfig('account.minimum-password-length');
|
||||
$min_len = (int)$min_len;
|
||||
$content_source = PhabricatorContentSource::newFromRequest($request);
|
||||
$account_type = PhabricatorAuthPassword::PASSWORD_TYPE_ACCOUNT;
|
||||
|
||||
$password_objects = id(new PhabricatorAuthPasswordQuery())
|
||||
->setViewer($viewer)
|
||||
->withObjectPHIDs(array($viewer->getPHID()))
|
||||
->withPasswordTypes(array($account_type))
|
||||
->withIsRevoked(false)
|
||||
->execute();
|
||||
if ($password_objects) {
|
||||
$password_object = head($password_objects);
|
||||
$has_password = true;
|
||||
} else {
|
||||
$password_object = PhabricatorAuthPassword::initializeNewPassword(
|
||||
$viewer,
|
||||
$account_type);
|
||||
$has_password = false;
|
||||
}
|
||||
|
||||
$engine = id(new PhabricatorAuthPasswordEngine())
|
||||
->setViewer($viewer)
|
||||
->setContentSource($content_source)
|
||||
->setPasswordType($account_type)
|
||||
->setObject($viewer);
|
||||
|
||||
$e_password = true;
|
||||
$e_confirm = true;
|
||||
|
@ -50,46 +72,23 @@ final class PhabricatorAuthSetPasswordController
|
|||
$password = $request->getStr('password');
|
||||
$confirm = $request->getStr('confirm');
|
||||
|
||||
$password_envelope = new PhutilOpaqueEnvelope($password);
|
||||
$confirm_envelope = new PhutilOpaqueEnvelope($confirm);
|
||||
|
||||
try {
|
||||
$engine->checkNewPassword($password_envelope, $confirm_envelope, true);
|
||||
$e_password = null;
|
||||
$e_confirm = null;
|
||||
|
||||
if (!strlen($password)) {
|
||||
$errors[] = pht('You must choose a password or skip this step.');
|
||||
$e_password = pht('Required');
|
||||
} else if (strlen($password) < $min_len) {
|
||||
$errors[] = pht(
|
||||
'The selected password is too short. Passwords must be a minimum '.
|
||||
'of %s characters.',
|
||||
new PhutilNumber($min_len));
|
||||
$e_password = pht('Too Short');
|
||||
} else if (!strlen($confirm)) {
|
||||
$errors[] = pht('You must confirm the selecetd password.');
|
||||
$e_confirm = pht('Required');
|
||||
} else if ($password !== $confirm) {
|
||||
$errors[] = pht('The password and confirmation do not match.');
|
||||
$e_password = pht('Invalid');
|
||||
$e_confirm = pht('Invalid');
|
||||
} else if (PhabricatorCommonPasswords::isCommonPassword($password)) {
|
||||
$e_password = pht('Very Weak');
|
||||
$errors[] = pht(
|
||||
'The selected password is very weak: it is one of the most common '.
|
||||
'passwords in use. Choose a stronger password.');
|
||||
} catch (PhabricatorAuthPasswordException $ex) {
|
||||
$errors[] = $ex->getMessage();
|
||||
$e_password = $ex->getPasswordError();
|
||||
$e_confirm = $ex->getConfirmError();
|
||||
}
|
||||
|
||||
if (!$errors) {
|
||||
$envelope = new PhutilOpaqueEnvelope($password);
|
||||
|
||||
// This write is unguarded because the CSRF token has already
|
||||
// been checked in the call to $request->isFormPost() and
|
||||
// the CSRF token depends on the password hash, so when it
|
||||
// is changed here the CSRF token check will fail.
|
||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
||||
|
||||
id(new PhabricatorUserEditor())
|
||||
->setActor($viewer)
|
||||
->changePassword($viewer, $envelope);
|
||||
|
||||
unset($unguarded);
|
||||
$password_object
|
||||
->setPassword($password_envelope, $viewer)
|
||||
->save();
|
||||
|
||||
// Destroy the token.
|
||||
$auth_token->delete();
|
||||
|
@ -98,12 +97,15 @@ final class PhabricatorAuthSetPasswordController
|
|||
}
|
||||
}
|
||||
|
||||
$min_len = PhabricatorEnv::getEnvConfig('account.minimum-password-length');
|
||||
$min_len = (int)$min_len;
|
||||
|
||||
$len_caption = null;
|
||||
if ($min_len) {
|
||||
$len_caption = pht('Minimum password length: %d characters.', $min_len);
|
||||
}
|
||||
|
||||
if ($viewer->hasPassword()) {
|
||||
if ($has_password) {
|
||||
$title = pht('Reset Password');
|
||||
$crumb = pht('Reset Password');
|
||||
$submit = pht('Reset Password');
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorAuthPasswordEditor
|
||||
extends PhabricatorApplicationTransactionEditor {
|
||||
|
||||
private $oldHasher;
|
||||
|
||||
public function setOldHasher(PhabricatorPasswordHasher $old_hasher) {
|
||||
$this->oldHasher = $old_hasher;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getOldHasher() {
|
||||
return $this->oldHasher;
|
||||
}
|
||||
|
||||
public function getEditorApplicationClass() {
|
||||
return 'PhabricatorAuthApplication';
|
||||
}
|
||||
|
||||
public function getEditorObjectsDescription() {
|
||||
return pht('Passwords');
|
||||
}
|
||||
|
||||
public function getCreateObjectTitle($author, $object) {
|
||||
return pht('%s created this password.', $author);
|
||||
}
|
||||
|
||||
public function getCreateObjectTitleForFeed($author, $object) {
|
||||
return pht('%s created %s.', $author, $object);
|
||||
}
|
||||
|
||||
}
|
|
@ -3,6 +3,17 @@
|
|||
final class PhabricatorAuthSSHKeyEditor
|
||||
extends PhabricatorApplicationTransactionEditor {
|
||||
|
||||
private $isAdministrativeEdit;
|
||||
|
||||
public function setIsAdministrativeEdit($is_administrative_edit) {
|
||||
$this->isAdministrativeEdit = $is_administrative_edit;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getIsAdministrativeEdit() {
|
||||
return $this->isAdministrativeEdit;
|
||||
}
|
||||
|
||||
public function getEditorApplicationClass() {
|
||||
return 'PhabricatorAuthApplication';
|
||||
}
|
||||
|
@ -93,6 +104,7 @@ final class PhabricatorAuthSSHKeyEditor
|
|||
array $xactions) {
|
||||
|
||||
$errors = parent::validateTransaction($object, $type, $xactions);
|
||||
$viewer = $this->requireActor();
|
||||
|
||||
switch ($type) {
|
||||
case PhabricatorAuthSSHKeyTransaction::TYPE_NAME:
|
||||
|
@ -138,6 +150,30 @@ final class PhabricatorAuthSSHKeyEditor
|
|||
pht('Invalid'),
|
||||
$ex->getMessage(),
|
||||
$xaction);
|
||||
continue;
|
||||
}
|
||||
|
||||
// The database does not have a unique key on just the <keyBody>
|
||||
// column because we allow multiple accounts to revoke the same
|
||||
// key, so we can't rely on database constraints to prevent users
|
||||
// from adding keys that are on the revocation list back to their
|
||||
// accounts. Explicitly check for a revoked copy of the key.
|
||||
|
||||
$revoked_keys = id(new PhabricatorAuthSSHKeyQuery())
|
||||
->setViewer($viewer)
|
||||
->withObjectPHIDs(array($object->getObjectPHID()))
|
||||
->withIsActive(0)
|
||||
->withKeys(array($public_key))
|
||||
->execute();
|
||||
if ($revoked_keys) {
|
||||
$errors[] = new PhabricatorApplicationTransactionValidationError(
|
||||
$type,
|
||||
pht('Revoked'),
|
||||
pht(
|
||||
'This key has been revoked. Choose or generate a new, '.
|
||||
'unique key.'),
|
||||
$xaction);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -239,11 +275,13 @@ final class PhabricatorAuthSSHKeyEditor
|
|||
|
||||
$body = parent::buildMailBody($object, $xactions);
|
||||
|
||||
if (!$this->getIsAdministrativeEdit()) {
|
||||
$body->addTextSection(
|
||||
pht('SECURITY WARNING'),
|
||||
pht(
|
||||
'If you do not recognize this change, it may indicate your account '.
|
||||
'has been compromised.'));
|
||||
}
|
||||
|
||||
$detail_uri = $object->getURI();
|
||||
$detail_uri = PhabricatorEnv::getProductionURI($detail_uri);
|
||||
|
@ -253,4 +291,17 @@ final class PhabricatorAuthSSHKeyEditor
|
|||
return $body;
|
||||
}
|
||||
|
||||
|
||||
protected function getCustomWorkerState() {
|
||||
return array(
|
||||
'isAdministrativeEdit' => $this->isAdministrativeEdit,
|
||||
);
|
||||
}
|
||||
|
||||
protected function loadCustomWorkerState(array $state) {
|
||||
$this->isAdministrativeEdit = idx($state, 'isAdministrativeEdit');
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
320
src/applications/auth/engine/PhabricatorAuthPasswordEngine.php
Normal file
320
src/applications/auth/engine/PhabricatorAuthPasswordEngine.php
Normal file
|
@ -0,0 +1,320 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorAuthPasswordEngine
|
||||
extends Phobject {
|
||||
|
||||
private $viewer;
|
||||
private $contentSource;
|
||||
private $object;
|
||||
private $passwordType;
|
||||
private $upgradeHashers = true;
|
||||
|
||||
public function setViewer(PhabricatorUser $viewer) {
|
||||
$this->viewer = $viewer;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getViewer() {
|
||||
return $this->viewer;
|
||||
}
|
||||
|
||||
public function setContentSource(PhabricatorContentSource $content_source) {
|
||||
$this->contentSource = $content_source;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getContentSource() {
|
||||
return $this->contentSource;
|
||||
}
|
||||
|
||||
public function setObject(PhabricatorAuthPasswordHashInterface $object) {
|
||||
$this->object = $object;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getObject() {
|
||||
return $this->object;
|
||||
}
|
||||
|
||||
public function setPasswordType($password_type) {
|
||||
$this->passwordType = $password_type;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPasswordType() {
|
||||
return $this->passwordType;
|
||||
}
|
||||
|
||||
public function setUpgradeHashers($upgrade_hashers) {
|
||||
$this->upgradeHashers = $upgrade_hashers;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getUpgradeHashers() {
|
||||
return $this->upgradeHashers;
|
||||
}
|
||||
|
||||
public function checkNewPassword(
|
||||
PhutilOpaqueEnvelope $password,
|
||||
PhutilOpaqueEnvelope $confirm,
|
||||
$can_skip = false) {
|
||||
|
||||
$raw_password = $password->openEnvelope();
|
||||
|
||||
if (!strlen($raw_password)) {
|
||||
if ($can_skip) {
|
||||
throw new PhabricatorAuthPasswordException(
|
||||
pht('You must choose a password or skip this step.'),
|
||||
pht('Required'));
|
||||
} else {
|
||||
throw new PhabricatorAuthPasswordException(
|
||||
pht('You must choose a password.'),
|
||||
pht('Required'));
|
||||
}
|
||||
}
|
||||
|
||||
$min_len = PhabricatorEnv::getEnvConfig('account.minimum-password-length');
|
||||
$min_len = (int)$min_len;
|
||||
if ($min_len) {
|
||||
if (strlen($raw_password) < $min_len) {
|
||||
throw new PhabricatorAuthPasswordException(
|
||||
pht(
|
||||
'The selected password is too short. Passwords must be a minimum '.
|
||||
'of %s characters long.',
|
||||
new PhutilNumber($min_len)),
|
||||
pht('Too Short'));
|
||||
}
|
||||
}
|
||||
|
||||
$raw_confirm = $confirm->openEnvelope();
|
||||
|
||||
if (!strlen($raw_confirm)) {
|
||||
throw new PhabricatorAuthPasswordException(
|
||||
pht('You must confirm the selected password.'),
|
||||
null,
|
||||
pht('Required'));
|
||||
}
|
||||
|
||||
if ($raw_password !== $raw_confirm) {
|
||||
throw new PhabricatorAuthPasswordException(
|
||||
pht('The password and confirmation do not match.'),
|
||||
pht('Invalid'),
|
||||
pht('Invalid'));
|
||||
}
|
||||
|
||||
if (PhabricatorCommonPasswords::isCommonPassword($raw_password)) {
|
||||
throw new PhabricatorAuthPasswordException(
|
||||
pht(
|
||||
'The selected password is very weak: it is one of the most common '.
|
||||
'passwords in use. Choose a stronger password.'),
|
||||
pht('Very Weak'));
|
||||
}
|
||||
|
||||
// If we're creating a brand new object (like registering a new user)
|
||||
// and it does not have a PHID yet, it isn't possible for it to have any
|
||||
// revoked passwords or colliding passwords either, so we can skip these
|
||||
// checks.
|
||||
|
||||
if ($this->getObject()->getPHID()) {
|
||||
if ($this->isRevokedPassword($password)) {
|
||||
throw new PhabricatorAuthPasswordException(
|
||||
pht(
|
||||
'The password you entered has been revoked. You can not reuse '.
|
||||
'a password which has been revoked. Choose a new password.'),
|
||||
pht('Revoked'));
|
||||
}
|
||||
|
||||
if (!$this->isUniquePassword($password)) {
|
||||
throw new PhabricatorAuthPasswordException(
|
||||
pht(
|
||||
'The password you entered is the same as another password '.
|
||||
'associated with your account. Each password must be unique.'),
|
||||
pht('Not Unique'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function isValidPassword(PhutilOpaqueEnvelope $envelope) {
|
||||
$this->requireSetup();
|
||||
|
||||
$password_type = $this->getPasswordType();
|
||||
|
||||
$passwords = $this->newQuery()
|
||||
->withPasswordTypes(array($password_type))
|
||||
->withIsRevoked(false)
|
||||
->execute();
|
||||
|
||||
$matches = $this->getMatches($envelope, $passwords);
|
||||
if (!$matches) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->shouldUpgradeHashers()) {
|
||||
$this->upgradeHashers($envelope, $matches);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isUniquePassword(PhutilOpaqueEnvelope $envelope) {
|
||||
$this->requireSetup();
|
||||
|
||||
$password_type = $this->getPasswordType();
|
||||
|
||||
// To test that the password is unique, we're loading all active and
|
||||
// revoked passwords for all roles for the given user, then throwing out
|
||||
// the active passwords for the current role (so a password can't
|
||||
// collide with itself).
|
||||
|
||||
// Note that two different objects can have the same password (say,
|
||||
// users @alice and @bailey). We're only preventing @alice from using
|
||||
// the same password for everything.
|
||||
|
||||
$passwords = $this->newQuery()
|
||||
->execute();
|
||||
|
||||
foreach ($passwords as $key => $password) {
|
||||
$same_type = ($password->getPasswordType() === $password_type);
|
||||
$is_active = !$password->getIsRevoked();
|
||||
|
||||
if ($same_type && $is_active) {
|
||||
unset($passwords[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$matches = $this->getMatches($envelope, $passwords);
|
||||
|
||||
return !$matches;
|
||||
}
|
||||
|
||||
public function isRevokedPassword(PhutilOpaqueEnvelope $envelope) {
|
||||
$this->requireSetup();
|
||||
|
||||
// To test if a password is revoked, we're loading all revoked passwords
|
||||
// across all roles for the given user. If a password was revoked in one
|
||||
// role, you can't reuse it in a different role.
|
||||
|
||||
$passwords = $this->newQuery()
|
||||
->withIsRevoked(true)
|
||||
->execute();
|
||||
|
||||
$matches = $this->getMatches($envelope, $passwords);
|
||||
|
||||
return (bool)$matches;
|
||||
}
|
||||
|
||||
private function requireSetup() {
|
||||
if (!$this->getObject()) {
|
||||
throw new PhutilInvalidStateException('setObject');
|
||||
}
|
||||
|
||||
if (!$this->getPasswordType()) {
|
||||
throw new PhutilInvalidStateException('setPasswordType');
|
||||
}
|
||||
|
||||
if (!$this->getViewer()) {
|
||||
throw new PhutilInvalidStateException('setViewer');
|
||||
}
|
||||
|
||||
if ($this->shouldUpgradeHashers()) {
|
||||
if (!$this->getContentSource()) {
|
||||
throw new PhutilInvalidStateException('setContentSource');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function shouldUpgradeHashers() {
|
||||
if (!$this->getUpgradeHashers()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (PhabricatorEnv::isReadOnly()) {
|
||||
// Don't try to upgrade hashers if we're in read-only mode, since we
|
||||
// won't be able to write the new hash to the database.
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function newQuery() {
|
||||
$viewer = $this->getViewer();
|
||||
$object = $this->getObject();
|
||||
$password_type = $this->getPasswordType();
|
||||
|
||||
return id(new PhabricatorAuthPasswordQuery())
|
||||
->setViewer($viewer)
|
||||
->withObjectPHIDs(array($object->getPHID()));
|
||||
}
|
||||
|
||||
private function getMatches(
|
||||
PhutilOpaqueEnvelope $envelope,
|
||||
array $passwords) {
|
||||
|
||||
$object = $this->getObject();
|
||||
|
||||
$matches = array();
|
||||
foreach ($passwords as $password) {
|
||||
try {
|
||||
$is_match = $password->comparePassword($envelope, $object);
|
||||
} catch (PhabricatorPasswordHasherUnavailableException $ex) {
|
||||
$is_match = false;
|
||||
}
|
||||
|
||||
if ($is_match) {
|
||||
$matches[] = $password;
|
||||
}
|
||||
}
|
||||
|
||||
return $matches;
|
||||
}
|
||||
|
||||
private function upgradeHashers(
|
||||
PhutilOpaqueEnvelope $envelope,
|
||||
array $passwords) {
|
||||
|
||||
assert_instances_of($passwords, 'PhabricatorAuthPassword');
|
||||
|
||||
$need_upgrade = array();
|
||||
foreach ($passwords as $password) {
|
||||
if (!$password->canUpgrade()) {
|
||||
continue;
|
||||
}
|
||||
$need_upgrade[] = $password;
|
||||
}
|
||||
|
||||
if (!$need_upgrade) {
|
||||
return;
|
||||
}
|
||||
|
||||
$upgrade_type = PhabricatorAuthPasswordUpgradeTransaction::TRANSACTIONTYPE;
|
||||
$viewer = $this->getViewer();
|
||||
$content_source = $this->getContentSource();
|
||||
|
||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
||||
foreach ($need_upgrade as $password) {
|
||||
|
||||
// This does the actual upgrade. We then apply a transaction to make
|
||||
// the upgrade more visible and auditable.
|
||||
$old_hasher = $password->getHasher();
|
||||
$password->upgradePasswordHasher($envelope, $this->getObject());
|
||||
$new_hasher = $password->getHasher();
|
||||
|
||||
$xactions = array();
|
||||
|
||||
$xactions[] = $password->getApplicationTransactionTemplate()
|
||||
->setTransactionType($upgrade_type)
|
||||
->setNewValue($new_hasher->getHashName());
|
||||
|
||||
$editor = $password->getApplicationTransactionEditor()
|
||||
->setActor($viewer)
|
||||
->setContinueOnNoEffect(true)
|
||||
->setContinueOnMissingFields(true)
|
||||
->setContentSource($content_source)
|
||||
->setOldHasher($old_hasher)
|
||||
->applyTransactions($password, $xactions);
|
||||
}
|
||||
unset($unguarded);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorPasswordDestructionEngineExtension
|
||||
extends PhabricatorDestructionEngineExtension {
|
||||
|
||||
const EXTENSIONKEY = 'passwords';
|
||||
|
||||
public function getExtensionName() {
|
||||
return pht('Passwords');
|
||||
}
|
||||
|
||||
public function destroyObject(
|
||||
PhabricatorDestructionEngine $engine,
|
||||
$object) {
|
||||
|
||||
$viewer = $engine->getViewer();
|
||||
$object_phid = $object->getPHID();
|
||||
|
||||
$passwords = id(new PhabricatorAuthPasswordQuery())
|
||||
->setViewer($viewer)
|
||||
->withObjectPHIDs(array($object_phid))
|
||||
->execute();
|
||||
|
||||
foreach ($passwords as $password) {
|
||||
$engine->destroyObject($password);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -9,8 +9,8 @@ final class PhabricatorAuthManagementRecoverWorkflow
|
|||
->setExamples('**recover** __username__')
|
||||
->setSynopsis(
|
||||
pht(
|
||||
'Recover access to an administrative account if you have locked '.
|
||||
'yourself out of Phabricator.'))
|
||||
'Recover access to an account if you have locked yourself out '.
|
||||
'of Phabricator.'))
|
||||
->setArguments(
|
||||
array(
|
||||
'username' => array(
|
||||
|
@ -21,23 +21,6 @@ final class PhabricatorAuthManagementRecoverWorkflow
|
|||
}
|
||||
|
||||
public function execute(PhutilArgumentParser $args) {
|
||||
|
||||
$can_recover = id(new PhabricatorPeopleQuery())
|
||||
->setViewer($this->getViewer())
|
||||
->withIsAdmin(true)
|
||||
->execute();
|
||||
if (!$can_recover) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
pht(
|
||||
'This Phabricator installation has no recoverable administrator '.
|
||||
'accounts. You can use `%s` to create a new administrator '.
|
||||
'account or make an existing user an administrator.',
|
||||
'bin/accountadmin'));
|
||||
}
|
||||
$can_recover = mpull($can_recover, 'getUsername');
|
||||
sort($can_recover);
|
||||
$can_recover = implode(', ', $can_recover);
|
||||
|
||||
$usernames = $args->getArg('username');
|
||||
if (!$usernames) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
|
@ -57,18 +40,8 @@ final class PhabricatorAuthManagementRecoverWorkflow
|
|||
if (!$user) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
pht(
|
||||
'No such user "%s". Recoverable administrator accounts are: %s.',
|
||||
$username,
|
||||
$can_recover));
|
||||
}
|
||||
|
||||
if (!$user->getIsAdmin()) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
pht(
|
||||
'You can only recover administrator accounts, but %s is not an '.
|
||||
'administrator. Recoverable administrator accounts are: %s.',
|
||||
$username,
|
||||
$can_recover));
|
||||
'No such user "%s" to recover.',
|
||||
$username));
|
||||
}
|
||||
|
||||
if (!$user->canEstablishWebSessions()) {
|
||||
|
|
|
@ -7,7 +7,8 @@ final class PhabricatorAuthManagementRevokeWorkflow
|
|||
$this
|
||||
->setName('revoke')
|
||||
->setExamples(
|
||||
"**revoke** --type __type__ --from __user__\n".
|
||||
"**revoke** --list\n".
|
||||
"**revoke** --type __type__ --from __@user__\n".
|
||||
"**revoke** --everything --everywhere")
|
||||
->setSynopsis(
|
||||
pht(
|
||||
|
@ -16,15 +17,20 @@ final class PhabricatorAuthManagementRevokeWorkflow
|
|||
array(
|
||||
array(
|
||||
'name' => 'from',
|
||||
'param' => 'user',
|
||||
'param' => 'object',
|
||||
'help' => pht(
|
||||
'Revoke credentials for the specified user.'),
|
||||
'Revoke credentials for the specified object. To revoke '.
|
||||
'credentials for a user, use "@username".'),
|
||||
),
|
||||
array(
|
||||
'name' => 'type',
|
||||
'param' => 'type',
|
||||
'help' => pht('Revoke credentials of the given type.'),
|
||||
),
|
||||
array(
|
||||
'name' => 'list',
|
||||
'help' => pht(
|
||||
'Revoke credentials of the given type.'),
|
||||
'List information about available credential revokers.'),
|
||||
),
|
||||
array(
|
||||
'name' => 'everything',
|
||||
|
@ -34,21 +40,37 @@ final class PhabricatorAuthManagementRevokeWorkflow
|
|||
'name' => 'everywhere',
|
||||
'help' => pht('Revoke from all credential owners.'),
|
||||
),
|
||||
array(
|
||||
'name' => 'force',
|
||||
'help' => pht('Revoke credentials without prompting.'),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
public function execute(PhutilArgumentParser $args) {
|
||||
$viewer = PhabricatorUser::getOmnipotentUser();
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$all_types = PhabricatorAuthRevoker::getAllRevokers();
|
||||
$is_force = $args->getArg('force');
|
||||
|
||||
// The "--list" flag is compatible with revoker selection flags like
|
||||
// "--type" to filter the list, but not compatible with target selection
|
||||
// flags like "--from".
|
||||
$is_list = $args->getArg('list');
|
||||
|
||||
$type = $args->getArg('type');
|
||||
$is_everything = $args->getArg('everything');
|
||||
if (!strlen($type) && !$is_everything) {
|
||||
if ($is_list) {
|
||||
// By default, "bin/revoke --list" implies "--everything".
|
||||
$types = $all_types;
|
||||
} else {
|
||||
throw new PhutilArgumentUsageException(
|
||||
pht(
|
||||
'Specify the credential type to revoke with "--type" or specify '.
|
||||
'"--everything".'));
|
||||
'"--everything". Use "--list" to list available credential '.
|
||||
'types.'));
|
||||
}
|
||||
} else if (strlen($type) && $is_everything) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
pht(
|
||||
|
@ -70,6 +92,32 @@ final class PhabricatorAuthManagementRevokeWorkflow
|
|||
|
||||
$is_everywhere = $args->getArg('everywhere');
|
||||
$from = $args->getArg('from');
|
||||
|
||||
if ($is_list) {
|
||||
if (strlen($from) || $is_everywhere) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
pht(
|
||||
'You can not "--list" and revoke credentials (with "--from" or '.
|
||||
'"--everywhere") in the same operation.'));
|
||||
}
|
||||
}
|
||||
|
||||
if ($is_list) {
|
||||
$last_key = last_key($types);
|
||||
foreach ($types as $key => $type) {
|
||||
echo tsprintf(
|
||||
"**%s** (%s)\n\n",
|
||||
$type->getRevokerKey(),
|
||||
$type->getRevokerName());
|
||||
|
||||
id(new PhutilConsoleBlock())
|
||||
->addParagraph(tsprintf('%B', $type->getRevokerDescription()))
|
||||
->draw();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$target = null;
|
||||
if (!strlen($from) && !$is_everywhere) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
|
@ -97,7 +145,7 @@ final class PhabricatorAuthManagementRevokeWorkflow
|
|||
}
|
||||
}
|
||||
|
||||
if ($is_everywhere) {
|
||||
if ($is_everywhere && !$is_force) {
|
||||
echo id(new PhutilConsoleBlock())
|
||||
->addParagraph(
|
||||
pht(
|
||||
|
@ -128,6 +176,13 @@ final class PhabricatorAuthManagementRevokeWorkflow
|
|||
'Destroyed %s credential(s) of type "%s".',
|
||||
new PhutilNumber($count),
|
||||
$type->getRevokerKey()));
|
||||
|
||||
$guidance = $type->getRevokerNextSteps();
|
||||
if ($guidance !== null) {
|
||||
echo tsprintf(
|
||||
"%s\n",
|
||||
$guidance);
|
||||
}
|
||||
}
|
||||
|
||||
echo tsprintf(
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorAuthPasswordException
|
||||
extends Exception {
|
||||
|
||||
private $passwordError;
|
||||
private $confirmErorr;
|
||||
|
||||
public function __construct(
|
||||
$message,
|
||||
$password_error,
|
||||
$confirm_error = null) {
|
||||
|
||||
$this->passwordError = $password_error;
|
||||
$this->confirmError = $confirm_error;
|
||||
|
||||
parent::__construct($message);
|
||||
}
|
||||
|
||||
public function getPasswordError() {
|
||||
return $this->passwordError;
|
||||
}
|
||||
|
||||
public function getConfirmError() {
|
||||
return $this->confirmError;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
interface PhabricatorAuthPasswordHashInterface {
|
||||
|
||||
public function newPasswordDigest(
|
||||
PhutilOpaqueEnvelope $envelope,
|
||||
PhabricatorAuthPassword $password);
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorAuthPasswordPHIDType extends PhabricatorPHIDType {
|
||||
|
||||
const TYPECONST = 'APAS';
|
||||
|
||||
public function getTypeName() {
|
||||
return pht('Auth Password');
|
||||
}
|
||||
|
||||
public function newObject() {
|
||||
return new PhabricatorAuthPassword();
|
||||
}
|
||||
|
||||
public function getPHIDTypeApplicationClass() {
|
||||
return 'PhabricatorAuthApplication';
|
||||
}
|
||||
|
||||
protected function buildQueryForObjects(
|
||||
PhabricatorObjectQuery $query,
|
||||
array $phids) {
|
||||
return id(new PhabricatorAuthPasswordQuery())
|
||||
->withPHIDs($phids);
|
||||
}
|
||||
|
||||
public function loadHandles(
|
||||
PhabricatorHandleQuery $query,
|
||||
array $handles,
|
||||
array $objects) {
|
||||
|
||||
foreach ($handles as $phid => $handle) {
|
||||
$password = $objects[$phid];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -253,6 +253,7 @@ final class PhabricatorPasswordAuthProvider extends PhabricatorAuthProvider {
|
|||
|
||||
$request = $controller->getRequest();
|
||||
$viewer = $request->getUser();
|
||||
$content_source = PhabricatorContentSource::newFromRequest($request);
|
||||
|
||||
$require_captcha = false;
|
||||
$captcha_valid = false;
|
||||
|
@ -285,22 +286,16 @@ final class PhabricatorPasswordAuthProvider extends PhabricatorAuthProvider {
|
|||
|
||||
if ($user) {
|
||||
$envelope = new PhutilOpaqueEnvelope($request->getStr('password'));
|
||||
if ($user->comparePassword($envelope)) {
|
||||
|
||||
$engine = id(new PhabricatorAuthPasswordEngine())
|
||||
->setViewer($user)
|
||||
->setContentSource($content_source)
|
||||
->setPasswordType(PhabricatorAuthPassword::PASSWORD_TYPE_ACCOUNT)
|
||||
->setObject($user);
|
||||
|
||||
if ($engine->isValidPassword($envelope)) {
|
||||
$account = $this->loadOrCreateAccount($user->getPHID());
|
||||
$log_user = $user;
|
||||
|
||||
// If the user's password is stored using a less-than-optimal
|
||||
// hash, upgrade them to the strongest available hash.
|
||||
|
||||
$hash_envelope = new PhutilOpaqueEnvelope(
|
||||
$user->getPasswordHash());
|
||||
if (PhabricatorPasswordHasher::canUpgradeHash($hash_envelope)) {
|
||||
$user->setPassword($envelope);
|
||||
|
||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
||||
$user->save();
|
||||
unset($unguarded);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
114
src/applications/auth/query/PhabricatorAuthPasswordQuery.php
Normal file
114
src/applications/auth/query/PhabricatorAuthPasswordQuery.php
Normal file
|
@ -0,0 +1,114 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorAuthPasswordQuery
|
||||
extends PhabricatorCursorPagedPolicyAwareQuery {
|
||||
|
||||
private $ids;
|
||||
private $phids;
|
||||
private $objectPHIDs;
|
||||
private $passwordTypes;
|
||||
private $isRevoked;
|
||||
|
||||
public function withIDs(array $ids) {
|
||||
$this->ids = $ids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withPHIDs(array $phids) {
|
||||
$this->phids = $phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withObjectPHIDs(array $object_phids) {
|
||||
$this->objectPHIDs = $object_phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withPasswordTypes(array $types) {
|
||||
$this->passwordTypes = $types;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withIsRevoked($is_revoked) {
|
||||
$this->isRevoked = $is_revoked;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function newResultObject() {
|
||||
return new PhabricatorAuthPassword();
|
||||
}
|
||||
|
||||
protected function loadPage() {
|
||||
return $this->loadStandardPage($this->newResultObject());
|
||||
}
|
||||
|
||||
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
|
||||
$where = parent::buildWhereClauseParts($conn);
|
||||
|
||||
if ($this->ids !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'id IN (%Ld)',
|
||||
$this->ids);
|
||||
}
|
||||
|
||||
if ($this->phids !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'phid IN (%Ls)',
|
||||
$this->phids);
|
||||
}
|
||||
|
||||
if ($this->objectPHIDs !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'objectPHID IN (%Ls)',
|
||||
$this->objectPHIDs);
|
||||
}
|
||||
|
||||
if ($this->passwordTypes !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'passwordType IN (%Ls)',
|
||||
$this->passwordTypes);
|
||||
}
|
||||
|
||||
if ($this->isRevoked !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'isRevoked = %d',
|
||||
(int)$this->isRevoked);
|
||||
}
|
||||
|
||||
return $where;
|
||||
}
|
||||
|
||||
protected function willFilterPage(array $passwords) {
|
||||
$object_phids = mpull($passwords, 'getObjectPHID');
|
||||
|
||||
$objects = id(new PhabricatorObjectQuery())
|
||||
->setViewer($this->getViewer())
|
||||
->setParentQuery($this)
|
||||
->withPHIDs($object_phids)
|
||||
->execute();
|
||||
$objects = mpull($objects, null, 'getPHID');
|
||||
|
||||
foreach ($passwords as $key => $password) {
|
||||
$object = idx($objects, $password->getObjectPHID());
|
||||
if (!$object) {
|
||||
unset($passwords[$key]);
|
||||
$this->didRejectResult($password);
|
||||
continue;
|
||||
}
|
||||
|
||||
$password->attachObject($object);
|
||||
}
|
||||
|
||||
return $passwords;
|
||||
}
|
||||
|
||||
public function getQueryApplicationClass() {
|
||||
return 'PhabricatorAuthApplication';
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorAuthPasswordTransactionQuery
|
||||
extends PhabricatorApplicationTransactionQuery {
|
||||
|
||||
public function getTemplateApplicationTransaction() {
|
||||
return new PhabricatorAuthPasswordTransaction();
|
||||
}
|
||||
|
||||
}
|
|
@ -5,6 +5,19 @@ final class PhabricatorAuthConduitTokenRevoker
|
|||
|
||||
const REVOKERKEY = 'conduit';
|
||||
|
||||
public function getRevokerName() {
|
||||
return pht('Conduit API Tokens');
|
||||
}
|
||||
|
||||
public function getRevokerDescription() {
|
||||
return pht(
|
||||
"Revokes all Conduit API tokens used to access the API.\n\n".
|
||||
"Users will need to use `arc install-certificate` to install new ".
|
||||
"API tokens before `arc` commands will work. Bots and scripts which ".
|
||||
"access the API will need to have new tokens generated and ".
|
||||
"installed.");
|
||||
}
|
||||
|
||||
public function revokeAllCredentials() {
|
||||
$table = id(new PhabricatorConduitToken());
|
||||
$conn = $table->establishConnection('w');
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorAuthPasswordRevoker
|
||||
extends PhabricatorAuthRevoker {
|
||||
|
||||
const REVOKERKEY = 'password';
|
||||
|
||||
public function getRevokerName() {
|
||||
return pht('Passwords');
|
||||
}
|
||||
|
||||
public function getRevokerDescription() {
|
||||
return pht(
|
||||
"Revokes all stored passwords.\n\n".
|
||||
"Account passwords and VCS passwords (used to access repositories ".
|
||||
"over HTTP) will both be revoked. Passwords for any third party ".
|
||||
"applications which use shared password infrastructure will also ".
|
||||
"be revoked.\n\n".
|
||||
"Users will need to reset account passwords, possibly by using the ".
|
||||
"\"Forgot Password?\" link on the login page. They will also need ".
|
||||
"to reset VCS passwords.\n\n".
|
||||
"Passwords are revoked, not just removed. Users will be unable to ".
|
||||
"select the passwords they used previously and must choose new, ".
|
||||
"unique passwords.\n\n".
|
||||
"Revoking passwords will not terminate outstanding login sessions. ".
|
||||
"Use the \"session\" revoker in conjunction with this revoker to force ".
|
||||
"users to login again.");
|
||||
}
|
||||
|
||||
public function getRevokerNextSteps() {
|
||||
return pht(
|
||||
'NOTE: Revoking passwords does not terminate existing sessions which '.
|
||||
'were established using the old passwords. To terminate existing '.
|
||||
'sessions, run the "session" revoker now.');
|
||||
}
|
||||
|
||||
public function revokeAllCredentials() {
|
||||
$query = new PhabricatorAuthPasswordQuery();
|
||||
return $this->revokeWithQuery($query);
|
||||
}
|
||||
|
||||
public function revokeCredentialsFrom($object) {
|
||||
$query = id(new PhabricatorAuthPasswordQuery())
|
||||
->withObjectPHIDs(array($object->getPHID()));
|
||||
return $this->revokeWithQuery($query);
|
||||
}
|
||||
|
||||
private function revokeWithQuery(PhabricatorAuthPasswordQuery $query) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$passwords = $query
|
||||
->setViewer($viewer)
|
||||
->withIsRevoked(false)
|
||||
->execute();
|
||||
|
||||
$content_source = PhabricatorContentSource::newForSource(
|
||||
PhabricatorDaemonContentSource::SOURCECONST);
|
||||
|
||||
$revoke_type = PhabricatorAuthPasswordRevokeTransaction::TRANSACTIONTYPE;
|
||||
|
||||
$auth_phid = id(new PhabricatorAuthApplication())->getPHID();
|
||||
foreach ($passwords as $password) {
|
||||
$xactions = array();
|
||||
|
||||
$xactions[] = $password->getApplicationTransactionTemplate()
|
||||
->setTransactionType($revoke_type)
|
||||
->setNewValue(true);
|
||||
|
||||
$editor = $password->getApplicationTransactionEditor()
|
||||
->setActor($viewer)
|
||||
->setActingAsPHID($auth_phid)
|
||||
->setContinueOnNoEffect(true)
|
||||
->setContinueOnMissingFields(true)
|
||||
->setContentSource($content_source)
|
||||
->applyTransactions($password, $xactions);
|
||||
}
|
||||
|
||||
return count($passwords);
|
||||
}
|
||||
|
||||
}
|
|
@ -5,9 +5,16 @@ abstract class PhabricatorAuthRevoker
|
|||
|
||||
private $viewer;
|
||||
|
||||
abstract public function revokeAlLCredentials();
|
||||
abstract public function revokeAllCredentials();
|
||||
abstract public function revokeCredentialsFrom($object);
|
||||
|
||||
abstract public function getRevokerName();
|
||||
abstract public function getRevokerDescription();
|
||||
|
||||
public function getRevokerNextSteps() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function setViewer(PhabricatorUser $viewer) {
|
||||
$this->viewer = $viewer;
|
||||
return $this;
|
||||
|
|
65
src/applications/auth/revoker/PhabricatorAuthSSHRevoker.php
Normal file
65
src/applications/auth/revoker/PhabricatorAuthSSHRevoker.php
Normal file
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorAuthSSHRevoker
|
||||
extends PhabricatorAuthRevoker {
|
||||
|
||||
const REVOKERKEY = 'ssh';
|
||||
|
||||
public function getRevokerName() {
|
||||
return pht('SSH Keys');
|
||||
}
|
||||
|
||||
public function getRevokerDescription() {
|
||||
return pht(
|
||||
"Revokes all SSH public keys.\n\n".
|
||||
"SSH public keys are revoked, not just removed. Users will need to ".
|
||||
"generate and upload new, unique keys before they can access ".
|
||||
"repositories or other services over SSH.");
|
||||
}
|
||||
|
||||
public function revokeAllCredentials() {
|
||||
$query = new PhabricatorAuthSSHKeyQuery();
|
||||
return $this->revokeWithQuery($query);
|
||||
}
|
||||
|
||||
public function revokeCredentialsFrom($object) {
|
||||
$query = id(new PhabricatorAuthSSHKeyQuery())
|
||||
->withObjectPHIDs(array($object->getPHID()));
|
||||
|
||||
return $this->revokeWithQuery($query);
|
||||
}
|
||||
|
||||
private function revokeWithQuery(PhabricatorAuthSSHKeyQuery $query) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
// We're only going to revoke keys which have not already been revoked.
|
||||
|
||||
$ssh_keys = $query
|
||||
->setViewer($viewer)
|
||||
->withIsActive(true)
|
||||
->execute();
|
||||
|
||||
$content_source = PhabricatorContentSource::newForSource(
|
||||
PhabricatorDaemonContentSource::SOURCECONST);
|
||||
|
||||
$auth_phid = id(new PhabricatorAuthApplication())->getPHID();
|
||||
foreach ($ssh_keys as $ssh_key) {
|
||||
$xactions = array();
|
||||
$xactions[] = $ssh_key->getApplicationTransactionTemplate()
|
||||
->setTransactionType(PhabricatorAuthSSHKeyTransaction::TYPE_DEACTIVATE)
|
||||
->setNewValue(1);
|
||||
|
||||
$editor = $ssh_key->getApplicationTransactionEditor()
|
||||
->setActor($viewer)
|
||||
->setActingAsPHID($auth_phid)
|
||||
->setContinueOnNoEffect(true)
|
||||
->setContinueOnMissingFields(true)
|
||||
->setContentSource($content_source)
|
||||
->setIsAdministrativeEdit(true)
|
||||
->applyTransactions($ssh_key, $xactions);
|
||||
}
|
||||
|
||||
return count($ssh_keys);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorAuthSessionRevoker
|
||||
extends PhabricatorAuthRevoker {
|
||||
|
||||
const REVOKERKEY = 'session';
|
||||
|
||||
public function getRevokerName() {
|
||||
return pht('Sessions');
|
||||
}
|
||||
|
||||
public function getRevokerDescription() {
|
||||
return pht(
|
||||
"Revokes all active login sessions.\n\n".
|
||||
"Affected users will be logged out and need to log in again.");
|
||||
}
|
||||
|
||||
public function revokeAllCredentials() {
|
||||
$table = new PhabricatorAuthSession();
|
||||
$conn = $table->establishConnection('w');
|
||||
|
||||
queryfx(
|
||||
$conn,
|
||||
'DELETE FROM %T',
|
||||
$table->getTableName());
|
||||
|
||||
return $conn->getAffectedRows();
|
||||
}
|
||||
|
||||
public function revokeCredentialsFrom($object) {
|
||||
$table = new PhabricatorAuthSession();
|
||||
$conn = $table->establishConnection('w');
|
||||
|
||||
queryfx(
|
||||
$conn,
|
||||
'DELETE FROM %T WHERE userPHID = %s',
|
||||
$table->getTableName(),
|
||||
$object->getPHID());
|
||||
|
||||
return $conn->getAffectedRows();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorAuthTemporaryTokenRevoker
|
||||
extends PhabricatorAuthRevoker {
|
||||
|
||||
const REVOKERKEY = 'temporary';
|
||||
|
||||
public function getRevokerName() {
|
||||
return pht('Temporary Tokens');
|
||||
}
|
||||
|
||||
public function getRevokerDescription() {
|
||||
return pht(
|
||||
"Revokes temporary authentication tokens.\n\n".
|
||||
"Temporary tokens are used in password reset mail, welcome mail, and ".
|
||||
"by some other systems like Git LFS. Revoking temporary tokens will ".
|
||||
"invalidate existing links in password reset and invite mail that ".
|
||||
"was sent before the revocation occurred.");
|
||||
}
|
||||
|
||||
public function revokeAllCredentials() {
|
||||
$table = new PhabricatorAuthTemporaryToken();
|
||||
$conn = $table->establishConnection('w');
|
||||
|
||||
queryfx(
|
||||
$conn,
|
||||
'DELETE FROM %T',
|
||||
$table->getTableName());
|
||||
|
||||
return $conn->getAffectedRows();
|
||||
}
|
||||
|
||||
public function revokeCredentialsFrom($object) {
|
||||
$table = new PhabricatorAuthTemporaryToken();
|
||||
$conn = $table->establishConnection('w');
|
||||
|
||||
queryfx(
|
||||
$conn,
|
||||
'DELETE FROM %T WHERE tokenResource = %s',
|
||||
$table->getTableName(),
|
||||
$object->getPHID());
|
||||
|
||||
return $conn->getAffectedRows();
|
||||
}
|
||||
|
||||
}
|
235
src/applications/auth/storage/PhabricatorAuthPassword.php
Normal file
235
src/applications/auth/storage/PhabricatorAuthPassword.php
Normal file
|
@ -0,0 +1,235 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorAuthPassword
|
||||
extends PhabricatorAuthDAO
|
||||
implements
|
||||
PhabricatorPolicyInterface,
|
||||
PhabricatorDestructibleInterface,
|
||||
PhabricatorApplicationTransactionInterface {
|
||||
|
||||
protected $objectPHID;
|
||||
protected $passwordType;
|
||||
protected $passwordHash;
|
||||
protected $passwordSalt;
|
||||
protected $isRevoked;
|
||||
protected $legacyDigestFormat;
|
||||
|
||||
private $object = self::ATTACHABLE;
|
||||
|
||||
const PASSWORD_TYPE_ACCOUNT = 'account';
|
||||
const PASSWORD_TYPE_VCS = 'vcs';
|
||||
const PASSWORD_TYPE_TEST = 'test';
|
||||
|
||||
public static function initializeNewPassword(
|
||||
PhabricatorAuthPasswordHashInterface $object,
|
||||
$type) {
|
||||
|
||||
return id(new self())
|
||||
->setObjectPHID($object->getPHID())
|
||||
->attachObject($object)
|
||||
->setPasswordType($type)
|
||||
->setIsRevoked(0);
|
||||
}
|
||||
|
||||
protected function getConfiguration() {
|
||||
return array(
|
||||
self::CONFIG_AUX_PHID => true,
|
||||
self::CONFIG_COLUMN_SCHEMA => array(
|
||||
'passwordType' => 'text64',
|
||||
'passwordHash' => 'text128',
|
||||
'passwordSalt' => 'text64',
|
||||
'isRevoked' => 'bool',
|
||||
'legacyDigestFormat' => 'text32?',
|
||||
),
|
||||
self::CONFIG_KEY_SCHEMA => array(
|
||||
'key_role' => array(
|
||||
'columns' => array('objectPHID', 'passwordType'),
|
||||
),
|
||||
),
|
||||
) + parent::getConfiguration();
|
||||
}
|
||||
|
||||
public function getPHIDType() {
|
||||
return PhabricatorAuthPasswordPHIDType::TYPECONST;
|
||||
}
|
||||
|
||||
public function getObject() {
|
||||
return $this->assertAttached($this->object);
|
||||
}
|
||||
|
||||
public function attachObject($object) {
|
||||
$this->object = $object;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getHasher() {
|
||||
$hash = $this->newPasswordEnvelope();
|
||||
return PhabricatorPasswordHasher::getHasherForHash($hash);
|
||||
}
|
||||
|
||||
public function canUpgrade() {
|
||||
// If this password uses a legacy digest format, we can upgrade it to the
|
||||
// new digest format even if a better hasher isn't available.
|
||||
if ($this->getLegacyDigestFormat() !== null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$hash = $this->newPasswordEnvelope();
|
||||
return PhabricatorPasswordHasher::canUpgradeHash($hash);
|
||||
}
|
||||
|
||||
public function upgradePasswordHasher(
|
||||
PhutilOpaqueEnvelope $envelope,
|
||||
PhabricatorAuthPasswordHashInterface $object) {
|
||||
|
||||
// Before we make changes, double check that this is really the correct
|
||||
// password. It could be really bad if we "upgraded" a password and changed
|
||||
// the secret!
|
||||
|
||||
if (!$this->comparePassword($envelope, $object)) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Attempting to upgrade password hasher, but the password for the '.
|
||||
'upgrade is not the stored credential!'));
|
||||
}
|
||||
|
||||
return $this->setPassword($envelope, $object);
|
||||
}
|
||||
|
||||
public function setPassword(
|
||||
PhutilOpaqueEnvelope $password,
|
||||
PhabricatorAuthPasswordHashInterface $object) {
|
||||
|
||||
$hasher = PhabricatorPasswordHasher::getBestHasher();
|
||||
return $this->setPasswordWithHasher($password, $object, $hasher);
|
||||
}
|
||||
|
||||
public function setPasswordWithHasher(
|
||||
PhutilOpaqueEnvelope $password,
|
||||
PhabricatorAuthPasswordHashInterface $object,
|
||||
PhabricatorPasswordHasher $hasher) {
|
||||
|
||||
if (!strlen($password->openEnvelope())) {
|
||||
throw new Exception(
|
||||
pht('Attempting to set an empty password!'));
|
||||
}
|
||||
|
||||
// Generate (or regenerate) the salt first.
|
||||
$new_salt = Filesystem::readRandomCharacters(64);
|
||||
$this->setPasswordSalt($new_salt);
|
||||
|
||||
// Clear any legacy digest format to force a modern digest.
|
||||
$this->setLegacyDigestFormat(null);
|
||||
|
||||
$digest = $this->digestPassword($password, $object);
|
||||
$hash = $hasher->getPasswordHashForStorage($digest);
|
||||
$raw_hash = $hash->openEnvelope();
|
||||
|
||||
return $this->setPasswordHash($raw_hash);
|
||||
}
|
||||
|
||||
public function comparePassword(
|
||||
PhutilOpaqueEnvelope $password,
|
||||
PhabricatorAuthPasswordHashInterface $object) {
|
||||
|
||||
$digest = $this->digestPassword($password, $object);
|
||||
$hash = $this->newPasswordEnvelope();
|
||||
|
||||
return PhabricatorPasswordHasher::comparePassword($digest, $hash);
|
||||
}
|
||||
|
||||
public function newPasswordEnvelope() {
|
||||
return new PhutilOpaqueEnvelope($this->getPasswordHash());
|
||||
}
|
||||
|
||||
private function digestPassword(
|
||||
PhutilOpaqueEnvelope $password,
|
||||
PhabricatorAuthPasswordHashInterface $object) {
|
||||
|
||||
$object_phid = $object->getPHID();
|
||||
|
||||
if ($this->getObjectPHID() !== $object->getPHID()) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'This password is associated with an object PHID ("%s") for '.
|
||||
'a different object than the provided one ("%s").',
|
||||
$this->getObjectPHID(),
|
||||
$object->getPHID()));
|
||||
}
|
||||
|
||||
$digest = $object->newPasswordDigest($password, $this);
|
||||
|
||||
if (!($digest instanceof PhutilOpaqueEnvelope)) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Failed to digest password: object ("%s") did not return an '.
|
||||
'opaque envelope with a password digest.',
|
||||
$object->getPHID()));
|
||||
}
|
||||
|
||||
return $digest;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||
|
||||
|
||||
public function getCapabilities() {
|
||||
return array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
);
|
||||
}
|
||||
|
||||
public function getPolicy($capability) {
|
||||
return PhabricatorPolicies::getMostOpenPolicy();
|
||||
}
|
||||
|
||||
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* -( PhabricatorExtendedPolicyInterface )--------------------------------- */
|
||||
|
||||
|
||||
public function getExtendedPolicy($capability, PhabricatorUser $viewer) {
|
||||
return array(
|
||||
array($this->getObject(), PhabricatorPolicyCapability::CAN_VIEW),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/* -( PhabricatorDestructibleInterface )----------------------------------- */
|
||||
|
||||
|
||||
public function destroyObjectPermanently(
|
||||
PhabricatorDestructionEngine $engine) {
|
||||
$this->delete();
|
||||
}
|
||||
|
||||
|
||||
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
|
||||
|
||||
|
||||
public function getApplicationTransactionEditor() {
|
||||
return new PhabricatorAuthPasswordEditor();
|
||||
}
|
||||
|
||||
public function getApplicationTransactionObject() {
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getApplicationTransactionTemplate() {
|
||||
return new PhabricatorAuthPasswordTransaction();
|
||||
}
|
||||
|
||||
public function willRenderTimeline(
|
||||
PhabricatorApplicationTransactionView $timeline,
|
||||
AphrontRequest $request) {
|
||||
|
||||
return $timeline;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorAuthPasswordTransaction
|
||||
extends PhabricatorModularTransaction {
|
||||
|
||||
public function getApplicationName() {
|
||||
return 'auth';
|
||||
}
|
||||
|
||||
public function getApplicationTransactionType() {
|
||||
return PhabricatorAuthPasswordPHIDType::TYPECONST;
|
||||
}
|
||||
|
||||
public function getApplicationTransactionCommentObject() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getBaseTransactionClass() {
|
||||
return 'PhabricatorAuthPasswordTransactionType';
|
||||
}
|
||||
}
|
|
@ -139,7 +139,7 @@ final class PhabricatorAuthSSHKey
|
|||
public function describeAutomaticCapability($capability) {
|
||||
if (!$this->getIsACtive()) {
|
||||
return pht(
|
||||
'Deactivated SSH keys can not be edited or reactivated.');
|
||||
'Revoked SSH keys can not be edited or reinstated.');
|
||||
}
|
||||
|
||||
return pht(
|
||||
|
|
|
@ -43,11 +43,11 @@ final class PhabricatorAuthSSHKeyTransaction
|
|||
case self::TYPE_DEACTIVATE:
|
||||
if ($new) {
|
||||
return pht(
|
||||
'%s deactivated this key.',
|
||||
'%s revoked this key.',
|
||||
$this->renderHandleLink($author_phid));
|
||||
} else {
|
||||
return pht(
|
||||
'%s activated this key.',
|
||||
'%s reinstated this key.',
|
||||
$this->renderHandleLink($author_phid));
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorAuthPasswordRevokeTransaction
|
||||
extends PhabricatorAuthPasswordTransactionType {
|
||||
|
||||
const TRANSACTIONTYPE = 'password.revoke';
|
||||
|
||||
public function generateOldValue($object) {
|
||||
return (bool)$object->getIsRevoked();
|
||||
}
|
||||
|
||||
public function generateNewValue($object, $value) {
|
||||
return (bool)$value;
|
||||
}
|
||||
|
||||
public function applyInternalEffects($object, $value) {
|
||||
$object->setIsRevoked((int)$value);
|
||||
}
|
||||
|
||||
public function getTitle() {
|
||||
if ($this->getNewValue()) {
|
||||
return pht(
|
||||
'%s revoked this password.',
|
||||
$this->renderAuthor());
|
||||
} else {
|
||||
return pht(
|
||||
'%s removed this password from the revocation list.',
|
||||
$this->renderAuthor());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
<?php
|
||||
|
||||
abstract class PhabricatorAuthPasswordTransactionType
|
||||
extends PhabricatorModularTransactionType {}
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorAuthPasswordUpgradeTransaction
|
||||
extends PhabricatorAuthPasswordTransactionType {
|
||||
|
||||
const TRANSACTIONTYPE = 'password.upgrade';
|
||||
|
||||
public function generateOldValue($object) {
|
||||
$old_hasher = $this->getEditor()->getOldHasher();
|
||||
|
||||
if (!$old_hasher) {
|
||||
throw new PhutilInvalidStateException('setOldHasher');
|
||||
}
|
||||
|
||||
return $old_hasher->getHashName();
|
||||
}
|
||||
|
||||
public function generateNewValue($object, $value) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function getTitle() {
|
||||
return pht(
|
||||
'%s upgraded the hash algorithm for this password from "%s" to "%s".',
|
||||
$this->renderAuthor(),
|
||||
$this->renderOldValue(),
|
||||
$this->renderNewValue());
|
||||
}
|
||||
|
||||
}
|
|
@ -618,10 +618,14 @@ abstract class PhabricatorApplication
|
|||
')?';
|
||||
}
|
||||
|
||||
protected function getQueryRoutePattern($base = null) {
|
||||
protected function getBulkRoutePattern($base = null) {
|
||||
return $base.'(?:query/(?P<queryKey>[^/]+)/)?';
|
||||
}
|
||||
|
||||
protected function getQueryRoutePattern($base = null) {
|
||||
return $base.'(?:query/(?P<queryKey>[^/]+)/(?:(?P<queryAction>[^/]+)/)?)?';
|
||||
}
|
||||
|
||||
protected function getProfileMenuRouting($controller) {
|
||||
$edit_route = $this->getEditRoutePattern();
|
||||
|
||||
|
|
|
@ -49,13 +49,6 @@ final class PhabricatorCalendarEventHeraldAdapter extends HeraldAdapter {
|
|||
}
|
||||
}
|
||||
|
||||
public function getRepetitionOptions() {
|
||||
return array(
|
||||
HeraldRepetitionPolicyConfig::EVERY,
|
||||
HeraldRepetitionPolicyConfig::FIRST,
|
||||
);
|
||||
}
|
||||
|
||||
public function getHeraldName() {
|
||||
return $this->getObject()->getMonogram();
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ final class ConduitSSHWorkflow extends PhabricatorSSHWorkflow {
|
|||
|
||||
try {
|
||||
$call = new ConduitCall($method, $params);
|
||||
$call->setUser($this->getUser());
|
||||
$call->setUser($this->getSSHUser());
|
||||
|
||||
$result = $call->execute();
|
||||
} catch (ConduitException $ex) {
|
||||
|
@ -77,7 +77,7 @@ final class ConduitSSHWorkflow extends PhabricatorSSHWorkflow {
|
|||
|
||||
$connection_id = idx($metadata, 'connectionID');
|
||||
$log = id(new PhabricatorConduitMethodCallLog())
|
||||
->setCallerPHID($this->getUser()->getPHID())
|
||||
->setCallerPHID($this->getSSHUser()->getPHID())
|
||||
->setConnectionID($connection_id)
|
||||
->setMethod($method)
|
||||
->setError((string)$error_code)
|
||||
|
|
|
@ -18,7 +18,8 @@ final class PhabricatorGDSetupCheck extends PhabricatorSetupCheck {
|
|||
|
||||
$this->newIssue('extension.gd')
|
||||
->setName(pht("Missing '%s' Extension", 'gd'))
|
||||
->setMessage($message);
|
||||
->setMessage($message)
|
||||
->addPHPExtension('gd');
|
||||
} else {
|
||||
$image_type_map = array(
|
||||
'imagecreatefrompng' => 'PNG',
|
||||
|
|
|
@ -49,13 +49,22 @@ final class PhabricatorDaemonBulkJobMonitorController
|
|||
return id(new AphrontRedirectResponse())
|
||||
->setURI($job->getMonitorURI());
|
||||
} else {
|
||||
return $this->newDialog()
|
||||
->setTitle(pht('Confirm Bulk Job'))
|
||||
->appendParagraph($job->getDescriptionForConfirm())
|
||||
$dialog = $this->newDialog()
|
||||
->setTitle(pht('Confirm Bulk Job'));
|
||||
|
||||
$confirm = $job->getDescriptionForConfirm();
|
||||
$confirm = (array)$confirm;
|
||||
foreach ($confirm as $paragraph) {
|
||||
$dialog->appendParagraph($paragraph);
|
||||
}
|
||||
|
||||
$dialog
|
||||
->appendParagraph(
|
||||
pht('Start work on this bulk job?'))
|
||||
->addCancelButton($job->getManageURI(), pht('Details'))
|
||||
->addSubmitButton(pht('Start Work'));
|
||||
|
||||
return $dialog;
|
||||
}
|
||||
} else {
|
||||
return $this->newDialog()
|
||||
|
|
|
@ -79,13 +79,20 @@ final class PhabricatorWorkerTaskDetailController
|
|||
->appendChild($view);
|
||||
}
|
||||
|
||||
private function buildPropertyListView(
|
||||
PhabricatorWorkerTask $task) {
|
||||
|
||||
$viewer = $this->getRequest()->getUser();
|
||||
private function buildPropertyListView(PhabricatorWorkerTask $task) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$view = new PHUIPropertyListView();
|
||||
|
||||
$object_phid = $task->getObjectPHID();
|
||||
if ($object_phid) {
|
||||
$handles = $viewer->loadHandles(array($object_phid));
|
||||
$handle = $handles[$object_phid];
|
||||
if ($handle->isComplete()) {
|
||||
$view->addProperty(pht('Object'), $handle->renderLink());
|
||||
}
|
||||
}
|
||||
|
||||
if ($task->isArchived()) {
|
||||
switch ($task->getResult()) {
|
||||
case PhabricatorWorkerArchiveTask::RESULT_SUCCESS:
|
||||
|
|
|
@ -106,9 +106,11 @@ final class DifferentialCreateCommentConduitAPIMethod
|
|||
}
|
||||
}
|
||||
|
||||
// NOTE: The legacy "silent" flag is now ignored and has no effect. See
|
||||
// T13042.
|
||||
|
||||
$editor = id(new DifferentialTransactionEditor())
|
||||
->setActor($viewer)
|
||||
->setDisableEmail($request->getValue('silent'))
|
||||
->setContentSource($request->newContentSource())
|
||||
->setContinueOnNoEffect(true)
|
||||
->setContinueOnMissingFields(true);
|
||||
|
|
|
@ -700,20 +700,26 @@ final class DifferentialTransactionEditor
|
|||
->addHeader('Thread-Topic', $thread_topic);
|
||||
}
|
||||
|
||||
protected function buildMailBody(
|
||||
protected function getTransactionsForMail(
|
||||
PhabricatorLiskDAO $object,
|
||||
array $xactions) {
|
||||
|
||||
$viewer = $this->requireActor();
|
||||
|
||||
// If this is the first time we're sending mail about this revision, we
|
||||
// generate mail for all prior transactions, not just whatever is being
|
||||
// applied now. This gets the "added reviewers" lines and other relevant
|
||||
// information into the mail.
|
||||
if ($this->isFirstBroadcast()) {
|
||||
$xactions = $this->loadUnbroadcastTransactions($object);
|
||||
return $this->loadUnbroadcastTransactions($object);
|
||||
}
|
||||
|
||||
return $xactions;
|
||||
}
|
||||
|
||||
protected function buildMailBody(
|
||||
PhabricatorLiskDAO $object,
|
||||
array $xactions) {
|
||||
|
||||
$viewer = $this->requireActor();
|
||||
|
||||
$body = new PhabricatorMetaMTAMailBody();
|
||||
$body->setViewer($this->requireActor());
|
||||
|
||||
|
@ -1565,9 +1571,29 @@ final class DifferentialTransactionEditor
|
|||
|
||||
|
||||
protected function didApplyTransactions($object, array $xactions) {
|
||||
// In a moment, we're going to try to publish draft revisions which have
|
||||
// completed all their builds. However, we only want to do that if the
|
||||
// actor is either the revision author or an omnipotent user (generally,
|
||||
// the Harbormaster application).
|
||||
|
||||
// If we let any actor publish the revision as a side effect of other
|
||||
// changes then an unlucky third party who innocently comments on the draft
|
||||
// can end up racing Harbormaster and promoting the revision. At best, this
|
||||
// is confusing. It can also run into validation problems with the "Request
|
||||
// Review" transaction. See PHI309 for some discussion.
|
||||
$author_phid = $object->getAuthorPHID();
|
||||
$viewer = $this->requireActor();
|
||||
$can_undraft =
|
||||
($this->getActingAsPHID() === $author_phid) ||
|
||||
($viewer->isOmnipotent());
|
||||
|
||||
// If a draft revision has no outstanding builds and we're automatically
|
||||
// making drafts public after builds finish, make the revision public.
|
||||
if ($can_undraft) {
|
||||
$auto_undraft = !$object->getHoldAsDraft();
|
||||
} else {
|
||||
$auto_undraft = false;
|
||||
}
|
||||
|
||||
if ($object->isDraft() && $auto_undraft) {
|
||||
$active_builds = $this->hasActiveBuilds($object);
|
||||
|
@ -1575,7 +1601,6 @@ final class DifferentialTransactionEditor
|
|||
// When Harbormaster moves a revision out of the draft state, we
|
||||
// attribute the action to the revision author since this is more
|
||||
// natural and more useful.
|
||||
$author_phid = $object->getAuthorPHID();
|
||||
|
||||
// Additionally, we change the acting PHID for the transaction set
|
||||
// to the author if it isn't already a user so that mail comes from
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
final class DifferentialRevisionStatusHeraldField
|
||||
extends DifferentialRevisionHeraldField {
|
||||
|
||||
const FIELDCONST = 'revision.status';
|
||||
|
||||
public function getHeraldFieldName() {
|
||||
return pht('Revision status');
|
||||
}
|
||||
|
||||
public function getHeraldFieldValue($object) {
|
||||
return $object->getStatus();
|
||||
}
|
||||
|
||||
protected function getHeraldFieldStandardType() {
|
||||
return self::STANDARD_PHID;
|
||||
}
|
||||
|
||||
protected function getDatasource() {
|
||||
return new DifferentialRevisionStatusDatasource();
|
||||
}
|
||||
|
||||
protected function getDatasourceValueMap() {
|
||||
$map = DifferentialRevisionStatus::getAll();
|
||||
return mpull($map, 'getDisplayName', 'getKey');
|
||||
}
|
||||
|
||||
}
|
|
@ -53,12 +53,6 @@ final class HeraldDifferentialDiffAdapter extends HeraldDifferentialAdapter {
|
|||
}
|
||||
}
|
||||
|
||||
public function getRepetitionOptions() {
|
||||
return array(
|
||||
HeraldRepetitionPolicyConfig::FIRST,
|
||||
);
|
||||
}
|
||||
|
||||
public function getHeraldName() {
|
||||
return pht('New Diff');
|
||||
}
|
||||
|
|
|
@ -69,13 +69,6 @@ final class HeraldDifferentialRevisionAdapter
|
|||
}
|
||||
}
|
||||
|
||||
public function getRepetitionOptions() {
|
||||
return array(
|
||||
HeraldRepetitionPolicyConfig::EVERY,
|
||||
HeraldRepetitionPolicyConfig::FIRST,
|
||||
);
|
||||
}
|
||||
|
||||
public static function newLegacyAdapter(
|
||||
DifferentialRevision $revision,
|
||||
DifferentialDiff $diff) {
|
||||
|
|
|
@ -173,7 +173,7 @@ final class DifferentialChangeset
|
|||
}
|
||||
|
||||
public function getAnchorName() {
|
||||
return 'change-'.PhabricatorHash::digestForIndex($this->getFilename());
|
||||
return 'change-'.PhabricatorHash::digestForAnchor($this->getFilename());
|
||||
}
|
||||
|
||||
public function getAbsoluteRepositoryPath(
|
||||
|
|
|
@ -100,6 +100,13 @@ final class DifferentialTransaction
|
|||
return true;
|
||||
}
|
||||
break;
|
||||
case DifferentialRevisionRequestReviewTransaction::TRANSACTIONTYPE:
|
||||
// Don't hide the initial "X requested review: ..." transaction from
|
||||
// mail or feed even when it occurs during creation. We need this
|
||||
// transaction to survive so we'll generate mail and feed stories when
|
||||
// revisions immediately leave the draft state. See T13035 for
|
||||
// discussion.
|
||||
return false;
|
||||
}
|
||||
|
||||
return parent::shouldHide();
|
||||
|
@ -111,12 +118,6 @@ final class DifferentialTransaction
|
|||
// Don't hide the initial "X added reviewers: ..." transaction during
|
||||
// object creation from mail. See T12118 and PHI54.
|
||||
return false;
|
||||
case DifferentialRevisionRequestReviewTransaction::TRANSACTIONTYPE:
|
||||
// Don't hide the initial "X requested review: ..." transaction from
|
||||
// mail even when it occurs during creation. We need this transaction
|
||||
// to survive so we'll generate mail when revisions immediately leave
|
||||
// the draft state. See T13035 for discussion.
|
||||
return false;
|
||||
}
|
||||
|
||||
return parent::shouldHideForMail($xactions);
|
||||
|
|
|
@ -204,6 +204,7 @@ final class DifferentialChangesetDetailView extends AphrontView {
|
|||
'loaded' => $this->getLoaded(),
|
||||
'undoTemplates' => hsprintf('%s', $renderer->renderUndoTemplates()),
|
||||
'displayPath' => hsprintf('%s', $display_parts),
|
||||
'path' => $display_filename,
|
||||
'icon' => $display_icon,
|
||||
),
|
||||
'class' => $class,
|
||||
|
|
|
@ -124,6 +124,9 @@ final class PhabricatorDiffusionApplication extends PhabricatorApplication {
|
|||
'(?:query/(?P<queryKey>[^/]+)/)?' => 'DiffusionPushLogListController',
|
||||
'view/(?P<id>\d+)/' => 'DiffusionPushEventViewController',
|
||||
),
|
||||
'pulllog/' => array(
|
||||
$this->getQueryRoutePattern() => 'DiffusionPullLogListController',
|
||||
),
|
||||
'(?P<repositoryCallsign>[A-Z]+)' => $repository_routes,
|
||||
'(?P<repositoryID>[1-9]\d*)' => $repository_routes,
|
||||
|
||||
|
|
|
@ -54,6 +54,12 @@ final class DiffusionSearchQueryConduitAPIMethod
|
|||
$limit = $request->getValue('limit');
|
||||
$offset = $request->getValue('offset');
|
||||
|
||||
// Starting with Git 2.16.0, Git assumes passing an empty argument is
|
||||
// an error and recommends you pass "." instead.
|
||||
if (!strlen($path)) {
|
||||
$path = '.';
|
||||
}
|
||||
|
||||
$results = array();
|
||||
$future = $repository->getLocalCommandFuture(
|
||||
// NOTE: --perl-regexp is available only with libpcre compiled in.
|
||||
|
|
|
@ -658,6 +658,11 @@ final class DiffusionBrowseController extends DiffusionController {
|
|||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->appendChild($corpus)
|
||||
->addClass('diffusion-mobile-view')
|
||||
->addSigil('diffusion-file-content-view')
|
||||
->setMetadata(
|
||||
array(
|
||||
'path' => $this->getDiffusionRequest()->getPath(),
|
||||
))
|
||||
->setCollapsed(true);
|
||||
|
||||
$messages = array();
|
||||
|
@ -947,6 +952,10 @@ final class DiffusionBrowseController extends DiffusionController {
|
|||
}
|
||||
|
||||
foreach ($revision_ids as $commit_phid => $revision_id) {
|
||||
// If the viewer can't actually see this revision, skip it.
|
||||
if (!isset($revisions[$revision_id])) {
|
||||
continue;
|
||||
}
|
||||
$revision_map[$commit_map[$commit_phid]] = $revision_id;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
abstract class DiffusionPushLogController extends DiffusionController {
|
||||
abstract class DiffusionLogController extends DiffusionController {
|
||||
|
||||
protected function shouldLoadDiffusionRequest() {
|
||||
return false;
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionPullLogListController
|
||||
extends DiffusionLogController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
return id(new DiffusionPullLogSearchEngine())
|
||||
->setController($this)
|
||||
->buildResponse();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,11 +1,7 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionPushEventViewController
|
||||
extends DiffusionPushLogController {
|
||||
|
||||
public function shouldAllowPublic() {
|
||||
return true;
|
||||
}
|
||||
extends DiffusionLogController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $this->getViewer();
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionPushLogListController extends DiffusionPushLogController {
|
||||
|
||||
public function shouldAllowPublic() {
|
||||
return true;
|
||||
}
|
||||
final class DiffusionPushLogListController
|
||||
extends DiffusionLogController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
return id(new PhabricatorRepositoryPushLogSearchEngine())
|
||||
|
|
|
@ -365,7 +365,7 @@ final class DiffusionRepositoryController extends DiffusionController {
|
|||
|
||||
if ($repository->isHosted()) {
|
||||
$push_uri = $this->getApplicationURI(
|
||||
'pushlog/?repositories='.$repository->getMonogram());
|
||||
'pushlog/?repositories='.$repository->getPHID());
|
||||
|
||||
$action_view->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
|
@ -374,6 +374,15 @@ final class DiffusionRepositoryController extends DiffusionController {
|
|||
->setHref($push_uri));
|
||||
}
|
||||
|
||||
$pull_uri = $this->getApplicationURI(
|
||||
'pulllog/?repositories='.$repository->getPHID());
|
||||
|
||||
$action_view->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('View Pull Logs'))
|
||||
->setIcon('fa-list-alt')
|
||||
->setHref($pull_uri));
|
||||
|
||||
return $action_view;
|
||||
}
|
||||
|
||||
|
|
|
@ -104,15 +104,29 @@ final class DiffusionServeController extends DiffusionController {
|
|||
try {
|
||||
$remote_addr = $request->getRemoteAddress();
|
||||
|
||||
if ($request->isHTTPS()) {
|
||||
$remote_protocol = PhabricatorRepositoryPullEvent::PROTOCOL_HTTPS;
|
||||
} else {
|
||||
$remote_protocol = PhabricatorRepositoryPullEvent::PROTOCOL_HTTP;
|
||||
}
|
||||
|
||||
$pull_event = id(new PhabricatorRepositoryPullEvent())
|
||||
->setEpoch(PhabricatorTime::getNow())
|
||||
->setRemoteAddress($remote_addr)
|
||||
->setRemoteProtocol('http');
|
||||
->setRemoteProtocol($remote_protocol);
|
||||
|
||||
if ($response) {
|
||||
$response_code = $response->getHTTPResponseCode();
|
||||
|
||||
if ($response_code == 200) {
|
||||
$pull_event
|
||||
->setResultType('wild')
|
||||
->setResultCode($response->getHTTPResponseCode());
|
||||
->setResultType(PhabricatorRepositoryPullEvent::RESULT_PULL)
|
||||
->setResultCode($response_code);
|
||||
} else {
|
||||
$pull_event
|
||||
->setResultType(PhabricatorRepositoryPullEvent::RESULT_ERROR)
|
||||
->setResultCode($response_code);
|
||||
}
|
||||
|
||||
if ($response instanceof PhabricatorVCSResponse) {
|
||||
$pull_event->setProperties(
|
||||
|
@ -122,7 +136,7 @@ final class DiffusionServeController extends DiffusionController {
|
|||
}
|
||||
} else {
|
||||
$pull_event
|
||||
->setResultType('exception')
|
||||
->setResultType(PhabricatorRepositoryPullEvent::RESULT_EXCEPTION)
|
||||
->setResultCode(500)
|
||||
->setProperties(
|
||||
array(
|
||||
|
@ -715,30 +729,19 @@ final class DiffusionServeController extends DiffusionController {
|
|||
return null;
|
||||
}
|
||||
|
||||
$password_entry = id(new PhabricatorRepositoryVCSPassword())
|
||||
->loadOneWhere('userPHID = %s', $user->getPHID());
|
||||
if (!$password_entry) {
|
||||
// User doesn't have a password set.
|
||||
$request = $this->getRequest();
|
||||
$content_source = PhabricatorContentSource::newFromRequest($request);
|
||||
|
||||
$engine = id(new PhabricatorAuthPasswordEngine())
|
||||
->setViewer($user)
|
||||
->setContentSource($content_source)
|
||||
->setPasswordType(PhabricatorAuthPassword::PASSWORD_TYPE_VCS)
|
||||
->setObject($user);
|
||||
|
||||
if (!$engine->isValidPassword($password)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!$password_entry->comparePassword($password, $user)) {
|
||||
// Password doesn't match.
|
||||
return null;
|
||||
}
|
||||
|
||||
// If the user's password is stored using a less-than-optimal hash, upgrade
|
||||
// them to the strongest available hash.
|
||||
|
||||
$hash_envelope = new PhutilOpaqueEnvelope(
|
||||
$password_entry->getPasswordHash());
|
||||
if (PhabricatorPasswordHasher::canUpgradeHash($hash_envelope)) {
|
||||
$password_entry->setPassword($password, $user);
|
||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
||||
$password_entry->save();
|
||||
unset($unguarded);
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ final class DiffusionSymbolController extends DiffusionController {
|
|||
$query->setLanguage($request->getStr('lang'));
|
||||
}
|
||||
|
||||
$repos = array();
|
||||
if ($request->getStr('repositories')) {
|
||||
$phids = $request->getStr('repositories');
|
||||
$phids = explode(',', $phids);
|
||||
|
@ -33,9 +34,9 @@ final class DiffusionSymbolController extends DiffusionController {
|
|||
->withPHIDs($phids)
|
||||
->execute();
|
||||
|
||||
$repos = mpull($repos, 'getPHID');
|
||||
if ($repos) {
|
||||
$query->withRepositoryPHIDs($repos);
|
||||
$repo_phids = mpull($repos, 'getPHID');
|
||||
if ($repo_phids) {
|
||||
$query->withRepositoryPHIDs($repo_phids);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +46,6 @@ final class DiffusionSymbolController extends DiffusionController {
|
|||
|
||||
$symbols = $query->execute();
|
||||
|
||||
|
||||
$external_query = id(new DiffusionExternalSymbolQuery())
|
||||
->withNames(array($name));
|
||||
|
||||
|
@ -61,13 +61,51 @@ final class DiffusionSymbolController extends DiffusionController {
|
|||
$external_query->withLanguages(array($request->getStr('lang')));
|
||||
}
|
||||
|
||||
if ($request->getStr('path')) {
|
||||
$external_query->withPaths(array($request->getStr('path')));
|
||||
}
|
||||
|
||||
if ($request->getInt('line')) {
|
||||
$external_query->withLines(array($request->getInt('line')));
|
||||
}
|
||||
|
||||
if ($request->getInt('char')) {
|
||||
$external_query->withCharacterPositions(
|
||||
array(
|
||||
$request->getInt('char'),
|
||||
));
|
||||
}
|
||||
|
||||
if ($repos) {
|
||||
$external_query->withRepositories($repos);
|
||||
}
|
||||
|
||||
$external_sources = id(new PhutilClassMapQuery())
|
||||
->setAncestorClass('DiffusionExternalSymbolsSource')
|
||||
->execute();
|
||||
|
||||
$results = array($symbols);
|
||||
foreach ($external_sources as $source) {
|
||||
$results[] = $source->executeQuery($external_query);
|
||||
$source_results = $source->executeQuery($external_query);
|
||||
|
||||
if (!is_array($source_results)) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Expected a list of results from external symbol source "%s".',
|
||||
get_class($source)));
|
||||
}
|
||||
|
||||
try {
|
||||
assert_instances_of($source_results, 'PhabricatorRepositorySymbol');
|
||||
} catch (InvalidArgumentException $ex) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Expected a list of PhabricatorRepositorySymbol objects '.
|
||||
'from external symbol source "%s".',
|
||||
get_class($source)));
|
||||
}
|
||||
|
||||
$results[] = $source_results;
|
||||
}
|
||||
$symbols = array_mergev($results);
|
||||
|
||||
|
|
|
@ -6,7 +6,11 @@ final class DiffusionCommitReviewerHeraldField
|
|||
const FIELDCONST = 'diffusion.commit.reviewer';
|
||||
|
||||
public function getHeraldFieldName() {
|
||||
return pht('Reviewer');
|
||||
return pht('Reviewer (Deprecated)');
|
||||
}
|
||||
|
||||
public function getFieldGroupKey() {
|
||||
return HeraldDeprecatedFieldGroup::FIELDGROUPKEY;
|
||||
}
|
||||
|
||||
public function getHeraldFieldValue($object) {
|
||||
|
|
|
@ -209,7 +209,7 @@ final class HeraldCommitAdapter
|
|||
}
|
||||
|
||||
private function loadCommitDiff() {
|
||||
$viewer = PhabricatorUser::getOmnipotentUser();
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$byte_limit = self::getEnormousByteLimit();
|
||||
$time_limit = self::getEnormousTimeLimit();
|
||||
|
|
|
@ -35,13 +35,20 @@ final class DiffusionSetPasswordSettingsPanel extends PhabricatorSettingsPanel {
|
|||
$request,
|
||||
'/settings/');
|
||||
|
||||
$vcspassword = id(new PhabricatorRepositoryVCSPassword())
|
||||
->loadOneWhere(
|
||||
'userPHID = %s',
|
||||
$user->getPHID());
|
||||
if (!$vcspassword) {
|
||||
$vcspassword = id(new PhabricatorRepositoryVCSPassword());
|
||||
$vcspassword->setUserPHID($user->getPHID());
|
||||
$vcs_type = PhabricatorAuthPassword::PASSWORD_TYPE_VCS;
|
||||
|
||||
$vcspasswords = id(new PhabricatorAuthPasswordQuery())
|
||||
->setViewer($viewer)
|
||||
->withObjectPHIDs(array($user->getPHID()))
|
||||
->withPasswordTypes(array($vcs_type))
|
||||
->withIsRevoked(false)
|
||||
->execute();
|
||||
if ($vcspasswords) {
|
||||
$vcspassword = head($vcspasswords);
|
||||
} else {
|
||||
$vcspassword = PhabricatorAuthPassword::initializeNewPassword(
|
||||
$user,
|
||||
$vcs_type);
|
||||
}
|
||||
|
||||
$panel_uri = $this->getPanelURI('?saved=true');
|
||||
|
@ -51,6 +58,19 @@ final class DiffusionSetPasswordSettingsPanel extends PhabricatorSettingsPanel {
|
|||
$e_password = true;
|
||||
$e_confirm = true;
|
||||
|
||||
$content_source = PhabricatorContentSource::newFromRequest($request);
|
||||
|
||||
// NOTE: This test is against $viewer (not $user), so that the error
|
||||
// message below makes sense in the case that the two are different,
|
||||
// and because an admin reusing their own password is bad, while
|
||||
// system agents generally do not have passwords anyway.
|
||||
|
||||
$engine = id(new PhabricatorAuthPasswordEngine())
|
||||
->setViewer($viewer)
|
||||
->setContentSource($content_source)
|
||||
->setObject($viewer)
|
||||
->setPasswordType($vcs_type);
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
if ($request->getBool('remove')) {
|
||||
if ($vcspassword->getID()) {
|
||||
|
@ -61,64 +81,28 @@ final class DiffusionSetPasswordSettingsPanel extends PhabricatorSettingsPanel {
|
|||
|
||||
$new_password = $request->getStr('password');
|
||||
$confirm = $request->getStr('confirm');
|
||||
if (!strlen($new_password)) {
|
||||
$e_password = pht('Required');
|
||||
$errors[] = pht('Password is required.');
|
||||
} else {
|
||||
$e_password = null;
|
||||
}
|
||||
|
||||
if (!strlen($confirm)) {
|
||||
$e_confirm = pht('Required');
|
||||
$errors[] = pht('You must confirm the new password.');
|
||||
} else {
|
||||
$e_confirm = null;
|
||||
}
|
||||
|
||||
if (!$errors) {
|
||||
$envelope = new PhutilOpaqueEnvelope($new_password);
|
||||
$confirm_envelope = new PhutilOpaqueEnvelope($confirm);
|
||||
|
||||
try {
|
||||
// NOTE: This test is against $viewer (not $user), so that the error
|
||||
// message below makes sense in the case that the two are different,
|
||||
// and because an admin reusing their own password is bad, while
|
||||
// system agents generally do not have passwords anyway.
|
||||
|
||||
$same_password = $viewer->comparePassword($envelope);
|
||||
} catch (PhabricatorPasswordHasherUnavailableException $ex) {
|
||||
// If we're missing the hasher, just let the user continue.
|
||||
$same_password = false;
|
||||
$engine->checkNewPassword($envelope, $confirm_envelope);
|
||||
$e_password = null;
|
||||
$e_confirm = null;
|
||||
} catch (PhabricatorAuthPasswordException $ex) {
|
||||
$errors[] = $ex->getMessage();
|
||||
$e_password = $ex->getPasswordError();
|
||||
$e_confirm = $ex->getConfirmError();
|
||||
}
|
||||
|
||||
if ($new_password !== $confirm) {
|
||||
$e_password = pht('Does Not Match');
|
||||
$e_confirm = pht('Does Not Match');
|
||||
$errors[] = pht('Password and confirmation do not match.');
|
||||
} else if ($same_password) {
|
||||
$e_password = pht('Not Unique');
|
||||
$e_confirm = pht('Not Unique');
|
||||
$errors[] = pht(
|
||||
'This password is the same as another password associated '.
|
||||
'with your account. You must use a unique password for '.
|
||||
'VCS access.');
|
||||
} else if (
|
||||
PhabricatorCommonPasswords::isCommonPassword($new_password)) {
|
||||
$e_password = pht('Very Weak');
|
||||
$e_confirm = pht('Very Weak');
|
||||
$errors[] = pht(
|
||||
'This password is extremely weak: it is one of the most common '.
|
||||
'passwords in use. Choose a stronger password.');
|
||||
}
|
||||
|
||||
|
||||
if (!$errors) {
|
||||
$vcspassword->setPassword($envelope, $user);
|
||||
$vcspassword->save();
|
||||
$vcspassword
|
||||
->setPassword($envelope, $user)
|
||||
->save();
|
||||
|
||||
return id(new AphrontRedirectResponse())->setURI($panel_uri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$title = pht('Set VCS Password');
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ final class DiffusionGitCommandEngine
|
|||
$env['HOME'] = PhabricatorEnv::getEmptyCWD();
|
||||
|
||||
$env['GIT_SSH'] = $this->getSSHWrapper();
|
||||
$env['GIT_SSH_VARIANT'] = 'ssh';
|
||||
|
||||
if ($this->isAnyHTTPProtocol()) {
|
||||
$uri = $this->getURI();
|
||||
|
|
|
@ -88,7 +88,7 @@ abstract class DiffusionFileFutureQuery
|
|||
}
|
||||
|
||||
final protected function executeQuery() {
|
||||
$future = $this->newQueryFuture();
|
||||
$future = $this->newConfiguredQueryFuture();
|
||||
|
||||
$drequest = $this->getRequest();
|
||||
|
||||
|
@ -105,6 +105,11 @@ abstract class DiffusionFileFutureQuery
|
|||
->setViewPolicy(PhabricatorPolicies::POLICY_NOONE)
|
||||
->setExecFuture($future);
|
||||
|
||||
$byte_limit = $this->getByteLimit();
|
||||
if ($byte_limit) {
|
||||
$source->setByteLimit($byte_limit);
|
||||
}
|
||||
|
||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
||||
$file = $source->uploadFile();
|
||||
unset($unguarded);
|
||||
|
@ -116,18 +121,8 @@ abstract class DiffusionFileFutureQuery
|
|||
|
||||
$this->didHitTimeLimit = true;
|
||||
$file = null;
|
||||
}
|
||||
|
||||
$byte_limit = $this->getByteLimit();
|
||||
|
||||
if ($byte_limit && ($file->getByteSize() > $byte_limit)) {
|
||||
} catch (PhabricatorFileUploadSourceByteLimitException $ex) {
|
||||
$this->didHitByteLimit = true;
|
||||
|
||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
||||
id(new PhabricatorDestructionEngine())
|
||||
->destroyObject($file);
|
||||
unset($unguarded);
|
||||
|
||||
$file = null;
|
||||
}
|
||||
|
||||
|
@ -141,11 +136,6 @@ abstract class DiffusionFileFutureQuery
|
|||
$future->setTimeout($this->getTimeout());
|
||||
}
|
||||
|
||||
$byte_limit = $this->getByteLimit();
|
||||
if ($byte_limit) {
|
||||
$future->setStdoutSizeLimit($byte_limit + 1);
|
||||
}
|
||||
|
||||
return $future;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,166 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionPullLogSearchEngine
|
||||
extends PhabricatorApplicationSearchEngine {
|
||||
|
||||
public function getResultTypeDescription() {
|
||||
return pht('Pull Logs');
|
||||
}
|
||||
|
||||
public function getApplicationClassName() {
|
||||
return 'PhabricatorDiffusionApplication';
|
||||
}
|
||||
|
||||
public function newQuery() {
|
||||
return new PhabricatorRepositoryPullEventQuery();
|
||||
}
|
||||
|
||||
protected function buildQueryFromParameters(array $map) {
|
||||
$query = $this->newQuery();
|
||||
|
||||
if ($map['repositoryPHIDs']) {
|
||||
$query->withRepositoryPHIDs($map['repositoryPHIDs']);
|
||||
}
|
||||
|
||||
if ($map['pullerPHIDs']) {
|
||||
$query->withPullerPHIDs($map['pullerPHIDs']);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
protected function buildCustomSearchFields() {
|
||||
return array(
|
||||
id(new PhabricatorSearchDatasourceField())
|
||||
->setDatasource(new DiffusionRepositoryDatasource())
|
||||
->setKey('repositoryPHIDs')
|
||||
->setAliases(array('repository', 'repositories', 'repositoryPHID'))
|
||||
->setLabel(pht('Repositories'))
|
||||
->setDescription(
|
||||
pht('Search for pull logs for specific repositories.')),
|
||||
id(new PhabricatorUsersSearchField())
|
||||
->setKey('pullerPHIDs')
|
||||
->setAliases(array('puller', 'pullers', 'pullerPHID'))
|
||||
->setLabel(pht('Pullers'))
|
||||
->setDescription(
|
||||
pht('Search for pull logs by specific users.')),
|
||||
);
|
||||
}
|
||||
|
||||
protected function newExportFields() {
|
||||
return array(
|
||||
id(new PhabricatorIDExportField())
|
||||
->setKey('id')
|
||||
->setLabel(pht('ID')),
|
||||
id(new PhabricatorPHIDExportField())
|
||||
->setKey('phid')
|
||||
->setLabel(pht('PHID')),
|
||||
id(new PhabricatorPHIDExportField())
|
||||
->setKey('repositoryPHID')
|
||||
->setLabel(pht('Repository PHID')),
|
||||
id(new PhabricatorStringExportField())
|
||||
->setKey('repository')
|
||||
->setLabel(pht('Repository')),
|
||||
id(new PhabricatorPHIDExportField())
|
||||
->setKey('pullerPHID')
|
||||
->setLabel(pht('Puller PHID')),
|
||||
id(new PhabricatorStringExportField())
|
||||
->setKey('puller')
|
||||
->setLabel(pht('Puller')),
|
||||
id(new PhabricatorStringExportField())
|
||||
->setKey('protocol')
|
||||
->setLabel(pht('Protocol')),
|
||||
id(new PhabricatorStringExportField())
|
||||
->setKey('result')
|
||||
->setLabel(pht('Result')),
|
||||
id(new PhabricatorIntExportField())
|
||||
->setKey('code')
|
||||
->setLabel(pht('Code')),
|
||||
id(new PhabricatorEpochExportField())
|
||||
->setKey('date')
|
||||
->setLabel(pht('Date')),
|
||||
);
|
||||
}
|
||||
|
||||
public function newExport(array $events) {
|
||||
$viewer = $this->requireViewer();
|
||||
|
||||
$phids = array();
|
||||
foreach ($events as $event) {
|
||||
if ($event->getPullerPHID()) {
|
||||
$phids[] = $event->getPullerPHID();
|
||||
}
|
||||
}
|
||||
$handles = $viewer->loadHandles($phids);
|
||||
|
||||
$export = array();
|
||||
foreach ($events as $event) {
|
||||
$repository = $event->getRepository();
|
||||
if ($repository) {
|
||||
$repository_phid = $repository->getPHID();
|
||||
$repository_name = $repository->getDisplayName();
|
||||
} else {
|
||||
$repository_phid = null;
|
||||
$repository_name = null;
|
||||
}
|
||||
|
||||
$puller_phid = $event->getPullerPHID();
|
||||
if ($puller_phid) {
|
||||
$puller_name = $handles[$puller_phid]->getName();
|
||||
} else {
|
||||
$puller_name = null;
|
||||
}
|
||||
|
||||
$export[] = array(
|
||||
'id' => $event->getID(),
|
||||
'phid' => $event->getPHID(),
|
||||
'repositoryPHID' => $repository_phid,
|
||||
'repository' => $repository_name,
|
||||
'pullerPHID' => $puller_phid,
|
||||
'puller' => $puller_name,
|
||||
'protocol' => $event->getRemoteProtocol(),
|
||||
'result' => $event->getResultType(),
|
||||
'code' => $event->getResultCode(),
|
||||
'date' => $event->getEpoch(),
|
||||
);
|
||||
}
|
||||
|
||||
return $export;
|
||||
}
|
||||
|
||||
protected function getURI($path) {
|
||||
return '/diffusion/pulllog/'.$path;
|
||||
}
|
||||
|
||||
protected function getBuiltinQueryNames() {
|
||||
return array(
|
||||
'all' => pht('All Pull Logs'),
|
||||
);
|
||||
}
|
||||
|
||||
public function buildSavedQueryFromBuiltin($query_key) {
|
||||
$query = $this->newSavedQuery();
|
||||
$query->setQueryKey($query_key);
|
||||
|
||||
switch ($query_key) {
|
||||
case 'all':
|
||||
return $query;
|
||||
}
|
||||
|
||||
return parent::buildSavedQueryFromBuiltin($query_key);
|
||||
}
|
||||
|
||||
protected function renderResultList(
|
||||
array $logs,
|
||||
PhabricatorSavedQuery $query,
|
||||
array $handles) {
|
||||
|
||||
$table = id(new DiffusionPullLogListView())
|
||||
->setViewer($this->requireViewer())
|
||||
->setLogs($logs);
|
||||
|
||||
return id(new PhabricatorApplicationSearchResultView())
|
||||
->setTable($table);
|
||||
}
|
||||
|
||||
}
|
|
@ -15,7 +15,7 @@ final class DiffusionGitReceivePackSSHWorkflow extends DiffusionGitSSHWorkflow {
|
|||
|
||||
protected function executeRepositoryOperations() {
|
||||
$repository = $this->getRepository();
|
||||
$viewer = $this->getUser();
|
||||
$viewer = $this->getSSHUser();
|
||||
$device = AlmanacKeys::getLiveDevice();
|
||||
|
||||
// This is a write, and must have write access.
|
||||
|
|
|
@ -15,7 +15,7 @@ final class DiffusionGitUploadPackSSHWorkflow extends DiffusionGitSSHWorkflow {
|
|||
|
||||
protected function executeRepositoryOperations() {
|
||||
$repository = $this->getRepository();
|
||||
$viewer = $this->getUser();
|
||||
$viewer = $this->getSSHUser();
|
||||
$device = AlmanacKeys::getLiveDevice();
|
||||
|
||||
$skip_sync = $this->shouldSkipReadSynchronization();
|
||||
|
@ -61,11 +61,11 @@ final class DiffusionGitUploadPackSSHWorkflow extends DiffusionGitSSHWorkflow {
|
|||
|
||||
if ($err) {
|
||||
$pull_event
|
||||
->setResultType('error')
|
||||
->setResultType(PhabricatorRepositoryPullEvent::RESULT_ERROR)
|
||||
->setResultCode($err);
|
||||
} else {
|
||||
$pull_event
|
||||
->setResultType('pull')
|
||||
->setResultType(PhabricatorRepositoryPullEvent::RESULT_PULL)
|
||||
->setResultCode(0);
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ abstract class DiffusionSSHWorkflow extends PhabricatorSSHWorkflow {
|
|||
|
||||
public function getEnvironment() {
|
||||
$env = array(
|
||||
DiffusionCommitHookEngine::ENV_USER => $this->getUser()->getUsername(),
|
||||
DiffusionCommitHookEngine::ENV_USER => $this->getSSHUser()->getUsername(),
|
||||
DiffusionCommitHookEngine::ENV_REMOTE_PROTOCOL => 'ssh',
|
||||
);
|
||||
|
||||
|
@ -122,14 +122,14 @@ abstract class DiffusionSSHWorkflow extends PhabricatorSSHWorkflow {
|
|||
$key_path,
|
||||
$port,
|
||||
$host,
|
||||
'@'.$this->getUser()->getUsername(),
|
||||
'@'.$this->getSSHUser()->getUsername(),
|
||||
$this->getOriginalArguments());
|
||||
}
|
||||
|
||||
final public function execute(PhutilArgumentParser $args) {
|
||||
$this->args = $args;
|
||||
|
||||
$viewer = $this->getUser();
|
||||
$viewer = $this->getSSHUser();
|
||||
$have_diffusion = PhabricatorApplication::isClassInstalledForViewer(
|
||||
'PhabricatorDiffusionApplication',
|
||||
$viewer);
|
||||
|
@ -164,7 +164,7 @@ abstract class DiffusionSSHWorkflow extends PhabricatorSSHWorkflow {
|
|||
}
|
||||
|
||||
protected function loadRepositoryWithPath($path, $vcs) {
|
||||
$viewer = $this->getUser();
|
||||
$viewer = $this->getSSHUser();
|
||||
|
||||
$info = PhabricatorRepository::parseRepositoryServicePath($path, $vcs);
|
||||
if ($info === null) {
|
||||
|
@ -214,7 +214,7 @@ abstract class DiffusionSSHWorkflow extends PhabricatorSSHWorkflow {
|
|||
}
|
||||
|
||||
$repository = $this->getRepository();
|
||||
$viewer = $this->getUser();
|
||||
$viewer = $this->getSSHUser();
|
||||
|
||||
if ($viewer->isOmnipotent()) {
|
||||
throw new Exception(
|
||||
|
@ -252,7 +252,7 @@ abstract class DiffusionSSHWorkflow extends PhabricatorSSHWorkflow {
|
|||
}
|
||||
|
||||
protected function shouldSkipReadSynchronization() {
|
||||
$viewer = $this->getUser();
|
||||
$viewer = $this->getSSHUser();
|
||||
|
||||
// Currently, the only case where devices interact over SSH without
|
||||
// assuming user credentials is when synchronizing before a read. These
|
||||
|
@ -265,14 +265,14 @@ abstract class DiffusionSSHWorkflow extends PhabricatorSSHWorkflow {
|
|||
}
|
||||
|
||||
protected function newPullEvent() {
|
||||
$viewer = $this->getViewer();
|
||||
$viewer = $this->getSSHUser();
|
||||
$repository = $this->getRepository();
|
||||
$remote_address = $this->getSSHRemoteAddress();
|
||||
|
||||
return id(new PhabricatorRepositoryPullEvent())
|
||||
->setEpoch(PhabricatorTime::getNow())
|
||||
->setRemoteAddress($remote_address)
|
||||
->setRemoteProtocol('ssh')
|
||||
->setRemoteProtocol(PhabricatorRepositoryPullEvent::PROTOCOL_SSH)
|
||||
->setPullerPHID($viewer->getPHID())
|
||||
->setRepositoryPHID($repository->getPHID());
|
||||
}
|
||||
|
|
|
@ -154,7 +154,7 @@ final class DiffusionSubversionServeSSHWorkflow
|
|||
} else {
|
||||
$command = csprintf(
|
||||
'svnserve -t --tunnel-user=%s',
|
||||
$this->getUser()->getUsername());
|
||||
$this->getSSHUser()->getUsername());
|
||||
$cwd = PhabricatorEnv::getEmptyCWD();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,45 +1,93 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionExternalSymbolQuery extends Phobject {
|
||||
|
||||
private $languages = array();
|
||||
private $types = array();
|
||||
private $names = array();
|
||||
private $contexts = array();
|
||||
private $paths = array();
|
||||
private $lines = array();
|
||||
private $repositories = array();
|
||||
private $characterPositions = array();
|
||||
|
||||
public function withLanguages(array $languages) {
|
||||
$this->languages = $languages;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withTypes(array $types) {
|
||||
$this->types = $types;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withNames(array $names) {
|
||||
$this->names = $names;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withContexts(array $contexts) {
|
||||
$this->contexts = $contexts;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withPaths(array $paths) {
|
||||
$this->paths = $paths;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withLines(array $lines) {
|
||||
$this->lines = $lines;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withCharacterPositions(array $positions) {
|
||||
$this->characterPositions = $positions;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withRepositories(array $repositories) {
|
||||
assert_instances_of($repositories, 'PhabricatorRepository');
|
||||
$this->repositories = $repositories;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLanguages() {
|
||||
return $this->languages;
|
||||
}
|
||||
|
||||
public function getTypes() {
|
||||
return $this->types;
|
||||
}
|
||||
|
||||
public function getNames() {
|
||||
return $this->names;
|
||||
}
|
||||
|
||||
public function getContexts() {
|
||||
return $this->contexts;
|
||||
}
|
||||
|
||||
public function getPaths() {
|
||||
return $this->paths;
|
||||
}
|
||||
|
||||
public function getLines() {
|
||||
return $this->lines;
|
||||
}
|
||||
|
||||
public function getRepositories() {
|
||||
return $this->repositories;
|
||||
}
|
||||
|
||||
public function getCharacterPositions() {
|
||||
return $this->characterPositions;
|
||||
}
|
||||
|
||||
public function matchesAnyLanguage(array $languages) {
|
||||
return (!$this->languages) || array_intersect($languages, $this->languages);
|
||||
}
|
||||
|
||||
public function matchesAnyType(array $types) {
|
||||
return (!$this->types) || array_intersect($types, $this->types);
|
||||
}
|
||||
|
|
115
src/applications/diffusion/view/DiffusionPullLogListView.php
Normal file
115
src/applications/diffusion/view/DiffusionPullLogListView.php
Normal file
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionPullLogListView extends AphrontView {
|
||||
|
||||
private $logs;
|
||||
|
||||
public function setLogs(array $logs) {
|
||||
assert_instances_of($logs, 'PhabricatorRepositoryPullEvent');
|
||||
$this->logs = $logs;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
$events = $this->logs;
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$handle_phids = array();
|
||||
foreach ($events as $event) {
|
||||
if ($event->getPullerPHID()) {
|
||||
$handle_phids[] = $event->getPullerPHID();
|
||||
}
|
||||
}
|
||||
$handles = $viewer->loadHandles($handle_phids);
|
||||
|
||||
// Figure out which repositories are editable. We only let you see remote
|
||||
// IPs if you have edit capability on a repository.
|
||||
$editable_repos = array();
|
||||
if ($events) {
|
||||
$editable_repos = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer($viewer)
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->withPHIDs(mpull($events, 'getRepositoryPHID'))
|
||||
->execute();
|
||||
$editable_repos = mpull($editable_repos, null, 'getPHID');
|
||||
}
|
||||
|
||||
$rows = array();
|
||||
$any_host = false;
|
||||
foreach ($events as $event) {
|
||||
if ($event->getRepositoryPHID()) {
|
||||
$repository = $event->getRepository();
|
||||
} else {
|
||||
$repository = null;
|
||||
}
|
||||
|
||||
// Reveal this if it's valid and the user can edit the repository. For
|
||||
// invalid requests you currently have to go fishing in the database.
|
||||
$remote_address = '-';
|
||||
if ($repository) {
|
||||
if (isset($editable_repos[$event->getRepositoryPHID()])) {
|
||||
$remote_address = $event->getRemoteAddress();
|
||||
}
|
||||
}
|
||||
|
||||
$event_id = $event->getID();
|
||||
|
||||
$repository_link = null;
|
||||
if ($repository) {
|
||||
$repository_link = phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $repository->getURI(),
|
||||
),
|
||||
$repository->getDisplayName());
|
||||
}
|
||||
|
||||
$puller_link = null;
|
||||
if ($event->getPullerPHID()) {
|
||||
$puller_link = $viewer->renderHandle($event->getPullerPHID());
|
||||
}
|
||||
|
||||
$rows[] = array(
|
||||
$event_id,
|
||||
$repository_link,
|
||||
$puller_link,
|
||||
$remote_address,
|
||||
$event->getRemoteProtocolDisplayName(),
|
||||
$event->newResultIcon(),
|
||||
$event->getResultCode(),
|
||||
phabricator_datetime($event->getEpoch(), $viewer),
|
||||
);
|
||||
}
|
||||
|
||||
$table = id(new AphrontTableView($rows))
|
||||
->setHeaders(
|
||||
array(
|
||||
pht('Pull'),
|
||||
pht('Repository'),
|
||||
pht('Puller'),
|
||||
pht('From'),
|
||||
pht('Via'),
|
||||
null,
|
||||
pht('Code'),
|
||||
pht('Date'),
|
||||
))
|
||||
->setColumnClasses(
|
||||
array(
|
||||
'n',
|
||||
'',
|
||||
'',
|
||||
'n',
|
||||
'wide',
|
||||
'',
|
||||
'n',
|
||||
'right',
|
||||
));
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
}
|
|
@ -12,6 +12,8 @@ abstract class PhabricatorFileUploadSource
|
|||
private $shouldChunk;
|
||||
private $didRewind;
|
||||
private $totalBytesWritten = 0;
|
||||
private $totalBytesRead = 0;
|
||||
private $byteLimit = 0;
|
||||
|
||||
public function setName($name) {
|
||||
$this->name = $name;
|
||||
|
@ -40,6 +42,15 @@ abstract class PhabricatorFileUploadSource
|
|||
return $this->viewPolicy;
|
||||
}
|
||||
|
||||
public function setByteLimit($byte_limit) {
|
||||
$this->byteLimit = $byte_limit;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getByteLimit() {
|
||||
return $this->byteLimit;
|
||||
}
|
||||
|
||||
public function uploadFile() {
|
||||
if (!$this->shouldChunkFile()) {
|
||||
return $this->writeSingleFile();
|
||||
|
@ -81,8 +92,15 @@ abstract class PhabricatorFileUploadSource
|
|||
return false;
|
||||
}
|
||||
|
||||
$read_bytes = $data->current();
|
||||
$this->totalBytesRead += strlen($read_bytes);
|
||||
|
||||
if ($this->byteLimit && ($this->totalBytesRead > $this->byteLimit)) {
|
||||
throw new PhabricatorFileUploadSourceByteLimitException();
|
||||
}
|
||||
|
||||
$rope = $this->getRope();
|
||||
$rope->append($data->current());
|
||||
$rope->append($read_bytes);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -160,8 +178,10 @@ abstract class PhabricatorFileUploadSource
|
|||
}
|
||||
}
|
||||
|
||||
// If we have extra bytes at the end, write them.
|
||||
if ($rope->getByteLength()) {
|
||||
// If we have extra bytes at the end, write them. Note that it's possible
|
||||
// that we have more than one chunk of bytes left if the read was very
|
||||
// fast.
|
||||
while ($rope->getByteLength()) {
|
||||
$this->writeChunk($file, $engine);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorFileUploadSourceByteLimitException
|
||||
extends Exception {}
|
|
@ -38,6 +38,7 @@ abstract class HeraldAdapter extends Phobject {
|
|||
private $actionMap;
|
||||
private $edgeCache = array();
|
||||
private $forbiddenActions = array();
|
||||
private $viewer;
|
||||
|
||||
public function getEmailPHIDs() {
|
||||
return array_values($this->emailPHIDs);
|
||||
|
@ -55,10 +56,29 @@ abstract class HeraldAdapter extends Phobject {
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function setViewer(PhabricatorUser $viewer) {
|
||||
$this->viewer = $viewer;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getViewer() {
|
||||
// See PHI276. Normally, Herald runs without regard for policy checks.
|
||||
// However, we use a real viewer during test console runs: this makes
|
||||
// intracluster calls to Diffusion APIs work even if web nodes don't
|
||||
// have privileged credentials.
|
||||
|
||||
if ($this->viewer) {
|
||||
return $this->viewer;
|
||||
}
|
||||
|
||||
return PhabricatorUser::getOmnipotentUser();
|
||||
}
|
||||
|
||||
public function setContentSource(PhabricatorContentSource $content_source) {
|
||||
$this->contentSource = $content_source;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getContentSource() {
|
||||
return $this->contentSource;
|
||||
}
|
||||
|
@ -764,9 +784,20 @@ abstract class HeraldAdapter extends Phobject {
|
|||
|
||||
|
||||
public function getRepetitionOptions() {
|
||||
return array(
|
||||
HeraldRepetitionPolicyConfig::EVERY,
|
||||
);
|
||||
$options = array();
|
||||
|
||||
$options[] = HeraldRule::REPEAT_EVERY;
|
||||
|
||||
// Some rules, like pre-commit rules, only ever fire once. It doesn't
|
||||
// make sense to use state-based repetition policies like "only the first
|
||||
// time" for these rules.
|
||||
|
||||
if (!$this->isSingleEventAdapter()) {
|
||||
$options[] = HeraldRule::REPEAT_FIRST;
|
||||
$options[] = HeraldRule::REPEAT_CHANGE;
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
protected function initializeNewAdapter() {
|
||||
|
@ -887,15 +918,15 @@ abstract class HeraldAdapter extends Phobject {
|
|||
));
|
||||
}
|
||||
|
||||
$integer_code_for_every = HeraldRepetitionPolicyConfig::toInt(
|
||||
HeraldRepetitionPolicyConfig::EVERY);
|
||||
|
||||
if ($rule->getRepetitionPolicy() == $integer_code_for_every) {
|
||||
$action_text =
|
||||
pht('Take these actions every time this rule matches:');
|
||||
if ($rule->isRepeatFirst()) {
|
||||
$action_text = pht(
|
||||
'Take these actions the first time this rule matches:');
|
||||
} else if ($rule->isRepeatOnChange()) {
|
||||
$action_text = pht(
|
||||
'Take these actions if this rule did not match the last time:');
|
||||
} else {
|
||||
$action_text =
|
||||
pht('Take these actions the first time this rule matches:');
|
||||
$action_text = pht(
|
||||
'Take these actions every time this rule matches:');
|
||||
}
|
||||
|
||||
$action_title = phutil_tag(
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class HeraldRepetitionPolicyConfig extends Phobject {
|
||||
|
||||
const FIRST = 'first'; // only execute the first time (no repeating)
|
||||
const EVERY = 'every'; // repeat every time
|
||||
|
||||
private static $policyIntMap = array(
|
||||
self::FIRST => 0,
|
||||
self::EVERY => 1,
|
||||
);
|
||||
|
||||
public static function getMap() {
|
||||
return array(
|
||||
self::EVERY => pht('every time'),
|
||||
self::FIRST => pht('only the first time'),
|
||||
);
|
||||
}
|
||||
|
||||
public static function toInt($str) {
|
||||
return idx(self::$policyIntMap, $str, self::$policyIntMap[self::EVERY]);
|
||||
}
|
||||
|
||||
public static function toString($int) {
|
||||
return idx(array_flip(self::$policyIntMap), $int, self::EVERY);
|
||||
}
|
||||
|
||||
}
|
|
@ -218,7 +218,7 @@ final class HeraldRuleController extends HeraldController {
|
|||
),
|
||||
pht('New Action')))
|
||||
->setDescription(pht(
|
||||
'Take these actions %s this rule matches:',
|
||||
'Take these actions %s',
|
||||
$repetition_selector))
|
||||
->setContent(javelin_tag(
|
||||
'table',
|
||||
|
@ -373,8 +373,7 @@ final class HeraldRuleController extends HeraldController {
|
|||
// mutate current rule, so it would be sent to the client in the right state
|
||||
$rule->setMustMatchAll((int)$match_all);
|
||||
$rule->setName($new_name);
|
||||
$rule->setRepetitionPolicy(
|
||||
HeraldRepetitionPolicyConfig::toInt($repetition_policy_param));
|
||||
$rule->setRepetitionPolicyStringConstant($repetition_policy_param);
|
||||
$rule->attachConditions($conditions);
|
||||
$rule->attachActions($actions);
|
||||
|
||||
|
@ -594,11 +593,10 @@ final class HeraldRuleController extends HeraldController {
|
|||
* time) this rule matches..." element.
|
||||
*/
|
||||
private function renderRepetitionSelector($rule, HeraldAdapter $adapter) {
|
||||
$repetition_policy = HeraldRepetitionPolicyConfig::toString(
|
||||
$rule->getRepetitionPolicy());
|
||||
$repetition_policy = $rule->getRepetitionPolicyStringConstant();
|
||||
|
||||
$repetition_options = $adapter->getRepetitionOptions();
|
||||
$repetition_names = HeraldRepetitionPolicyConfig::getMap();
|
||||
$repetition_names = HeraldRule::getRepetitionPolicySelectOptionMap();
|
||||
$repetition_map = array_select_keys($repetition_names, $repetition_options);
|
||||
|
||||
if (count($repetition_map) < 2) {
|
||||
|
|
|
@ -39,7 +39,9 @@ final class HeraldTestConsoleController extends HeraldController {
|
|||
$object = $this->getTestObject();
|
||||
$adapter = $this->getTestAdapter();
|
||||
|
||||
$adapter->setIsNewObject(false);
|
||||
$adapter
|
||||
->setIsNewObject(false)
|
||||
->setViewer($viewer);
|
||||
|
||||
$rules = id(new HeraldRuleQuery())
|
||||
->setViewer($viewer)
|
||||
|
|
|
@ -66,8 +66,10 @@ final class HeraldRuleEditor
|
|||
$object->setMustMatchAll((int)$new_state['match_all']);
|
||||
$object->attachConditions($new_state['conditions']);
|
||||
$object->attachActions($new_state['actions']);
|
||||
$object->setRepetitionPolicy(
|
||||
HeraldRepetitionPolicyConfig::toInt($new_state['repetition_policy']));
|
||||
|
||||
$new_repetition = $new_state['repetition_policy'];
|
||||
$object->setRepetitionPolicyStringConstant($new_repetition);
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ final class HeraldRuleSerializer extends Phobject {
|
|||
(bool)$rule->getMustMatchAll(),
|
||||
$rule->getConditions(),
|
||||
$rule->getActions(),
|
||||
HeraldRepetitionPolicyConfig::toString($rule->getRepetitionPolicy()));
|
||||
$rule->getRepetitionPolicyStringConstant());
|
||||
}
|
||||
|
||||
public function serializeRuleComponents(
|
||||
|
|
|
@ -14,6 +14,7 @@ final class HeraldEngine extends Phobject {
|
|||
|
||||
private $forbiddenFields = array();
|
||||
private $forbiddenActions = array();
|
||||
private $skipEffects = array();
|
||||
|
||||
public function setDryRun($dry_run) {
|
||||
$this->dryRun = $dry_run;
|
||||
|
@ -68,9 +69,7 @@ final class HeraldEngine extends Phobject {
|
|||
foreach ($rules as $phid => $rule) {
|
||||
$this->stack = array();
|
||||
|
||||
$policy_first = HeraldRepetitionPolicyConfig::FIRST;
|
||||
$policy_first_int = HeraldRepetitionPolicyConfig::toInt($policy_first);
|
||||
$is_first_only = ($rule->getRepetitionPolicy() == $policy_first_int);
|
||||
$is_first_only = $rule->isRepeatFirst();
|
||||
|
||||
try {
|
||||
if (!$this->getDryRun() &&
|
||||
|
@ -173,15 +172,31 @@ final class HeraldEngine extends Phobject {
|
|||
return;
|
||||
}
|
||||
|
||||
$rules = mpull($rules, null, 'getID');
|
||||
$applied_ids = array();
|
||||
$first_policy = HeraldRepetitionPolicyConfig::toInt(
|
||||
HeraldRepetitionPolicyConfig::FIRST);
|
||||
// Update the "applied" state table. How this table works depends on the
|
||||
// repetition policy for the rule.
|
||||
//
|
||||
// REPEAT_EVERY: We delete existing rows for the rule, then write nothing.
|
||||
// This policy doesn't use any state.
|
||||
//
|
||||
// REPEAT_FIRST: We keep existing rows, then write additional rows for
|
||||
// rules which fired. This policy accumulates state over the life of the
|
||||
// object.
|
||||
//
|
||||
// REPEAT_CHANGE: We delete existing rows, then write all the rows which
|
||||
// matched. This policy only uses the state from the previous run.
|
||||
|
||||
// Mark all the rules that have had their effects applied as having been
|
||||
// executed for the current object.
|
||||
$rules = mpull($rules, null, 'getID');
|
||||
$rule_ids = mpull($xscripts, 'getRuleID');
|
||||
|
||||
$delete_ids = array();
|
||||
foreach ($rules as $rule_id => $rule) {
|
||||
if ($rule->isRepeatFirst()) {
|
||||
continue;
|
||||
}
|
||||
$delete_ids[] = $rule_id;
|
||||
}
|
||||
|
||||
$applied_ids = array();
|
||||
foreach ($rule_ids as $rule_id) {
|
||||
if (!$rule_id) {
|
||||
// Some apply transcripts are purely informational and not associated
|
||||
|
@ -194,13 +209,30 @@ final class HeraldEngine extends Phobject {
|
|||
continue;
|
||||
}
|
||||
|
||||
if ($rule->getRepetitionPolicy() == $first_policy) {
|
||||
if ($rule->isRepeatFirst() || $rule->isRepeatOnChange()) {
|
||||
$applied_ids[] = $rule_id;
|
||||
}
|
||||
}
|
||||
|
||||
if ($applied_ids) {
|
||||
// Also include "only if this rule did not match the last time" rules
|
||||
// which matched but were skipped in the "applied" list.
|
||||
foreach ($this->skipEffects as $rule_id => $ignored) {
|
||||
$applied_ids[] = $rule_id;
|
||||
}
|
||||
|
||||
if ($delete_ids || $applied_ids) {
|
||||
$conn_w = id(new HeraldRule())->establishConnection('w');
|
||||
|
||||
if ($delete_ids) {
|
||||
queryfx(
|
||||
$conn_w,
|
||||
'DELETE FROM %T WHERE phid = %s AND ruleID IN (%Ld)',
|
||||
HeraldRule::TABLE_RULE_APPLIED,
|
||||
$adapter->getPHID(),
|
||||
$delete_ids);
|
||||
}
|
||||
|
||||
if ($applied_ids) {
|
||||
$sql = array();
|
||||
foreach ($applied_ids as $id) {
|
||||
$sql[] = qsprintf(
|
||||
|
@ -216,6 +248,7 @@ final class HeraldEngine extends Phobject {
|
|||
implode(', ', $sql));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getTranscript() {
|
||||
$this->transcript->save();
|
||||
|
@ -315,6 +348,30 @@ final class HeraldEngine extends Phobject {
|
|||
}
|
||||
}
|
||||
|
||||
// If this rule matched, and is set to run "if it did not match the last
|
||||
// time", and we matched the last time, we're going to return a match in
|
||||
// the transcript but set a flag so we don't actually apply any effects.
|
||||
|
||||
// We need the rule to match so that storage gets updated properly. If we
|
||||
// just pretend the rule didn't match it won't cause any effects (which
|
||||
// is correct), but it also won't set the "it matched" flag in storage,
|
||||
// so the next run after this one would incorrectly trigger again.
|
||||
|
||||
$is_dry_run = $this->getDryRun();
|
||||
if ($result && !$is_dry_run) {
|
||||
$is_on_change = $rule->isRepeatOnChange();
|
||||
if ($is_on_change) {
|
||||
$did_apply = $rule->getRuleApplied($object->getPHID());
|
||||
if ($did_apply) {
|
||||
$reason = pht(
|
||||
'This rule matched, but did not take any actions because it '.
|
||||
'is configured to act only if it did not match the last time.');
|
||||
|
||||
$this->skipEffects[$rule->getID()] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->newRuleTranscript($rule)
|
||||
->setResult($result)
|
||||
->setReason($reason);
|
||||
|
@ -367,6 +424,11 @@ final class HeraldEngine extends Phobject {
|
|||
HeraldRule $rule,
|
||||
HeraldAdapter $object) {
|
||||
|
||||
$rule_id = $rule->getID();
|
||||
if (isset($this->skipEffects[$rule_id])) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$effects = array();
|
||||
foreach ($rule->getActions() as $action) {
|
||||
$effect = id(new HeraldEffect())
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue