]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/DomainWhitelist/DomainWhitelistPlugin.php
Merge remote-tracking branch 'upstream/master' into social-master
[quix0rs-gnu-social.git] / plugins / DomainWhitelist / DomainWhitelistPlugin.php
1 <?php
2 /**
3  * StatusNet - the distributed open-source microblogging tool
4  * Copyright (C) 2011, StatusNet, Inc.
5  *
6  * Restrict the email addresses in a domain to a select whitelist
7  *
8  * PHP version 5
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU Affero General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Affero General Public License for more details.
19  *
20  * You should have received a copy of the GNU Affero General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  * @category  Cache
24  * @package   StatusNet
25  * @author    Evan Prodromou <evan@status.net>
26  * @author    Zach Copley <zach@status.net>
27  * @copyright 2011 StatusNet, Inc.
28  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
29  * @link      http://status.net/
30  */
31
32 if (!defined('STATUSNET')) {
33     // This check helps protect against security problems;
34     // your code file can't be executed directly from the web.
35     exit(1);
36 }
37
38 /**
39  * Restrict the email addresses to a domain whitelist
40  *
41  * @category  General
42  * @package   StatusNet
43  * @author    Evan Prodromou <evan@status.net>
44  * @author    Zach Copley <zach@status.net>
45  * @copyright 2011 StatusNet, Inc.
46  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
47  * @link      http://status.net/
48  */
49 class DomainWhitelistPlugin extends Plugin
50 {
51     /**
52      * Get the path to the plugin's installation directory. Used
53      * to link in js files and whatnot.
54      *
55      * @return String the absolute path
56      */
57     protected function getPath() {
58         return preg_replace('/^' . preg_quote(INSTALLDIR, '/') . '\//', '', dirname(__FILE__));
59     }
60
61     /**
62      * Link in a JavaScript script for the whitelist invite form
63      *
64      * @param Action $action Action being shown
65      *
66      * @return boolean hook flag
67      */
68     public function onEndShowStatusNetScripts(Action $action) {
69         $name = $action->arg('action');
70         if ($name == 'invite') {
71             $action->script($this->getPath() . '/js/whitelistinvite.js');
72         }
73         return true;
74     }
75
76     public function onRequireValidatedEmailPlugin_Override(User $user, &$knownGood)
77     {
78         $knownGood = (!empty($user->email) && $this->matchesWhitelist($user->email));
79         return true;
80     }
81
82     // @TODO Most callers are given NULL as first argument
83     public function onEndValidateUserEmail($user, $email, &$valid)
84     {
85         if ($valid) { // it's otherwise valid
86             if (!$this->matchesWhitelist($email)) {
87                 $whitelist = $this->getWhitelist();
88                 if (count($whitelist) == 1) {
89                     // TRANS: Client exception thrown when a given e-mailaddress is not in the domain whitelist.
90                     // TRANS: %s is a whitelisted e-mail domain.
91                     $message = sprintf(_m('Email address must be in this domain: %s.'),
92                                        $whitelist[0]);
93                 } else {
94                     // TRANS: Client exception thrown when a given e-mailaddress is not in the domain whitelist.
95                     // TRANS: %s are whitelisted e-mail domains separated by comma's (localisable).
96                     $message = sprintf(_m('Email address must be in one of these domains: %s.'),
97                                        // TRANS: Separator for whitelisted domains.
98                                        implode(_m('SEPARATOR',', '), $whitelist));
99                 }
100                 throw new ClientException($message);
101             }
102         }
103         return true;
104     }
105
106     public function onStartAddEmailAddress(User $user, $email)
107     {
108         if (!$this->matchesWhitelist($email)) {
109             // TRANS: Exception thrown when an e-mail address does not match the site's domain whitelist.
110             throw new Exception(_m('That email address is not allowed on this site.'));
111         }
112
113         return true;
114     }
115
116     function onEndValidateEmailInvite($user, $email, &$valid)
117     {
118         if ($valid) {
119             $valid = $this->matchesWhitelist($email);
120         }
121
122         return true;
123     }
124
125     function matchesWhitelist($email)
126     {
127         $whitelist = $this->getWhitelist();
128
129         if (empty($whitelist) || empty($whitelist[0])) {
130             return true;
131         }
132
133         $userDomain = $this->domainFromEmail($email);
134
135         return in_array($userDomain, $whitelist);
136     }
137
138     /**
139      * Helper function to pull out a domain from
140      * an email address
141      *
142      * @param string $email and email address
143      * @return string the domain
144      */
145     function domainFromEmail($email)
146     {
147         $parts = explode('@', $email);
148         return strtolower(trim($parts[1]));
149     }
150
151     function getWhitelist()
152     {
153         $whitelist = common_config('email', 'whitelist');
154
155         if (is_array($whitelist)) {
156             return $this->sortWhiteList($whitelist);
157         } else {
158             return explode('|', $whitelist);
159         }
160     }
161
162     /**
163      * This is a filter function passed in to array_filter()
164      * in order to strip out the user's domain, which will
165      * be re-inserted as the first element (see sortWhitelist()
166      * below).
167      *
168      * @param string $domain domain to check
169      * @return boolean whether to include the domain
170      */
171     function userDomainFilter($domain)
172     {
173         $user       = common_current_user();
174         $userDomain = $this->domainFromEmail($user->email);
175         if ($userDomain == $domain) {
176             return false;
177         }
178         return true;
179     }
180
181     /**
182      * This function sorts the whitelist alphabetically, and sets the
183      * current user's domain as the first element in the array of
184      * allowed domains. Mostly, this is for the JavaScript on the invite
185      * page--in the case of multiple allowed domains, it's nicer if the
186      * user's own domain is the first option, and this seemed like a good
187      * way to do it.
188      *
189      * @param array $whitelist whitelist of allowed email domains
190      * @return array an ordered or sorted version of the whitelist
191      */
192     function sortWhitelist($whitelist)
193     {
194         $whitelist = array_unique($whitelist);
195         natcasesort($whitelist);
196
197         $user = common_current_user();
198
199         if (!empty($user) && !empty($user->email)) {
200             $userDomain = $this->domainFromEmail($user->email);
201
202             $orderedWhitelist = array_values(
203                 array_filter(
204                     $whitelist,
205                     array($this, "userDomainFilter")
206                 )
207             );
208
209             if (in_array($userDomain, $whitelist)) {
210                 array_unshift($orderedWhitelist, $userDomain);
211             }
212             return $orderedWhitelist;
213         }
214
215         return $whitelist;
216     }
217
218     /**
219      * Show a fancier invite form when domains are restricted to the
220      * whitelist.
221      *
222      * @param action $action the invite action
223      * @return boolean hook value
224      */
225     function onStartShowInviteForm($action)
226     {
227         $this->showConfirmDialog($action);
228         $form = new WhitelistInviteForm($action, $this->getWhitelist());
229         $form->show();
230         return false;
231     }
232
233     function showConfirmDialog($action)
234     {
235         // For JQuery UI modal dialog
236         $action->elementStart(
237             'div',
238             // TRANS: Title for invitiation deletion dialog.
239             array('id' => 'confirm-dialog', 'title' => _m('Confirmation Required'))
240         );
241         // TRANS: Confirmation text for invitation deletion dialog.
242         $action->text(_m('Really delete this invitation?'));
243         $action->elementEnd('div');
244     }
245
246     /**
247      * This is a bit of a hack. We take the values from the custom
248      * whitelist invite form and reformat them so they look like
249      * their coming from the the normal invite form.
250      *
251      * @param action &$action the invite action
252      * @return boolean hook value
253      */
254     function onStartSendInvitations(&$action)
255     {
256        $emails    = array();
257        $usernames = $action->arg('username');
258        $domains   = $action->arg('domain');
259
260        for($i = 0; $i < count($usernames); $i++) {
261            if (!empty($usernames[$i])) {
262                $emails[] = $usernames[$i] . '@' . $domains[$i] . "\n";
263            }
264        }
265
266        $action->args['addresses'] = implode($emails);
267
268        return true;
269     }
270
271     function onPluginVersion(array &$versions)
272     {
273         $versions[] = array('name' => 'DomainWhitelist',
274                             'version' => GNUSOCIAL_VERSION,
275                             'author' => 'Evan Prodromou, Zach Copley',
276                             'homepage' => 'http://status.net/wiki/Plugin:DomainWhitelist',
277                             'rawdescription' =>
278                             // TRANS: Plugin description.
279                             _m('Restrict domains for email users.'));
280         return true;
281     }
282 }