Passed
Push — feature/329_Subsonic_API ( d9d298 )
by Pauli
10:35
created

SubsonicMiddleware::credentialsAreValid()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 5
nc 3
nop 2
dl 0
loc 10
rs 10
c 0
b 0
f 0
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\Utility\MethodAnnotationReader;
19
use \OCA\Music\Db\AmpacheUserMapper;
20
use \OCA\Music\Utility\Util;
21
22
23
/**
24
 * Checks the authentication on each Subsonic API call before the
25
 * request is allowed to be passed to SubsonicController.
26
 * Map SubsonicExceptions from the controller to proper Subsonic error results.
27
 */
28
class SubsonicMiddleware extends Middleware {
29
	private $request;
30
	private $isSubsonicCall;
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 is run before any HTTP request handler method.
40
	 * Need for Subsonic authentication checking is detected from the function
41
	 * annotation 'SubsonicAPI'
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
		// get annotations from comments
49
		$annotationReader = new MethodAnnotationReader($controller, $methodName);
50
51
		$this->$isSubsonicCall = $annotationReader->hasAnnotation('SubsonicAPI');
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $isSubsonicCall seems to be never defined.
Loading history...
52
53
		if ($this->$isSubsonicCall) {
54
			$user = $this->request->getParam('u');
55
			$pass = $this->request->getParam('p');
56
57
			if ($user === null || $pass === null) {
58
				throw new SubsonicException('Required credentials missing', 10);
59
			}
60
61
			// The password may be given in hexadecimal format
62
			if (Util::startsWith($pass, 'enc:')) {
63
				$pass = \hex2bin(\substr($pass, \strlen('enc:')));
64
			}
65
66
			if ($this->credentialsAreValid($user, $pass)) {
67
				$controller->setAuthenticatedUser($user);
68
			} else {
69
				throw new SubsonicException('Invalid Login', 40);
70
			}
71
		}
72
	}
73
74
	/**
75
	 * @param string $user Username
76
	 * @param string $pass Password
77
	 * @return boolean
78
	 */
79
	private function credentialsAreValid($user, $pass) {
80
		$hashes = $this->userMapper->getPasswordHashes($user);
81
82
		foreach ($hashes as $hash) {
83
			if ($hash === \hash('sha256', $pass)) {
84
				return true;
85
			}
86
		}
87
88
		return false;
89
	}
90
91
	/**
92
	 * If an SubsonicException is being caught, the appropiate subsonic
93
	 * exception response is rendered
94
	 * @param Controller $controller the controller that was being called
95
	 * @param string $methodName the name of the method that was called on
96
	 *                           the controller
97
	 * @param \Exception $exception the thrown exception
98
	 * @throws \Exception the passed in exception if it couldn't be handled
99
	 * @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...
100
	 */
101
	public function afterException($controller, $methodName, \Exception $exception) {
102
		if ($exception instanceof SubsonicException && $this->$isSubsonicCall) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $isSubsonicCall seems to be never defined.
Loading history...
103
			return $controller->subsonicErrorResponse(
104
					$exception->getCode(),
105
					$exception->getMessage()
106
			);
107
		}
108
		throw $exception;
109
	}
110
}
111