Completed
Push — master ( 87a00d...80388d )
by Maxence
02:18
created

ConfigService::deleteAppValue()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
/**
3
 * Circles - Bring cloud-users closer together.
4
 *
5
 * This file is licensed under the Affero General Public License version 3 or
6
 * later. See the COPYING file.
7
 *
8
 * @author Maxence Lange <[email protected]>
9
 * @copyright 2017
10
 * @license GNU AGPL version 3 or any later version
11
 *
12
 * This program is free software: you can redistribute it and/or modify
13
 * it under the terms of the GNU Affero General Public License as
14
 * published by the Free Software Foundation, either version 3 of the
15
 * License, or (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU Affero General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU Affero General Public License
23
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
24
 *
25
 */
26
27
namespace OCA\Circles\Service;
28
29
use daita\MySmallPhpTools\Model\Nextcloud\NC19Request;
30
use OCA\Circles\Exceptions\GSStatusException;
31
use OCA\Circles\Model\Circle;
32
use OCP\IConfig;
33
use OCP\IRequest;
34
use OCP\IURLGenerator;
35
use OCP\PreConditionNotMetException;
36
use OCP\Util;
37
38
class ConfigService {
39
40
	const CIRCLES_ALLOW_CIRCLES = 'allow_circles';
41
	const CIRCLES_CONTACT_BACKEND = 'contact_backend';
42
	const CIRCLES_STILL_FRONTEND = 'still_frontend';
43
	const CIRCLES_SWAP_TO_TEAMS = 'swap_to_teams';
44
	const CIRCLES_ALLOW_FEDERATED_CIRCLES = 'allow_federated';
45
	const CIRCLES_GS_ENABLED = 'gs_enabled';
46
	const CIRCLES_MEMBERS_LIMIT = 'members_limit';
47
	const CIRCLES_ACCOUNTS_ONLY = 'accounts_only';
48
	const CIRCLES_ALLOW_LINKED_GROUPS = 'allow_linked_groups';
49
	const CIRCLES_ALLOW_NON_SSL_LINKS = 'allow_non_ssl_links';
50
	const CIRCLES_NON_SSL_LOCAL = 'local_is_non_ssl';
51
	const CIRCLES_SELF_SIGNED = 'self_signed_cert';
52
	const LOCAL_CLOUD_ID = 'local_cloud_id';
53
	const CIRCLES_LOCAL_GSKEY = 'local_gskey';
54
	const CIRCLES_ACTIVITY_ON_CREATION = 'creation_activity';
55
	const CIRCLES_SKIP_INVITATION_STEP = 'skip_invitation_to_closed_circles';
56
	const CIRCLES_SEARCH_FROM_COLLABORATOR = 'search_from_collaborator';
57
	const CIRCLES_TEST_ASYNC_LOCK = 'test_async_lock';
58
	const CIRCLES_TEST_ASYNC_INIT = 'test_async_init';
59
	const CIRCLES_TEST_ASYNC_HAND = 'test_async_hand';
60
	const CIRCLES_TEST_ASYNC_COUNT = 'test_async_count';
61
	const FORCE_NC_BASE = 'force_nc_base';
62
	const TEST_NC_BASE = 'test_nc_base';
63
64
	const GS_ENABLED = 'enabled';
65
	const GS_MODE = 'mode';
66
	const GS_KEY = 'key';
67
	const GS_LOOKUP = 'lookup';
68
69
	const GS_LOOKUP_INSTANCES = '/instances';
70
	const GS_LOOKUP_USERS = '/users';
71
72
73
	private $defaults = [
74
		self::CIRCLES_ALLOW_CIRCLES            => Circle::CIRCLES_ALL,
75
		self::CIRCLES_CONTACT_BACKEND          => '0',
76
		self::CIRCLES_STILL_FRONTEND           => '0',
77
		self::CIRCLES_TEST_ASYNC_INIT          => '0',
78
		self::CIRCLES_SWAP_TO_TEAMS            => '0',
79
		self::CIRCLES_ACCOUNTS_ONLY            => '0',
80
		self::CIRCLES_MEMBERS_LIMIT            => '50',
81
		self::CIRCLES_ALLOW_LINKED_GROUPS      => '0',
82
		self::CIRCLES_ALLOW_FEDERATED_CIRCLES  => '0',
83
		self::CIRCLES_GS_ENABLED               => '0',
84
		self::CIRCLES_LOCAL_GSKEY              => '',
85
		self::CIRCLES_ALLOW_NON_SSL_LINKS      => '0',
86
		self::CIRCLES_NON_SSL_LOCAL            => '0',
87
		self::CIRCLES_SELF_SIGNED              => '0',
88
		self::LOCAL_CLOUD_ID                   => '',
89
		self::FORCE_NC_BASE                    => '',
90
		self::CIRCLES_ACTIVITY_ON_CREATION     => '1',
91
		self::CIRCLES_SKIP_INVITATION_STEP     => '0',
92
		self::CIRCLES_SEARCH_FROM_COLLABORATOR => '0'
93
	];
94
95
	/** @var string */
96
	private $appName;
97
98
	/** @var IConfig */
99
	private $config;
100
101
	/** @var string */
102
	private $userId;
103
104
	/** @var IRequest */
105
	private $request;
106
107
	/** @var IURLGenerator */
108
	private $urlGenerator;
109
110
	/** @var MiscService */
111
	private $miscService;
112
113
	/** @var int */
114
	private $allowedCircle = -1;
115
116
	/** @var int */
117
	private $allowedLinkedGroups = -1;
118
119
	/** @var int */
120
	private $allowedFederatedCircles = -1;
121
122
	/** @var int */
123
	private $allowedNonSSLLinks = -1;
124
125
	/** @var int */
126
	private $localNonSSL = -1;
127
128
	/**
129
	 * ConfigService constructor.
130
	 *
131
	 * @param string $appName
132
	 * @param IConfig $config
133
	 * @param IRequest $request
134
	 * @param string $userId
135
	 * @param IURLGenerator $urlGenerator
136
	 * @param MiscService $miscService
137
	 */
138
	public function __construct(
139
		$appName, IConfig $config, IRequest $request, $userId, IURLGenerator $urlGenerator,
140
		MiscService $miscService
141
	) {
142
		$this->appName = $appName;
143
		$this->config = $config;
144
		$this->request = $request;
145
		$this->userId = $userId;
146
		$this->urlGenerator = $urlGenerator;
147
		$this->miscService = $miscService;
148
	}
149
150
151
	public function getLocalAddress() {
152
		return (($this->isLocalNonSSL()) ? 'http://' : '')
153
			   . $this->request->getServerHost();
154
	}
155
156
157
	/**
158
	 * returns if this type of circle is allowed by the current configuration.
159
	 *
160
	 * @param $type
161
	 *
162
	 * @return int
163
	 */
164
	public function isCircleAllowed($type) {
165
		if ($this->allowedCircle === -1) {
166
			$this->allowedCircle = (int)$this->getAppValue(self::CIRCLES_ALLOW_CIRCLES);
167
		}
168
169
		return ((int)$type & (int)$this->allowedCircle);
170
	}
171
172
173
	/**
174
	 * @return bool
175
	 * @throws GSStatusException
176
	 */
177
	public function isLinkedGroupsAllowed() {
178
		if ($this->allowedLinkedGroups === -1) {
179
			$allowed = ($this->getAppValue(self::CIRCLES_ALLOW_LINKED_GROUPS) === '1'
180
						&& !$this->getGSStatus(self::GS_ENABLED));
181
			$this->allowedLinkedGroups = ($allowed) ? 1 : 0;
182
		}
183
184
		return ($this->allowedLinkedGroups === 1);
185
	}
186
187
188
	/**
189
	 * @return bool
190
	 */
191
	public function isFederatedCirclesAllowed() {
192
		if ($this->allowedFederatedCircles === -1) {
193
			$this->allowedFederatedCircles =
194
				(int)$this->getAppValue(self::CIRCLES_ALLOW_FEDERATED_CIRCLES);
195
		}
196
197
		return ($this->allowedFederatedCircles === 1);
198
	}
199
200
	/**
201
	 * @return bool
202
	 */
203
	public function isInvitationSkipped() {
204
		return (int)$this->getAppValue(self::CIRCLES_SKIP_INVITATION_STEP) === 1;
205
	}
206
207
	/**
208
	 * @return bool
209
	 */
210
	public function isLocalNonSSL() {
211
		if ($this->localNonSSL === -1) {
212
			$this->localNonSSL =
213
				(int)$this->getAppValue(self::CIRCLES_NON_SSL_LOCAL);
214
		}
215
216
		return ($this->localNonSSL === 1);
217
	}
218
219
220
	/**
221
	 * @return bool
222
	 */
223
	public function isNonSSLLinksAllowed() {
224
		if ($this->allowedNonSSLLinks === -1) {
225
			$this->allowedNonSSLLinks =
226
				(int)$this->getAppValue(self::CIRCLES_ALLOW_NON_SSL_LINKS);
227
		}
228
229
		return ($this->allowedNonSSLLinks === 1);
230
	}
231
232
233
	/**
234
	 * @param string $remote
235
	 *
236
	 * @return string
237
	 */
238
	public function generateRemoteHost($remote) {
239
		if ((!$this->isNonSSLLinksAllowed() || strpos($remote, 'http://') !== 0)
240
			&& strpos($remote, 'https://') !== 0
241
		) {
242
			$remote = 'https://' . $remote;
243
		}
244
245
		return rtrim($remote, '/');
246
	}
247
248
249
	/**
250
	 * Get a value by key
251
	 *
252
	 * @param string $key
253
	 *
254
	 * @return string
255
	 */
256
	public function getCoreValue($key) {
257
		$defaultValue = null;
258
259
		return $this->config->getAppValue('core', $key, $defaultValue);
260
	}
261
262
	/**
263
	 * Get a value by key
264
	 *
265
	 * @param string $key
266
	 *
267
	 * @return string
268
	 */
269
	public function getSystemValue($key) {
270
		$defaultValue = null;
271
272
		return $this->config->getSystemValue($key, $defaultValue);
273
	}
274
275
276
	/**
277
	 * Get available hosts
278
	 *
279
	 * @return array
280
	 */
281
	public function getAvailableHosts(): array {
282
		return $this->config->getSystemValue('trusted_domains', []);
283
	}
284
285
286
	/**
287
	 * Get a value by key
288
	 *
289
	 * @param string $key
290
	 *
291
	 * @return string
292
	 */
293
	public function getAppValue($key) {
294
		$defaultValue = null;
295
296
		if (array_key_exists($key, $this->defaults)) {
297
			$defaultValue = $this->defaults[$key];
298
		}
299
300
		return $this->config->getAppValue($this->appName, $key, $defaultValue);
301
	}
302
303
	/**
304
	 * Set a value by key
305
	 *
306
	 * @param string $key
307
	 * @param string $value
308
	 *
309
	 * @return void
310
	 */
311
	public function setAppValue($key, $value) {
312
		$this->config->setAppValue($this->appName, $key, $value);
313
	}
314
315
	/**
316
	 * remove a key
317
	 *
318
	 * @param string $key
319
	 *
320
	 * @return string
321
	 */
322
	public function deleteAppValue($key) {
323
		return $this->config->deleteAppValue($this->appName, $key);
324
	}
325
326
	/**
327
	 * Get a user value by key
328
	 *
329
	 * @param string $key
330
	 *
331
	 * @return string
332
	 */
333
	public function getUserValue($key) {
334
		return $this->config->getUserValue($this->userId, $this->appName, $key);
335
	}
336
337
	/**
338
	 * Set a user value by key
339
	 *
340
	 * @param string $key
341
	 * @param string $value
342
	 *
343
	 * @return string
344
	 * @throws PreConditionNotMetException
345
	 */
346
	public function setUserValue($key, $value) {
347
		return $this->config->setUserValue($this->userId, $this->appName, $key, $value);
348
	}
349
350
351
	/**
352
	 * Get a user value by key and user
353
	 *
354
	 * @param string $userId
355
	 * @param string $key
356
	 *
357
	 * @param string $default
358
	 *
359
	 * @return string
360
	 */
361
	public function getCoreValueForUser($userId, $key, $default = '') {
362
		return $this->config->getUserValue($userId, 'core', $key, $default);
363
	}
364
365
366
	/**
367
	 * Get a user value by key and user
368
	 *
369
	 * @param string $userId
370
	 * @param string $key
371
	 *
372
	 * @return string
373
	 */
374
	public function getValueForUser($userId, $key) {
375
		return $this->config->getUserValue($userId, $this->appName, $key);
376
	}
377
378
	/**
379
	 * Set a user value by key
380
	 *
381
	 * @param string $userId
382
	 * @param string $key
383
	 * @param string $value
384
	 *
385
	 * @return string
386
	 * @throws PreConditionNotMetException
387
	 */
388
	public function setValueForUser($userId, $key, $value) {
389
		return $this->config->setUserValue($userId, $this->appName, $key, $value);
390
	}
391
392
	/**
393
	 * return the cloud version.
394
	 * if $complete is true, return a string x.y.z
395
	 *
396
	 * @param boolean $complete
397
	 *
398
	 * @return string|integer
399
	 */
400
	public function getCloudVersion($complete = false) {
401
		$ver = Util::getVersion();
402
403
		if ($complete) {
404
			return implode('.', $ver);
405
		}
406
407
		return $ver[0];
408
	}
409
410
411
	/**
412
	 * @return bool
413
	 */
414
	public function isAccountOnly() {
415
		return ($this->getAppValue(self::CIRCLES_ACCOUNTS_ONLY) === '1');
416
	}
417
418
419
	/**
420
	 * @return bool
421
	 */
422
	public function isContactsBackend(): bool {
423
		return ($this->getAppValue(ConfigService::CIRCLES_CONTACT_BACKEND) !== '0'
424
				&& $this->getAppValue(ConfigService::CIRCLES_CONTACT_BACKEND) !== '');
425
	}
426
427
428
	/**
429
	 * @return int
430
	 */
431
	public function contactsBackendType(): int {
432
		return (int)$this->getAppValue(ConfigService::CIRCLES_CONTACT_BACKEND);
433
	}
434
435
436
	/**
437
	 * @return bool
438
	 */
439
	public function stillFrontEnd(): bool {
440
		if (!$this->isContactsBackend()) {
441
			return true;
442
		}
443
444
		if ($this->getAppValue(self::CIRCLES_STILL_FRONTEND) === '1') {
0 ignored issues
show
Unused Code introduced by
This if statement, and the following return statement can be replaced with return $this->getAppValu...TILL_FRONTEND) === '1';.
Loading history...
445
			return true;
446
		}
447
448
		return false;
449
	}
