Passed
Push — feature/329_Subsonic_API ( 9d1353...9783d2 )
by Pauli
11:16
created

SubsonicMiddleware::beforeController()   B

Complexity

Conditions 7
Paths 7

Size

Total Lines 22
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 5
Bugs 0 Features 0
Metric Value
cc 7
eloc 14
c 5
b 0
f 0
nc 7
nop 2
dl 0
loc 22
rs 8.8333
1
<?php
2
3
/**
4
 * ownCloud - Music app
5
 *
6
 * This file is licensed under the Affero General Public License version 3 or
7
 * later. See the COPYING file.
8
 *
9
 * @author Pauli Järvinen <[email protected]>
10
 * @copyright Pauli Järvinen 2019
11
 */
12
13
namespace OCA\Music\Middleware;
14
15
use \OCP\IRequest;
0 ignored issues
show
Bug introduced by
The type OCP\IRequest was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
16
use \OCP\AppFramework\Middleware;
0 ignored issues
show
Bug introduced by
The type OCP\AppFramework\Middleware was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
17
18
use \OCA\Music\AppFramework\BusinessLayer\BusinessLayerException;
19
use \OCA\Music\Controller\SubsonicController;
20
use \OCA\Music\Db\AmpacheUserMapper;
21
use \OCA\Music\Utility\Util;
22
23
24
/**
25
 * Checks the authentication on each Subsonic API call before the
26
 * request is allowed to be passed to SubsonicController.
27
 * Map SubsonicExceptions from the controller to proper Subsonic error results.
28
 */
29
class SubsonicMiddleware extends Middleware {
30
	private $request;
31
	private $userMapper;
32
33
	public function __construct(IRequest $request, AmpacheUserMapper $userMapper) {
34
		$this->request = $request;
35
		$this->userMapper = $userMapper;
36
	}
37
38
	/**
39
	 * This function is run before any HTTP request handler method, but it does
40
	 * nothing if the call in question is not routed to SubsonicController. In
41
	 * case of Subsonic call, this checks the user authentication.
42
	 * 
43
	 * @param Controller $controller the controller that is being called
0 ignored issues
show
Bug introduced by
The type OCA\Music\Middleware\Controller was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
44
	 * @param string $methodName the name of the method
45
	 * @throws SubsonicException when a security check fails
46
	 */
47
	public function beforeController($controller, $methodName) {
48
		if ($controller instanceof SubsonicController) {
49
			$user = $this->request->getParam('u');
50
			$pass = $this->request->getParam('p');
51
52
			if ($user === null || $pass === null) {
53
				if ($this->request->getParam('t') !== null) {
54
					throw new SubsonicException('Token-based authentication not supported', 41);
55
				} else {
56
					throw new SubsonicException('Required credentials missing', 10);
57
				}
58
			}
59
60
			// The password may be given in hexadecimal format
61
			if (Util::startsWith($pass, 'enc:')) {
62
				$pass = \hex2bin(\substr($pass, \strlen('enc:')));
63
			}
64
65
			if ($this->credentialsAreValid($user, $pass)) {
66
				$controller->setAuthenticatedUser($user);
67
			} else {
68
				throw new SubsonicException('Invalid Login', 40);
69
			}
70
		}
71
	}
72
73
	/**
74
	 * @param string $user Username
75
	 * @param string $pass Password
76
	 * @return boolean
77
	 */
78
	private function credentialsAreValid($user, $pass) {
79
		$hashes = $this->userMapper->getPasswordHashes($user);
80
81
		foreach ($hashes as $hash) {
82
			if ($hash === \hash('sha256', $pass)) {
83
				return true;
84
			}
85
		}
86
87
		return false;
88
	}
89
90
	/**
91
	 * Catch SubsonicException and BusinessLayerExcpetion instances thrown when handling
92
	 * Subsonic requests, and render the the appropiate Subsonic error response. Any other
93
	 * exceptions are allowed to flow through, reaching eventually the default handler if
94
	 * no-one else intercepts them. The default handler logs the error and returns response
95
	 * code 500.
96
	 * 
97
	 * @param Controller $controller the controller that was being called
98
	 * @param string $methodName the name of the method that was called on the controller
99
	 * @param \Exception $exception the thrown exception
100
	 * @throws \Exception the passed in exception if it couldn't be handled
101
	 * @return Response a Response object in case the exception could be handled
0 ignored issues
show
Bug introduced by
The type OCA\Music\Middleware\Response was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
102
	 */
103
	public function afterException($controller, $methodName, \Exception $exception) {
104
		if ($controller instanceof SubsonicController) {
105
			if ($exception instanceof SubsonicException) {
106
				return $controller->subsonicErrorResponse(
107
						$exception->getCode(),
108
						$exception->getMessage()
109
				);
110
			}
111
			elseif ($exception instanceof BusinessLayerException) {
112
				return $controller->subsonicErrorResponse(70, 'Entity not found');
113
			}
114
		}
115
		throw $exception;
116
	}
117
}
118