public function testURIGeneration() { $svn = PhabricatorRepositoryType::REPOSITORY_TYPE_SVN; $git = PhabricatorRepositoryType::REPOSITORY_TYPE_GIT; $hg = PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL; $user = $this->generateNewTestUser(); $http_secret = id(new PassphraseSecret())->setSecretData('quack')->save(); $http_credential = PassphraseCredential::initializeNewCredential($user)->setCredentialType(PassphrasePasswordCredentialType::CREDENTIAL_TYPE)->setProvidesType(PassphrasePasswordCredentialType::PROVIDES_TYPE)->setUsername('duck')->setSecretID($http_secret->getID())->save(); $repo = PhabricatorRepository::initializeNewRepository($user)->setVersionControlSystem($svn)->setName(pht('Test Repo'))->setCallsign('TESTREPO')->setCredentialPHID($http_credential->getPHID())->save(); // Test HTTP URIs. $repo->setDetail('remote-uri', 'http://example.com/'); $repo->setVersionControlSystem($svn); $this->assertEqual('http://example.com/', $repo->getRemoteURI()); $this->assertEqual('http://example.com/', $repo->getPublicCloneURI()); $this->assertEqual('http://example.com/', $repo->getRemoteURIEnvelope()->openEnvelope()); $repo->setVersionControlSystem($git); $this->assertEqual('http://example.com/', $repo->getRemoteURI()); $this->assertEqual('http://example.com/', $repo->getPublicCloneURI()); $this->assertEqual('http://*****:*****@example.com/', $repo->getRemoteURIEnvelope()->openEnvelope()); $repo->setVersionControlSystem($hg); $this->assertEqual('http://example.com/', $repo->getRemoteURI()); $this->assertEqual('http://example.com/', $repo->getPublicCloneURI()); $this->assertEqual('http://*****:*****@example.com/', $repo->getRemoteURIEnvelope()->openEnvelope()); // Test SSH URIs. $repo->setDetail('remote-uri', 'ssh://example.com/'); $repo->setVersionControlSystem($svn); $this->assertEqual('ssh://example.com/', $repo->getRemoteURI()); $this->assertEqual('ssh://example.com/', $repo->getPublicCloneURI()); $this->assertEqual('ssh://example.com/', $repo->getRemoteURIEnvelope()->openEnvelope()); $repo->setVersionControlSystem($git); $this->assertEqual('ssh://example.com/', $repo->getRemoteURI()); $this->assertEqual('ssh://example.com/', $repo->getPublicCloneURI()); $this->assertEqual('ssh://example.com/', $repo->getRemoteURIEnvelope()->openEnvelope()); $repo->setVersionControlSystem($hg); $this->assertEqual('ssh://example.com/', $repo->getRemoteURI()); $this->assertEqual('ssh://example.com/', $repo->getPublicCloneURI()); $this->assertEqual('ssh://example.com/', $repo->getRemoteURIEnvelope()->openEnvelope()); // Test Git URIs. $repo->setDetail('remote-uri', 'git@example.com:path.git'); $repo->setVersionControlSystem($git); $this->assertEqual('git@example.com:path.git', $repo->getRemoteURI()); $this->assertEqual('git@example.com:path.git', $repo->getPublicCloneURI()); $this->assertEqual('git@example.com:path.git', $repo->getRemoteURIEnvelope()->openEnvelope()); // Test SVN "Import Only" paths. $repo->setDetail('remote-uri', 'http://example.com/'); $repo->setVersionControlSystem($svn); $repo->setDetail('svn-subpath', 'projects/example/'); $this->assertEqual('http://example.com/', $repo->getRemoteURI()); $this->assertEqual('http://example.com/projects/example/', $repo->getPublicCloneURI()); $this->assertEqual('http://example.com/', $repo->getRemoteURIEnvelope()->openEnvelope()); }
echo pht('...will migrate.') . "\n"; } $passphrase = new PassphraseSecret(); $passphrase->openTransaction(); $table->openTransaction(); foreach ($map as $credential_type => $credential_usernames) { $type = PassphraseCredentialType::getTypeByConstant($credential_type); foreach ($credential_usernames as $username => $credential_secrets) { foreach ($credential_secrets as $secret_plaintext => $repositories) { $callsigns = mpull($repositories, 'getCallsign'); $signs = implode(', ', $callsigns); $name = pht('Migrated Repository Credential (%s)', id(new PhutilUTF8StringTruncator())->setMaximumGlyphs(128)->truncateString($signs)); echo pht('Creating: %s...', $name) . "\n"; $secret = id(new PassphraseSecret())->setSecretData($secret_plaintext)->save(); $secret_id = $secret->getID(); $credential = PassphraseCredential::initializeNewCredential($viewer)->setCredentialType($type->getCredentialType())->setProvidesType($type->getProvidesType())->setViewPolicy(PhabricatorPolicies::POLICY_ADMIN)->setEditPolicy(PhabricatorPolicies::POLICY_ADMIN)->setName($name)->setUsername($username)->setSecretID($secret_id); $credential->setPHID($credential->generatePHID()); queryfx($credential->establishConnection('w'), 'INSERT INTO %T (name, credentialType, providesType, viewPolicy, editPolicy, description, username, secretID, isDestroyed, phid, dateCreated, dateModified) VALUES (%s, %s, %s, %s, %s, %s, %s, %d, %d, %s, %d, %d)', $credential->getTableName(), $credential->getName(), $credential->getCredentialType(), $credential->getProvidesType(), $credential->getViewPolicy(), $credential->getEditPolicy(), $credential->getDescription(), $credential->getUsername(), $credential->getSecretID(), $credential->getIsDestroyed(), $credential->getPHID(), time(), time()); foreach ($repositories as $repository) { queryfx($conn_w, 'UPDATE %T SET credentialPHID = %s WHERE id = %d', $table->getTableName(), $credential->getPHID(), $repository->getID()); $edge_type = PhabricatorObjectUsesCredentialsEdgeType::EDGECONST; id(new PhabricatorEdgeEditor())->addEdge($repository->getPHID(), $edge_type, $credential->getPHID())->save(); } } } } $table->saveTransaction(); $passphrase->saveTransaction();
public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); $id = $request->getURIData('id'); if ($id) { $credential = id(new PassphraseCredentialQuery())->setViewer($viewer)->withIDs(array($id))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne(); if (!$credential) { return new Aphront404Response(); } $type = $this->getCredentialType($credential->getCredentialType()); $is_new = false; } else { $type_const = $request->getStr('type'); $type = $this->getCredentialType($type_const); if (!$type->isCreateable()) { throw new Exception(pht('Credential has noncreateable type "%s"!', $type_const)); } $credential = PassphraseCredential::initializeNewCredential($viewer)->setCredentialType($type->getCredentialType())->setProvidesType($type->getProvidesType()); $is_new = true; // Prefill username if provided. $credential->setUsername((string) $request->getStr('username')); if (!$request->getStr('isInitialized')) { $type->didInitializeNewCredential($viewer, $credential); } } $errors = array(); $v_name = $credential->getName(); $e_name = true; $v_desc = $credential->getDescription(); $v_space = $credential->getSpacePHID(); $v_username = $credential->getUsername(); $e_username = true; $v_is_locked = false; $bullet = "•"; $v_secret = $credential->getSecretID() ? str_repeat($bullet, 32) : null; if ($is_new && $v_secret === null) { // If we're creating a new credential, the credential type may have // populated the secret for us (for example, generated an SSH key). In // this case, try { $v_secret = $credential->getSecret()->openEnvelope(); } catch (Exception $ex) { // Ignore this. } } $validation_exception = null; $errors = array(); $e_password = null; if ($request->isFormPost()) { $v_name = $request->getStr('name'); $v_desc = $request->getStr('description'); $v_username = $request->getStr('username'); $v_view_policy = $request->getStr('viewPolicy'); $v_edit_policy = $request->getStr('editPolicy'); $v_is_locked = $request->getStr('lock'); $v_secret = $request->getStr('secret'); $v_space = $request->getStr('spacePHID'); $v_password = $request->getStr('password'); $v_decrypt = $v_secret; $env_secret = new PhutilOpaqueEnvelope($v_secret); $env_password = new PhutilOpaqueEnvelope($v_password); if ($type->requiresPassword($env_secret)) { if (strlen($v_password)) { $v_decrypt = $type->decryptSecret($env_secret, $env_password); if ($v_decrypt === null) { $e_password = pht('Incorrect'); $errors[] = pht('This key requires a password, but the password you provided ' . 'is incorrect.'); } else { $v_decrypt = $v_decrypt->openEnvelope(); } } else { $e_password = pht('Required'); $errors[] = pht('This key requires a password. You must provide the password ' . 'for the key.'); } } if (!$errors) { $type_name = PassphraseCredentialTransaction::TYPE_NAME; $type_desc = PassphraseCredentialTransaction::TYPE_DESCRIPTION; $type_username = PassphraseCredentialTransaction::TYPE_USERNAME; $type_destroy = PassphraseCredentialTransaction::TYPE_DESTROY; $type_secret_id = PassphraseCredentialTransaction::TYPE_SECRET_ID; $type_is_locked = PassphraseCredentialTransaction::TYPE_LOCK; $type_view_policy = PhabricatorTransactions::TYPE_VIEW_POLICY; $type_edit_policy = PhabricatorTransactions::TYPE_EDIT_POLICY; $type_space = PhabricatorTransactions::TYPE_SPACE; $xactions = array(); $xactions[] = id(new PassphraseCredentialTransaction())->setTransactionType($type_name)->setNewValue($v_name); $xactions[] = id(new PassphraseCredentialTransaction())->setTransactionType($type_desc)->setNewValue($v_desc); $xactions[] = id(new PassphraseCredentialTransaction())->setTransactionType($type_view_policy)->setNewValue($v_view_policy); $xactions[] = id(new PassphraseCredentialTransaction())->setTransactionType($type_edit_policy)->setNewValue($v_edit_policy); $xactions[] = id(new PassphraseCredentialTransaction())->setTransactionType($type_space)->setNewValue($v_space); // Open a transaction in case we're writing a new secret; this limits // the amount of code which handles secret plaintexts. $credential->openTransaction(); if (!$credential->getIsLocked()) { if ($type->shouldRequireUsername()) { $xactions[] = id(new PassphraseCredentialTransaction())->setTransactionType($type_username)->setNewValue($v_username); } // If some value other than a sequence of bullets was provided for // the credential, update it. In particular, note that we are // explicitly allowing empty secrets: one use case is HTTP auth where // the username is a secret token which covers both identity and // authentication. if (!preg_match('/^(' . $bullet . ')+$/', trim($v_decrypt))) { // If the credential was previously destroyed, restore it when it is // edited if a secret is provided. $xactions[] = id(new PassphraseCredentialTransaction())->setTransactionType($type_destroy)->setNewValue(0); $new_secret = id(new PassphraseSecret())->setSecretData($v_decrypt)->save(); $xactions[] = id(new PassphraseCredentialTransaction())->setTransactionType($type_secret_id)->setNewValue($new_secret->getID()); } $xactions[] = id(new PassphraseCredentialTransaction())->setTransactionType($type_is_locked)->setNewValue($v_is_locked); } try { $editor = id(new PassphraseCredentialTransactionEditor())->setActor($viewer)->setContinueOnNoEffect(true)->setContentSourceFromRequest($request)->applyTransactions($credential, $xactions); $credential->saveTransaction(); if ($request->isAjax()) { return id(new AphrontAjaxResponse())->setContent(array('phid' => $credential->getPHID(), 'name' => 'K' . $credential->getID() . ' ' . $credential->getName())); } else { return id(new AphrontRedirectResponse())->setURI('/K' . $credential->getID()); } } catch (PhabricatorApplicationTransactionValidationException $ex) { $credential->killTransaction(); $validation_exception = $ex; $e_name = $ex->getShortMessage($type_name); $e_username = $ex->getShortMessage($type_username); $credential->setViewPolicy($v_view_policy); $credential->setEditPolicy($v_edit_policy); } } } $policies = id(new PhabricatorPolicyQuery())->setViewer($viewer)->setObject($credential)->execute(); $secret_control = $type->newSecretControl(); $credential_is_locked = $credential->getIsLocked(); $form = id(new AphrontFormView())->setUser($viewer)->addHiddenInput('isInitialized', true)->appendChild(id(new AphrontFormTextControl())->setName('name')->setLabel(pht('Name'))->setValue($v_name)->setError($e_name))->appendChild(id(new AphrontFormTextAreaControl())->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_SHORT)->setName('description')->setLabel(pht('Description'))->setValue($v_desc))->appendChild(id(new AphrontFormMarkupControl())->setLabel(pht('Credential Type'))->setValue($type->getCredentialTypeName()))->appendChild(id(new AphrontFormDividerControl()))->appendControl(id(new AphrontFormPolicyControl())->setName('viewPolicy')->setPolicyObject($credential)->setCapability(PhabricatorPolicyCapability::CAN_VIEW)->setPolicies($policies))->appendControl(id(new AphrontFormPolicyControl())->setName('editPolicy')->setPolicyObject($credential)->setCapability(PhabricatorPolicyCapability::CAN_EDIT)->setPolicies($policies))->appendChild(id(new AphrontFormDividerControl())); if ($credential_is_locked) { $form->appendRemarkupInstructions(pht('This credential is permanently locked and can not be edited.')); } if ($type->shouldRequireUsername()) { $form->appendChild(id(new AphrontFormTextControl())->setName('username')->setLabel(pht('Login/Username'))->setValue($v_username)->setDisabled($credential_is_locked)->setError($e_username)); } $form->appendChild($secret_control->setName('secret')->setLabel($type->getSecretLabel())->setDisabled($credential_is_locked)->setValue($v_secret)); if ($type->shouldShowPasswordField()) { $form->appendChild(id(new AphrontFormPasswordControl())->setDisableAutocomplete(true)->setName('password')->setLabel($type->getPasswordLabel())->setDisabled($credential_is_locked)->setError($e_password)); } if ($is_new) { $form->appendChild(id(new AphrontFormCheckboxControl())->addCheckbox('lock', 1, array(phutil_tag('strong', array(), pht('Lock Permanently:')), ' ', pht('Prevent the secret from being revealed or changed.')), $v_is_locked)->setDisabled($credential_is_locked)); } $crumbs = $this->buildApplicationCrumbs(); if ($is_new) { $title = pht('Create Credential'); $header = pht('Create New Credential'); $crumbs->addTextCrumb(pht('Create')); $cancel_uri = $this->getApplicationURI(); } else { $title = pht('Edit Credential'); $header = pht('Edit Credential %s', 'K' . $credential->getID()); $crumbs->addTextCrumb('K' . $credential->getID(), '/K' . $credential->getID()); $crumbs->addTextCrumb(pht('Edit')); $cancel_uri = '/K' . $credential->getID(); } if ($request->isAjax()) { if ($errors) { $errors = id(new PHUIInfoView())->setErrors($errors); } $dialog = id(new AphrontDialogView())->setUser($viewer)->setWidth(AphrontDialogView::WIDTH_FORM)->setTitle($title)->appendChild($errors)->appendChild($form->buildLayoutView())->addSubmitButton(pht('Create Credential'))->addCancelButton($cancel_uri); return id(new AphrontDialogResponse())->setDialog($dialog); } $form->appendChild(id(new AphrontFormSubmitControl())->setValue(pht('Save'))->addCancelButton($cancel_uri)); $box = id(new PHUIObjectBoxView())->setHeaderText($header)->setFormErrors($errors)->setValidationException($validation_exception)->setForm($form); return $this->buildApplicationPage(array($crumbs, $box), array('title' => $title)); }