450
451
452
	/**
453
	 * should the password for a mail share be send to the recipient
454
	 *
455
	 * @return bool
456
	 */
457
	public function sendPasswordByMail() {
458
		if ($this->isContactsBackend()) {
459
			return false;
460
		}
461
462
		return ($this->config->getAppValue('sharebymail', 'sendpasswordmail', 'yes') === 'yes');
463
	}
464
465
	/**
466
	 * do we require a share by mail to be password protected
467
	 *
468
	 * @param Circle $circle
469
	 *
470
	 * @return bool
471
	 */
472
	public function enforcePasswordProtection(Circle $circle) {
473
		if ($this->isContactsBackend()) {
474
			return false;
475
		}
476
477
		if ($circle->getSetting('password_enforcement') === 'true') {
478
			return true;
479
		}
480
481
		return ($this->config->getAppValue('sharebymail', 'enforcePasswordProtection', 'no') === 'yes');
482
	}
483
484
485
	/**
486
	 * @param string $type
487
	 *
488
	 * @return array|bool|mixed
489
	 * @throws GSStatusException
490
	 */
491
	public function getGSStatus(string $type = '') {
492
		$enabled = $this->config->getSystemValueBool('gs.enabled', false);
493
		$lookup = $this->config->getSystemValue('lookup_server', '');
494
495
		if ($lookup === '' || !$enabled) {
496
			if ($type === self::GS_ENABLED) {
497
				return false;
498
			}
499
500
			throw new GSStatusException('GS and lookup are not configured : ' . $lookup . ', ' . $enabled);
501
		}
502
503
		$clef = $this->config->getSystemValue('gss.jwt.key', '');
504
		$mode = $this->config->getSystemValue('gss.mode', '');
505
506
		switch ($type) {
507
			case self::GS_ENABLED:
508
				return $enabled;
509
510
			case self::GS_MODE:
511
				return $mode;
512
513
			case self::GS_KEY:
514
				return $clef;
515
516
			case self::GS_LOOKUP:
517
				return $lookup;
518
		}
519
520
		return [
521
			self::GS_ENABLED => $enabled,
522
			self::GS_LOOKUP  => $lookup,
523
			self::GS_MODE    => $clef,
524
			self::GS_KEY     => $mode,
525
		];
526
	}
