Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/auth/query/PhabricatorExternalAccountQuery.php
12256 views
1
<?php
2
3
/**
4
* NOTE: When loading ExternalAccounts for use in an authentication context
5
* (that is, you're going to act as the account or link identities or anything
6
* like that) you should require CAN_EDIT capability even if you aren't actually
7
* editing the ExternalAccount.
8
*
9
* ExternalAccounts have a permissive CAN_VIEW policy (like users) because they
10
* interact directly with objects and can leave comments, sign documents, etc.
11
* However, CAN_EDIT is restricted to users who own the accounts.
12
*/
13
final class PhabricatorExternalAccountQuery
14
extends PhabricatorCursorPagedPolicyAwareQuery {
15
16
private $ids;
17
private $phids;
18
private $userPHIDs;
19
private $needImages;
20
private $accountSecrets;
21
private $providerConfigPHIDs;
22
private $needAccountIdentifiers;
23
private $rawAccountIdentifiers;
24
25
public function withUserPHIDs(array $user_phids) {
26
$this->userPHIDs = $user_phids;
27
return $this;
28
}
29
30
public function withPHIDs(array $phids) {
31
$this->phids = $phids;
32
return $this;
33
}
34
35
public function withIDs($ids) {
36
$this->ids = $ids;
37
return $this;
38
}
39
40
public function withAccountSecrets(array $secrets) {
41
$this->accountSecrets = $secrets;
42
return $this;
43
}
44
45
public function needImages($need) {
46
$this->needImages = $need;
47
return $this;
48
}
49
50
public function needAccountIdentifiers($need) {
51
$this->needAccountIdentifiers = $need;
52
return $this;
53
}
54
55
public function withProviderConfigPHIDs(array $phids) {
56
$this->providerConfigPHIDs = $phids;
57
return $this;
58
}
59
60
public function withRawAccountIdentifiers(array $identifiers) {
61
$this->rawAccountIdentifiers = $identifiers;
62
return $this;
63
}
64
65
public function newResultObject() {
66
return new PhabricatorExternalAccount();
67
}
68
69
protected function willFilterPage(array $accounts) {
70
$viewer = $this->getViewer();
71
72
$configs = id(new PhabricatorAuthProviderConfigQuery())
73
->setViewer($viewer)
74
->withPHIDs(mpull($accounts, 'getProviderConfigPHID'))
75
->execute();
76
$configs = mpull($configs, null, 'getPHID');
77
78
foreach ($accounts as $key => $account) {
79
$config_phid = $account->getProviderConfigPHID();
80
$config = idx($configs, $config_phid);
81
82
if (!$config) {
83
unset($accounts[$key]);
84
continue;
85
}
86
87
$account->attachProviderConfig($config);
88
}
89
90
if ($this->needImages) {
91
$file_phids = mpull($accounts, 'getProfileImagePHID');
92
$file_phids = array_filter($file_phids);
93
94
if ($file_phids) {
95
// NOTE: We use the omnipotent viewer here because these files are
96
// usually created during registration and can't be associated with
97
// the correct policies, since the relevant user account does not exist
98
// yet. In effect, if you can see an ExternalAccount, you can see its
99
// profile image.
100
$files = id(new PhabricatorFileQuery())
101
->setViewer(PhabricatorUser::getOmnipotentUser())
102
->withPHIDs($file_phids)
103
->execute();
104
$files = mpull($files, null, 'getPHID');
105
} else {
106
$files = array();
107
}
108
109
$default_file = null;
110
foreach ($accounts as $account) {
111
$image_phid = $account->getProfileImagePHID();
112
if ($image_phid && isset($files[$image_phid])) {
113
$account->attachProfileImageFile($files[$image_phid]);
114
} else {
115
if ($default_file === null) {
116
$default_file = PhabricatorFile::loadBuiltin(
117
$this->getViewer(),
118
'profile.png');
119
}
120
$account->attachProfileImageFile($default_file);
121
}
122
}
123
}
124
125
if ($this->needAccountIdentifiers) {
126
$account_phids = mpull($accounts, 'getPHID');
127
128
$identifiers = id(new PhabricatorExternalAccountIdentifierQuery())
129
->setViewer($viewer)
130
->setParentQuery($this)
131
->withExternalAccountPHIDs($account_phids)
132
->execute();
133
134
$identifiers = mgroup($identifiers, 'getExternalAccountPHID');
135
foreach ($accounts as $account) {
136
$account_phid = $account->getPHID();
137
$account_identifiers = idx($identifiers, $account_phid, array());
138
$account->attachAccountIdentifiers($account_identifiers);
139
}
140
}
141
142
return $accounts;
143
}
144
145
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
146
$where = parent::buildWhereClauseParts($conn);
147
148
if ($this->ids !== null) {
149
$where[] = qsprintf(
150
$conn,
151
'account.id IN (%Ld)',
152
$this->ids);
153
}
154
155
if ($this->phids !== null) {
156
$where[] = qsprintf(
157
$conn,
158
'account.phid IN (%Ls)',
159
$this->phids);
160
}
161
162
if ($this->userPHIDs !== null) {
163
$where[] = qsprintf(
164
$conn,
165
'account.userPHID IN (%Ls)',
166
$this->userPHIDs);
167
}
168
169
if ($this->accountSecrets !== null) {
170
$where[] = qsprintf(
171
$conn,
172
'account.accountSecret IN (%Ls)',
173
$this->accountSecrets);
174
}
175
176
if ($this->providerConfigPHIDs !== null) {
177
$where[] = qsprintf(
178
$conn,
179
'account.providerConfigPHID IN (%Ls)',
180
$this->providerConfigPHIDs);
181
182
// If we have a list of ProviderConfig PHIDs and are joining the
183
// identifiers table, also include the list as an additional constraint
184
// on the identifiers table.
185
186
// This does not change the query results (an Account and its
187
// Identifiers always have the same ProviderConfig PHID) but it allows
188
// us to use keys on the Identifier table more efficiently.
189
190
if ($this->shouldJoinIdentifiersTable()) {
191
$where[] = qsprintf(
192
$conn,
193
'identifier.providerConfigPHID IN (%Ls)',
194
$this->providerConfigPHIDs);
195
}
196
}
197
198
if ($this->rawAccountIdentifiers !== null) {
199
$hashes = array();
200
201
foreach ($this->rawAccountIdentifiers as $raw_identifier) {
202
$hashes[] = PhabricatorHash::digestForIndex($raw_identifier);
203
}
204
205
$where[] = qsprintf(
206
$conn,
207
'identifier.identifierHash IN (%Ls)',
208
$hashes);
209
}
210
211
return $where;
212
}
213
214
protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) {
215
$joins = parent::buildJoinClauseParts($conn);
216
217
if ($this->shouldJoinIdentifiersTable()) {
218
$joins[] = qsprintf(
219
$conn,
220
'JOIN %R identifier ON account.phid = identifier.externalAccountPHID',
221
new PhabricatorExternalAccountIdentifier());
222
}
223
224
return $joins;
225
}
226
227
protected function shouldJoinIdentifiersTable() {
228
return ($this->rawAccountIdentifiers !== null);
229
}
230
231
protected function shouldGroupQueryResultRows() {
232
if ($this->shouldJoinIdentifiersTable()) {
233
return true;
234
}
235
236
return parent::shouldGroupQueryResultRows();
237
}
238
239
protected function getPrimaryTableAlias() {
240
return 'account';
241
}
242
243
public function getQueryApplicationClass() {
244
return 'PhabricatorPeopleApplication';
245
}
246
247
}
248
249