packages = $this->initialize(); } protected function initialize(): array { $loadedExtensions = get_loaded_extensions(); $packages = []; // Extensions scanning foreach ($loadedExtensions as $name) { if (in_array($name, ['standard', 'Core'])) { continue; } $ext = new \ReflectionExtension($name); try { $prettyVersion = $ext->getVersion(); /** @psalm-suppress TypeDoesNotContainNull * @psalm-suppress RedundantCondition * TODO Remove these annotations once psalm fixes the method signature ( https://github.com/vimeo/psalm/pull/8655 ) */ $prettyVersion = $this->normalizeVersion($prettyVersion ?? '0'); } catch (\UnexpectedValueException $e) { $prettyVersion = '0'; $prettyVersion = $this->normalizeVersion($prettyVersion); } $packages[$this->buildPackageName($name)] = $prettyVersion; } foreach ($loadedExtensions as $name) { $prettyVersion = null; switch ($name) { case 'curl': $curlVersion = curl_version(); $prettyVersion = $curlVersion['version']; break; case 'intl': $name = 'ICU'; if (defined('INTL_ICU_VERSION')) { $prettyVersion = INTL_ICU_VERSION; } else { $reflector = new \ReflectionExtension('intl'); ob_start(); $reflector->info(); $output = ob_get_clean(); preg_match('/^ICU version => (.*)$/m', $output, $matches); $prettyVersion = $matches[1]; } break; case 'libxml': $prettyVersion = LIBXML_DOTTED_VERSION; break; case 'openssl': $prettyVersion = preg_replace_callback('{^(?:OpenSSL\s*)?([0-9.]+)([a-z]?).*}', function ($match) { return $match[1] . (empty($match[2]) ? '' : '.' . (ord($match[2]) - 96)); }, OPENSSL_VERSION_TEXT); break; case 'pcre': $prettyVersion = preg_replace('{^(\S+).*}', '$1', PCRE_VERSION); break; case 'uuid': $prettyVersion = phpversion('uuid'); break; case 'xsl': $prettyVersion = LIBXSLT_DOTTED_VERSION; break; default: // None handled extensions have no special cases, skip continue 2; } if ($prettyVersion === null) { continue; } try { $prettyVersion = $this->normalizeVersion($prettyVersion); } catch (\UnexpectedValueException $e) { continue; } $packages[$this->buildPackageName($name)] = $prettyVersion; } return $packages; } private function buildPackageName(string $name): string { return str_replace(' ', '-', $name); } public function findLibrary(string $name): ?string { $extName = $this->buildPackageName($name); if (isset($this->packages[$extName])) { return $this->packages[$extName]; } return null; } private static string $modifierRegex = '[._-]?(?:(stable|beta|b|RC|alpha|a|patch|pl|p)(?:[.-]?(\d+))?)?([.-]?dev)?'; /** * Normalizes a version string to be able to perform comparisons on it * * https://github.com/composer/composer/blob/master/src/Composer/Package/Version/VersionParser.php#L94 * * @param string $fullVersion optional complete version string to give more context * @throws \UnexpectedValueException */ public function normalizeVersion(string $version, ?string $fullVersion = null): string { $version = trim($version); if ($fullVersion === null) { $fullVersion = $version; } // ignore aliases and just assume the alias is required instead of the source if (preg_match('{^([^,\s]+) +as +([^,\s]+)$}', $version, $match)) { $version = $match[1]; } // match master-like branches if (preg_match('{^(?:dev-)?(?:master|trunk|default)$}i', $version)) { return '9999999-dev'; } if (strtolower(substr($version, 0, 4)) === 'dev-') { return 'dev-' . substr($version, 4); } // match classical versioning if (preg_match('{^v?(\d{1,3})(\.\d+)?(\.\d+)?(\.\d+)?' . self::$modifierRegex . '$}i', $version, $matches)) { $version = $matches[1] . (!empty($matches[2]) ? $matches[2] : '.0') . (!empty($matches[3]) ? $matches[3] : '.0') . (!empty($matches[4]) ? $matches[4] : '.0'); $index = 5; } elseif (preg_match('{^v?(\d{4}(?:[.:-]?\d{2}){1,6}(?:[.:-]?\d{1,3})?)' . self::$modifierRegex . '$}i', $version, $matches)) { // match date-based versioning $version = preg_replace('{\D}', '-', $matches[1]); $index = 2; } elseif (preg_match('{^v?(\d{4,})(\.\d+)?(\.\d+)?(\.\d+)?' . self::$modifierRegex . '$}i', $version, $matches)) { $version = $matches[1] . (!empty($matches[2]) ? $matches[2] : '.0') . (!empty($matches[3]) ? $matches[3] : '.0') . (!empty($matches[4]) ? $matches[4] : '.0'); $index = 5; } // add version modifiers if a version was matched if (isset($index)) { if (!empty($matches[$index])) { if ($matches[$index] === 'stable') { return $version; } $version .= '-' . $this->expandStability($matches[$index]) . (!empty($matches[$index + 1]) ? $matches[$index + 1] : ''); } if (!empty($matches[$index + 2])) { $version .= '-dev'; } return $version; } $extraMessage = ''; if (preg_match('{ +as +' . preg_quote($version) . '$}', $fullVersion)) { $extraMessage = ' in "' . $fullVersion . '", the alias must be an exact version'; } elseif (preg_match('{^' . preg_quote($version) . ' +as +}', $fullVersion)) { $extraMessage = ' in "' . $fullVersion . '", the alias source must be an exact version, if it is a branch name you should prefix it with dev-'; } throw new \UnexpectedValueException('Invalid version string "' . $version . '"' . $extraMessage); } private function expandStability(string $stability): string { $stability = strtolower($stability); switch ($stability) { case 'a': return 'alpha'; case 'b': return 'beta'; case 'p': case 'pl': return 'patch'; case 'rc': return 'RC'; default: return $stability; } } } set_period'>artonge/feat/pwd_confirmation_allow_set_period Nextcloud server, a safe home for all your data: https://github.com/nextcloud/serverwww-data
aboutsummaryrefslogtreecommitdiffstats
path: root/apps/oauth2/lib/Controller/SettingsController.php
blob: 00d16ce4976a435684a332d55b5bf4b2a69f47fa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
<?php

declare(strict_types=1);

/**
 * @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch>
 *
 * @author Bjoern Schiessle <bjoern@schiessle.org>
 * @author Christoph Wurst <christoph@winzerhof-wurst.at>
 * @author Lukas Reschke <lukas@statuscode.ch>
 * @author Patrik Kernstock <info@pkern.at>
 * @author rakekniven <mark.ziegler@rakekniven.de>
 * @author Roeland Jago Douma <roeland@famdouma.nl>
 *
 * @license GNU AGPL version 3 or any later version
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 *
 */

namespace OCA\OAuth2\Controller;

use OC\Authentication\Token\DefaultTokenMapper;
use OCA\OAuth2\Db\AccessTokenMapper;
use OCA\OAuth2\Db\Client;
use OCA\OAuth2\Db\ClientMapper;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\JSONResponse;
use OCP\IL10N;
use OCP\IRequest;
use OCP\Security\ISecureRandom;

class SettingsController extends Controller {
	/** @var ClientMapper */
	private $clientMapper;
	/** @var ISecureRandom */
	private $secureRandom;
	/** @var AccessTokenMapper  */
	private $accessTokenMapper;
	/** @var  DefaultTokenMapper */
	private $defaultTokenMapper;
	/** @var IL10N */
	private $l;

	public const validChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';

	/**
	 * @param string $appName
	 * @param IRequest $request
	 * @param ClientMapper $clientMapper
	 * @param ISecureRandom $secureRandom
	 * @param AccessTokenMapper $accessTokenMapper
	 * @param DefaultTokenMapper $defaultTokenMapper
	 */
	public function __construct(string $appName,
								IRequest $request,
								ClientMapper $clientMapper,
								ISecureRandom $secureRandom,
								AccessTokenMapper $accessTokenMapper,
								DefaultTokenMapper $defaultTokenMapper,
								IL10N $l
	) {
		parent::__construct($appName, $request);
		$this->secureRandom = $secureRandom;
		$this->clientMapper = $clientMapper;
		$this->accessTokenMapper = $accessTokenMapper;
		$this->defaultTokenMapper = $defaultTokenMapper;
		$this->l = $l;
	}

	public function addClient(string $name,
							  string $redirectUri): JSONResponse {
		if (filter_var($redirectUri, FILTER_VALIDATE_URL) === false) {
			return new JSONResponse(['message' => $this->l->t('Your redirect URL needs to be a full URL for example: https://yourdomain.com/path')], Http::STATUS_BAD_REQUEST);
		}

		$client = new Client();
		$client->setName($name);
		$client->setRedirectUri($redirectUri);
		$client->setSecret($this->secureRandom->generate(64, self::validChars));
		$client->setClientIdentifier($this->secureRandom->generate(64, self::validChars));
		$client = $this->clientMapper->insert($client);

		$result = [
			'id' => $client->getId(),
			'name' => $client->getName(),
			'redirectUri' => $client->getRedirectUri(),
			'clientId' => $client->getClientIdentifier(),
			'clientSecret' => $client->getSecret(),
		];

		return new JSONResponse($result);
	}

	public function deleteClient(int $id): JSONResponse {
		$client = $this->clientMapper->getByUid($id);
		$this->accessTokenMapper->deleteByClientId($id);
		$this->defaultTokenMapper->deleteByName($client->getName());
		$this->clientMapper->delete($client);
		return new JSONResponse([]);
	}
}