Issues (36)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

controller/main_controller.php (3 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 *
4
 * Ajax Shoutbox extension for the phpBB Forum Software package.
5
 *
6
 * @copyright (c) 2014 Paul Sohier <http://www.ajax-shoutbox.com>
7
 * @license       GNU General Public License, version 2 (GPL-2.0)
8
 *
9
 */
10
11
namespace paul999\ajaxshoutbox\controller;
12
13
use Symfony\Component\HttpFoundation\JsonResponse;
14
15
/**
16
 * Main controller
17
 */
18
class main_controller
19
{
20
	/** @var \phpbb\config\config */
21
	protected $config;
22
	/** @var \phpbb\controller\helper */
23
	protected $helper;
24
	/** @var \phpbb\template\template */
25
	protected $template;
26
	/** @var \phpbb\user */
27
	protected $user;
28
	/** @var string phpBB root path */
29
	protected $root_path;
30
	/** @var string phpEx */
31
	protected $php_ext;
32
33
	/** @var \phpbb\request\request */
34
	private $request;
35
36
	/** @var \phpbb\db\driver\driver_interface */
37
	private $db;
38
39
	/** @var \phpbb\auth\auth */
40
	private $auth;
41
42
	/** @var \paul999\ajaxshoutbox\actions\Delete  */
43
	private $delete;
44
45
	/** @var  string */
46
	private $table;
47
48
	/** @var string */
49
	private $usertable;
50
51
	/**
52
	 * @param \phpbb\config\config                 $config
53
	 * @param \phpbb\controller\helper             $helper
54
	 * @param \phpbb\template\template             $template
55
	 * @param \phpbb\user                          $user
56
	 * @param \phpbb\request\request               $request
57
	 * @param \phpbb\db\driver\driver_interface    $db
58
	 * @param \phpbb\auth\auth                     $auth
59
	 * @param \paul999\ajaxshoutbox\actions\delete $delete
60
	 * @param string                               $root_path
61
	 * @param string                               $php_ext
62
	 * @param string                               $table
63
	 * @param string                               $usertable
64
	 */
65
	public function __construct(\phpbb\config\config $config, \phpbb\controller\helper $helper,
66
								\phpbb\template\template $template, \phpbb\user $user, \phpbb\request\request $request,
67
								\phpbb\db\driver\driver_interface $db, \phpbb\auth\auth $auth,
68
								\paul999\ajaxshoutbox\actions\delete $delete,
69
								$root_path, $php_ext, $table, $usertable)
70
	{
71
		$this->config    = $config;
72
		$this->helper    = $helper;
73
		$this->template  = $template;
74
		$this->user      = $user;
75
		$this->request   = $request;
76
		$this->db        = $db;
77
		$this->auth      = $auth;
78
		$this->delete    = $delete;
79
		$this->root_path = $root_path;
80
		$this->php_ext   = $php_ext;
81
		$this->table     = $table;
82
		$this->usertable = $usertable;
83
84
		$this->user->add_lang_ext("paul999/ajaxshoutbox", "ajax_shoutbox");
85
	}
86
87
	/**
88
	 * Validate the push connection with shoutbox-app.com
89
	 *
90
	 * @param $id
91
	 *
92
	 * @return \Symfony\Component\HttpFoundation\JsonResponse
93
	 */
94
	public function validate($id)
95
	{
96
		$result = array();
97
98
		// Language used here won't be seen by the user.
99
		// It is used on shoutbox-app.com to specify the result.
100
		// Do not change.
101
		if ($this->config['ajaxshoutbox_push_enabled'])
102
		{
103
			if ($id == $this->config['ajaxshoutbox_validation_id'])
104
			{
105
				$result['ok'] = 'ok';
106
				$result['key'] = $this->config['ajaxshoutbox_validation_id'];
107
			}
108
			else
109
			{
110
				$result['error'] = 'Incorrect key';
111
			}
112
		}
113
		else
114
		{
115
			$result['error'] = 'disabled';
116
		}
117
118
		return new JsonResponse(array($result));
119
	}
120
121
	/**
122
	 * Post a new message to the shoutbox.
123
	 *
124
	 * @return \Symfony\Component\HttpFoundation\JsonResponse
125
	 */
126
	public function post()
127
	{
128
		// We always disallow guests to post in the shoutbox.
129
		if (!$this->auth->acl_get('u_shoutbox_post') || $this->user->data['user_id'] == ANONYMOUS)
130
		{
131
			return $this->error('AJAX_SHOUTBOX_ERROR', 'AJAX_SHOUTBOX_NO_PERMISSION', 403);
132
		}
133
134
		if (!check_form_key('ajaxshoutbox_posting', 3600 * 12)) // Allow 12 hours.
135
		{
136
			return $this->error('AJAX_SHOUTBOX_ERROR', 'FORM_INVALID', 500);
137
		}
138
139
		if ($this->request->is_ajax())
140
		{
141
			$message = $msg     = trim($this->request->variable('text_shoutbox', '', true));
142
143
			if (empty($message))
144
			{
145
				return $this->error('AJAX_SHOUTBOX_ERROR', 'AJAX_SHOUTBOX_MESSAGE_EMPTY', 500);
146
			}
147
148
			$uid          = $bitfield = $options = '';
149
			$allow_bbcode = $this->auth->acl_get('u_shoutbox_bbcode');
150
			$allow_urls   = $allow_smilies = true;
151
152
			if (!function_exists('generate_text_for_storage'))
153
			{
154
				include($this->root_path . 'includes/functions_content.' . $this->php_ext);
155
			}
156
157
			generate_text_for_storage($message, $uid, $bitfield, $options, $allow_bbcode, $allow_urls, $allow_smilies);
158
159
			$insert = array(
160
				'post_message'    => $message,
161
				'post_time'       => time(),
162
				'user_id'         => $this->user->data['user_id'],
163
				'bbcode_options'  => $options,
164
				'bbcode_bitfield' => $bitfield,
165
				'bbcode_uid'      => $uid,
166
			);
167
			$sql    = 'INSERT INTO ' . $this->table . ' ' . $this->db->sql_build_array('INSERT', $insert);
168
			$this->db->sql_query($sql);
169
170
			return new JsonResponse(array('OK'));
171
		}
172
		else
173
		{
174
			return $this->error('AJAX_SHOUTBOX_ERROR', 'AJAX_SHOUTBOX_ONLY_AJAX', 500);
175
		}
176
	}
177
178
	/**
179
	 * Delete a post from the client.
180
	 *
181
	 * @return \Symfony\Component\HttpFoundation\JsonResponse
182
	 */
183
	public function delete()
184
	{
185
		$id = $this->request->variable('id', 0, false, \phpbb\request\request_interface::POST);
186
187
		if (!$id)
188
		{
189
			return $this->error('AJAX_SHOUTBOX_ERROR', 'AJAX_SHOUTBOX_MISSING_ID', 500);
190
		}
191
192
		if (!check_form_key('ajaxshoutbox_delete_' . $id)) // Every delete form has its unique form key, based on ID.
193
		{
194
			return $this->error('AJAX_SHOUTBOX_ERROR', 'FORM_INVALID', 500);
195
		}
196
197
		try
198
		{
199
			$this->delete->delete_post($id);
200
		}
201
		catch (\paul999\ajaxshoutbox\exceptions\shoutbox_exception $exception)
202
		{
203
			return $this->error('AJAX_SHOUTBOX_ERROR', $exception->getMessage(), 500);
204
		}
205
		return new JsonResponse(array('OK'));
206
	}
207
208
	/**
209
	 * Get the last 10 shouts
210
	 *
211
	 * @return \Symfony\Component\HttpFoundation\JsonResponse
212
	 */
213
	public function getAll()
214
	{
215
		if (!$this->auth->acl_get('u_shoutbox_view'))
216
		{
217
			return $this->error('AJAX_SHOUTBOX_ERROR', 'AJAX_SHOUTBOX_NO_PERMISSION', 403);
218
		}
219
220
		$sql    = 'SELECT c.*, u.username, u.user_colour FROM
221
					' . $this->table . ' c,
222
					' . $this->usertable . ' u
223
					WHERE
224
						u.user_id = c.user_id
225
					ORDER BY post_time DESC';
226
		$result = $this->db->sql_query_limit($sql, 10);
227
228
		return $this->returnPosts($result);
229
	}
230
231
	/**
232
	 * Get all shouts since a specific shout ID.
233
	 *
234
	 * @param int $id Last selected ID.
235
	 *
236
	 * @return \Symfony\Component\HttpFoundation\JsonResponse
237
	 */
238 View Code Duplication
	public function getAfter($id)
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
239
	{
240
		if (!$this->auth->acl_get('u_shoutbox_view'))
241
		{
242
			return $this->error('AJAX_SHOUTBOX_ERROR', 'AJAX_SHOUTBOX_NO_PERMISSION', 403);
243
		}
244
245
		$sql    = 'SELECT c.*, u.username, u.user_colour FROM
246
				' . $this->table . ' c,
247
				' . $this->usertable . ' u
248
				WHERE post_time >= (
249
						SELECT post_time FROM ' . $this->table . '
250
						WHERE shout_id = ' . (int) $id . '
251
					)
252
					AND c.shout_id != ' . (int) $id . '
253
					AND u.user_id = c.user_id
254
				ORDER BY post_time DESC, shout_id DESC';
255
		$result = $this->db->sql_query($sql);
256
257
		return $this->returnPosts($result);
258
	}
259
260
	/**
261
	 * Get 10 shouts before the current shout ID.
262
	 *
263
	 * @param $id
264
	 *
265
	 * @return \Symfony\Component\HttpFoundation\JsonResponse
266
	 */
267 View Code Duplication
	public function getBefore($id)
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
268
	{
269
		if (!$this->auth->acl_get('u_shoutbox_view'))
270
		{
271
			return $this->error('AJAX_SHOUTBOX_ERROR', 'AJAX_SHOUTBOX_NO_PERMISSION', 403);
272
		}
273
274
		$sql    = 'SELECT c.*, u.username, u.user_colour FROM
275
				' . $this->table . ' c,
276
				' . $this->usertable . ' u
277
				WHERE post_time <= (
278
						SELECT post_time FROM ' . $this->table . '
279
						WHERE shout_id = ' . (int) $id . '
280
					)
281
					AND c.shout_id != ' . (int) $id . '
282
					AND u.user_id = c.user_id
283
				ORDER BY post_time DESC, shout_id ASC';
284
		$result = $this->db->sql_query_limit($sql, 10);
285
286
		return $this->returnPosts($result, false);
287
	}
288
289
	/**
290
	 * Loop over a SQL result set, and generate a JSON array based on the post data.
291
	 *
292
	 * @param mixed $result return the data for the posts
293
	 * @param bool  $reverse
294
	 *
295
	 * @return \Symfony\Component\HttpFoundation\JsonResponse
296
	 */
297
	private function returnPosts($result, $reverse = true)
298
	{
299
		$posts = array();
300
301
		while ($row = $this->db->sql_fetchrow($result))
302
		{
303
			$posts[] = $this->getPost($row);
304
		}
305
		$this->db->sql_freeresult($result);
306
307
		return new JsonResponse($reverse ? array_reverse($posts) : $posts);
308
	}
309
310
	/**
311
	 * Generate a array with the specific post for this shout.
312
	 *
313
	 * @param array $row Input row
314
	 *
315
	 * @return array output
316
	 */
317
	private function getPost($row)
318
	{
319
		if (!defined('PHPBB_USE_BOARD_URL_PATH'))
320
		{
321
			define('PHPBB_USE_BOARD_URL_PATH', true); // Require full URL to smilies.
322
		}
323
324
		$text = generate_text_for_display(
325
			$row['post_message'], $row['bbcode_uid'], $row['bbcode_bitfield'], $row['bbcode_options']
326
		);
327
328
		$username = get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']);
329
		$username = str_replace('./../../', generate_board_url() . '/', $username); // Fix paths
330
		$username = str_replace('./../', generate_board_url() . '/', $username); // Fix paths
331
332
		$result = array(
333
			'id'      => $row['shout_id'],
334
			'user'    => $username,
335
			'date'    => $this->user->format_date($row['post_time'], $this->user->data['user_ajaxshoutbox_format']),
336
			'message' => $text,
337
			'delete'  => ($this->auth->acl_get('m_shoutbox_delete') || ($this->auth->acl_get('u_shoutbox_delete') && $row['user_id'] == $this->user->data['user_id'])),
338
		);
339
340
		return array_merge($result, $this->add_form_key('ajaxshoutbox_delete_' . $row['shout_id']));
341
	}
342
343
	/**
344
	 * Send a error to the user.
345
	 *
346
	 * Important: phpBB (<= 3.1.2) handles non 200 status as error.
347
	 * Due to the way this is implemented, phpBB will display the browser
348
	 * generated error, instead of the user returned error.
349
	 * This method will result in a 200 OK, but the correct status is in
350
	 * the JsonResponse.status.
351
	 *
352
	 * @param string $title
353
	 * @param string $message
354
	 * @param integer $status
355
	 *
356
	 * @return \Symfony\Component\HttpFoundation\JsonResponse
357
	 */
358
	private function error($title, $message, $status)
359
	{
360
		$json = new JsonResponse(array(
361
			'title'     => $this->user->lang[$title],
362
			'error'     => $this->user->lang[$message],
363
			'status'    => $status,
364
		));
365
366
		return $json;
367
	}
368
369
	/**
370
	 * Add a secret token and returns it as array with creation_time and form_token.
371
	 *
372
	 * Based on phpBB's add_form_key. Compatible with check_form_key.
373
	 *
374
	 * IMPORTANT: The original event is not included, because the form is build before the event,
375
	 * while this function returns the (Possible modified) data after the event.
376
	 *
377
	 * @param string $form_name The name of the form; has to match the name used in check_form_key, otherwise no
378
	 *                          restrictions apply
379
	 *
380
	 * @return array
381
	 */
382
	function add_form_key($form_name)
0 ignored issues
show
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
383
	{
384
		$now = time();
385
		$token_sid = ($this->user->data['user_id'] == ANONYMOUS && !empty($this->config['form_token_sid_guests'])) ? $this->user->session_id : '';
386
		$token = sha1($now . $this->user->data['user_form_salt'] . $form_name . $token_sid);
387
388
		return array(
389
			'creation_time' => $now,
390
			'form_token' => $token,
391
		);
392
	}
393
}
394