527
528
529
	/**
530
	 * @return array
531
	 */
532
	public function getTrustedDomains(): array {
533
		$domains = [];
534
		foreach ($this->config->getSystemValue('trusted_domains', []) as $v) {
535
			$domains[] = $v;
536
		}
537
538
		return $domains;
539
	}
540
541
542
	/**
543
	 * @return string
544
	 */
545
	public function getLocalCloudId(): string {
546
		$localCloudId = $this->getAppValue(self::LOCAL_CLOUD_ID);
547
		if ($localCloudId === '') {
548
			return $this->getTrustedDomains()[0];
549
		}
550
551
		return $localCloudId;
552
	}
553
554
555
	/**
556
	 * @return mixed
557
	 */
558
	public function getInstanceId() {
559
		return $this->config->getSystemValue('instanceid');
560
	}
561
562
563
	/**
564
	 * @param NC19Request $request
565
	 * @param string $routeName
566
	 * @param array $args
567
	 */
568
	public function configureRequest(NC19Request $request, string $routeName = '', array $args = []) {
569
		$this->configureRequestAddress($request, $routeName, $args);
570
571
		if ($this->getAppValue(ConfigService::CIRCLES_SELF_SIGNED) === '1') {
572
			$request->setVerifyPeer(false);
573
		}
574
575
		$request->setLocalAddressAllowed(true);
576
	}
577
578
	/**
579
	 * @param NC19Request $request
580
	 * @param string $routeName
581
	 * @param array $args
582
	 *
583
	 * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
584
	 */
585
	private function configureRequestAddress(NC19Request $request, string $routeName, array $args = []) {
586
		if ($routeName === '') {
587
			return;
588
		}
589
590
		$ncBase = ($this->getAppValue(self::TEST_NC_BASE)) ?
591
			$this->getAppValue(self::TEST_NC_BASE) : $this->getAppValue(self::FORCE_NC_BASE);
592
593
		if ($ncBase !== '') {
594
			$absolute = rtrim($ncBase, '/') . $this->urlGenerator->linkToRoute($routeName, $args);
595
		} else {
596
			$absolute = $this->urlGenerator->linkToRouteAbsolute($routeName, $args);
597
		}
598
599
		$request->basedOnUrl($absolute);
600
	}
601
602
}
603
604