Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/passphrase/view/PassphraseCredentialControl.php
12256 views
1
<?php
2
3
final class PassphraseCredentialControl extends AphrontFormControl {
4
5
private $options = array();
6
private $credentialType;
7
private $defaultUsername;
8
private $allowNull;
9
10
public function setAllowNull($allow_null) {
11
$this->allowNull = $allow_null;
12
return $this;
13
}
14
15
public function setDefaultUsername($default_username) {
16
$this->defaultUsername = $default_username;
17
return $this;
18
}
19
20
public function setCredentialType($credential_type) {
21
$this->credentialType = $credential_type;
22
return $this;
23
}
24
25
public function getCredentialType() {
26
return $this->credentialType;
27
}
28
29
public function setOptions(array $options) {
30
assert_instances_of($options, 'PassphraseCredential');
31
$this->options = $options;
32
return $this;
33
}
34
35
protected function getCustomControlClass() {
36
return 'passphrase-credential-control';
37
}
38
39
protected function renderInput() {
40
41
$options_map = array();
42
foreach ($this->options as $option) {
43
$options_map[$option->getPHID()] = pht(
44
'%s %s',
45
$option->getMonogram(),
46
$option->getName());
47
}
48
49
// The user editing the form may not have permission to see the current
50
// credential. Populate it into the menu to allow them to save the form
51
// without making any changes.
52
$current_phid = $this->getValue();
53
if ($current_phid !== null && strlen($current_phid)
54
&& empty($options_map[$current_phid])) {
55
56
$viewer = $this->getViewer();
57
58
$current_name = null;
59
try {
60
$user_credential = id(new PassphraseCredentialQuery())
61
->setViewer($viewer)
62
->withPHIDs(array($current_phid))
63
->executeOne();
64
65
if ($user_credential) {
66
$current_name = pht(
67
'%s %s',
68
$user_credential->getMonogram(),
69
$user_credential->getName());
70
}
71
} catch (PhabricatorPolicyException $policy_exception) {
72
// Pull the credential with the omnipotent viewer so we can look up
73
// the ID and provide the monogram.
74
$omnipotent_credential = id(new PassphraseCredentialQuery())
75
->setViewer(PhabricatorUser::getOmnipotentUser())
76
->withPHIDs(array($current_phid))
77
->executeOne();
78
if ($omnipotent_credential) {
79
$current_name = pht(
80
'%s (Restricted Credential)',
81
$omnipotent_credential->getMonogram());
82
}
83
}
84
85
if ($current_name === null) {
86
$current_name = pht(
87
'Invalid Credential ("%s")',
88
$current_phid);
89
}
90
91
$options_map = array(
92
$current_phid => $current_name,
93
) + $options_map;
94
}
95
96
97
$disabled = $this->getDisabled();
98
if ($this->allowNull) {
99
$options_map = array('' => pht('(No Credentials)')) + $options_map;
100
} else {
101
if (!$options_map) {
102
$options_map[''] = pht('(No Existing Credentials)');
103
$disabled = true;
104
}
105
}
106
107
Javelin::initBehavior('passphrase-credential-control');
108
109
$options = AphrontFormSelectControl::renderSelectTag(
110
$this->getValue(),
111
$options_map,
112
array(
113
'id' => $this->getControlID(),
114
'name' => $this->getName(),
115
'disabled' => $disabled ? 'disabled' : null,
116
'sigil' => 'passphrase-credential-select',
117
));
118
119
if ($this->credentialType) {
120
$button = javelin_tag(
121
'a',
122
array(
123
'href' => '#',
124
'class' => 'button button-grey mll',
125
'sigil' => 'passphrase-credential-add',
126
'mustcapture' => true,
127
'style' => 'height: 20px;', // move aphront-form to tables
128
),
129
pht('Add New Credential'));
130
} else {
131
$button = null;
132
}
133
134
return javelin_tag(
135
'div',
136
array(
137
'sigil' => 'passphrase-credential-control',
138
'meta' => array(
139
'type' => $this->getCredentialType(),
140
'username' => $this->defaultUsername,
141
'allowNull' => $this->allowNull,
142
),
143
),
144
array(
145
$options,
146
$button,
147
));
148
}
149
150
/**
151
* Verify that a given actor has permission to use all of the credentials
152
* in a list of credential transactions.
153
*
154
* In general, the rule here is:
155
*
156
* - If you're editing an object and it uses a credential you can't use,
157
* that's fine as long as you don't change the credential.
158
* - If you do change the credential, the new credential must be one you
159
* can use.
160
*
161
* @param PhabricatorUser The acting user.
162
* @param list<PhabricatorApplicationTransaction> List of credential altering
163
* transactions.
164
* @return bool True if the transactions are valid.
165
*/
166
public static function validateTransactions(
167
PhabricatorUser $actor,
168
array $xactions) {
169
170
$new_phids = array();
171
foreach ($xactions as $xaction) {
172
$new = $xaction->getNewValue();
173
if (!$new) {
174
// Removing a credential, so this is OK.
175
continue;
176
}
177
178
$old = $xaction->getOldValue();
179
if ($old == $new) {
180
// This is a no-op transaction, so this is also OK.
181
continue;
182
}
183
184
// Otherwise, we need to check this credential.
185
$new_phids[] = $new;
186
}
187
188
if (!$new_phids) {
189
// No new credentials being set, so this is fine.
190
return true;
191
}
192
193
$usable_credentials = id(new PassphraseCredentialQuery())
194
->setViewer($actor)
195
->withPHIDs($new_phids)
196
->execute();
197
$usable_credentials = mpull($usable_credentials, null, 'getPHID');
198
199
foreach ($new_phids as $phid) {
200
if (empty($usable_credentials[$phid])) {
201
return false;
202
}
203
}
204
205
return true;
206
}
207
208
209
}
210
211