]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/OStatus/scripts/fixup-shadow.php
XSS vulnerability when remote-subscribing
[quix0rs-gnu-social.git] / plugins / OStatus / scripts / fixup-shadow.php
1 #!/usr/bin/env php
2 <?php
3 /*
4  * StatusNet - a distributed open-source microblogging tool
5  * Copyright (C) 2010 StatusNet, Inc.
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Affero General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Affero General Public License for more details.
16  *
17  * You should have received a copy of the GNU Affero General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 define('INSTALLDIR', realpath(dirname(__FILE__) . '/../../..'));
22
23 $longoptions = array('dry-run');
24
25 $helptext = <<<END_OF_USERROLE_HELP
26 fixup_shadow.php [options]
27 Patches up stray ostatus_profile entries with corrupted shadow entries
28 for local users and groups.
29
30      --dry-run  look but don't touch
31
32 END_OF_USERROLE_HELP;
33
34 require_once INSTALLDIR.'/scripts/commandline.inc';
35
36 $dry = have_option('dry-run');
37
38 // Look for user.uri matches... These may not match up with the current
39 // URL schema if the site has changed names.
40 echo "Checking for bogus ostatus_profile entries matching user.uri...\n";
41
42 $user = new User();
43 $oprofile = new Ostatus_profile();
44 $user->joinAdd($oprofile, 'INNER', 'oprofile', 'uri');
45 $user->find();
46 $count = $user->N;
47 echo "Found $count...\n";
48
49 while ($user->fetch()) {
50     $uri = $user->getUri();
51     echo "user $user->id ($user->nickname) hidden by $uri";
52     if ($dry) {
53         echo " - skipping\n";
54     } else {
55         echo " - removing bogus ostatus_profile entry...";
56         $evil = Ostatus_profile::getKV('uri', $uri);
57         $evil->delete();
58         echo "  ok\n";
59     }
60 }
61 echo "\n";
62
63 // Also try user_group.uri matches for local groups.
64 // Not all group entries will have this filled out, though, as it's new!
65 echo "Checking for bogus ostatus_profile entries matching local user_group.uri...\n";
66 $group = new User_group();
67 $group->joinAdd(array('uri', 'ostatus_profile:uri'));
68 $group->joinAdd(array('id', 'local_group:group_id'));
69 $group->find();
70 $count = $group->N;
71 echo "Found $count...\n";
72
73 while ($group->fetch()) {
74     $uri = $group->getUri();
75     echo "group $group->id ($group->nickname) hidden by $uri";
76     if ($dry) {
77         echo " - skipping\n";
78     } else {
79         echo " - removing bogus ostatus_profile entry...";
80         $evil = Ostatus_profile::getKV('uri', $uri);
81         $evil->delete();
82         echo "  ok\n";
83     }
84 }
85 echo "\n";
86
87 // And there may be user_group entries remaining where we've already killed
88 // the ostatus_profile. These were "harmless" until our lookup started actually
89 // using the uri field, at which point we can clearly see it breaks stuff.
90 echo "Checking for leftover bogus user_group.uri entries obscuring local_group entries...\n";
91
92 $group = new User_group();
93 $group->joinAdd(array('id', 'local_group:group_id'), 'LEFT');
94 $group->whereAdd('group_id IS NULL');
95
96
97 $marker = mt_rand(31337, 31337000);
98 $groupTemplate = common_local_url('groupbyid', array('id' => $marker));
99 $encGroup = $group->escape($groupTemplate, true);
100 $encGroup = str_replace($marker, '%', $encGroup);
101 echo "  LIKE '$encGroup'\n";
102 $group->whereAdd("uri LIKE '$encGroup'");
103
104 $group->find();
105 $count = $group->N;
106 echo "Found $count...\n";
107
108 while ($group->fetch()) {
109     $uri = $group->getUri();
110     if (preg_match('!/group/(\d+)/id!', $uri, $matches)) {
111         $id = intval($matches[1]);
112         $local = Local_group::getKV('group_id', $id);
113         if ($local) {
114             $nick = $local->nickname;
115         } else {
116             $nick = '<deleted>';
117         }
118         echo "local group $id ($local->nickname) hidden by $uri (bogus group id $group->id)";
119         if ($dry) {
120             echo " - skipping\n";
121         } else {
122             echo " - removing bogus user_group entry...";
123             $evil = User_group::getKV('id', $group->id);
124             $evil->delete();
125             echo "  ok\n";
126         }
127     }
128 }
129 echo "\n";
130
131
132 // Fallback?
133 echo "Checking for bogus profiles blocking local users/groups by URI pattern match...\n";
134 $oprofile = new Ostatus_profile();
135
136 $marker = mt_rand(31337, 31337000);
137
138 $profileTemplate = common_local_url('userbyid', array('id' => $marker));
139 $encProfile = $oprofile->escape($profileTemplate, true);
140 $encProfile = str_replace($marker, '%', $encProfile);
141 echo "  LIKE '$encProfile'\n";
142
143 $groupTemplate = common_local_url('groupbyid', array('id' => $marker));
144 $encGroup = $oprofile->escape($groupTemplate, true);
145 $encGroup = str_replace($marker, '%', $encGroup);
146 echo "  LIKE '$encGroup'\n";
147
148 $sql = "SELECT * FROM ostatus_profile WHERE uri LIKE '%s' OR uri LIKE '%s'";
149 $oprofile->query(sprintf($sql, $encProfile, $encGroup));
150
151 $count = $oprofile->N;
152 echo "Found $count...\n";
153
154 while ($oprofile->fetch()) {
155     $uri = $oprofile->getUri();
156     if (preg_match('!/group/(\d+)/id!', $oprofile->getUri(), $matches)) {
157         $id = intval($matches[1]);
158         $group = Local_group::getKV('group_id', $id);
159         if ($group) {
160             $nick = $group->nickname;
161         } else {
162             $nick = '<deleted>';
163         }
164         echo "group $id ($nick) hidden by $uri";
165     } else if (preg_match('!/user/(\d+)!', $uri, $matches)) {
166         $id = intval($matches[1]);
167         $user = User::getKV('id', $id);
168         if ($user) {
169             $nick = $user->nickname;
170         } else {
171             $nick = '<deleted>';
172         }
173         echo "user $id ($nick) hidden by $uri";
174     } else {
175         echo "$uri matched query, but we don't recognize it.\n";
176         continue;
177     }
178
179     if ($dry) {
180         echo " - skipping\n";
181     } else {
182         echo " - removing bogus ostatus_profile entry...";
183         $evil = clone($oprofile);
184         $evil->delete();
185         echo "  ok\n";
186     }
187 }
188
189 if ($count && $dry) {
190     echo "NO CHANGES MADE -- To delete the bogus entries, run again without --dry-run option.\n";
191 } else {
192     echo "done.\n";
193 }