Friendica Communications Platform (please note that this is a clone of the repository at github, issues are handled there) https://friendi.ca
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

489 lines
14 KiB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
  1. <?php
  2. if(! function_exists('dfrn_request_init')) {
  3. function dfrn_request_init(&$a) {
  4. if($a->argc > 1)
  5. $which = $a->argv[1];
  6. require_once('mod/profile.php');
  7. profile_init($a,$which);
  8. return;
  9. }}
  10. if(! function_exists('dfrn_request_post')) {
  11. function dfrn_request_post(&$a) {
  12. if(($a->argc != 2) || (! count($a->profile)))
  13. return;
  14. if($_POST['cancel']) {
  15. goaway($a->get_baseurl());
  16. }
  17. // We've introduced ourself to another cell, then have been returned to our own cell
  18. // to confirm the request, and then we've clicked submit (perhaps after logging in).
  19. // That brings us here:
  20. if((x($_POST,'localconfirm')) && ($_POST['localconfirm'] == 1)) {
  21. // Ensure this is a valid request
  22. if(local_user() && ($a->user['nickname'] == $a->argv[1]) && (x($_POST,'dfrn_url'))) {
  23. $dfrn_url = notags(trim($_POST['dfrn_url']));
  24. $aes_allow = (((x($_POST,'aes_allow')) && ($_POST['aes_allow'] == 1)) ? 1 : 0);
  25. $confirm_key = ((x($_POST,'confirm_key')) ? $_POST['confirm_key'] : "");
  26. $contact_record = null;
  27. if(x($dfrn_url)) {
  28. $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `url` = '%s' AND `self` = 0 LIMIT 1",
  29. intval(local_user()),
  30. dbesc($dfrn_url)
  31. );
  32. if(count($r)) {
  33. if(strlen($r[0]['dfrn-id'])) {
  34. notice( t("This introduction has already been accepted.") . EOL );
  35. return;
  36. }
  37. else
  38. $contact_record = $r[0];
  39. }
  40. if(is_array($contact_record)) {
  41. $r = q("UPDATE `contact` SET `ret-aes` = %d WHERE `id` = %d LIMIT 1",
  42. intval($aes_allow),
  43. intval($contact_record['id'])
  44. );
  45. }
  46. else {
  47. require_once('Scrape.php');
  48. $parms = scrape_dfrn($dfrn_url);
  49. if(! count($parms)) {
  50. notice( t('Profile location is not valid or does not contain profile information.') . EOL );
  51. return;
  52. }
  53. else {
  54. if(! x($parms,'fn'))
  55. notice( t('Warning: profile location has no identifiable owner name.') . EOL );
  56. if(! x($parms,'photo'))
  57. notice( t('Warning: profile location has no profile photo.') . EOL );
  58. $invalid = validate_dfrn($parms);
  59. if($invalid) {
  60. notice( $invalid . t(' required parameter')
  61. . (($invalid == 1) ? t(" was ") : t("s were ") )
  62. . t("not found at the given location.") . EOL ) ;
  63. return;
  64. }
  65. }
  66. $dfrn_request = $parms['dfrn-request'];
  67. dbesc_array($parms);
  68. $r = q("INSERT INTO `contact` ( `uid`, `created`,`url`, `name`, `nick`, `photo`, `site-pubkey`,
  69. `request`, `confirm`, `notify`, `poll`, `aes_allow`)
  70. VALUES ( %d, '%s', '%s', '%s' , '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d)",
  71. intval(local_user()),
  72. datetime_convert(),
  73. dbesc($dfrn_url),
  74. $parms['fn'],
  75. $parms['nick'],
  76. $parms['photo'],
  77. $parms['key'],
  78. $parms['dfrn-request'],
  79. $parms['dfrn-confirm'],
  80. $parms['dfrn-notify'],
  81. $parms['dfrn-poll'],
  82. intval($aes_allow)
  83. );
  84. }
  85. if($r) {
  86. notice( t("Introduction complete.") . EOL);
  87. }
  88. // Allow the blocked remote notification to complete
  89. if(is_array($contact_record))
  90. $dfrn_request = $contact_record['request'];
  91. if(strlen($dfrn_request) && strlen($confirm_key))
  92. $s = fetch_url($dfrn_request . '?confirm_key=' . $confirm_key);
  93. // ignore reply
  94. goaway($dfrn_url);
  95. return; // NOTREACHED
  96. }
  97. }
  98. // invalid/bogus request
  99. notice( t('Unrecoverable protocol error.') . EOL );
  100. goaway($a->get_baseurl());
  101. return; // NOTREACHED
  102. }
  103. // Otherwise:
  104. // We are the requestee. A person from a remote cell has made an introduction
  105. // on our profile web page and clicked submit. We will use their DFRN-URL to
  106. // figure out how to contact their cell.
  107. // Scrape the originating DFRN-URL for everything we need. Create a contact record
  108. // and an introduction to show our user next time he/she logs in.
  109. // Finally redirect back to the requestor so that their site can record the request.
  110. // If our user (the requestee) later confirms this request, a record of it will need
  111. // to exist on the requestor's cell in order for the confirmation process to complete..
  112. // It's possible that neither the requestor or the requestee are logged in at the moment,
  113. // and the requestor does not yet have any credentials to the requestee profile.
  114. // Who is the requestee? We've already loaded their profile which means their nickname should be
  115. // in $a->argv[1] and we should have their complete info in $a->profile.
  116. if(! (is_array($a->profile) && count($a->profile))) {
  117. notice( t('Profile unavailable.') . EOL);
  118. return;
  119. }
  120. $nickname = $a->profile['nickname'];
  121. $notify_flags = $a->profile['notify-flags'];
  122. $uid = $a->profile['uid'];
  123. $contact_record = null;
  124. $failed = false;
  125. $parms = null;
  126. if( x($_POST,'dfrn_url')) {
  127. $url = trim($_POST['dfrn_url']);
  128. if(! strlen($url)) {
  129. notice( t("Invalid locator") . EOL );
  130. return;
  131. }
  132. // Canonicalise email-style profile locator
  133. $url = webfinger_dfrn($url);
  134. if(substr($url,0,5) === 'stat:') {
  135. $network = 'stat';
  136. $url = substr($url,5);
  137. }
  138. else {
  139. $network = 'dfrn';
  140. }
  141. if(! strlen($url)) {
  142. notice( t("Unable to resolve your name at the provided location.") . EOL);
  143. return;
  144. }
  145. if($network === 'dfrn') {
  146. $ret = q("SELECT * FROM `contact` WHERE `uid` = %d AND `url` = '%s' AND `self` = 0 LIMIT 1",
  147. intval($uid),
  148. dbesc($url)
  149. );
  150. if(count($ret)) {
  151. if(strlen($ret[0]['issued-id'])) {
  152. notice( t('You have already introduced yourself here.') . EOL );
  153. return;
  154. }
  155. elseif($ret[0]['rel'] == REL_BUD) {
  156. notice( t('Apparently you are already friends with .') . $a->profile['name'] . EOL);
  157. return;
  158. }
  159. else {
  160. $contact_record = $ret[0];
  161. $parms = array('dfrn-request' => $ret[0]['request']);
  162. }
  163. }
  164. $issued_id = random_string();
  165. if(is_array($contact_record)) {
  166. // There is a contact record but no issued-id, so this
  167. // is a reciprocal introduction from a known contact
  168. $r = q("UPDATE `contact` SET `issued-id` = '%s' WHERE `id` = %d LIMIT 1",
  169. dbesc($issued_id),
  170. intval($contact_record['id'])
  171. );
  172. }
  173. else {
  174. if(! validate_url($url)) {
  175. notice( t('Invalid profile URL.') . EOL);
  176. goaway($a->get_baseurl() . '/' . $a->cmd);
  177. return; // NOTREACHED
  178. }
  179. if(! allowed_url($url)) {
  180. notice( t('Disallowed profile URL.') . EOL);
  181. goaway($a->get_baseurl() . '/' . $a->cmd);
  182. return; // NOTREACHED
  183. }
  184. require_once('Scrape.php');
  185. $parms = scrape_dfrn($url);
  186. if(! count($parms)) {
  187. notice( t('Profile location is not valid or does not contain profile information.') . EOL );
  188. goaway($a->get_baseurl() . '/' . $a->cmd);
  189. }
  190. else {
  191. if(! x($parms,'fn'))
  192. notice( t('Warning: profile location has no identifiable owner name.') . EOL );
  193. if(! x($parms,'photo'))
  194. notice( t('Warning: profile location has no profile photo.') . EOL );
  195. $invalid = validate_dfrn($parms);
  196. if($invalid) {
  197. notice( $invalid . t(' required parameter')
  198. . (($invalid == 1) ? t(" was ") : t("s were ") )
  199. . t("not found at the given location.") . EOL ) ;
  200. return;
  201. }
  202. }
  203. $parms['url'] = $url;
  204. $parms['issued-id'] = $issued_id;
  205. dbesc_array($parms);
  206. $r = q("INSERT INTO `contact` ( `uid`, `created`, `url`, `name`, `nick`, `issued-id`, `photo`, `site-pubkey`,
  207. `request`, `confirm`, `notify`, `poll` )
  208. VALUES ( %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' )",
  209. intval($uid),
  210. datetime_convert(),
  211. $parms['url'],
  212. $parms['fn'],
  213. $parms['nick'],
  214. $parms['issued-id'],
  215. $parms['photo'],
  216. $parms['key'],
  217. $parms['dfrn-request'],
  218. $parms['dfrn-confirm'],
  219. $parms['dfrn-notify'],
  220. $parms['dfrn-poll']
  221. );
  222. // find the contact record we just created
  223. if($r) {
  224. $r = q("SELECT `id` FROM `contact`
  225. WHERE `uid` = %d AND `url` = '%s' AND `issued-id` = '%s' LIMIT 1",
  226. intval($uid),
  227. $parms['url'],
  228. $parms['issued-id']
  229. );
  230. if(count($r))
  231. $contact_record = $r[0];
  232. }
  233. }
  234. if($r === false) {
  235. notice( t('Failed to update contact record.') . EOL );
  236. return;
  237. }
  238. $hash = random_string() . (string) time(); // Generate a confirm_key
  239. if(is_array($contact_record)) {
  240. $ret = q("INSERT INTO `intro` ( `uid`, `contact-id`, `blocked`, `knowyou`, `note`, `hash`, `datetime`)
  241. VALUES ( %d, %d, 1, %d, '%s', '%s', '%s' )",
  242. intval($uid),
  243. intval($contact_record['id']),
  244. ((x($_POST,'knowyou') && ($_POST['knowyou'] == 1)) ? 1 : 0),
  245. dbesc(notags(trim($_POST['dfrn-request-message']))),
  246. dbesc($hash),
  247. dbesc(datetime_convert())
  248. );
  249. }
  250. // This notice will only be seen by the requestor if the requestor and requestee are on the same server.
  251. if(! $failed)
  252. notice( t('Your introduction has been sent.') . EOL );
  253. // "Homecoming" - send the requestor back to their site to record the introduction.
  254. $dfrn_url = bin2hex($a->get_baseurl() . '/profile/' . $nickname);
  255. $aes_allow = ((function_exists('openssl_encrypt')) ? 1 : 0);
  256. goaway($parms['dfrn-request'] . "?dfrn_url=$dfrn_url"
  257. . '&dfrn_version=' . DFRN_PROTOCOL_VERSION
  258. . '&confirm_key=' . $hash
  259. . (($aes_allow) ? "&aes_allow=1" : "")
  260. );
  261. // NOTREACHED
  262. // END $network === 'dfrn'
  263. }
  264. elseif($network === 'stat') {
  265. /**
  266. *
  267. * OStatus network
  268. * Check contact existence
  269. * Try and scrape together enough information to create a contact record, with us as REL_VIP
  270. * Substitute our user's feed URL into $url template
  271. * Send the subscriber home to subscribe
  272. *
  273. **/
  274. $url = str_replace('{uri}', $a->get_baseurl() . '/dfrn_poll/' . $nickname, $url);
  275. goaway($url);
  276. // NOTREACHED
  277. // END $network === 'stat'
  278. }
  279. } return;
  280. }}
  281. if(! function_exists('dfrn_request_content')) {
  282. function dfrn_request_content(&$a) {
  283. if(($a->argc != 2) || (! count($a->profile)))
  284. return "";
  285. $a->page['template'] = 'profile';
  286. // "Homecoming". Make sure we're logged in to this site as the correct user. Then offer a confirm button
  287. // to send us to the post section to record the introduction.
  288. if(x($_GET,'dfrn_url')) {
  289. if(! local_user()) {
  290. notice( t("Please login to confirm introduction.") . EOL );
  291. return login();
  292. }
  293. // Edge case, but can easily happen in the wild. This person is authenticated,
  294. // but not as the person who needs to deal with this request.
  295. if ($a->user['nickname'] != $a->argv[1]) {
  296. notice( t("Incorrect identity currently logged in. Please login to <strong>this</strong> profile.") . EOL);
  297. return login();
  298. }
  299. $dfrn_url = notags(trim(hex2bin($_GET['dfrn_url'])));
  300. $aes_allow = (((x($_GET,'aes_allow')) && ($_GET['aes_allow'] == 1)) ? 1 : 0);
  301. $confirm_key = (x($_GET,'confirm_key') ? $_GET['confirm_key'] : "");
  302. $o .= load_view_file("view/dfrn_req_confirm.tpl");
  303. $o = replace_macros($o,array(
  304. '$dfrn_url' => $dfrn_url,
  305. '$aes_allow' => (($aes_allow) ? '<input type="hidden" name="aes_allow" value="1" />' : "" ),
  306. '$confirm_key' => $confirm_key,
  307. '$username' => $a->user['username'],
  308. '$uid' => $_SESSION['uid'],
  309. '$nickname' => $a->user['nickname'],
  310. 'dfrn_rawurl' => $_GET['dfrn_url']
  311. ));
  312. return $o;
  313. }
  314. elseif((x($_GET,'confirm_key')) && strlen($_GET['confirm_key'])) {
  315. // we are the requestee and it is now safe to send our user their introduction,
  316. // We could just unblock it, but first we have to jump through a few hoops to
  317. // send an email, or even to find out if we need to send an email.
  318. $intro = q("SELECT * FROM `intro` WHERE `hash` = '%s' LIMIT 1",
  319. dbesc($_GET['confirm_key'])
  320. );
  321. if(count($intro)) {
  322. $r = q("SELECT `contact`.*, `user`.* FROM `contact` LEFT JOIN `user` ON `contact`.`uid` = `user`.`uid`
  323. WHERE `contact`.`id` = %d LIMIT 1",
  324. intval($intro[0]['contact-id'])
  325. );
  326. $auto_confirm = false;
  327. if(count($r)) {
  328. if($r[0]['page-flags'] != PAGE_NORMAL)
  329. $auto_confirm = true;
  330. if(($r[0]['notify-flags'] & NOTIFY_INTRO) && (! $auto_confirm)) {
  331. $email_tpl = load_view_file('view/request_notify_eml.tpl');
  332. $email = replace_macros($email_tpl, array(
  333. '$requestor' => ((strlen(stripslashes($r[0]['name']))) ? stripslashes($r[0]['name']) : t('[Name Withheld]')),
  334. '$url' => stripslashes($r[0]['url']),
  335. '$myname' => $r[0]['username'],
  336. '$siteurl' => $a->get_baseurl(),
  337. '$sitename' => $a->config['sitename']
  338. ));
  339. $res = mail($r[0]['email'],
  340. t("Introduction received at ") . $a->config['sitename'],
  341. $email,
  342. 'From: ' . t('Administrator') . '@' . $_SERVER[SERVER_NAME] );
  343. // This is a redundant notification - no point throwing errors if it fails.
  344. }
  345. if($auto_confirm) {
  346. require_once('mod/dfrn_confirm.php');
  347. $handsfree = array(
  348. 'uid' => $r[0]['uid'],
  349. 'node' => $r[0]['nickname'],
  350. 'dfrn_id' => $r[0]['issued-id'],
  351. 'intro_id' => $intro[0]['id'],
  352. 'duplex' => (($r[0]['page-flags'] == PAGE_FREELOVE) ? 1 : 0)
  353. );
  354. dfrn_confirm_post($a,$handsfree);
  355. }
  356. }
  357. if(! $auto_confirm) {
  358. // If we are auto_confirming, this record will have already been nuked
  359. // in dfrn_confirm_post()
  360. $r = q("UPDATE `intro` SET `blocked` = 0 WHERE `hash` = '%s' LIMIT 1",
  361. dbesc($_GET['confirm_key'])
  362. );
  363. }
  364. }
  365. killme();
  366. return; // NOTREACHED
  367. }
  368. else {
  369. $myaddr = ((x($_GET,'address')) ? urldecode($_GET['address']) : '');
  370. // Normal web request. Display our user's introduction form.
  371. if($a->profile['page-flags'] == PAGE_NORMAL)
  372. $tpl = load_view_file('view/dfrn_request.tpl');
  373. else
  374. $tpl = load_view_file('view/auto_request.tpl');
  375. $o .= replace_macros($tpl,array(
  376. '$nickname' => $a->argv[1],
  377. '$name' => $a->profile['name'],
  378. '$myaddr' => $myaddr
  379. ));
  380. return $o;
  381. }
  382. return; // Somebody is fishing.
  383. }}