]> git.mxchange.org Git - friendica.git/blob - src/Console/ServerBlock.php
Merge remote-tracking branch 'upstream/develop' into server-detection
[friendica.git] / src / Console / ServerBlock.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2010-2022, the Friendica project
4  *
5  * @license GNU AGPL version 3 or any later version
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
9  * published by the Free Software Foundation, either version 3 of the
10  * License, or (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 <https://www.gnu.org/licenses/>.
19  *
20  */
21
22 namespace Friendica\Console;
23
24 use Asika\SimpleConsole\CommandArgsException;
25 use Asika\SimpleConsole\Console;
26 use Console_Table;
27 use Friendica\Core\Config\Capability\IManageConfigValues;
28
29 /**
30  * Manage blocked servers
31  *
32  * With this tool, you can list the current blocked servers
33  * or you can add / remove a blocked server from the list
34  */
35 class ServerBlock extends Console
36 {
37         const DEFAULT_REASON = 'blocked';
38
39         protected $helpOptions = ['h', 'help', '?'];
40
41         /**
42          * @var IManageConfigValues
43          */
44         private $config;
45
46         protected function getHelp()
47         {
48                 $help = <<<HELP
49 console serverblock - Manage blocked server domain patterns
50 Usage
51     bin/console serverblock [-h|--help|-?] [-v]
52     bin/console serverblock add <pattern> <reason> [-h|--help|-?] [-v]
53     bin/console serverblock remove <pattern> [-h|--help|-?] [-v]
54     bin/console serverblock export <filename>
55     bin/console serverblock import <filename>
56
57 Description
58     With this tool, you can list the current blocked server domain patterns
59     or you can add / remove a blocked server domain pattern from the list.
60     Using the export and import options you can share your server blocklist
61     with other node admins by CSV files.
62
63     Patterns are case-insensitive shell wildcard comprising the following special characters:
64     - * : Any number of characters
65     - ? : Any single character
66     - [<char1><char2>...] : char1 or char2 or...
67
68 Options
69     -h|--help|-? Show help information
70     -v           Show more debug information.
71 HELP;
72                 return $help;
73         }
74
75         public function __construct(IManageConfigValues $config, $argv = null)
76         {
77                 parent::__construct($argv);
78
79                 $this->config = $config;
80         }
81
82         protected function doExecute(): int
83         {
84                 if (count($this->args) == 0) {
85                         $this->printBlockedServers($this->config);
86                         return 0;
87                 }
88
89                 switch ($this->getArgument(0)) {
90                         case 'add':
91                                 return $this->addBlockedServer($this->config);
92                         case 'remove':
93                                 return $this->removeBlockedServer($this->config);
94                         case 'export':
95                                 return $this->exportBlockedServers($this->config);
96                         case 'import':
97                                 return $this->importBlockedServers($this->config);
98                         default:
99                                 throw new CommandArgsException('Unknown command.');
100                                 break;
101                 }
102         }
103
104         /**
105          * Exports the list of blocked domains including the reason for the
106          * block to a CSV file.
107          *
108          * @param IManageConfigValues $config
109          */
110         private function exportBlockedServers(IManageConfigValues $config)
111         {
112                 $filename = $this->getArgument(1);
113                 $blocklist = $config->get('system', 'blocklist', []);
114                 $fp = fopen($filename, 'w');
115                 if (!$fp) {
116                         throw new Exception(sprintf('The file "%s" could not be created.', $filename));
117                 }
118                 foreach ($blocklist as $domain) {
119                         fputcsv($fp, $domain);
120                 }
121
122                 // Success
123                 return 0;
124         }
125         /**
126          * Imports a list of domains and a reason for the block from a CSV
127          * file, e.g. created with the export function.
128          *
129          * @param IManageConfigValues $config
130          */
131         private function importBlockedServers(IManageConfigValues $config)
132         {
133                 $filename = $this->getArgument(1);
134                 $currBlockList = $config->get('system', 'blocklist', []);
135                 $newBlockList = [];
136
137                 if (($fp = fopen($filename, 'r')) !== false) {
138                         while (($data = fgetcsv($fp, 1000, ',')) !== false) {
139                                 $domain = $data[0];
140                                 if (count($data) == 0) {
141                                         $reason = self::DEFAULT_REASON;
142                                 } else {
143                                         $reason = $data[1];
144                                 }
145                                 $data = [
146                                         'domain' => $domain,
147                                         'reason' => $reason
148                                 ];
149                                 if (!in_array($data, $newBlockList)) {
150                                         $newBlockList[] = $data;
151                                 }
152                         }
153
154                         foreach ($currBlockList as $blocked) {
155                                 if (!in_array($blocked, $newBlockList)) {
156                                         $newBlockList[] = $blocked;
157                                 }
158                         }
159
160                         if ($config->set('system', 'blocklist', $newBlockList)) {
161                                 $this->out(sprintf("Entries from %s that were not blocked before are now blocked", $filename));
162                                 return 0;
163                         } else {
164                                 $this->out(sprintf("Couldn't save '%s' as blocked server", $domain));
165                                 return 1;
166                         }
167                 } else {
168                         throw new Exception(sprintf('The file "%s" could not be opened for importing', $filename));
169                 }
170         }
171
172         /**
173          * Prints the whole list of blocked domains including the reason
174          *
175          * @param IManageConfigValues $config
176          */
177         private function printBlockedServers(IManageConfigValues $config)
178         {
179                 $table = new Console_Table();
180                 $table->setHeaders(['Domain', 'Reason']);
181                 $blocklist = $config->get('system', 'blocklist', []);
182                 foreach ($blocklist as $domain) {
183                         $table->addRow($domain);
184                 }
185                 $this->out($table->getTable());
186
187                 // Success
188                 return 0;
189         }
190
191         /**
192          * Adds a server to the blocked list
193          *
194          * @param IManageConfigValues $config
195          *
196          * @return int The return code (0 = success, 1 = failed)
197          */
198         private function addBlockedServer(IManageConfigValues $config)
199         {
200                 if (count($this->args) < 2 || count($this->args) > 3) {
201                         throw new CommandArgsException('Add needs a domain and optional a reason.');
202                 }
203
204                 $domain = $this->getArgument(1);
205                 $reason = (count($this->args) === 3) ? $this->getArgument(2) : self::DEFAULT_REASON;
206
207                 $update = false;
208
209                 $currBlockList = $config->get('system', 'blocklist', []);
210                 $newBlockList = [];
211                 foreach ($currBlockList  as $blocked) {
212                         if ($blocked['domain'] === $domain) {
213                                 $update = true;
214                                 $newBlockList[] = [
215                                         'domain' => $domain,
216                                         'reason' => $reason,
217                                 ];
218                         } else {
219                                 $newBlockList[] = $blocked;
220                         }
221                 }
222
223                 if (!$update) {
224                         $newBlockList[] = [
225                                 'domain' => $domain,
226                                 'reason' => $reason,
227                         ];
228                 }
229
230                 if ($config->set('system', 'blocklist', $newBlockList)) {
231                         if ($update) {
232                                 $this->out(sprintf("The domain '%s' is now updated. (Reason: '%s')", $domain, $reason));
233                         } else {
234                                 $this->out(sprintf("The domain '%s' is now blocked. (Reason: '%s')", $domain, $reason));
235                         }
236                         return 0;
237                 } else {
238                         $this->out(sprintf("Couldn't save '%s' as blocked server", $domain));
239                         return 1;
240                 }
241         }
242
243         /**
244          * Removes a server from the blocked list
245          *
246          * @param IManageConfigValues $config
247          *
248          * @return int The return code (0 = success, 1 = failed)
249          */
250         private function removeBlockedServer(IManageConfigValues $config)
251         {
252                 if (count($this->args) !== 2) {
253                         throw new CommandArgsException('Remove needs a second parameter.');
254                 }
255
256                 $domain = $this->getArgument(1);
257
258                 $found = false;
259
260                 $currBlockList = $config->get('system', 'blocklist', []);
261                 $newBlockList = [];
262                 foreach ($currBlockList as $blocked) {
263                         if ($blocked['domain'] === $domain) {
264                                 $found = true;
265                         } else {
266                                 $newBlockList[] = $blocked;
267                         }
268                 }
269
270                 if (!$found) {
271                         $this->out(sprintf("The domain '%s' is not blocked.", $domain));
272                         return 1;
273                 }
274
275                 if ($config->set('system', 'blocklist', $newBlockList)) {
276                         $this->out(sprintf("The domain '%s' is not more blocked", $domain));
277                         return 0;
278                 } else {
279                         $this->out(sprintf("Couldn't remove '%s' from blocked servers", $domain));
280                         return 1;
281                 }
282         }
283 }