This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * ownCloud - AddressbookProvider |
||
4 | * |
||
5 | * @author Thomas Tanghus |
||
6 | * @copyright 2012-2014 Thomas Tanghus ([email protected]) |
||
7 | * |
||
8 | * This library is free software; you can redistribute it and/or |
||
9 | * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE |
||
10 | * License as published by the Free Software Foundation; either |
||
11 | * version 3 of the License, or any later version. |
||
12 | * |
||
13 | * This library is distributed in the hope that it will be useful, |
||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
16 | * GNU AFFERO GENERAL PUBLIC LICENSE for more details. |
||
17 | * |
||
18 | * You should have received a copy of the GNU Affero General Public |
||
19 | * License along with this library. If not, see <http://www.gnu.org/licenses/>. |
||
20 | * |
||
21 | */ |
||
22 | |||
23 | namespace OCA\Contacts; |
||
24 | use OCA\Contacts\Utils\JSONSerializer; |
||
25 | use OCA\Contacts\Utils\Properties; |
||
26 | use OCA\Contacts\VObject\VCard; |
||
27 | |||
28 | /** |
||
29 | * This class manages our addressbooks. |
||
30 | * TODO: Port this to use the new backend |
||
31 | */ |
||
32 | class AddressbookProvider implements \OCP\IAddressBook { |
||
33 | |||
34 | const CONTACT_TABLE = '*PREFIX*contacts_cards'; |
||
35 | const PROPERTY_TABLE = '*PREFIX*contacts_cards_properties'; |
||
36 | const ADDRESSBOOK_TABLE = '*PREFIX*contacts_addressbooks'; |
||
37 | |||
38 | /** |
||
39 | * Addressbook id |
||
40 | * @var integer |
||
41 | */ |
||
42 | public $id; |
||
43 | |||
44 | /** |
||
45 | * Addressbook info array |
||
46 | * @var AddressBook |
||
47 | */ |
||
48 | public $addressBook; |
||
49 | |||
50 | /** |
||
51 | * Constructor |
||
52 | * @param AddressBook $addressBook |
||
53 | */ |
||
54 | 2 | public function __construct($addressBook) { |
|
55 | 2 | $this->addressBook = $addressBook; |
|
56 | 2 | $this->app = new App(); |
|
57 | 2 | } |
|
58 | |||
59 | public function getAddressbook() { |
||
60 | return $this->addressBook; |
||
61 | } |
||
62 | |||
63 | /** |
||
64 | * @return string defining the technical unique key |
||
65 | */ |
||
66 | public function getKey() { |
||
67 | $metaData = $this->addressBook->getMetaData(); |
||
68 | return $metaData['backend'].':'.$metaData['id']; |
||
69 | } |
||
70 | |||
71 | /** |
||
72 | * In comparison to getKey() this function returns a human readable (maybe translated) name |
||
73 | * @return string |
||
74 | */ |
||
75 | public function getDisplayName() { |
||
76 | return $this->addressBook->getDisplayName(); |
||
77 | } |
||
78 | |||
79 | /** |
||
80 | * @return integer |
||
81 | */ |
||
82 | public function getPermissions() { |
||
83 | return $this->addressBook->getPermissions(); |
||
84 | } |
||
85 | |||
86 | /** |
||
87 | * @param string $pattern |
||
88 | * @param string[] $searchProperties |
||
89 | * @param $options |
||
90 | * @return array|false |
||
91 | */ |
||
92 | 2 | public function search($pattern, $searchProperties, $options) { |
|
93 | 2 | $propTable = self::PROPERTY_TABLE; |
|
94 | 2 | $contTable = self::CONTACT_TABLE; |
|
95 | 2 | $addrTable = self::ADDRESSBOOK_TABLE; |
|
96 | 2 | $results = array(); |
|
97 | |||
98 | /** |
||
99 | * This query will fetch all contacts which match the $searchProperties |
||
100 | * It will look up the addressbookid of the contact and the user id of the owner of the contact app |
||
101 | */ |
||
102 | $query = <<<SQL |
||
103 | SELECT |
||
104 | DISTINCT |
||
105 | `$propTable`.`contactid`, |
||
106 | 2 | `$contTable`.`addressbookid`, |
|
107 | 2 | `$addrTable`.`userid` |
|
108 | |||
109 | FROM |
||
110 | 2 | `$propTable` |
|
111 | INNER JOIN |
||
112 | 2 | `$contTable` |
|
113 | 2 | ON `$contTable`.`id` = `$propTable`.`contactid` |
|
114 | 2 | INNER JOIN `$addrTable` |
|
115 | 2 | ON `$addrTable`.id = `$contTable`.addressbookid |
|
116 | WHERE |
||
117 | 2 | (`$contTable`.addressbookid = ?) AND |
|
118 | 2 | ( |
|
119 | 2 | SQL; |
|
120 | |||
121 | 2 | $params = array(); |
|
122 | 2 | $params[] = $this->addressBook->getMetaData()['id']; |
|
123 | 2 | foreach ($searchProperties as $property) { |
|
124 | 2 | $params[] = $property; |
|
125 | 2 | $params[] = '%' . $pattern . '%'; |
|
126 | 2 | $query .= '(`name` = ? AND `value` ILIKE ?) OR '; |
|
127 | 2 | } |
|
128 | 2 | $query = substr($query, 0, strlen($query) - 4); |
|
129 | 2 | $query .= ')'; |
|
130 | |||
131 | 2 | $stmt = \OCP\DB::prepare($query); |
|
132 | 2 | $result = $stmt->execute($params); |
|
133 | 2 | View Code Duplication | if (\OCP\DB::isError($result)) { |
134 | \OCP\Util::writeLog('contacts', __METHOD__ . 'DB error: ' . \OC_DB::getErrorMessage($result), |
||
135 | \OCP\Util::ERROR); |
||
136 | return false; |
||
137 | } |
||
138 | 2 | while ($row = $result->fetchRow()) { |
|
139 | 2 | $id = $row['contactid']; |
|
140 | 2 | $addressbookKey = $row['addressbookid']; |
|
141 | // Check if we are the owner of the contact |
||
142 | 2 | if ($row['userid'] !== \OC::$server->getUserSession()->getUser()->getUId()) { |
|
143 | // we aren't the owner of the contact |
||
144 | try { |
||
145 | // it is possible that the contact is shared with us |
||
146 | // if so, $contact will be an object |
||
147 | // if not getContact will throw an Exception |
||
148 | $contact = $this->app->getContact('shared', $addressbookKey, $id); |
||
149 | } catch (\Exception $e){ |
||
150 | // the contact isn't shared with us |
||
151 | $contact = null; |
||
152 | } |
||
153 | } else { |
||
154 | // We are the owner of the contact |
||
155 | // thus we can easily fetch it |
||
156 | 2 | $contact = $this->app->getContact('local', $addressbookKey, $id); |
|
157 | } |
||
158 | 2 | if ($contact !== null) { |
|
159 | 2 | $j = JSONSerializer::serializeContact($contact); |
|
160 | 2 | $j['data']['id'] = $id; |
|
161 | 2 | if (isset($contact->PHOTO)) { |
|
162 | $url = \OCP\Util::linkToRoute('contacts_contact_photo', |
||
163 | array( |
||
164 | 'backend' => $contact->getBackend()->name, |
||
165 | 'addressBookId' => $addressbookKey, |
||
166 | 'contactId' => $contact->getId() |
||
167 | )); |
||
168 | $url = \OC::$server->getURLGenerator()->getAbsoluteURL($url); |
||
169 | $j['data']['PHOTO'] = "VALUE=uri:$url"; |
||
170 | } |
||
171 | 2 | $results[] = $this->convertToSearchResult($j); |
|
172 | 2 | } |
|
173 | 2 | } |
|
174 | 2 | return $results; |
|
175 | } |
||
176 | |||
177 | /** |
||
178 | * @param $properties |
||
179 | * @return Contact|null |
||
180 | */ |
||
181 | public function createOrUpdate($properties) { |
||
182 | $addressBook = $this->getAddressbook(); |
||
183 | |||
184 | if(array_key_exists('id', $properties)) { |
||
185 | // we must "update" the contact by replacing the entire data set |
||
186 | $id = $properties['id']; |
||
187 | $contact = $this->addressBook->getChild($properties['id']); |
||
188 | foreach(array_keys($properties) as $name) { |
||
189 | if(isset($contact->{$name})) { |
||
190 | unset($contact->{$name}); |
||
191 | } |
||
192 | } |
||
193 | } else { |
||
194 | // the contact doesn't exist |
||
195 | // we must create a new one |
||
196 | try { |
||
197 | $id = $addressBook->addChild(); |
||
198 | } catch(\Exception $e) { |
||
199 | } |
||
200 | $contact = $addressBook->getChild($id); |
||
0 ignored issues
–
show
|
|||
201 | } |
||
202 | |||
203 | foreach($properties as $name => $value) { |
||
204 | $contact->setPropertyByName($name, $value); |
||
205 | } |
||
206 | $contact->save(); |
||
207 | return $contact; |
||
208 | } |
||
209 | |||
210 | /** |
||
211 | * @param $id |
||
212 | * @return mixed |
||
213 | */ |
||
214 | public function delete($id) { |
||
215 | try { |
||
216 | $query = 'SELECT COUNT(*) as `count` FROM `*PREFIX*contacts_cards` WHERE `id` = ? AND `addressbookid` = ?'; |
||
217 | $stmt = \OCP\DB::prepare($query); |
||
218 | $result = $stmt->execute(array($id, $this->id)); |
||
219 | View Code Duplication | if (\OCP\DB::isError($result)) { |
|
220 | \OCP\Util::writeLog('contacts', __METHOD__ . 'DB error: ' . \OC_DB::getErrorMessage($result), |
||
221 | \OCP\Util::ERROR); |
||
222 | return false; |
||
223 | } |
||
224 | if((int)$result['count'] === 0) { |
||
225 | \OCP\Util::writeLog('contacts', __METHOD__ |
||
226 | . 'Contact with id ' . $id . 'doesn\'t belong to addressbook with id ' . $this->id, |
||
227 | \OCP\Util::ERROR); |
||
228 | return false; |
||
229 | } |
||
230 | } catch(\Exception $e) { |
||
231 | \OCP\Util::writeLog('contacts', __METHOD__ . ', exception: ' . $e->getMessage(), |
||
232 | \OCP\Util::ERROR); |
||
233 | return false; |
||
234 | } |
||
235 | return VCard::delete($id); |
||
0 ignored issues
–
show
It seems like you code against a specific sub-type and not the parent class
OCA\Contacts\VObject\VCard as the method delete() does only exist in the following sub-classes of OCA\Contacts\VObject\VCard : OCA\Contacts\Contact . Maybe you want to instanceof check for one of these explicitly?
Let’s take a look at an example: abstract class User
{
/** @return string */
abstract public function getPassword();
}
class MyUser extends User
{
public function getPassword()
{
// return something
}
public function getDisplayName()
{
// return some name.
}
}
class AuthSystem
{
public function authenticate(User $user)
{
$this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
// do something.
}
}
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break. Available Fixes
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types
inside the if block in such a case.
![]() |
|||
236 | } |
||
237 | |||
238 | /** |
||
239 | * @param $j |
||
240 | * @return array |
||
241 | */ |
||
242 | 2 | private function convertToSearchResult($j) { |
|
243 | 2 | $data = $j['data']; |
|
244 | 2 | $result = array(); |
|
245 | 2 | foreach( $data as $key => $d) { |
|
246 | 2 | $d = $data[$key]; |
|
247 | 2 | if (in_array($key, Properties::$multiProperties)) { |
|
248 | $result[$key] = array_map(function($v){ |
||
249 | return $v['value']; |
||
250 | }, $d); |
||
251 | } else { |
||
252 | 2 | if (is_array($d)) { |
|
253 | 2 | $result[$key] = $d[0]['value']; |
|
254 | 2 | } else { |
|
255 | 2 | $result[$key] = $d; |
|
256 | } |
||
257 | } |
||
258 | 2 | } |
|
259 | |||
260 | 2 | return $result; |
|
261 | } |
||
262 | |||
263 | } |
||
264 |
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.