PluginProbe
WebFinger / 2.0.0
WebFinger v2.0.0
4.1.0 trunk 0.5 0.7 0.9 0.9.1 1.0 1.0.1 1.1 1.2 1.3 1.3.1 2.0.0 2.0.1 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 All 36 releases
webfinger / plugin.php

plugin.php in WebFinger 2.0.0, at plugin.php

406 lines 11.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: Webfinger
4 Plugin URI: http://wordpress.org/extend/plugins/webfinger/
5 Description: Webfinger for WordPress
6 Version: 2.0.0
7 Author: pfefferle
8 Author URI: http://notizblog.org/
9 */
10
11 /**
12 * webfinger
13 *
14 * @author Matthias Pfefferle
15 */
16 class WebfingerPlugin {
17
18 /**
19 * adds some query vars
20 *
21 * @param array $vars
22 * @return array
23 */
24 public function query_vars($vars) {
25 $vars[] = 'webfinger-uri';
26 $vars[] = 'well-known';
27 $vars[] = 'format';
28 $vars[] = 'resource';
29 $vars[] = 'rel';
30
31 return $vars;
32 }
33
34 /**
35 * Add rewrite rules
36 *
37 * @param WP_Rewrite
38 */
39 function rewrite_rules( $wp_rewrite ) {
40 $webfinger_rules = array(
41 '.well-known/webfinger' => 'index.php?well-known=webfinger'
42 );
43
44 $wp_rewrite->rules = $webfinger_rules + $wp_rewrite->rules;
45 }
46
47 /**
48 * renders the output-file
49 *
50 * @param array
51 */
52 public function parse_request($wp) {
53 // check if "resource" param exists
54 if (!array_key_exists('resource', $wp->query_vars)) {
55 return;
56 }
57
58 // find matching user
59 $user = WebfingerPlugin::get_user_by_uri($wp->query_vars['resource']);
60
61 if (!$user) {
62 return;
63 }
64
65 $format = 'json';
66 if (array_key_exists('format', $wp->query_vars)) {
67 $format = $wp->query_vars['format'];
68 }
69
70 $webfinger = apply_filters('webfinger', array(), $user, $wp->query_vars['resource'], $wp->query_vars);
71
72 do_action("webfinger_render", $format, $webfinger, $user, $wp->query_vars);
73 do_action("webfinger_render_{$format}", $webfinger, $user, $wp->query_vars);
74 }
75
76 /**
77 * renders the webfinger file in json
78 */
79 public function render_jrd($webfinger) {
80 header("Access-Control-Allow-Origin: *");
81 header('Content-Type: application/jrd+json; charset=' . get_bloginfo('charset'), true);
82
83 echo json_encode($webfinger);
84 exit();
85 }
86
87 /**
88 * renders the webfinger file in xml
89 */
90 public function render_xrd($webfinger, $user) {
91 header("Access-Control-Allow-Origin: *");
92 header('Content-Type: application/xrd+xml; charset=' . get_bloginfo('charset'), true);
93
94 echo "<?xml version='1.0' encoding='".get_bloginfo('charset')."'?>\n";
95 echo "<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'\n";
96 // add xml-only namespaces
97 do_action('webfinger_ns');
98 echo ">\n";
99
100 echo WebfingerPlugin::jrd_to_xrd($webfinger);
101 // add xml-only content
102 do_action('webfinger_xrd', $user);
103
104 echo "\n</XRD>";
105 exit;
106 }
107
108 /**
109 * generates the webfinger base array
110 */
111 public function generate_default_content($webfinger, $user, $resource) {
112 $url = get_author_posts_url($user->ID, $user->user_nicename);
113 $photo = get_user_meta($user->ID, 'photo', true);
114 if(!$photo) $photo = 'http://www.gravatar.com/avatar/'.md5($user->user_email);
115 $webfinger = array('subject' => $resource,
116 'aliases' => WebfingerPlugin::get_resources($user->ID),
117 'links' => array(
118 array('rel' => 'http://webfinger.net/rel/profile-page', 'type' => 'text/html', 'href' => $url),
119 array('rel' => 'http://webfinger.net/rel/avatar', 'href' => $photo)
120 ));
121 if ($user->user_url) {
122 $webfinger['links'][] = array('rel' => 'http://webfinger.net/rel/profile-page', 'type' => 'text/html', 'href' => $user->user_url);
123 }
124
125 return $webfinger;
126 }
127
128 /**
129 * filters the webfinger array by request params like "rel"
130 *
131 * @link tools.ietf.org/html/draft-jones-appsawg-webfinger#section-4.3
132 * @param array $array
133 * @param stdClass $user
134 * @param array $queries
135 * @return array
136 */
137 public function filter_by_rel($webfinger, $user, $resource, $queries) {
138 // check if "rel" is set
139 if (!array_key_exists('rel', $queries)) {
140 return $webfinger;
141 }
142
143 remove_all_actions('webfinger_xrd');
144
145 // filter webfinger-array
146 $links = array();
147 foreach ($webfinger['links'] as $link) {
148 if ($link["rel"] == $queries["rel"]) {
149 $links[] = $link;
150 }
151 }
152 $webfinger['links'] = $links;
153
154 // return only "links" with the matching
155 return $webfinger;
156 }
157
158 /**
159 * add the host meta information
160 */
161 public function add_host_meta_links($array) {
162 $array["links"][] = array("rel" => "lrdd", "template" => site_url("/?well-known=webfinger&resource={uri}&format=xrd"), "type" => "application/xrd+xml");
163
164 return $array;
165 }
166
167 /**
168 * returns a Userobject
169 *
170 * @param string $uri
171 * @return stdClass
172 */
173 private function get_user_by_uri($uri) {
174 global $wpdb;
175
176 $uri = urldecode($uri);
177
178 if (preg_match("~^https?://~i", $uri)) {
179 // check if url matches with a
180 // users profile url
181 foreach (get_users_of_blog() as $user) {
182 if (rtrim(str_replace("www.", "", get_author_posts_url($user->ID, $user->user_nicename)), "/") ==
183 rtrim(str_replace("www.", "", $uri), "/")) {
184 return $user;
185 }
186 }
187 } elseif (preg_match('/^([a-zA-Z]+:)?([^@]+)@([a-zA-Z0-9._-]+)$/i', $uri, $array)) {
188 $username = $array[2];
189 $host = $array[3];
190 $email = $username."@".$host;
191
192 if ($host == parse_url(get_bloginfo('url'), PHP_URL_HOST)) {
193 $sql = "SELECT * FROM $wpdb->users u INNER JOIN $wpdb->usermeta um ON u.id=um.user_id WHERE u.user_email = '%s' OR
194 (um.meta_key = 'jabber' AND um.meta_value = '%s') OR
195 u.user_login = '%s' LIMIT 1;";
196 $user = $wpdb->get_results($wpdb->prepare($sql, $email, $email, $username));
197 if (!empty($user)) {
198 return $user[0];
199 }
200 }
201 }
202
203 return false;
204 }
205
206 /**
207 * recursive helper to generade the xrd-xml from the jrd array
208 *
209 * @param string $host_meta
210 * @return string
211 */
212 public function jrd_to_xrd($webfinger) {
213 $xrd = null;
214
215 foreach ($webfinger as $type => $content) {
216 // print subject
217 if ($type == "subject") {
218 $xrd .= "<Subject>$content</Subject>";
219 continue;
220 }
221
222 // print aliases
223 if ($type == "aliases") {
224 foreach ($content as $uri) {
225 $xrd .= "<Alias>".htmlentities($uri)."</Alias>";
226 }
227 continue;
228 }
229
230 // print properties
231 if ($type == "properties") {
232 foreach ($content as $type => $uri) {
233 $xrd .= "<Property type='".htmlentities($type)."'>".htmlentities($uri)."</Property>";
234 }
235 continue;
236 }
237
238 // print titles
239 if ($type == "titles") {
240 foreach ($content as $key => $value) {
241 if ($key == "default") {
242 $xrd .= "<Title>".htmlentities($value)."</Title>";
243 } else {
244 $xrd .= "<Title xml:lang='".htmlentities($key)."'>".htmlentities($value)."</Title>";
245 }
246 }
247 continue;
248 }
249
250 // print links
251 if ($type == "links") {
252 foreach ($content as $links) {
253 $temp = array();
254 $cascaded = false;
255 $xrd .= "<Link ";
256
257 foreach ($links as $key => $value) {
258 if (is_array($value)) {
259 $temp[$key] = $value;
260 $cascaded = true;
261 } else {
262 $xrd .= htmlentities($key)."='".htmlentities($value)."' ";
263 }
264 }
265 if ($cascaded) {
266 $xrd .= ">";
267 $xrd .= WebfingerPlugin::jrd_to_xrd($temp);
268 $xrd .= "</Link>";
269 } else {
270 $xrd .= " />";
271 }
272 }
273
274 continue;
275 }
276 }
277
278 return $xrd;
279 }
280
281 /**
282 * returns a users default webfinger
283 *
284 * @param mixed $id_or_name_or_object
285 * @param boolean $protocol
286 * @return string
287 */
288 function get_resource($id_or_name_or_object, $protocol = false) {
289 $user = WebfingerPlugin::get_user_by_various($id_or_name_or_object);
290
291 if ($user) {
292 $resource = $user->user_login."@".parse_url(home_url(), PHP_URL_HOST);
293 if ($protocol) {
294 $resource = "acct:".$resource;
295 }
296 return $resource;
297 } else {
298 return null;
299 }
300 }
301
302 /**
303 * returns all webfinger "resources"
304 *
305 * @param mixed $id_or_name_or_object
306 *
307 * @return array
308 */
309 public function get_resources($id_or_name_or_object) {
310 $user = WebfingerPlugin::get_user_by_various($id_or_name_or_object);
311
312 if ($user) {
313 $resources[] = WebfingerPlugin::get_resource($user, true);
314 $resources[] = get_author_posts_url($user->ID, $user->user_nicename);
315 if ($user->user_email && WebfingerPlugin::check_mail_domain($user->user_email)) {
316 $resources[] = "mailto:".$user->user_email;
317 }
318 if (get_user_meta($user->ID, "jabber", true) && $webfinger->check_mail_domain(get_user_meta($user->ID, "jabber", true))) {
319 $resources[] = "xmpp:".get_user_meta($user->ID, "jabber", true);
320 }
321 $resources = apply_filters('resources', $resources);
322
323 return array_unique($resources);
324 } else {
325 return array();
326 }
327 }
328
329 /**
330 * Convenience method to get user data by ID, username, object or from current user.
331 *
332 * @param mixed $id_or_name_or_object the username, ID or object. If not provided, the current user will be used.
333 * @return bool|object False on failure, User DB row object
334 *
335 * @author Will Norris
336 * @see get_userdata_by_various() # DiSo OpenID-Plugin
337 */
338 public function get_user_by_various($id_or_name_or_object = null) {
339 if ( $id_or_name_or_object === null ) {
340 $user = wp_get_current_user();
341 if ($user == null) return false;
342 return $user->data;
343 } else if ( is_object($id_or_name_or_object) ) {
344 return $id_or_name_or_object;
345 } else if ( is_numeric($id_or_name_or_object) ) {
346 return get_userdata($id_or_name_or_object);
347 } else {
348 return get_userdatabylogin($id_or_name_or_object);
349 }
350 }
351
352 /**
353 * check if the email address has the same domain as the blog
354 *
355 * @param string $email
356 * @return boolean
357 */
358 public function check_mail_domain($email) {
359 if (preg_match('/^([a-zA-Z]+:)?([^@]+)@([a-zA-Z0-9._-]+)$/i', $email, $email_parts) &&
360 ($email_parts[3] == parse_url(home_url(), PHP_URL_HOST))) {
361 return true;
362 }
363
364 return false;
365 }
366
367 public function host_meta_draft($format, $host_meta, $query_vars) {
368
369 if (!array_key_exists('resource', $query_vars)) {
370 return;
371 }
372
373 // find matching user
374 $user = WebfingerPlugin::get_user_by_uri($query_vars['resource']);
375
376 if (!$user) {
377 return;
378 }
379
380 $webfinger = apply_filters('webfinger', array(), $user, $query_vars['resource'], $query_vars);
381
382 do_action("webfinger_render", $format, $webfinger, $user, $query_vars);
383 do_action("webfinger_render_{$format}", $webfinger, $user, $query_vars);
384 }
385 }
386
387 add_action('query_vars', array('WebfingerPlugin', 'query_vars'));
388 add_action('parse_request', array('WebfingerPlugin', 'parse_request'));
389 add_action('generate_rewrite_rules', array('WebfingerPlugin', 'rewrite_rules'));
390
391 add_action('host_meta_render', array('WebfingerPlugin', 'host_meta_draft'), 1, 3);
392
393 add_action('webfinger_render_json', array('WebfingerPlugin', 'render_jrd'), 1, 1);
394 add_action('webfinger_render_jrd', array('WebfingerPlugin', 'render_jrd'), 1, 1);
395
396 add_action('webfinger_render_xml', array('WebfingerPlugin', 'render_xrd'), 1, 2);
397 add_action('webfinger_render_xrd', array('WebfingerPlugin', 'render_xrd'), 1, 2);
398
399 add_filter('webfinger', array('WebfingerPlugin', 'generate_default_content'), 0, 3);
400 add_filter('webfinger', array('WebfingerPlugin', 'filter_by_rel'), 99, 4);
401
402 add_filter('host_meta', array('WebfingerPlugin', 'add_host_meta_links'));
403
404 register_activation_hook(__FILE__, 'flush_rewrite_rules');
405 register_deactivation_hook(__FILE__, 'flush_rewrite_rules');
406