mirror of
https://we.phorge.it/source/phorge.git
synced 2025-03-29 04:28:12 +01:00
Summary: Ref T11140. This makes encryption actually work: - Provide a new configuation option, `keyring`, for specifying encryption keys. - One key may be marked as `default`. This activates AES256 encryption for Files. - Add `bin/files generate-key`. This is helps when generating valid encryption keys. - Add `bin/files encode`. This changes the storage encoding of a file, and helps test encodings and migrate existing data. - Add `bin/files cycle`. This re-encodes the block key with a new master key, if your master key leaks or you're just paraonid. - Document all these options and behaviors. Test Plan: - Configured a bad `keyring`, hit a bunch of different errors. - Used `bin/files generate-key` to try to generate bad keys, got appropriate errors ("raw doesn't support keys", etc). - Used `bin/files generate-key` to generate an AES256 key. - Put the new AES256 key into the `keyring`, without `default`. - Uploaded a new file, verified it still uploaded as raw data (no `default` key yet). - Used `bin/files encode` to change a file to ROT13 and back to raw. Verified old data got deleted and new data got stored properly. - Used `bin/files encode --key ...` to explicitly convert a file to AES256 with my non-default key. - Forced a re-encode of an AES256 file, verified the old data was deleted and a new key and IV were generated. - Used `bin/files cycle` to try to cycle raw/rot13 files, got errors. - Used `bin/files cycle` to cycle AES256 files. Verified metadata changed but file data did not. Verified file data was still decryptable with metadata. - Ran `bin/files cycle --all`. - Ran `encode` and `cycle` on chunked files, saw commands fail properly. These commands operate on the underlying data blocks, not the chunk metadata. - Set key to `default`, uploaded a file, saw it stored as AES256. - Read documentation. Reviewers: chad Reviewed By: chad Maniphest Tasks: T11140 Differential Revision: https://secure.phabricator.com/D16127
151 lines
3.7 KiB
PHP
151 lines
3.7 KiB
PHP
<?php
|
|
|
|
final class PhabricatorFilesManagementEncodeWorkflow
|
|
extends PhabricatorFilesManagementWorkflow {
|
|
|
|
protected function didConstruct() {
|
|
$this
|
|
->setName('encode')
|
|
->setSynopsis(
|
|
pht('Change the storage encoding of files.'))
|
|
->setArguments(
|
|
array(
|
|
array(
|
|
'name' => 'as',
|
|
'param' => 'format',
|
|
'help' => pht('Select the storage format to use.'),
|
|
),
|
|
array(
|
|
'name' => 'key',
|
|
'param' => 'keyname',
|
|
'help' => pht('Select a specific storage key.'),
|
|
),
|
|
array(
|
|
'name' => 'all',
|
|
'help' => pht('Change encoding for all files.'),
|
|
),
|
|
array(
|
|
'name' => 'force',
|
|
'help' => pht(
|
|
'Re-encode files which are already stored in the target '.
|
|
'encoding.'),
|
|
),
|
|
array(
|
|
'name' => 'names',
|
|
'wildcard' => true,
|
|
),
|
|
));
|
|
}
|
|
|
|
public function execute(PhutilArgumentParser $args) {
|
|
$iterator = $this->buildIterator($args);
|
|
if (!$iterator) {
|
|
throw new PhutilArgumentUsageException(
|
|
pht(
|
|
'Either specify a list of files to encode, or use --all to '.
|
|
'encode all files.'));
|
|
}
|
|
|
|
$force = (bool)$args->getArg('force');
|
|
|
|
$format_list = PhabricatorFileStorageFormat::getAllFormats();
|
|
$format_list = array_keys($format_list);
|
|
$format_list = implode(', ', $format_list);
|
|
|
|
$format_key = $args->getArg('as');
|
|
if (!strlen($format_key)) {
|
|
throw new PhutilArgumentUsageException(
|
|
pht(
|
|
'Use --as <format> to select a target encoding format. Available '.
|
|
'formats are: %s.',
|
|
$format_list));
|
|
}
|
|
|
|
$format = PhabricatorFileStorageFormat::getFormat($format_key);
|
|
if (!$format) {
|
|
throw new PhutilArgumentUsageException(
|
|
pht(
|
|
'Storage format "%s" is not valid. Available formats are: %s.',
|
|
$format_key,
|
|
$format_list));
|
|
}
|
|
|
|
$key_name = $args->getArg('key');
|
|
if (strlen($key_name)) {
|
|
$format->selectMasterKey($key_name);
|
|
}
|
|
|
|
$engines = PhabricatorFileStorageEngine::loadAllEngines();
|
|
|
|
$failed = array();
|
|
foreach ($iterator as $file) {
|
|
$monogram = $file->getMonogram();
|
|
|
|
$engine_key = $file->getStorageEngine();
|
|
$engine = idx($engines, $engine_key);
|
|
|
|
if (!$engine) {
|
|
echo tsprintf(
|
|
"%s\n",
|
|
pht(
|
|
'%s: Uses unknown storage engine "%s".',
|
|
$monogram,
|
|
$engine_key));
|
|
$failed[] = $file;
|
|
continue;
|
|
}
|
|
|
|
if ($engine->isChunkEngine()) {
|
|
echo tsprintf(
|
|
"%s\n",
|
|
pht(
|
|
'%s: Stored as chunks, no data to encode directly.',
|
|
$monogram));
|
|
continue;
|
|
}
|
|
|
|
if (($file->getStorageFormat() == $format_key) && !$force) {
|
|
echo tsprintf(
|
|
"%s\n",
|
|
pht(
|
|
'%s: Already encoded in target format.',
|
|
$monogram));
|
|
continue;
|
|
}
|
|
|
|
echo tsprintf(
|
|
"%s\n",
|
|
pht(
|
|
'%s: Changing encoding from "%s" to "%s".',
|
|
$monogram,
|
|
$file->getStorageFormat(),
|
|
$format_key));
|
|
|
|
try {
|
|
$file->migrateToStorageFormat($format);
|
|
|
|
echo tsprintf(
|
|
"%s\n",
|
|
pht('Done.'));
|
|
} catch (Exception $ex) {
|
|
echo tsprintf(
|
|
"%B\n",
|
|
pht('Failed! %s', (string)$ex));
|
|
$failed[] = $file;
|
|
}
|
|
}
|
|
|
|
if ($failed) {
|
|
$monograms = mpull($failed, 'getMonogram');
|
|
|
|
echo tsprintf(
|
|
"%s\n",
|
|
pht('Failures: %s.', implode(', ', $monograms)));
|
|
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
}
|