]> git.mxchange.org Git - friendica.git/blob - mod/dfrn_confirm.php
make it much easier to debug friend acceptance issues
[friendica.git] / mod / dfrn_confirm.php
1 <?php
2
3
4
5 function dfrn_confirm_post(&$a) {
6
7         if($a->argc > 1)
8                 $node = $a->argv[1];
9
10         if(x($_POST,'source_url')) {
11
12                 // We are processing an external confirmation to an introduction created by our user.
13
14                 $public_key = $_POST['public_key'];
15                 $dfrn_id    = $_POST['dfrn_id'];
16                 $source_url = $_POST['source_url'];
17                 $aes_key    = $_POST['aes_key'];
18                 $duplex     = $_POST['duplex'];
19                 $version_id = $_POST['dfrn_version'];
20
21                 // Find our user's account
22
23                 $r = q("SELECT * FROM `user` WHERE `nickname` = '%s' LIMIT 1",
24                         dbesc($node));
25
26                 if(! count($r)) {
27                         $message = t('No user record found for ') . '\'' . $node . '\'';
28                         xml_status(3,$message); // failure
29                         // NOTREACHED
30                 }
31
32                 $my_prvkey = $r[0]['prvkey'];
33                 $local_uid = $r[0]['uid'];
34
35                 // verify everything
36
37                 $decrypted_source_url = "";
38                 openssl_private_decrypt($source_url,$decrypted_source_url,$my_prvkey);
39
40
41                 if(! strlen($decrypted_source_url)) {
42                         $message = t('empty site URL was provided.');
43                         xml_status(3,$message);
44                         // NOTREACHED
45                 }
46
47                 $ret = q("SELECT * FROM `contact` WHERE `url` = '%s' AND `uid` = %d LIMIT 1",
48                         dbesc($decrypted_source_url),
49                         intval($local_uid)
50                 );
51
52                 if(! count($ret)) {
53                         // this is either a bogus confirmation (?) or we deleted the original introduction.
54                         $message = t('Contact record was not found for you on our site.');
55                         xml_status(3,$message);
56                         return; // NOTREACHED 
57                 }
58
59                 $relation = $ret[0]['rel'];
60
61                 // Decrypt all this stuff we just received
62
63                 $foreign_pubkey = $ret[0]['site-pubkey'];
64                 $dfrn_record    = $ret[0]['id'];
65
66                 $decrypted_dfrn_id = "";
67                 openssl_public_decrypt($dfrn_id,$decrypted_dfrn_id,$foreign_pubkey);
68
69                 if(strlen($aes_key)) {
70                         $decrypted_aes_key = "";
71                         openssl_private_decrypt($aes_key,$decrypted_aes_key,$my_prvkey);
72                         $dfrn_pubkey = openssl_decrypt($public_key,'AES-256-CBC',$decrypted_aes_key);
73                 }
74                 else {
75                         $dfrn_pubkey = $public_key;
76                 }
77
78                 $r = q("SELECT * FROM `contact` WHERE `dfrn-id` = '%s' LIMIT 1",
79                         dbesc($decrypted_dfrn_id),
80                         intval($local_uid)
81                 );
82                 if(count($r)) {
83                         $message = t('The ID provided is a duplicate on our system. Please try again.');
84                         xml_status(1,$message); // Birthday paradox - duplicate dfrn-id
85                         // NOTREACHED
86                 }
87
88                 $r = q("UPDATE `contact` SET `dfrn-id` = '%s', `pubkey` = '%s' WHERE `id` = %d LIMIT 1",
89                         dbesc($decrypted_dfrn_id),
90                         dbesc($dfrn_pubkey),
91                         intval($dfrn_record)
92                 );
93                 if(! count($r)) {
94                         $message = t('Unable to set your credentials on our system.');
95                         xml_status(3,$message);
96                 }
97
98                 // We're good but now we have to scrape the profile photo and send notifications.
99
100                 require_once("Photo.php");
101
102                 $photo_failure = false;
103
104                 $r = q("SELECT `photo` FROM `contact` WHERE `id` = %d LIMIT 1",
105                         intval($dfrn_record));
106                 if(count($r)) {
107
108                         $filename = basename($r[0]['photo']);
109                         $img_str = fetch_url($r[0]['photo'],true);
110                         $img = new Photo($img_str);
111                         if($img->is_valid()) {
112
113                                 $img->scaleImageSquare(175);
114                                         
115                                 $hash = photo_new_resource();
116
117                                 $r = $img->store($local_uid, $dfrn_record, $hash, $filename, t('Contact Photos') , 4);
118
119                                 if($r === false)
120                                         $photo_failure = true;
121                                         
122                                 $img->scaleImage(80);
123                                 $r = $img->store($local_uid, $dfrn_record, $hash, $filename, t('Contact Photos') , 5);
124
125                                 if($r === false)
126                                         $photo_failure = true;
127
128                                 $photo = $a->get_baseurl() . '/photo/' . $hash . '-4.jpg';
129                                 $thumb = $a->get_baseurl() . '/photo/' . $hash . '-5.jpg';      
130                         }
131                         else
132                                 $photo_failure = true;
133                 }
134                 else
135                         $photo_failure = true;
136
137                 if($photo_failure) {
138                         $photo = $a->get_baseurl() . '/images/default-profile.jpg';
139                         $thumb = $a->get_baseurl() . '/images/default-profile-sm.jpg';
140                 }
141
142                 $new_relation = REL_FAN;
143                 if(($relation == REL_VIP) || ($duplex))
144                         $new_relation = REL_BUD;
145
146                 $r = q("UPDATE `contact` SET 
147                         `photo` = '%s', 
148                         `thumb` = '%s', 
149                         `rel` = %d, 
150                         `name-date` = '%s', 
151                         `uri-date` = '%s', 
152                         `avatar-date` = '%s', 
153                         `blocked` = 0, 
154                         `pending` = 0,
155                         `duplex` = %d, 
156                         `network` = 'dfrn' WHERE `id` = %d LIMIT 1
157                 ",
158                         dbesc($photo),
159                         dbesc($thumb),
160                         intval($new_relation),
161                         dbesc(datetime_convert()),
162                         dbesc(datetime_convert()),
163                         dbesc(datetime_convert()),
164                         intval($duplex),
165                         intval($dfrn_record)
166                 );
167                 if($r === false) { // should not happen unless schema is messed up
168                         $message = t('Unable to update your contact profile on our system');
169                         xml_status(3,$message);
170                 }
171
172                 // Otherwise everything seems to have worked and we are almost done. Yay!
173                 // Send an email notification
174
175                 $r = q("SELECT * FROM `contact` LEFT JOIN `user` ON `contact`.`uid` = `user`.`uid`
176                         WHERE `contact`.`id` = %d LIMIT 1",
177                         intval($dfrn_record)
178                 );
179                 if((count($r)) && ($r[0]['notify-flags'] & NOTIFY_CONFIRM)) {
180
181                         $tpl = (($new_relation == REL_BUD) 
182                                 ? load_view_file('view/friend_complete_eml.tpl')
183                                 : load_view_file('view/intro_complete_eml.tpl'));
184                 
185                         $email_tpl = replace_macros($tpl, array(
186                                 '$sitename' => $a->config['sitename'],
187                                 '$siteurl' =>  $a->get_baseurl(),
188                                 '$username' => $r[0]['username'],
189                                 '$email' => $r[0]['email'],
190                                 '$fn' => $r[0]['name'],
191                                 '$dfrn_url' => $r[0]['url'],
192                                 '$uid' => $newuid )
193                         );
194         
195                         $res = mail($r[0]['email'], t("Connection accepted at ") . $a->config['sitename'],
196                                 $email_tpl, 'From: ' . t('Administrator') . '@' . $_SERVER[SERVER_NAME] );
197                         if(!$res) {
198                                 notice( t("Email notification failed.") . EOL );
199                         }
200                 }
201                 xml_status(0); // Success
202                 return; // NOTREACHED
203
204         ////////////////////// End of this scenario ///////////////////////////////////////////////
205         }
206         else {
207
208                 // We are processing a local confirmation initiated on this system by our user to an external introduction.
209
210                 $uid = get_uid();
211
212                 if(! $uid) {
213                         notice( t('Permission denied.') . EOL );
214                         return;
215                 }       
216         
217                 $dfrn_id  = ((x($_POST,'dfrn_id')) ? notags(trim($_POST['dfrn_id'])) : "");
218                 $intro_id = intval($_POST['intro_id']);
219                 $duplex   = intval($_POST['duplex']);
220
221                 $r = q("SELECT * FROM `contact` WHERE `issued-id` = '%s' AND `uid` = %d LIMIT 1",
222                                 dbesc($dfrn_id),
223                                 intval($uid)
224                 );
225
226                 if(! count($r)) {
227                         notice( t('Node does not exist.') . EOL );
228                         return;
229                 }
230
231                 $contact_id   = $r[0]['id'];
232                 $relation     = $r[0]['rel'];
233                 $site_pubkey  = $r[0]['site-pubkey'];
234                 $dfrn_confirm = $r[0]['confirm'];
235                 $aes_allow    = $r[0]['aes_allow'];
236
237                 $res = openssl_pkey_new(array(
238                         'digest_alg' => 'whirlpool',
239                         'private_key_bits' => 4096,
240                         'encrypt_key' => false )
241                 );
242
243
244                 $private_key = '';
245
246                 openssl_pkey_export($res, $private_key);
247
248                 $pubkey = openssl_pkey_get_details($res);
249                 $public_key = $pubkey["key"];
250
251                 $r = q("UPDATE `contact` SET `prvkey` = '%s' WHERE `id` = %d AND `uid` = %d LIMIT 1",
252                         dbesc($private_key),
253                         intval($contact_id),
254                         intval($uid) 
255                 );
256
257
258                 $params = array();
259
260                 $src_aes_key = random_string();
261
262                 $result = '';
263                 openssl_private_encrypt($dfrn_id,$result,$a->user['prvkey']);
264
265                 $params['dfrn_id'] = $result;
266                 $params['public_key'] = $public_key;
267
268
269                 $my_url = $a->get_baseurl() . '/profile/' . $a->user['nickname'];
270
271                 openssl_public_encrypt($my_url, $params['source_url'], $site_pubkey);
272
273                 if($aes_allow && function_exists('openssl_encrypt')) {
274                         openssl_public_encrypt($src_aes_key, $params['aes_key'], $site_pubkey);
275                         $params['public_key'] = openssl_encrypt($public_key,'AES-256-CBC',$src_aes_key);
276                 }
277
278                 $params['dfrn_version'] = '2.0';
279                 if($duplex == 1)
280                         $params['duplex'] = 1;
281
282                 $res = post_url($dfrn_confirm,$params);
283
284                 // Try to be robust if the remote site is having difficulty and throwing up
285                 // errors of some kind. 
286
287                 $leading_junk = substr($res,0,strpos($res,'<?xml'));
288
289                 $res = substr($res,strpos($res,'<?xml'));
290                 if(! strlen($res)) {
291
292                                 // No XML at all, this exchange is messed up really bad.
293                                 // We shouldn't proceed, because the xml parser might choke,
294                                 // and $status is going to be zero, which indicates success.
295                                 // We can hardly call this a success.  
296
297                         notice( t('Response from remote site was not understood.') . EOL);
298                         return;
299                 }
300
301                 if(strlen($leading_junk) && get_config('system','debugging')) {
302
303                                 // This might be more common. Mixed error text and some XML.
304                                 // If we're configured for debugging, show the text. Proceed in either case.
305
306                         notice( t('Unexpected response from remote site: ') . EOL . $leading_junk . EOL );
307                 }
308
309                 $xml = simplexml_load_string($res);
310                 $status = (int) $xml->status;
311                 $message = unxmlify($xml->message);
312                 switch($status) {
313                         case 0:
314                                 notice( t("Confirmation completed successfully.") . EOL);
315                                 if(strlen($message))
316                                         notice( t('Remote site reported: ') . $message . EOL);
317                                 break;
318                         case 1:
319                                 // birthday paradox - generate new dfrn-id and fall through.
320                                 $new_dfrn_id = random_string();
321                                 $r = q("UPDATE contact SET `issued-id` = '%s' WHERE `id` = %d AND `uid` = %d LIMIT 1",
322                                         dbesc($new_dfrn_id),
323                                         intval($contact_id),
324                                         intval($uid) 
325                                 );
326
327                         case 2:
328                                 notice( t("Temporary failure. Please wait and try again.") . EOL);
329                                 if(strlen($message))
330                                         notice( t('Remote site reported: ') . $message . EOL);
331                                 break;
332
333
334                         case 3:
335                                 notice( t("Introduction failed or was revoked.") . EOL);
336                                 if(strlen($message))
337                                         notice( t('Remote site reported: ') . $message . EOL);
338                                 break;
339                         }
340
341                 if(($status == 0) && ($intro_id)) {
342
343                         //delete the notification
344
345                         $r = q("DELETE FROM `intro` WHERE `id` = %d AND `uid` = %d LIMIT 1",
346                                 intval($intro_id),
347                                 intval($uid)
348                         );
349                         
350                 }
351
352                 if($status != 0) 
353                         return;
354                 
355                 require_once("Photo.php");
356
357                 $photo_failure = false;
358
359                 $r = q("SELECT `photo` FROM `contact` WHERE `id` = %d LIMIT 1",
360                         intval($contact_id));
361                 if(count($r)) {
362
363                         $filename = basename($r[0]['photo']);
364                         $img_str = fetch_url($r[0]['photo'],true);
365                         $img = new Photo($img_str);
366                         if($img->is_valid()) {
367
368                                 $img->scaleImageSquare(175);
369                                         
370                                 $hash = photo_new_resource();
371
372                                 $r = $img->store($uid, $contact_id, $hash, $filename, t('Contact Photos'), 4 );
373
374                                 if($r === false)
375                                         $photo_failure = true;
376
377                                 $img->scaleImage(80);
378
379                                 $r = $img->store($uid, $contact_id, $hash, $filename, t('Contact Photos'), 5 );
380
381                                 if($r === false)
382                                         $photo_failure = true;
383
384                                 $photo = $a->get_baseurl() . '/photo/' . $hash . '-4.jpg';
385                                 $thumb = $a->get_baseurl() . '/photo/' . $hash . '-5.jpg';
386                         }
387                         else
388                                 $photo_failure = true;
389                 }
390                 else
391                         $photo_failure = true;
392
393                 if($photo_failure) {
394                         $photo = $a->get_baseurl() . '/images/default-profile.jpg';
395                         $thumb = $a->get_baseurl() . '/images/default-profile-sm.jpg';
396                 }
397
398                 $new_relation = REL_VIP;
399                 if(($relation == REL_FAN) || ($duplex))
400                         $new_relation = REL_BUD;
401
402                 $r = q("UPDATE `contact` SET `photo` = '%s', 
403                         `thumb` = '%s', 
404                         `rel` = %d, 
405                         `name-date` = '%s', 
406                         `uri-date` = '%s', 
407                         `avatar-date` = '%s', 
408                         `blocked` = 0, 
409                         `pending` = 0,
410                         `duplex` = %d,
411                         `network` = 'dfrn' WHERE `id` = %d LIMIT 1
412                 ",
413                         dbesc($photo),
414                         dbesc($thumb),
415                         intval($new_relation),
416                         dbesc(datetime_convert()),
417                         dbesc(datetime_convert()),
418                         dbesc(datetime_convert()),
419                         intval($duplex),
420                         intval($contact_id)
421                 );
422                 if($r === false)
423                         notice( t('Unable to set contact photo.') . EOL);
424
425                 goaway($a->get_baseurl() . '/contacts/' . intval($contact_id));
426                 return;  //NOTREACHED
427         }
428         return;
429 }