]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - actions/userauthorization.php
Merge branch '1.0.x' into testing
[quix0rs-gnu-social.git] / actions / userauthorization.php
1 <?php
2 /**
3  * Let the user authorize a remote subscription request
4  *
5  * PHP version 5
6  *
7  * @category Action
8  * @package  StatusNet
9  * @author   Evan Prodromou <evan@status.net>
10  * @author   Robin Millette <millette@status.net>
11  * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
12  * @link     http://status.net/
13  *
14  * StatusNet - the distributed open-source microblogging tool
15  * Copyright (C) 2008, 2009, StatusNet, Inc.
16  *
17  * This program is free software: you can redistribute it and/or modify
18  * it under the terms of the GNU Affero General Public License as published by
19  * the Free Software Foundation, either version 3 of the License, or
20  * (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU Affero General Public License for more details.
26  *
27  * You should have received a copy of the GNU Affero General Public License
28  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
29  */
30
31 if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
32
33 require_once INSTALLDIR.'/lib/omb.php';
34 require_once INSTALLDIR.'/extlib/libomb/service_provider.php';
35 require_once INSTALLDIR.'/extlib/libomb/profile.php';
36 define('TIMESTAMP_THRESHOLD', 300);
37
38 // @todo FIXME: Missing documentation.
39 class UserauthorizationAction extends Action
40 {
41     var $error;
42     var $params;
43
44     function handle($args)
45     {
46         parent::handle($args);
47
48         if ($_SERVER['REQUEST_METHOD'] == 'POST') {
49             /* Use a session token for CSRF protection. */
50             $token = $this->trimmed('token');
51             if (!$token || $token != common_session_token()) {
52                 $srv = $this->getStoredParams();
53                 // TRANS: Client error displayed when the session token does not match or is not given.
54                 $this->showForm($srv->getRemoteUser(), _('There was a problem ' .
55                                         'with your session token. Try again, ' .
56                                         'please.'));
57                 return;
58             }
59             /* We've shown the form, now post user's choice. */
60             $this->sendAuthorization();
61         } else {
62             if (!common_logged_in()) {
63                 /* Go log in, and then come back. */
64                 common_set_returnto($_SERVER['REQUEST_URI']);
65
66                 common_redirect(common_local_url('login'));
67                 return;
68             }
69
70             $user    = common_current_user();
71             $profile = $user->getProfile();
72             if (!$profile) {
73                 common_log_db_error($user, 'SELECT', __FILE__);
74                 // TRANS: Server error displayed when trying to authorise a remote subscription request
75                 // TRANS: while the user has no profile.
76                 $this->serverError(_('User without matching profile.'));
77                 return;
78             }
79
80             /* TODO: If no token is passed the user should get a prompt to enter
81                it according to OAuth Core 1.0. */
82             try {
83                 $this->validateOmb();
84                 $srv = new OMB_Service_Provider(
85                         profile_to_omb_profile($user->uri, $profile),
86                         omb_oauth_datastore());
87
88                 $remote_user = $srv->handleUserAuth();
89             } catch (Exception $e) {
90                 $this->clearParams();
91                 $this->clientError($e->getMessage());
92                 return;
93             }
94
95             $this->storeParams($srv);
96             $this->showForm($remote_user);
97         }
98     }
99
100     function showForm($params, $error=null)
101     {
102         $this->params = $params;
103         $this->error  = $error;
104         $this->showPage();
105     }
106
107     function title()
108     {
109         // TRANS: Page title.
110         return _('Authorize subscription');
111     }
112
113     function showPageNotice()
114     {
115         // TRANS: Page notice on "Authorize subscription" page.
116         $this->element('p', null, _('Please check these details to make sure '.
117                                     'that you want to subscribe to this ' .
118                                     'user’s notices. If you didn’t just ask ' .
119                                     'to subscribe to someone’s notices, '.
120                                     'click "Reject".'));
121     }
122
123     function showContent()
124     {
125         $params = $this->params;
126
127         $nickname = $params->getNickname();
128         $profile  = $params->getProfileURL();
129         $license  = $params->getLicenseURL();
130         $fullname = $params->getFullname();
131         $homepage = $params->getHomepage();
132         $bio      = $params->getBio();
133         $location = $params->getLocation();
134         $avatar   = $params->getAvatarURL();
135
136         $this->elementStart('div', 'entity_profile vcard');
137
138         if ($avatar) {
139             $this->element('img', array('src' => $avatar,
140                                         'class' => 'photo avatar entity_depiction',
141                                         'width' => AVATAR_PROFILE_SIZE,
142                                         'height' => AVATAR_PROFILE_SIZE,
143                                         'alt' => $nickname));
144         }
145
146         // TRANS: Label for nickname on user authorisation page.
147         $this->element('div', 'entity_nickname', _('Nickname'));
148
149         $hasFN = ($fullname !== '') ? 'nickname' : 'fn nickname';
150
151         // XXX: why are these raw() instead of escaped...?
152
153         $this->elementStart('a', array('href' => $profile,
154                                        'class' => 'url '.$hasFN));
155         $this->raw($nickname);
156         $this->elementEnd('a');
157
158         if (!is_null($fullname)) {
159             $this->elementStart('div', 'fn entity_fn');
160             $this->raw($fullname);
161             $this->elementEnd('div');
162         }
163
164         if (!is_null($location)) {
165             $this->elementStart('div', 'label entity_location');
166             $this->raw($location);
167         }
168
169         if (!is_null($homepage)) {
170             $this->elementStart('a', array('href' => $homepage,
171                                            'class' => 'url entity_url'));
172             $this->raw($homepage);
173             $this->elementEnd('a');
174         }
175
176         if (!is_null($bio)) {
177             $this->elementStart('div', 'note entity_note');
178             $this->raw($bio);
179             $this->elementEnd('dd');
180         }
181
182         if (!is_null($license)) {
183             $this->element('a', array('href' => $license,
184                                       'class' => 'license entity_license'),
185                            $license);
186         }
187
188         $this->elementEnd('div');
189
190         $this->elementStart('div', 'entity_actions');
191         $this->elementStart('ul');
192         $this->elementStart('li', 'entity_subscribe');
193         $this->elementStart('form', array('method' => 'post',
194                                           'id' => 'userauthorization',
195                                           'class' => 'form_user_authorization',
196                                           'name' => 'userauthorization',
197                                           'action' => common_local_url(
198                                                          'userauthorization')));
199         $this->hidden('token', common_session_token());
200
201         $this->submit('accept',
202                       // TRANS: Button text on Authorise Subscription page.
203                       _m('BUTTON','Accept'), 'submit accept', null,
204                       // TRANS: Title for button on Authorise Subscription page.
205                       _('Subscribe to this user.'));
206         $this->submit('reject',
207                       // TRANS: Button text on Authorise Subscription page.
208                       _m('BUTTON','Reject'), 'submit reject', null,
209                       // TRANS: Title for button on Authorise Subscription page.
210                       _('Reject this subscription.'));
211         $this->elementEnd('form');
212         $this->elementEnd('li');
213         $this->elementEnd('ul');
214         $this->elementEnd('div');
215     }
216
217     function sendAuthorization()
218     {
219         $srv = $this->getStoredParams();
220
221         if (is_null($srv)) {
222             // TRANS: Client error displayed for an empty authorisation request.
223             $this->clientError(_('No authorization request!'));
224             return;
225         }
226
227         $accepted = $this->arg('accept');
228         try {
229             list($val, $token) = $srv->continueUserAuth($accepted);
230         } catch (Exception $e) {
231             $this->clientError($e->getMessage());
232             return;
233         }
234         if ($val !== false) {
235             common_redirect($val, 303);
236         } elseif ($accepted) {
237             $this->showAcceptMessage($token);
238         } else {
239             $this->showRejectMessage();
240         }
241     }
242
243     function showAcceptMessage($tok)
244     {
245         // TRANS: Accept message header from Authorise subscription page.
246         common_show_header(_('Subscription authorized'));
247         $this->element('p', null,
248                        // TRANS: Accept message text from Authorise subscription page.
249                        _('The subscription has been authorized, but no '.
250                          'callback URL was passed. Check with the site\'s ' .
251                          'instructions for details on how to authorize the ' .
252                          'subscription. Your subscription token is:'));
253         $this->element('blockquote', 'token', $tok);
254         common_show_footer();
255     }
256
257     function showRejectMessage()
258     {
259         // TRANS: Reject message header from Authorise subscription page.
260         common_show_header(_('Subscription rejected'));
261         $this->element('p', null,
262                        // TRANS: Reject message from Authorise subscription page.
263                        _('The subscription has been rejected, but no '.
264                          'callback URL was passed. Check with the site\'s ' .
265                          'instructions for details on how to fully reject ' .
266                          'the subscription.'));
267         common_show_footer();
268     }
269
270     function storeParams($params)
271     {
272         common_ensure_session();
273         $_SESSION['userauthorizationparams'] = serialize($params);
274     }
275
276     function clearParams()
277     {
278         common_ensure_session();
279         unset($_SESSION['userauthorizationparams']);
280     }
281
282     function getStoredParams()
283     {
284         common_ensure_session();
285         $params = unserialize($_SESSION['userauthorizationparams']);
286         return $params;
287     }
288
289     function validateOmb()
290     {
291         $listener = $_GET['omb_listener'];
292         $listenee = $_GET['omb_listenee'];
293         $nickname = $_GET['omb_listenee_nickname'];
294         $profile  = $_GET['omb_listenee_profile'];
295
296         $user = User::staticGet('uri', $listener);
297         if (!$user) {
298             // TRANS: Exception thrown when no valid user is found for an authorisation request.
299             // TRANS: %s is a listener URI.
300             throw new Exception(sprintf(_('Listener URI "%s" not found here.'),
301                                         $listener));
302         }
303
304         if (strlen($listenee) > 255) {
305             // TRANS: Exception thrown when listenee URI is too long for an authorisation request.
306             // TRANS: %s is a listenee URI.
307             throw new Exception(sprintf(_('Listenee URI "%s" is too long.'),
308                                         $listenee));
309         }
310
311         $other = User::staticGet('uri', $listenee);
312         if ($other) {
313             // TRANS: Exception thrown when listenee URI is a local user for an authorisation request.
314             // TRANS: %s is a listenee URI.
315             throw new Exception(sprintf(_('Listenee URI "%s" is a local user.'),
316                                         $listenee));
317         }
318
319         $remote = Remote_profile::staticGet('uri', $listenee);
320         if ($remote) {
321             $sub             = new Subscription();
322             $sub->subscriber = $user->id;
323             $sub->subscribed = $remote->id;
324             if ($sub->find(true)) {
325                 // TRANS: Exception thrown when already subscribed.
326                 throw new Exception('You are already subscribed to this user.');
327             }
328         }
329
330         if ($profile == common_profile_url($nickname)) {
331             // TRANS: Exception thrown when profile URL is a local user for an authorisation request.
332             // TRANS: %s is a profile URL.
333             throw new Exception(sprintf(_('Profile URL "%s" is for a local user.'),
334                                         $profile));
335
336         }
337
338         $license      = $_GET['omb_listenee_license'];
339         $site_license = common_config('license', 'url');
340         if (!common_compatible_license($license, $site_license)) {
341             // TRANS: Exception thrown when licenses are not compatible for an authorisation request.
342             // TRANS: %1$s is the license for the listenee, %2$s is the license for "this" StatusNet site.
343             throw new Exception(sprintf(_('Listenee stream license "%1$s" is not ' .
344                                           'compatible with site license "%2$s".'),
345                                         $license, $site_license));
346         }
347
348         $avatar = $_GET['omb_listenee_avatar'];
349         if ($avatar) {
350             if (!common_valid_http_url($avatar) || strlen($avatar) > 255) {
351                 // TRANS: Exception thrown when avatar URL is invalid for an authorisation request.
352                 // TRANS: %s is an avatar URL.
353                 throw new Exception(sprintf(_('Avatar URL "%s" is not valid.'),
354                                             $avatar));
355             }
356             $size = @getimagesize($avatar);
357             if (!$size) {
358                 // TRANS: Exception thrown when avatar URL could not be read for an authorisation request.
359                 // TRANS: %s is an avatar URL.
360                 throw new Exception(sprintf(_('Cannot read avatar URL "%s".'),
361                                             $avatar));
362             }
363             if (!in_array($size[2], array(IMAGETYPE_GIF, IMAGETYPE_JPEG,
364                                           IMAGETYPE_PNG))) {
365                 // TRANS: Exception thrown when avatar URL return an invalid image type for an authorisation request.
366                 // TRANS: %s is an avatar URL.
367                 throw new Exception(sprintf(_('Wrong image type for avatar URL '.
368                                               '"%s".'), $avatar));
369             }
370         }
371     }
372 }