Completed
Pull Request — master (#5174)
by Björn
16:04 queued 01:25
created
apps/encryption/lib/AppInfo/Application.php 1 patch
Indentation   +227 added lines, -227 removed lines patch added patch discarded remove patch
@@ -48,231 +48,231 @@
 block discarded – undo
48 48
 
49 49
 class Application extends \OCP\AppFramework\App {
50 50
 
51
-	/** @var IManager */
52
-	private $encryptionManager;
53
-	/** @var IConfig */
54
-	private $config;
55
-
56
-	/**
57
-	 * @param array $urlParams
58
-	 * @param bool $encryptionSystemReady
59
-	 */
60
-	public function __construct($urlParams = array(), $encryptionSystemReady = true) {
61
-		parent::__construct('encryption', $urlParams);
62
-		$this->encryptionManager = \OC::$server->getEncryptionManager();
63
-		$this->config = \OC::$server->getConfig();
64
-		$this->registerServices();
65
-		if($encryptionSystemReady === false) {
66
-			/** @var Session $session */
67
-			$session = $this->getContainer()->query('Session');
68
-			$session->setStatus(Session::RUN_MIGRATION);
69
-		}
70
-
71
-	}
72
-
73
-	public function setUp() {
74
-		if ($this->encryptionManager->isEnabled()) {
75
-			/** @var Setup $setup */
76
-			$setup = $this->getContainer()->query('UserSetup');
77
-			$setup->setupSystem();
78
-		}
79
-	}
80
-
81
-	/**
82
-	 * register hooks
83
-	 */
84
-	public function registerHooks() {
85
-		if (!$this->config->getSystemValue('maintenance', false)) {
86
-
87
-			$container = $this->getContainer();
88
-			$server = $container->getServer();
89
-			// Register our hooks and fire them.
90
-			$hookManager = new HookManager();
91
-
92
-			$hookManager->registerHook([
93
-				new UserHooks($container->query('KeyManager'),
94
-					$server->getUserManager(),
95
-					$server->getLogger(),
96
-					$container->query('UserSetup'),
97
-					$server->getUserSession(),
98
-					$container->query('Util'),
99
-					$container->query('Session'),
100
-					$container->query('Crypt'),
101
-					$container->query('Recovery'))
102
-			]);
103
-
104
-			$hookManager->fireHooks();
105
-
106
-		} else {
107
-			// Logout user if we are in maintenance to force re-login
108
-			$this->getContainer()->getServer()->getUserSession()->logout();
109
-		}
110
-	}
111
-
112
-	public function registerEncryptionModule() {
113
-		$container = $this->getContainer();
114
-
115
-
116
-		$this->encryptionManager->registerEncryptionModule(
117
-			Encryption::ID,
118
-			Encryption::DISPLAY_NAME,
119
-			function() use ($container) {
120
-
121
-			return new Encryption(
122
-				$container->query('Crypt'),
123
-				$container->query('KeyManager'),
124
-				$container->query('Util'),
125
-				$container->query('Session'),
126
-				$container->query('EncryptAll'),
127
-				$container->query('DecryptAll'),
128
-				$container->getServer()->getLogger(),
129
-				$container->getServer()->getL10N($container->getAppName())
130
-			);
131
-		});
132
-
133
-	}
134
-
135
-	public function registerServices() {
136
-		$container = $this->getContainer();
137
-
138
-		$container->registerService('Crypt',
139
-			function (IAppContainer $c) {
140
-				$server = $c->getServer();
141
-				return new Crypt($server->getLogger(),
142
-					$server->getUserSession(),
143
-					$server->getConfig(),
144
-					$server->getL10N($c->getAppName()));
145
-			});
146
-
147
-		$container->registerService('Session',
148
-			function (IAppContainer $c) {
149
-				$server = $c->getServer();
150
-				return new Session($server->getSession());
151
-			}
152
-		);
153
-
154
-		$container->registerService('KeyManager',
155
-			function (IAppContainer $c) {
156
-				$server = $c->getServer();
157
-
158
-				return new KeyManager($server->getEncryptionKeyStorage(),
159
-					$c->query('Crypt'),
160
-					$server->getConfig(),
161
-					$server->getUserSession(),
162
-					new Session($server->getSession()),
163
-					$server->getLogger(),
164
-					$c->query('Util')
165
-				);
166
-			});
167
-
168
-		$container->registerService('Recovery',
169
-			function (IAppContainer $c) {
170
-				$server = $c->getServer();
171
-
172
-				return new Recovery(
173
-					$server->getUserSession(),
174
-					$c->query('Crypt'),
175
-					$server->getSecureRandom(),
176
-					$c->query('KeyManager'),
177
-					$server->getConfig(),
178
-					$server->getEncryptionKeyStorage(),
179
-					$server->getEncryptionFilesHelper(),
180
-					new View());
181
-			});
182
-
183
-		$container->registerService('RecoveryController', function (IAppContainer $c) {
184
-			$server = $c->getServer();
185
-			return new RecoveryController(
186
-				$c->getAppName(),
187
-				$server->getRequest(),
188
-				$server->getConfig(),
189
-				$server->getL10N($c->getAppName()),
190
-				$c->query('Recovery'));
191
-		});
192
-
193
-		$container->registerService('StatusController', function (IAppContainer $c) {
194
-			$server = $c->getServer();
195
-			return new StatusController(
196
-				$c->getAppName(),
197
-				$server->getRequest(),
198
-				$server->getL10N($c->getAppName()),
199
-				$c->query('Session'),
200
-				$server->getEncryptionManager()
201
-			);
202
-		});
203
-
204
-		$container->registerService('SettingsController', function (IAppContainer $c) {
205
-			$server = $c->getServer();
206
-			return new SettingsController(
207
-				$c->getAppName(),
208
-				$server->getRequest(),
209
-				$server->getL10N($c->getAppName()),
210
-				$server->getUserManager(),
211
-				$server->getUserSession(),
212
-				$c->query('KeyManager'),
213
-				$c->query('Crypt'),
214
-				$c->query('Session'),
215
-				$server->getSession(),
216
-				$c->query('Util')
217
-			);
218
-		});
219
-
220
-		$container->registerService('UserSetup',
221
-			function (IAppContainer $c) {
222
-				$server = $c->getServer();
223
-				return new Setup($server->getLogger(),
224
-					$server->getUserSession(),
225
-					$c->query('Crypt'),
226
-					$c->query('KeyManager'));
227
-			});
228
-
229
-		$container->registerService('Util',
230
-			function (IAppContainer $c) {
231
-				$server = $c->getServer();
232
-
233
-				return new Util(
234
-					new View(),
235
-					$c->query('Crypt'),
236
-					$server->getLogger(),
237
-					$server->getUserSession(),
238
-					$server->getConfig(),
239
-					$server->getUserManager());
240
-			});
241
-
242
-		$container->registerService('EncryptAll',
243
-			function (IAppContainer $c) {
244
-				$server = $c->getServer();
245
-				return new EncryptAll(
246
-					$c->query('UserSetup'),
247
-					$c->getServer()->getUserManager(),
248
-					new View(),
249
-					$c->query('KeyManager'),
250
-					$c->query('Util'),
251
-					$server->getConfig(),
252
-					$server->getMailer(),
253
-					$server->getL10N('encryption'),
254
-					new QuestionHelper(),
255
-					$server->getSecureRandom()
256
-				);
257
-			}
258
-		);
259
-
260
-		$container->registerService('DecryptAll',
261
-			function (IAppContainer $c) {
262
-				return new DecryptAll(
263
-					$c->query('Util'),
264
-					$c->query('KeyManager'),
265
-					$c->query('Crypt'),
266
-					$c->query('Session'),
267
-					new QuestionHelper()
268
-				);
269
-			}
270
-		);
271
-
272
-	}
273
-
274
-	public function registerSettings() {
275
-		// Register settings scripts
276
-		App::registerPersonal('encryption', 'settings/settings-personal');
277
-	}
51
+    /** @var IManager */
52
+    private $encryptionManager;
53
+    /** @var IConfig */
54
+    private $config;
55
+
56
+    /**
57
+     * @param array $urlParams
58
+     * @param bool $encryptionSystemReady
59
+     */
60
+    public function __construct($urlParams = array(), $encryptionSystemReady = true) {
61
+        parent::__construct('encryption', $urlParams);
62
+        $this->encryptionManager = \OC::$server->getEncryptionManager();
63
+        $this->config = \OC::$server->getConfig();
64
+        $this->registerServices();
65
+        if($encryptionSystemReady === false) {
66
+            /** @var Session $session */
67
+            $session = $this->getContainer()->query('Session');
68
+            $session->setStatus(Session::RUN_MIGRATION);
69
+        }
70
+
71
+    }
72
+
73
+    public function setUp() {
74
+        if ($this->encryptionManager->isEnabled()) {
75
+            /** @var Setup $setup */
76
+            $setup = $this->getContainer()->query('UserSetup');
77
+            $setup->setupSystem();
78
+        }
79
+    }
80
+
81
+    /**
82
+     * register hooks
83
+     */
84
+    public function registerHooks() {
85
+        if (!$this->config->getSystemValue('maintenance', false)) {
86
+
87
+            $container = $this->getContainer();
88
+            $server = $container->getServer();
89
+            // Register our hooks and fire them.
90
+            $hookManager = new HookManager();
91
+
92
+            $hookManager->registerHook([
93
+                new UserHooks($container->query('KeyManager'),
94
+                    $server->getUserManager(),
95
+                    $server->getLogger(),
96
+                    $container->query('UserSetup'),
97
+                    $server->getUserSession(),
98
+                    $container->query('Util'),
99
+                    $container->query('Session'),
100
+                    $container->query('Crypt'),
101
+                    $container->query('Recovery'))
102
+            ]);
103
+
104
+            $hookManager->fireHooks();
105
+
106
+        } else {
107
+            // Logout user if we are in maintenance to force re-login
108
+            $this->getContainer()->getServer()->getUserSession()->logout();
109
+        }
110
+    }
111
+
112
+    public function registerEncryptionModule() {
113
+        $container = $this->getContainer();
114
+
115
+
116
+        $this->encryptionManager->registerEncryptionModule(
117
+            Encryption::ID,
118
+            Encryption::DISPLAY_NAME,
119
+            function() use ($container) {
120
+
121
+            return new Encryption(
122
+                $container->query('Crypt'),
123
+                $container->query('KeyManager'),
124
+                $container->query('Util'),
125
+                $container->query('Session'),
126
+                $container->query('EncryptAll'),
127
+                $container->query('DecryptAll'),
128
+                $container->getServer()->getLogger(),
129
+                $container->getServer()->getL10N($container->getAppName())
130
+            );
131
+        });
132
+
133
+    }
134
+
135
+    public function registerServices() {
136
+        $container = $this->getContainer();
137
+
138
+        $container->registerService('Crypt',
139
+            function (IAppContainer $c) {
140
+                $server = $c->getServer();
141
+                return new Crypt($server->getLogger(),
142
+                    $server->getUserSession(),
143
+                    $server->getConfig(),
144
+                    $server->getL10N($c->getAppName()));
145
+            });
146
+
147
+        $container->registerService('Session',
148
+            function (IAppContainer $c) {
149
+                $server = $c->getServer();
150
+                return new Session($server->getSession());
151
+            }
152
+        );
153
+
154
+        $container->registerService('KeyManager',
155
+            function (IAppContainer $c) {
156
+                $server = $c->getServer();
157
+
158
+                return new KeyManager($server->getEncryptionKeyStorage(),
159
+                    $c->query('Crypt'),
160
+                    $server->getConfig(),
161
+                    $server->getUserSession(),
162
+                    new Session($server->getSession()),
163
+                    $server->getLogger(),
164
+                    $c->query('Util')
165
+                );
166
+            });
167
+
168
+        $container->registerService('Recovery',
169
+            function (IAppContainer $c) {
170
+                $server = $c->getServer();
171
+
172
+                return new Recovery(
173
+                    $server->getUserSession(),
174
+                    $c->query('Crypt'),
175
+                    $server->getSecureRandom(),
176
+                    $c->query('KeyManager'),
177
+                    $server->getConfig(),
178
+                    $server->getEncryptionKeyStorage(),
179
+                    $server->getEncryptionFilesHelper(),
180
+                    new View());
181
+            });
182
+
183
+        $container->registerService('RecoveryController', function (IAppContainer $c) {
184
+            $server = $c->getServer();
185
+            return new RecoveryController(
186
+                $c->getAppName(),
187
+                $server->getRequest(),
188
+                $server->getConfig(),
189
+                $server->getL10N($c->getAppName()),
190
+                $c->query('Recovery'));
191
+        });
192
+
193
+        $container->registerService('StatusController', function (IAppContainer $c) {
194
+            $server = $c->getServer();
195
+            return new StatusController(
196
+                $c->getAppName(),
197
+                $server->getRequest(),
198
+                $server->getL10N($c->getAppName()),
199
+                $c->query('Session'),
200
+                $server->getEncryptionManager()
201
+            );
202
+        });
203
+
204
+        $container->registerService('SettingsController', function (IAppContainer $c) {
205
+            $server = $c->getServer();
206
+            return new SettingsController(
207
+                $c->getAppName(),
208
+                $server->getRequest(),
209
+                $server->getL10N($c->getAppName()),
210
+                $server->getUserManager(),
211
+                $server->getUserSession(),
212
+                $c->query('KeyManager'),
213
+                $c->query('Crypt'),
214
+                $c->query('Session'),
215
+                $server->getSession(),
216
+                $c->query('Util')
217
+            );
218
+        });
219
+
220
+        $container->registerService('UserSetup',
221
+            function (IAppContainer $c) {
222
+                $server = $c->getServer();
223
+                return new Setup($server->getLogger(),
224
+                    $server->getUserSession(),
225
+                    $c->query('Crypt'),
226
+                    $c->query('KeyManager'));
227
+            });
228
+
229
+        $container->registerService('Util',
230
+            function (IAppContainer $c) {
231
+                $server = $c->getServer();
232
+
233
+                return new Util(
234
+                    new View(),
235
+                    $c->query('Crypt'),
236
+                    $server->getLogger(),
237
+                    $server->getUserSession(),
238
+                    $server->getConfig(),
239
+                    $server->getUserManager());
240
+            });
241
+
242
+        $container->registerService('EncryptAll',
243
+            function (IAppContainer $c) {
244
+                $server = $c->getServer();
245
+                return new EncryptAll(
246
+                    $c->query('UserSetup'),
247
+                    $c->getServer()->getUserManager(),
248
+                    new View(),
249
+                    $c->query('KeyManager'),
250
+                    $c->query('Util'),
251
+                    $server->getConfig(),
252
+                    $server->getMailer(),
253
+                    $server->getL10N('encryption'),
254
+                    new QuestionHelper(),
255
+                    $server->getSecureRandom()
256
+                );
257
+            }
258
+        );
259
+
260
+        $container->registerService('DecryptAll',
261
+            function (IAppContainer $c) {
262
+                return new DecryptAll(
263
+                    $c->query('Util'),
264
+                    $c->query('KeyManager'),
265
+                    $c->query('Crypt'),
266
+                    $c->query('Session'),
267
+                    new QuestionHelper()
268
+                );
269
+            }
270
+        );
271
+
272
+    }
273
+
274
+    public function registerSettings() {
275
+        // Register settings scripts
276
+        App::registerPersonal('encryption', 'settings/settings-personal');
277
+    }
278 278
 }
Please login to merge, or discard this patch.
apps/encryption/lib/KeyManager.php 2 patches
Indentation   +681 added lines, -681 removed lines patch added patch discarded remove patch
@@ -38,685 +38,685 @@
 block discarded – undo
38 38
 
39 39
 class KeyManager {
40 40
 
41
-	/**
42
-	 * @var Session
43
-	 */
44
-	protected $session;
45
-	/**
46
-	 * @var IStorage
47
-	 */
48
-	private $keyStorage;
49
-	/**
50
-	 * @var Crypt
51
-	 */
52
-	private $crypt;
53
-	/**
54
-	 * @var string
55
-	 */
56
-	private $recoveryKeyId;
57
-	/**
58
-	 * @var string
59
-	 */
60
-	private $publicShareKeyId;
61
-	/**
62
-	 * @var string
63
-	 */
64
-	private $masterKeyId;
65
-	/**
66
-	 * @var string UserID
67
-	 */
68
-	private $keyId;
69
-	/**
70
-	 * @var string
71
-	 */
72
-	private $publicKeyId = 'publicKey';
73
-	/**
74
-	 * @var string
75
-	 */
76
-	private $privateKeyId = 'privateKey';
77
-
78
-	/**
79
-	 * @var string
80
-	 */
81
-	private $shareKeyId = 'shareKey';
82
-
83
-	/**
84
-	 * @var string
85
-	 */
86
-	private $fileKeyId = 'fileKey';
87
-	/**
88
-	 * @var IConfig
89
-	 */
90
-	private $config;
91
-	/**
92
-	 * @var ILogger
93
-	 */
94
-	private $log;
95
-	/**
96
-	 * @var Util
97
-	 */
98
-	private $util;
99
-
100
-	/**
101
-	 * @param IStorage $keyStorage
102
-	 * @param Crypt $crypt
103
-	 * @param IConfig $config
104
-	 * @param IUserSession $userSession
105
-	 * @param Session $session
106
-	 * @param ILogger $log
107
-	 * @param Util $util
108
-	 */
109
-	public function __construct(
110
-		IStorage $keyStorage,
111
-		Crypt $crypt,
112
-		IConfig $config,
113
-		IUserSession $userSession,
114
-		Session $session,
115
-		ILogger $log,
116
-		Util $util
117
-	) {
118
-
119
-		$this->util = $util;
120
-		$this->session = $session;
121
-		$this->keyStorage = $keyStorage;
122
-		$this->crypt = $crypt;
123
-		$this->config = $config;
124
-		$this->log = $log;
125
-
126
-		$this->recoveryKeyId = $this->config->getAppValue('encryption',
127
-			'recoveryKeyId');
128
-		if (empty($this->recoveryKeyId)) {
129
-			$this->recoveryKeyId = 'recoveryKey_' . substr(md5(time()), 0, 8);
130
-			$this->config->setAppValue('encryption',
131
-				'recoveryKeyId',
132
-				$this->recoveryKeyId);
133
-		}
134
-
135
-		$this->publicShareKeyId = $this->config->getAppValue('encryption',
136
-			'publicShareKeyId');
137
-		if (empty($this->publicShareKeyId)) {
138
-			$this->publicShareKeyId = 'pubShare_' . substr(md5(time()), 0, 8);
139
-			$this->config->setAppValue('encryption', 'publicShareKeyId', $this->publicShareKeyId);
140
-		}
141
-
142
-		$this->masterKeyId = $this->config->getAppValue('encryption',
143
-			'masterKeyId');
144
-		if (empty($this->masterKeyId)) {
145
-			$this->masterKeyId = 'master_' . substr(md5(time()), 0, 8);
146
-			$this->config->setAppValue('encryption', 'masterKeyId', $this->masterKeyId);
147
-		}
148
-
149
-		$this->keyId = $userSession && $userSession->isLoggedIn() ? $userSession->getUser()->getUID() : false;
150
-		$this->log = $log;
151
-	}
152
-
153
-	/**
154
-	 * check if key pair for public link shares exists, if not we create one
155
-	 */
156
-	public function validateShareKey() {
157
-		$shareKey = $this->getPublicShareKey();
158
-		if (empty($shareKey)) {
159
-			$keyPair = $this->crypt->createKeyPair();
160
-
161
-			// Save public key
162
-			$this->keyStorage->setSystemUserKey(
163
-				$this->publicShareKeyId . '.publicKey', $keyPair['publicKey'],
164
-				Encryption::ID);
165
-
166
-			// Encrypt private key empty passphrase
167
-			$encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], '');
168
-			$header = $this->crypt->generateHeader();
169
-			$this->setSystemPrivateKey($this->publicShareKeyId, $header . $encryptedKey);
170
-		}
171
-	}
172
-
173
-	/**
174
-	 * check if a key pair for the master key exists, if not we create one
175
-	 */
176
-	public function validateMasterKey() {
177
-
178
-		if ($this->util->isMasterKeyEnabled() === false) {
179
-			return;
180
-		}
181
-
182
-		$publicMasterKey = $this->getPublicMasterKey();
183
-		if (empty($publicMasterKey)) {
184
-			$keyPair = $this->crypt->createKeyPair();
185
-
186
-			// Save public key
187
-			$this->keyStorage->setSystemUserKey(
188
-				$this->masterKeyId . '.publicKey', $keyPair['publicKey'],
189
-				Encryption::ID);
190
-
191
-			// Encrypt private key with system password
192
-			$encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], $this->getMasterKeyPassword(), $this->masterKeyId);
193
-			$header = $this->crypt->generateHeader();
194
-			$this->setSystemPrivateKey($this->masterKeyId, $header . $encryptedKey);
195
-		}
196
-
197
-		if (!$this->session->isPrivateKeySet()) {
198
-			$masterKey = $this->getSystemPrivateKey($this->masterKeyId);
199
-			$decryptedMasterKey = $this->crypt->decryptPrivateKey($masterKey, $this->getMasterKeyPassword(), $this->masterKeyId);
200
-			$this->session->setPrivateKey($decryptedMasterKey);
201
-		}
202
-
203
-		// after the encryption key is available we are ready to go
204
-		$this->session->setStatus(Session::INIT_SUCCESSFUL);
205
-	}
206
-
207
-	/**
208
-	 * @return bool
209
-	 */
210
-	public function recoveryKeyExists() {
211
-		$key = $this->getRecoveryKey();
212
-		return (!empty($key));
213
-	}
214
-
215
-	/**
216
-	 * get recovery key
217
-	 *
218
-	 * @return string
219
-	 */
220
-	public function getRecoveryKey() {
221
-		return $this->keyStorage->getSystemUserKey($this->recoveryKeyId . '.publicKey', Encryption::ID);
222
-	}
223
-
224
-	/**
225
-	 * get recovery key ID
226
-	 *
227
-	 * @return string
228
-	 */
229
-	public function getRecoveryKeyId() {
230
-		return $this->recoveryKeyId;
231
-	}
232
-
233
-	/**
234
-	 * @param string $password
235
-	 * @return bool
236
-	 */
237
-	public function checkRecoveryPassword($password) {
238
-		$recoveryKey = $this->keyStorage->getSystemUserKey($this->recoveryKeyId . '.privateKey', Encryption::ID);
239
-		$decryptedRecoveryKey = $this->crypt->decryptPrivateKey($recoveryKey, $password);
240
-
241
-		if ($decryptedRecoveryKey) {
242
-			return true;
243
-		}
244
-		return false;
245
-	}
246
-
247
-	/**
248
-	 * @param string $uid
249
-	 * @param string $password
250
-	 * @param string $keyPair
251
-	 * @return bool
252
-	 */
253
-	public function storeKeyPair($uid, $password, $keyPair) {
254
-		// Save Public Key
255
-		$this->setPublicKey($uid, $keyPair['publicKey']);
256
-
257
-		$encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], $password, $uid);
258
-
259
-		$header = $this->crypt->generateHeader();
260
-
261
-		if ($encryptedKey) {
262
-			$this->setPrivateKey($uid, $header . $encryptedKey);
263
-			return true;
264
-		}
265
-		return false;
266
-	}
267
-
268
-	/**
269
-	 * @param string $password
270
-	 * @param array $keyPair
271
-	 * @return bool
272
-	 */
273
-	public function setRecoveryKey($password, $keyPair) {
274
-		// Save Public Key
275
-		$this->keyStorage->setSystemUserKey($this->getRecoveryKeyId().
276
-			'.publicKey',
277
-			$keyPair['publicKey'],
278
-			Encryption::ID);
279
-
280
-		$encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], $password);
281
-		$header = $this->crypt->generateHeader();
282
-
283
-		if ($encryptedKey) {
284
-			$this->setSystemPrivateKey($this->getRecoveryKeyId(), $header . $encryptedKey);
285
-			return true;
286
-		}
287
-		return false;
288
-	}
289
-
290
-	/**
291
-	 * @param $userId
292
-	 * @param $key
293
-	 * @return bool
294
-	 */
295
-	public function setPublicKey($userId, $key) {
296
-		return $this->keyStorage->setUserKey($userId, $this->publicKeyId, $key, Encryption::ID);
297
-	}
298
-
299
-	/**
300
-	 * @param $userId
301
-	 * @param string $key
302
-	 * @return bool
303
-	 */
304
-	public function setPrivateKey($userId, $key) {
305
-		return $this->keyStorage->setUserKey($userId,
306
-			$this->privateKeyId,
307
-			$key,
308
-			Encryption::ID);
309
-	}
310
-
311
-	/**
312
-	 * write file key to key storage
313
-	 *
314
-	 * @param string $path
315
-	 * @param string $key
316
-	 * @return boolean
317
-	 */
318
-	public function setFileKey($path, $key) {
319
-		return $this->keyStorage->setFileKey($path, $this->fileKeyId, $key, Encryption::ID);
320
-	}
321
-
322
-	/**
323
-	 * set all file keys (the file key and the corresponding share keys)
324
-	 *
325
-	 * @param string $path
326
-	 * @param array $keys
327
-	 */
328
-	public function setAllFileKeys($path, $keys) {
329
-		$this->setFileKey($path, $keys['data']);
330
-		foreach ($keys['keys'] as $uid => $keyFile) {
331
-			$this->setShareKey($path, $uid, $keyFile);
332
-		}
333
-	}
334
-
335
-	/**
336
-	 * write share key to the key storage
337
-	 *
338
-	 * @param string $path
339
-	 * @param string $uid
340
-	 * @param string $key
341
-	 * @return boolean
342
-	 */
343
-	public function setShareKey($path, $uid, $key) {
344
-		$keyId = $uid . '.' . $this->shareKeyId;
345
-		return $this->keyStorage->setFileKey($path, $keyId, $key, Encryption::ID);
346
-	}
347
-
348
-	/**
349
-	 * Decrypt private key and store it
350
-	 *
351
-	 * @param string $uid user id
352
-	 * @param string $passPhrase users password
353
-	 * @return boolean
354
-	 */
355
-	public function init($uid, $passPhrase) {
356
-
357
-		$this->session->setStatus(Session::INIT_EXECUTED);
358
-
359
-		try {
360
-			if($this->util->isMasterKeyEnabled()) {
361
-				$uid = $this->getMasterKeyId();
362
-				$passPhrase = $this->getMasterKeyPassword();
363
-				$privateKey = $this->getSystemPrivateKey($uid);
364
-			} else {
365
-				$privateKey = $this->getPrivateKey($uid);
366
-			}
367
-			$privateKey = $this->crypt->decryptPrivateKey($privateKey, $passPhrase, $uid);
368
-		} catch (PrivateKeyMissingException $e) {
369
-			return false;
370
-		} catch (DecryptionFailedException $e) {
371
-			return false;
372
-		} catch (\Exception $e) {
373
-			$this->log->warning(
374
-				'Could not decrypt the private key from user "' . $uid . '"" during login. ' .
375
-				'Assume password change on the user back-end. Error message: '
376
-				. $e->getMessage()
377
-			);
378
-			return false;
379
-		}
380
-
381
-		if ($privateKey) {
382
-			$this->session->setPrivateKey($privateKey);
383
-			$this->session->setStatus(Session::INIT_SUCCESSFUL);
384
-			return true;
385
-		}
386
-
387
-		return false;
388
-	}
389
-
390
-	/**
391
-	 * @param $userId
392
-	 * @return string
393
-	 * @throws PrivateKeyMissingException
394
-	 */
395
-	public function getPrivateKey($userId) {
396
-		$privateKey = $this->keyStorage->getUserKey($userId,
397
-			$this->privateKeyId, Encryption::ID);
398
-
399
-		if (strlen($privateKey) !== 0) {
400
-			return $privateKey;
401
-		}
402
-		throw new PrivateKeyMissingException($userId);
403
-	}
404
-
405
-	/**
406
-	 * @param string $path
407
-	 * @param $uid
408
-	 * @return string
409
-	 */
410
-	public function getFileKey($path, $uid) {
411
-		if ($uid === '') {
412
-			$uid = null;
413
-		}
414
-		$publicAccess = is_null($uid);
415
-		$encryptedFileKey = $this->keyStorage->getFileKey($path, $this->fileKeyId, Encryption::ID);
416
-
417
-		if (empty($encryptedFileKey)) {
418
-			return '';
419
-		}
420
-
421
-		if ($this->util->isMasterKeyEnabled()) {
422
-			$uid = $this->getMasterKeyId();
423
-			$shareKey = $this->getShareKey($path, $uid);
424
-			if ($publicAccess) {
425
-				$privateKey = $this->getSystemPrivateKey($uid);
426
-				$privateKey = $this->crypt->decryptPrivateKey($privateKey, $this->getMasterKeyPassword(), $uid);
427
-			} else {
428
-				// when logged in, the master key is already decrypted in the session
429
-				$privateKey = $this->session->getPrivateKey();
430
-			}
431
-		} else if ($publicAccess) {
432
-			// use public share key for public links
433
-			$uid = $this->getPublicShareKeyId();
434
-			$shareKey = $this->getShareKey($path, $uid);
435
-			$privateKey = $this->keyStorage->getSystemUserKey($this->publicShareKeyId . '.privateKey', Encryption::ID);
436
-			$privateKey = $this->crypt->decryptPrivateKey($privateKey);
437
-		} else {
438
-			$shareKey = $this->getShareKey($path, $uid);
439
-			$privateKey = $this->session->getPrivateKey();
440
-		}
441
-
442
-		if ($encryptedFileKey && $shareKey && $privateKey) {
443
-			return $this->crypt->multiKeyDecrypt($encryptedFileKey,
444
-				$shareKey,
445
-				$privateKey);
446
-		}
447
-
448
-		return '';
449
-	}
450
-
451
-	/**
452
-	 * Get the current version of a file
453
-	 *
454
-	 * @param string $path
455
-	 * @param View $view
456
-	 * @return int
457
-	 */
458
-	public function getVersion($path, View $view) {
459
-		$fileInfo = $view->getFileInfo($path);
460
-		if($fileInfo === false) {
461
-			return 0;
462
-		}
463
-		return $fileInfo->getEncryptedVersion();
464
-	}
465
-
466
-	/**
467
-	 * Set the current version of a file
468
-	 *
469
-	 * @param string $path
470
-	 * @param int $version
471
-	 * @param View $view
472
-	 */
473
-	public function setVersion($path, $version, View $view) {
474
-		$fileInfo= $view->getFileInfo($path);
475
-
476
-		if($fileInfo !== false) {
477
-			$cache = $fileInfo->getStorage()->getCache();
478
-			$cache->update($fileInfo->getId(), ['encrypted' => $version, 'encryptedVersion' => $version]);
479
-		}
480
-	}
481
-
482
-	/**
483
-	 * get the encrypted file key
484
-	 *
485
-	 * @param string $path
486
-	 * @return string
487
-	 */
488
-	public function getEncryptedFileKey($path) {
489
-		$encryptedFileKey = $this->keyStorage->getFileKey($path,
490
-			$this->fileKeyId, Encryption::ID);
491
-
492
-		return $encryptedFileKey;
493
-	}
494
-
495
-	/**
496
-	 * delete share key
497
-	 *
498
-	 * @param string $path
499
-	 * @param string $keyId
500
-	 * @return boolean
501
-	 */
502
-	public function deleteShareKey($path, $keyId) {
503
-		return $this->keyStorage->deleteFileKey(
504
-			$path,
505
-			$keyId . '.' . $this->shareKeyId,
506
-			Encryption::ID);
507
-	}
508
-
509
-
510
-	/**
511
-	 * @param $path
512
-	 * @param $uid
513
-	 * @return mixed
514
-	 */
515
-	public function getShareKey($path, $uid) {
516
-		$keyId = $uid . '.' . $this->shareKeyId;
517
-		return $this->keyStorage->getFileKey($path, $keyId, Encryption::ID);
518
-	}
519
-
520
-	/**
521
-	 * check if user has a private and a public key
522
-	 *
523
-	 * @param string $userId
524
-	 * @return bool
525
-	 * @throws PrivateKeyMissingException
526
-	 * @throws PublicKeyMissingException
527
-	 */
528
-	public function userHasKeys($userId) {
529
-		$privateKey = $publicKey = true;
530
-		$exception = null;
531
-
532
-		try {
533
-			$this->getPrivateKey($userId);
534
-		} catch (PrivateKeyMissingException $e) {
535
-			$privateKey = false;
536
-			$exception = $e;
537
-		}
538
-		try {
539
-			$this->getPublicKey($userId);
540
-		} catch (PublicKeyMissingException $e) {
541
-			$publicKey = false;
542
-			$exception = $e;
543
-		}
544
-
545
-		if ($privateKey && $publicKey) {
546
-			return true;
547
-		} elseif (!$privateKey && !$publicKey) {
548
-			return false;
549
-		} else {
550
-			throw $exception;
551
-		}
552
-	}
553
-
554
-	/**
555
-	 * @param $userId
556
-	 * @return mixed
557
-	 * @throws PublicKeyMissingException
558
-	 */
559
-	public function getPublicKey($userId) {
560
-		$publicKey = $this->keyStorage->getUserKey($userId, $this->publicKeyId, Encryption::ID);
561
-
562
-		if (strlen($publicKey) !== 0) {
563
-			return $publicKey;
564
-		}
565
-		throw new PublicKeyMissingException($userId);
566
-	}
567
-
568
-	public function getPublicShareKeyId() {
569
-		return $this->publicShareKeyId;
570
-	}
571
-
572
-	/**
573
-	 * get public key for public link shares
574
-	 *
575
-	 * @return string
576
-	 */
577
-	public function getPublicShareKey() {
578
-		return $this->keyStorage->getSystemUserKey($this->publicShareKeyId . '.publicKey', Encryption::ID);
579
-	}
580
-
581
-	/**
582
-	 * @param string $purpose
583
-	 * @param string $uid
584
-	 */
585
-	public function backupUserKeys($purpose, $uid) {
586
-		$this->keyStorage->backupUserKeys(Encryption::ID, $purpose, $uid);
587
-	}
588
-
589
-	/**
590
-	 * creat a backup of the users private and public key and then  delete it
591
-	 *
592
-	 * @param string $uid
593
-	 */
594
-	public function deleteUserKeys($uid) {
595
-		$this->deletePublicKey($uid);
596
-		$this->deletePrivateKey($uid);
597
-	}
598
-
599
-	/**
600
-	 * @param $uid
601
-	 * @return bool
602
-	 */
603
-	public function deletePublicKey($uid) {
604
-		return $this->keyStorage->deleteUserKey($uid, $this->publicKeyId, Encryption::ID);
605
-	}
606
-
607
-	/**
608
-	 * @param string $uid
609
-	 * @return bool
610
-	 */
611
-	private function deletePrivateKey($uid) {
612
-		return $this->keyStorage->deleteUserKey($uid, $this->privateKeyId, Encryption::ID);
613
-	}
614
-
615
-	/**
616
-	 * @param string $path
617
-	 * @return bool
618
-	 */
619
-	public function deleteAllFileKeys($path) {
620
-		return $this->keyStorage->deleteAllFileKeys($path);
621
-	}
622
-
623
-	/**
624
-	 * @param array $userIds
625
-	 * @return array
626
-	 * @throws PublicKeyMissingException
627
-	 */
628
-	public function getPublicKeys(array $userIds) {
629
-		$keys = [];
630
-
631
-		foreach ($userIds as $userId) {
632
-			try {
633
-				$keys[$userId] = $this->getPublicKey($userId);
634
-			} catch (PublicKeyMissingException $e) {
635
-				continue;
636
-			}
637
-		}
638
-
639
-		return $keys;
640
-
641
-	}
642
-
643
-	/**
644
-	 * @param string $keyId
645
-	 * @return string returns openssl key
646
-	 */
647
-	public function getSystemPrivateKey($keyId) {
648
-		return $this->keyStorage->getSystemUserKey($keyId . '.' . $this->privateKeyId, Encryption::ID);
649
-	}
650
-
651
-	/**
652
-	 * @param string $keyId
653
-	 * @param string $key
654
-	 * @return string returns openssl key
655
-	 */
656
-	public function setSystemPrivateKey($keyId, $key) {
657
-		return $this->keyStorage->setSystemUserKey(
658
-			$keyId . '.' . $this->privateKeyId,
659
-			$key,
660
-			Encryption::ID);
661
-	}
662
-
663
-	/**
664
-	 * add system keys such as the public share key and the recovery key
665
-	 *
666
-	 * @param array $accessList
667
-	 * @param array $publicKeys
668
-	 * @param string $uid
669
-	 * @return array
670
-	 * @throws PublicKeyMissingException
671
-	 */
672
-	public function addSystemKeys(array $accessList, array $publicKeys, $uid) {
673
-		if (!empty($accessList['public'])) {
674
-			$publicShareKey = $this->getPublicShareKey();
675
-			if (empty($publicShareKey)) {
676
-				throw new PublicKeyMissingException($this->getPublicShareKeyId());
677
-			}
678
-			$publicKeys[$this->getPublicShareKeyId()] = $publicShareKey;
679
-		}
680
-
681
-		if ($this->recoveryKeyExists() &&
682
-			$this->util->isRecoveryEnabledForUser($uid)) {
683
-
684
-			$publicKeys[$this->getRecoveryKeyId()] = $this->getRecoveryKey();
685
-		}
686
-
687
-		return $publicKeys;
688
-	}
689
-
690
-	/**
691
-	 * get master key password
692
-	 *
693
-	 * @return string
694
-	 * @throws \Exception
695
-	 */
696
-	public function getMasterKeyPassword() {
697
-		$password = $this->config->getSystemValue('secret');
698
-		if (empty($password)){
699
-			throw new \Exception('Can not get secret from Nextcloud instance');
700
-		}
701
-
702
-		return $password;
703
-	}
704
-
705
-	/**
706
-	 * return master key id
707
-	 *
708
-	 * @return string
709
-	 */
710
-	public function getMasterKeyId() {
711
-		return $this->masterKeyId;
712
-	}
713
-
714
-	/**
715
-	 * get public master key
716
-	 *
717
-	 * @return string
718
-	 */
719
-	public function getPublicMasterKey() {
720
-		return $this->keyStorage->getSystemUserKey($this->masterKeyId . '.publicKey', Encryption::ID);
721
-	}
41
+    /**
42
+     * @var Session
43
+     */
44
+    protected $session;
45
+    /**
46
+     * @var IStorage
47
+     */
48
+    private $keyStorage;
49
+    /**
50
+     * @var Crypt
51
+     */
52
+    private $crypt;
53
+    /**
54
+     * @var string
55
+     */
56
+    private $recoveryKeyId;
57
+    /**
58
+     * @var string
59
+     */
60
+    private $publicShareKeyId;
61
+    /**
62
+     * @var string
63
+     */
64
+    private $masterKeyId;
65
+    /**
66
+     * @var string UserID
67
+     */
68
+    private $keyId;
69
+    /**
70
+     * @var string
71
+     */
72
+    private $publicKeyId = 'publicKey';
73
+    /**
74
+     * @var string
75
+     */
76
+    private $privateKeyId = 'privateKey';
77
+
78
+    /**
79
+     * @var string
80
+     */
81
+    private $shareKeyId = 'shareKey';
82
+
83
+    /**
84
+     * @var string
85
+     */
86
+    private $fileKeyId = 'fileKey';
87
+    /**
88
+     * @var IConfig
89
+     */
90
+    private $config;
91
+    /**
92
+     * @var ILogger
93
+     */
94
+    private $log;
95
+    /**
96
+     * @var Util
97
+     */
98
+    private $util;
99
+
100
+    /**
101
+     * @param IStorage $keyStorage
102
+     * @param Crypt $crypt
103
+     * @param IConfig $config
104
+     * @param IUserSession $userSession
105
+     * @param Session $session
106
+     * @param ILogger $log
107
+     * @param Util $util
108
+     */
109
+    public function __construct(
110
+        IStorage $keyStorage,
111
+        Crypt $crypt,
112
+        IConfig $config,
113
+        IUserSession $userSession,
114
+        Session $session,
115
+        ILogger $log,
116
+        Util $util
117
+    ) {
118
+
119
+        $this->util = $util;
120
+        $this->session = $session;
121
+        $this->keyStorage = $keyStorage;
122
+        $this->crypt = $crypt;
123
+        $this->config = $config;
124
+        $this->log = $log;
125
+
126
+        $this->recoveryKeyId = $this->config->getAppValue('encryption',
127
+            'recoveryKeyId');
128
+        if (empty($this->recoveryKeyId)) {
129
+            $this->recoveryKeyId = 'recoveryKey_' . substr(md5(time()), 0, 8);
130
+            $this->config->setAppValue('encryption',
131
+                'recoveryKeyId',
132
+                $this->recoveryKeyId);
133
+        }
134
+
135
+        $this->publicShareKeyId = $this->config->getAppValue('encryption',
136
+            'publicShareKeyId');
137
+        if (empty($this->publicShareKeyId)) {
138
+            $this->publicShareKeyId = 'pubShare_' . substr(md5(time()), 0, 8);
139
+            $this->config->setAppValue('encryption', 'publicShareKeyId', $this->publicShareKeyId);
140
+        }
141
+
142
+        $this->masterKeyId = $this->config->getAppValue('encryption',
143
+            'masterKeyId');
144
+        if (empty($this->masterKeyId)) {
145
+            $this->masterKeyId = 'master_' . substr(md5(time()), 0, 8);
146
+            $this->config->setAppValue('encryption', 'masterKeyId', $this->masterKeyId);
147
+        }
148
+
149
+        $this->keyId = $userSession && $userSession->isLoggedIn() ? $userSession->getUser()->getUID() : false;
150
+        $this->log = $log;
151
+    }
152
+
153
+    /**
154
+     * check if key pair for public link shares exists, if not we create one
155
+     */
156
+    public function validateShareKey() {
157
+        $shareKey = $this->getPublicShareKey();
158
+        if (empty($shareKey)) {
159
+            $keyPair = $this->crypt->createKeyPair();
160
+
161
+            // Save public key
162
+            $this->keyStorage->setSystemUserKey(
163
+                $this->publicShareKeyId . '.publicKey', $keyPair['publicKey'],
164
+                Encryption::ID);
165
+
166
+            // Encrypt private key empty passphrase
167
+            $encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], '');
168
+            $header = $this->crypt->generateHeader();
169
+            $this->setSystemPrivateKey($this->publicShareKeyId, $header . $encryptedKey);
170
+        }
171
+    }
172
+
173
+    /**
174
+     * check if a key pair for the master key exists, if not we create one
175
+     */
176
+    public function validateMasterKey() {
177
+
178
+        if ($this->util->isMasterKeyEnabled() === false) {
179
+            return;
180
+        }
181
+
182
+        $publicMasterKey = $this->getPublicMasterKey();
183
+        if (empty($publicMasterKey)) {
184
+            $keyPair = $this->crypt->createKeyPair();
185
+
186
+            // Save public key
187
+            $this->keyStorage->setSystemUserKey(
188
+                $this->masterKeyId . '.publicKey', $keyPair['publicKey'],
189
+                Encryption::ID);
190
+
191
+            // Encrypt private key with system password
192
+            $encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], $this->getMasterKeyPassword(), $this->masterKeyId);
193
+            $header = $this->crypt->generateHeader();
194
+            $this->setSystemPrivateKey($this->masterKeyId, $header . $encryptedKey);
195
+        }
196
+
197
+        if (!$this->session->isPrivateKeySet()) {
198
+            $masterKey = $this->getSystemPrivateKey($this->masterKeyId);
199
+            $decryptedMasterKey = $this->crypt->decryptPrivateKey($masterKey, $this->getMasterKeyPassword(), $this->masterKeyId);
200
+            $this->session->setPrivateKey($decryptedMasterKey);
201
+        }
202
+
203
+        // after the encryption key is available we are ready to go
204
+        $this->session->setStatus(Session::INIT_SUCCESSFUL);
205
+    }
206
+
207
+    /**
208
+     * @return bool
209
+     */
210
+    public function recoveryKeyExists() {
211
+        $key = $this->getRecoveryKey();
212
+        return (!empty($key));
213
+    }
214
+
215
+    /**
216
+     * get recovery key
217
+     *
218
+     * @return string
219
+     */
220
+    public function getRecoveryKey() {
221
+        return $this->keyStorage->getSystemUserKey($this->recoveryKeyId . '.publicKey', Encryption::ID);
222
+    }
223
+
224
+    /**
225
+     * get recovery key ID
226
+     *
227
+     * @return string
228
+     */
229
+    public function getRecoveryKeyId() {
230
+        return $this->recoveryKeyId;
231
+    }
232
+
233
+    /**
234
+     * @param string $password
235
+     * @return bool
236
+     */
237
+    public function checkRecoveryPassword($password) {
238
+        $recoveryKey = $this->keyStorage->getSystemUserKey($this->recoveryKeyId . '.privateKey', Encryption::ID);
239
+        $decryptedRecoveryKey = $this->crypt->decryptPrivateKey($recoveryKey, $password);
240
+
241
+        if ($decryptedRecoveryKey) {
242
+            return true;
243
+        }
244
+        return false;
245
+    }
246
+
247
+    /**
248
+     * @param string $uid
249
+     * @param string $password
250
+     * @param string $keyPair
251
+     * @return bool
252
+     */
253
+    public function storeKeyPair($uid, $password, $keyPair) {
254
+        // Save Public Key
255
+        $this->setPublicKey($uid, $keyPair['publicKey']);
256
+
257
+        $encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], $password, $uid);
258
+
259
+        $header = $this->crypt->generateHeader();
260
+
261
+        if ($encryptedKey) {
262
+            $this->setPrivateKey($uid, $header . $encryptedKey);
263
+            return true;
264
+        }
265
+        return false;
266
+    }
267
+
268
+    /**
269
+     * @param string $password
270
+     * @param array $keyPair
271
+     * @return bool
272
+     */
273
+    public function setRecoveryKey($password, $keyPair) {
274
+        // Save Public Key
275
+        $this->keyStorage->setSystemUserKey($this->getRecoveryKeyId().
276
+            '.publicKey',
277
+            $keyPair['publicKey'],
278
+            Encryption::ID);
279
+
280
+        $encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], $password);
281
+        $header = $this->crypt->generateHeader();
282
+
283
+        if ($encryptedKey) {
284
+            $this->setSystemPrivateKey($this->getRecoveryKeyId(), $header . $encryptedKey);
285
+            return true;
286
+        }
287
+        return false;
288
+    }
289
+
290
+    /**
291
+     * @param $userId
292
+     * @param $key
293
+     * @return bool
294
+     */
295
+    public function setPublicKey($userId, $key) {
296
+        return $this->keyStorage->setUserKey($userId, $this->publicKeyId, $key, Encryption::ID);
297
+    }
298
+
299
+    /**
300
+     * @param $userId
301
+     * @param string $key
302
+     * @return bool
303
+     */
304
+    public function setPrivateKey($userId, $key) {
305
+        return $this->keyStorage->setUserKey($userId,
306
+            $this->privateKeyId,
307
+            $key,
308
+            Encryption::ID);
309
+    }
310
+
311
+    /**
312
+     * write file key to key storage
313
+     *
314
+     * @param string $path
315
+     * @param string $key
316
+     * @return boolean
317
+     */
318
+    public function setFileKey($path, $key) {
319
+        return $this->keyStorage->setFileKey($path, $this->fileKeyId, $key, Encryption::ID);
320
+    }
321
+
322
+    /**
323
+     * set all file keys (the file key and the corresponding share keys)
324
+     *
325
+     * @param string $path
326
+     * @param array $keys
327
+     */
328
+    public function setAllFileKeys($path, $keys) {
329
+        $this->setFileKey($path, $keys['data']);
330
+        foreach ($keys['keys'] as $uid => $keyFile) {
331
+            $this->setShareKey($path, $uid, $keyFile);
332
+        }
333
+    }
334
+
335
+    /**
336
+     * write share key to the key storage
337
+     *
338
+     * @param string $path
339
+     * @param string $uid
340
+     * @param string $key
341
+     * @return boolean
342
+     */
343
+    public function setShareKey($path, $uid, $key) {
344
+        $keyId = $uid . '.' . $this->shareKeyId;
345
+        return $this->keyStorage->setFileKey($path, $keyId, $key, Encryption::ID);
346
+    }
347
+
348
+    /**
349
+     * Decrypt private key and store it
350
+     *
351
+     * @param string $uid user id
352
+     * @param string $passPhrase users password
353
+     * @return boolean
354
+     */
355
+    public function init($uid, $passPhrase) {
356
+
357
+        $this->session->setStatus(Session::INIT_EXECUTED);
358
+
359
+        try {
360
+            if($this->util->isMasterKeyEnabled()) {
361
+                $uid = $this->getMasterKeyId();
362
+                $passPhrase = $this->getMasterKeyPassword();
363
+                $privateKey = $this->getSystemPrivateKey($uid);
364
+            } else {
365
+                $privateKey = $this->getPrivateKey($uid);
366
+            }
367
+            $privateKey = $this->crypt->decryptPrivateKey($privateKey, $passPhrase, $uid);
368
+        } catch (PrivateKeyMissingException $e) {
369
+            return false;
370
+        } catch (DecryptionFailedException $e) {
371
+            return false;
372
+        } catch (\Exception $e) {
373
+            $this->log->warning(
374
+                'Could not decrypt the private key from user "' . $uid . '"" during login. ' .
375
+                'Assume password change on the user back-end. Error message: '
376
+                . $e->getMessage()
377
+            );
378
+            return false;
379
+        }
380
+
381
+        if ($privateKey) {
382
+            $this->session->setPrivateKey($privateKey);
383
+            $this->session->setStatus(Session::INIT_SUCCESSFUL);
384
+            return true;
385
+        }
386
+
387
+        return false;
388
+    }
389
+
390
+    /**
391
+     * @param $userId
392
+     * @return string
393
+     * @throws PrivateKeyMissingException
394
+     */
395
+    public function getPrivateKey($userId) {
396
+        $privateKey = $this->keyStorage->getUserKey($userId,
397
+            $this->privateKeyId, Encryption::ID);
398
+
399
+        if (strlen($privateKey) !== 0) {
400
+            return $privateKey;
401
+        }
402
+        throw new PrivateKeyMissingException($userId);
403
+    }
404
+
405
+    /**
406
+     * @param string $path
407
+     * @param $uid
408
+     * @return string
409
+     */
410
+    public function getFileKey($path, $uid) {
411
+        if ($uid === '') {
412
+            $uid = null;
413
+        }
414
+        $publicAccess = is_null($uid);
415
+        $encryptedFileKey = $this->keyStorage->getFileKey($path, $this->fileKeyId, Encryption::ID);
416
+
417
+        if (empty($encryptedFileKey)) {
418
+            return '';
419
+        }
420
+
421
+        if ($this->util->isMasterKeyEnabled()) {
422
+            $uid = $this->getMasterKeyId();
423
+            $shareKey = $this->getShareKey($path, $uid);
424
+            if ($publicAccess) {
425
+                $privateKey = $this->getSystemPrivateKey($uid);
426
+                $privateKey = $this->crypt->decryptPrivateKey($privateKey, $this->getMasterKeyPassword(), $uid);
427
+            } else {
428
+                // when logged in, the master key is already decrypted in the session
429
+                $privateKey = $this->session->getPrivateKey();
430
+            }
431
+        } else if ($publicAccess) {
432
+            // use public share key for public links
433
+            $uid = $this->getPublicShareKeyId();
434
+            $shareKey = $this->getShareKey($path, $uid);
435
+            $privateKey = $this->keyStorage->getSystemUserKey($this->publicShareKeyId . '.privateKey', Encryption::ID);
436
+            $privateKey = $this->crypt->decryptPrivateKey($privateKey);
437
+        } else {
438
+            $shareKey = $this->getShareKey($path, $uid);
439
+            $privateKey = $this->session->getPrivateKey();
440
+        }
441
+
442
+        if ($encryptedFileKey && $shareKey && $privateKey) {
443
+            return $this->crypt->multiKeyDecrypt($encryptedFileKey,
444
+                $shareKey,
445
+                $privateKey);
446
+        }
447
+
448
+        return '';
449
+    }
450
+
451
+    /**
452
+     * Get the current version of a file
453
+     *
454
+     * @param string $path
455
+     * @param View $view
456
+     * @return int
457
+     */
458
+    public function getVersion($path, View $view) {
459
+        $fileInfo = $view->getFileInfo($path);
460
+        if($fileInfo === false) {
461
+            return 0;
462
+        }
463
+        return $fileInfo->getEncryptedVersion();
464
+    }
465
+
466
+    /**
467
+     * Set the current version of a file
468
+     *
469
+     * @param string $path
470
+     * @param int $version
471
+     * @param View $view
472
+     */
473
+    public function setVersion($path, $version, View $view) {
474
+        $fileInfo= $view->getFileInfo($path);
475
+
476
+        if($fileInfo !== false) {
477
+            $cache = $fileInfo->getStorage()->getCache();
478
+            $cache->update($fileInfo->getId(), ['encrypted' => $version, 'encryptedVersion' => $version]);
479
+        }
480
+    }
481
+
482
+    /**
483
+     * get the encrypted file key
484
+     *
485
+     * @param string $path
486
+     * @return string
487
+     */
488
+    public function getEncryptedFileKey($path) {
489
+        $encryptedFileKey = $this->keyStorage->getFileKey($path,
490
+            $this->fileKeyId, Encryption::ID);
491
+
492
+        return $encryptedFileKey;
493
+    }
494
+
495
+    /**
496
+     * delete share key
497
+     *
498
+     * @param string $path
499
+     * @param string $keyId
500
+     * @return boolean
501
+     */
502
+    public function deleteShareKey($path, $keyId) {
503
+        return $this->keyStorage->deleteFileKey(
504
+            $path,
505
+            $keyId . '.' . $this->shareKeyId,
506
+            Encryption::ID);
507
+    }
508
+
509
+
510
+    /**
511
+     * @param $path
512
+     * @param $uid
513
+     * @return mixed
514
+     */
515
+    public function getShareKey($path, $uid) {
516
+        $keyId = $uid . '.' . $this->shareKeyId;
517
+        return $this->keyStorage->getFileKey($path, $keyId, Encryption::ID);
518
+    }
519
+
520
+    /**
521
+     * check if user has a private and a public key
522
+     *
523
+     * @param string $userId
524
+     * @return bool
525
+     * @throws PrivateKeyMissingException
526
+     * @throws PublicKeyMissingException
527
+     */
528
+    public function userHasKeys($userId) {
529
+        $privateKey = $publicKey = true;
530
+        $exception = null;
531
+
532
+        try {
533
+            $this->getPrivateKey($userId);
534
+        } catch (PrivateKeyMissingException $e) {
535
+            $privateKey = false;
536
+            $exception = $e;
537
+        }
538
+        try {
539
+            $this->getPublicKey($userId);
540
+        } catch (PublicKeyMissingException $e) {
541
+            $publicKey = false;
542
+            $exception = $e;
543
+        }
544
+
545
+        if ($privateKey && $publicKey) {
546
+            return true;
547
+        } elseif (!$privateKey && !$publicKey) {
548
+            return false;
549
+        } else {
550
+            throw $exception;
551
+        }
552
+    }
553
+
554
+    /**
555
+     * @param $userId
556
+     * @return mixed
557
+     * @throws PublicKeyMissingException
558
+     */
559
+    public function getPublicKey($userId) {
560
+        $publicKey = $this->keyStorage->getUserKey($userId, $this->publicKeyId, Encryption::ID);
561
+
562
+        if (strlen($publicKey) !== 0) {
563
+            return $publicKey;
564
+        }
565
+        throw new PublicKeyMissingException($userId);
566
+    }
567
+
568
+    public function getPublicShareKeyId() {
569
+        return $this->publicShareKeyId;
570
+    }
571
+
572
+    /**
573
+     * get public key for public link shares
574
+     *
575
+     * @return string
576
+     */
577
+    public function getPublicShareKey() {
578
+        return $this->keyStorage->getSystemUserKey($this->publicShareKeyId . '.publicKey', Encryption::ID);
579
+    }
580
+
581
+    /**
582
+     * @param string $purpose
583
+     * @param string $uid
584
+     */
585
+    public function backupUserKeys($purpose, $uid) {
586
+        $this->keyStorage->backupUserKeys(Encryption::ID, $purpose, $uid);
587
+    }
588
+
589
+    /**
590
+     * creat a backup of the users private and public key and then  delete it
591
+     *
592
+     * @param string $uid
593
+     */
594
+    public function deleteUserKeys($uid) {
595
+        $this->deletePublicKey($uid);
596
+        $this->deletePrivateKey($uid);
597
+    }
598
+
599
+    /**
600
+     * @param $uid
601
+     * @return bool
602
+     */
603
+    public function deletePublicKey($uid) {
604
+        return $this->keyStorage->deleteUserKey($uid, $this->publicKeyId, Encryption::ID);
605
+    }
606
+
607
+    /**
608
+     * @param string $uid
609
+     * @return bool
610
+     */
611
+    private function deletePrivateKey($uid) {
612
+        return $this->keyStorage->deleteUserKey($uid, $this->privateKeyId, Encryption::ID);
613
+    }
614
+
615
+    /**
616
+     * @param string $path
617
+     * @return bool
618
+     */
619
+    public function deleteAllFileKeys($path) {
620
+        return $this->keyStorage->deleteAllFileKeys($path);
621
+    }
622
+
623
+    /**
624
+     * @param array $userIds
625
+     * @return array
626
+     * @throws PublicKeyMissingException
627
+     */
628
+    public function getPublicKeys(array $userIds) {
629
+        $keys = [];
630
+
631
+        foreach ($userIds as $userId) {
632
+            try {
633
+                $keys[$userId] = $this->getPublicKey($userId);
634
+            } catch (PublicKeyMissingException $e) {
635
+                continue;
636
+            }
637
+        }
638
+
639
+        return $keys;
640
+
641
+    }
642
+
643
+    /**
644
+     * @param string $keyId
645
+     * @return string returns openssl key
646
+     */
647
+    public function getSystemPrivateKey($keyId) {
648
+        return $this->keyStorage->getSystemUserKey($keyId . '.' . $this->privateKeyId, Encryption::ID);
649
+    }
650
+
651
+    /**
652
+     * @param string $keyId
653
+     * @param string $key
654
+     * @return string returns openssl key
655
+     */
656
+    public function setSystemPrivateKey($keyId, $key) {
657
+        return $this->keyStorage->setSystemUserKey(
658
+            $keyId . '.' . $this->privateKeyId,
659
+            $key,
660
+            Encryption::ID);
661
+    }
662
+
663
+    /**
664
+     * add system keys such as the public share key and the recovery key
665
+     *
666
+     * @param array $accessList
667
+     * @param array $publicKeys
668
+     * @param string $uid
669
+     * @return array
670
+     * @throws PublicKeyMissingException
671
+     */
672
+    public function addSystemKeys(array $accessList, array $publicKeys, $uid) {
673
+        if (!empty($accessList['public'])) {
674
+            $publicShareKey = $this->getPublicShareKey();
675
+            if (empty($publicShareKey)) {
676
+                throw new PublicKeyMissingException($this->getPublicShareKeyId());
677
+            }
678
+            $publicKeys[$this->getPublicShareKeyId()] = $publicShareKey;
679
+        }
680
+
681
+        if ($this->recoveryKeyExists() &&
682
+            $this->util->isRecoveryEnabledForUser($uid)) {
683
+
684
+            $publicKeys[$this->getRecoveryKeyId()] = $this->getRecoveryKey();
685
+        }
686
+
687
+        return $publicKeys;
688
+    }
689
+
690
+    /**
691
+     * get master key password
692
+     *
693
+     * @return string
694
+     * @throws \Exception
695
+     */
696
+    public function getMasterKeyPassword() {
697
+        $password = $this->config->getSystemValue('secret');
698
+        if (empty($password)){
699
+            throw new \Exception('Can not get secret from Nextcloud instance');
700
+        }
701
+
702
+        return $password;
703
+    }
704
+
705
+    /**
706
+     * return master key id
707
+     *
708
+     * @return string
709
+     */
710
+    public function getMasterKeyId() {
711
+        return $this->masterKeyId;
712
+    }
713
+
714
+    /**
715
+     * get public master key
716
+     *
717
+     * @return string
718
+     */
719
+    public function getPublicMasterKey() {
720
+        return $this->keyStorage->getSystemUserKey($this->masterKeyId . '.publicKey', Encryption::ID);
721
+    }
722 722
 }
Please login to merge, or discard this patch.
Spacing   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -126,7 +126,7 @@  discard block
 block discarded – undo
126 126
 		$this->recoveryKeyId = $this->config->getAppValue('encryption',
127 127
 			'recoveryKeyId');
128 128
 		if (empty($this->recoveryKeyId)) {
129
-			$this->recoveryKeyId = 'recoveryKey_' . substr(md5(time()), 0, 8);
129
+			$this->recoveryKeyId = 'recoveryKey_'.substr(md5(time()), 0, 8);
130 130
 			$this->config->setAppValue('encryption',
131 131
 				'recoveryKeyId',
132 132
 				$this->recoveryKeyId);
@@ -135,14 +135,14 @@  discard block
 block discarded – undo
135 135
 		$this->publicShareKeyId = $this->config->getAppValue('encryption',
136 136
 			'publicShareKeyId');
137 137
 		if (empty($this->publicShareKeyId)) {
138
-			$this->publicShareKeyId = 'pubShare_' . substr(md5(time()), 0, 8);
138
+			$this->publicShareKeyId = 'pubShare_'.substr(md5(time()), 0, 8);
139 139
 			$this->config->setAppValue('encryption', 'publicShareKeyId', $this->publicShareKeyId);
140 140
 		}
141 141
 
142 142
 		$this->masterKeyId = $this->config->getAppValue('encryption',
143 143
 			'masterKeyId');
144 144
 		if (empty($this->masterKeyId)) {
145
-			$this->masterKeyId = 'master_' . substr(md5(time()), 0, 8);
145
+			$this->masterKeyId = 'master_'.substr(md5(time()), 0, 8);
146 146
 			$this->config->setAppValue('encryption', 'masterKeyId', $this->masterKeyId);
147 147
 		}
148 148
 
@@ -160,13 +160,13 @@  discard block
 block discarded – undo
160 160
 
161 161
 			// Save public key
162 162
 			$this->keyStorage->setSystemUserKey(
163
-				$this->publicShareKeyId . '.publicKey', $keyPair['publicKey'],
163
+				$this->publicShareKeyId.'.publicKey', $keyPair['publicKey'],
164 164
 				Encryption::ID);
165 165
 
166 166
 			// Encrypt private key empty passphrase
167 167
 			$encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], '');
168 168
 			$header = $this->crypt->generateHeader();
169
-			$this->setSystemPrivateKey($this->publicShareKeyId, $header . $encryptedKey);
169
+			$this->setSystemPrivateKey($this->publicShareKeyId, $header.$encryptedKey);
170 170
 		}
171 171
 	}
172 172
 
@@ -185,13 +185,13 @@  discard block
 block discarded – undo
185 185
 
186 186
 			// Save public key
187 187
 			$this->keyStorage->setSystemUserKey(
188
-				$this->masterKeyId . '.publicKey', $keyPair['publicKey'],
188
+				$this->masterKeyId.'.publicKey', $keyPair['publicKey'],
189 189
 				Encryption::ID);
190 190
 
191 191
 			// Encrypt private key with system password
192 192
 			$encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], $this->getMasterKeyPassword(), $this->masterKeyId);
193 193
 			$header = $this->crypt->generateHeader();
194
-			$this->setSystemPrivateKey($this->masterKeyId, $header . $encryptedKey);
194
+			$this->setSystemPrivateKey($this->masterKeyId, $header.$encryptedKey);
195 195
 		}
196 196
 
197 197
 		if (!$this->session->isPrivateKeySet()) {
@@ -218,7 +218,7 @@  discard block
 block discarded – undo
218 218
 	 * @return string
219 219
 	 */
220 220
 	public function getRecoveryKey() {
221
-		return $this->keyStorage->getSystemUserKey($this->recoveryKeyId . '.publicKey', Encryption::ID);
221
+		return $this->keyStorage->getSystemUserKey($this->recoveryKeyId.'.publicKey', Encryption::ID);
222 222
 	}
223 223
 
224 224
 	/**
@@ -235,7 +235,7 @@  discard block
 block discarded – undo
235 235
 	 * @return bool
236 236
 	 */
237 237
 	public function checkRecoveryPassword($password) {
238
-		$recoveryKey = $this->keyStorage->getSystemUserKey($this->recoveryKeyId . '.privateKey', Encryption::ID);
238
+		$recoveryKey = $this->keyStorage->getSystemUserKey($this->recoveryKeyId.'.privateKey', Encryption::ID);
239 239
 		$decryptedRecoveryKey = $this->crypt->decryptPrivateKey($recoveryKey, $password);
240 240
 
241 241
 		if ($decryptedRecoveryKey) {
@@ -259,7 +259,7 @@  discard block
 block discarded – undo
259 259
 		$header = $this->crypt->generateHeader();
260 260
 
261 261
 		if ($encryptedKey) {
262
-			$this->setPrivateKey($uid, $header . $encryptedKey);
262
+			$this->setPrivateKey($uid, $header.$encryptedKey);
263 263
 			return true;
264 264
 		}
265 265
 		return false;
@@ -281,7 +281,7 @@  discard block
 block discarded – undo
281 281
 		$header = $this->crypt->generateHeader();
282 282
 
283 283
 		if ($encryptedKey) {
284
-			$this->setSystemPrivateKey($this->getRecoveryKeyId(), $header . $encryptedKey);
284
+			$this->setSystemPrivateKey($this->getRecoveryKeyId(), $header.$encryptedKey);
285 285
 			return true;
286 286
 		}
287 287
 		return false;
@@ -341,7 +341,7 @@  discard block
 block discarded – undo
341 341
 	 * @return boolean
342 342
 	 */
343 343
 	public function setShareKey($path, $uid, $key) {
344
-		$keyId = $uid . '.' . $this->shareKeyId;
344
+		$keyId = $uid.'.'.$this->shareKeyId;
345 345
 		return $this->keyStorage->setFileKey($path, $keyId, $key, Encryption::ID);
346 346
 	}
347 347
 
@@ -357,7 +357,7 @@  discard block
 block discarded – undo
357 357
 		$this->session->setStatus(Session::INIT_EXECUTED);
358 358
 
359 359
 		try {
360
-			if($this->util->isMasterKeyEnabled()) {
360
+			if ($this->util->isMasterKeyEnabled()) {
361 361
 				$uid = $this->getMasterKeyId();
362 362
 				$passPhrase = $this->getMasterKeyPassword();
363 363
 				$privateKey = $this->getSystemPrivateKey($uid);
@@ -371,7 +371,7 @@  discard block
 block discarded – undo
371 371
 			return false;
372 372
 		} catch (\Exception $e) {
373 373
 			$this->log->warning(
374
-				'Could not decrypt the private key from user "' . $uid . '"" during login. ' .
374
+				'Could not decrypt the private key from user "'.$uid.'"" during login. '.
375 375
 				'Assume password change on the user back-end. Error message: '
376 376
 				. $e->getMessage()
377 377
 			);
@@ -432,7 +432,7 @@  discard block
 block discarded – undo
432 432
 			// use public share key for public links
433 433
 			$uid = $this->getPublicShareKeyId();
434 434
 			$shareKey = $this->getShareKey($path, $uid);
435
-			$privateKey = $this->keyStorage->getSystemUserKey($this->publicShareKeyId . '.privateKey', Encryption::ID);
435
+			$privateKey = $this->keyStorage->getSystemUserKey($this->publicShareKeyId.'.privateKey', Encryption::ID);
436 436
 			$privateKey = $this->crypt->decryptPrivateKey($privateKey);
437 437
 		} else {
438 438
 			$shareKey = $this->getShareKey($path, $uid);
@@ -457,7 +457,7 @@  discard block
 block discarded – undo
457 457
 	 */
458 458
 	public function getVersion($path, View $view) {
459 459
 		$fileInfo = $view->getFileInfo($path);
460
-		if($fileInfo === false) {
460
+		if ($fileInfo === false) {
461 461
 			return 0;
462 462
 		}
463 463
 		return $fileInfo->getEncryptedVersion();
@@ -471,9 +471,9 @@  discard block
 block discarded – undo
471 471
 	 * @param View $view
472 472
 	 */
473 473
 	public function setVersion($path, $version, View $view) {
474
-		$fileInfo= $view->getFileInfo($path);
474
+		$fileInfo = $view->getFileInfo($path);
475 475
 
476
-		if($fileInfo !== false) {
476
+		if ($fileInfo !== false) {
477 477
 			$cache = $fileInfo->getStorage()->getCache();
478 478
 			$cache->update($fileInfo->getId(), ['encrypted' => $version, 'encryptedVersion' => $version]);
479 479
 		}
@@ -502,7 +502,7 @@  discard block
 block discarded – undo
502 502
 	public function deleteShareKey($path, $keyId) {
503 503
 		return $this->keyStorage->deleteFileKey(
504 504
 			$path,
505
-			$keyId . '.' . $this->shareKeyId,
505
+			$keyId.'.'.$this->shareKeyId,
506 506
 			Encryption::ID);
507 507
 	}
508 508
 
@@ -513,7 +513,7 @@  discard block
 block discarded – undo
513 513
 	 * @return mixed
514 514
 	 */
515 515
 	public function getShareKey($path, $uid) {
516
-		$keyId = $uid . '.' . $this->shareKeyId;
516
+		$keyId = $uid.'.'.$this->shareKeyId;
517 517
 		return $this->keyStorage->getFileKey($path, $keyId, Encryption::ID);
518 518
 	}
519 519
 
@@ -575,7 +575,7 @@  discard block
 block discarded – undo
575 575
 	 * @return string
576 576
 	 */
577 577
 	public function getPublicShareKey() {
578
-		return $this->keyStorage->getSystemUserKey($this->publicShareKeyId . '.publicKey', Encryption::ID);
578
+		return $this->keyStorage->getSystemUserKey($this->publicShareKeyId.'.publicKey', Encryption::ID);
579 579
 	}
580 580
 
581 581
 	/**
@@ -645,7 +645,7 @@  discard block
 block discarded – undo
645 645
 	 * @return string returns openssl key
646 646
 	 */
647 647
 	public function getSystemPrivateKey($keyId) {
648
-		return $this->keyStorage->getSystemUserKey($keyId . '.' . $this->privateKeyId, Encryption::ID);
648
+		return $this->keyStorage->getSystemUserKey($keyId.'.'.$this->privateKeyId, Encryption::ID);
649 649
 	}
650 650
 
651 651
 	/**
@@ -655,7 +655,7 @@  discard block
 block discarded – undo
655 655
 	 */
656 656
 	public function setSystemPrivateKey($keyId, $key) {
657 657
 		return $this->keyStorage->setSystemUserKey(
658
-			$keyId . '.' . $this->privateKeyId,
658
+			$keyId.'.'.$this->privateKeyId,
659 659
 			$key,
660 660
 			Encryption::ID);
661 661
 	}
@@ -695,7 +695,7 @@  discard block
 block discarded – undo
695 695
 	 */
696 696
 	public function getMasterKeyPassword() {
697 697
 		$password = $this->config->getSystemValue('secret');
698
-		if (empty($password)){
698
+		if (empty($password)) {
699 699
 			throw new \Exception('Can not get secret from Nextcloud instance');
700 700
 		}
701 701
 
@@ -717,6 +717,6 @@  discard block
 block discarded – undo
717 717
 	 * @return string
718 718
 	 */
719 719
 	public function getPublicMasterKey() {
720
-		return $this->keyStorage->getSystemUserKey($this->masterKeyId . '.publicKey', Encryption::ID);
720
+		return $this->keyStorage->getSystemUserKey($this->masterKeyId.'.publicKey', Encryption::ID);
721 721
 	}
722 722
 }
Please login to merge, or discard this patch.
settings/Controller/UsersController.php 1 patch
Indentation   +956 added lines, -956 removed lines patch added patch discarded remove patch
@@ -60,961 +60,961 @@
 block discarded – undo
60 60
  * @package OC\Settings\Controller
61 61
  */
62 62
 class UsersController extends Controller {
63
-	/** @var IL10N */
64
-	private $l10n;
65
-	/** @var IUserSession */
66
-	private $userSession;
67
-	/** @var bool */
68
-	private $isAdmin;
69
-	/** @var IUserManager */
70
-	private $userManager;
71
-	/** @var IGroupManager */
72
-	private $groupManager;
73
-	/** @var IConfig */
74
-	private $config;
75
-	/** @var ILogger */
76
-	private $log;
77
-	/** @var IMailer */
78
-	private $mailer;
79
-	/** @var bool contains the state of the encryption app */
80
-	private $isEncryptionAppEnabled;
81
-	/** @var bool contains the state of the admin recovery setting */
82
-	private $isRestoreEnabled = false;
83
-	/** @var IAppManager */
84
-	private $appManager;
85
-	/** @var IAvatarManager */
86
-	private $avatarManager;
87
-	/** @var AccountManager */
88
-	private $accountManager;
89
-	/** @var ISecureRandom */
90
-	private $secureRandom;
91
-	/** @var NewUserMailHelper */
92
-	private $newUserMailHelper;
93
-	/** @var ITimeFactory */
94
-	private $timeFactory;
95
-	/** @var ICrypto */
96
-	private $crypto;
97
-	/** @var Manager */
98
-	private $keyManager;
99
-	/** @var IJobList */
100
-	private $jobList;
101
-	/** @var IManager */
102
-	private $encryptionManager;
103
-
104
-	/**
105
-	 * @param string $appName
106
-	 * @param IRequest $request
107
-	 * @param IUserManager $userManager
108
-	 * @param IGroupManager $groupManager
109
-	 * @param IUserSession $userSession
110
-	 * @param IConfig $config
111
-	 * @param bool $isAdmin
112
-	 * @param IL10N $l10n
113
-	 * @param ILogger $log
114
-	 * @param IMailer $mailer
115
-	 * @param IURLGenerator $urlGenerator
116
-	 * @param IAppManager $appManager
117
-	 * @param IAvatarManager $avatarManager
118
-	 * @param AccountManager $accountManager
119
-	 * @param ISecureRandom $secureRandom
120
-	 * @param NewUserMailHelper $newUserMailHelper
121
-	 * @param ITimeFactory $timeFactory
122
-	 * @param ICrypto $crypto
123
-	 * @param Manager $keyManager
124
-	 * @param IJobList $jobList
125
-	 * @param IManager $encryptionManager
126
-	 */
127
-	public function __construct($appName,
128
-								IRequest $request,
129
-								IUserManager $userManager,
130
-								IGroupManager $groupManager,
131
-								IUserSession $userSession,
132
-								IConfig $config,
133
-								$isAdmin,
134
-								IL10N $l10n,
135
-								ILogger $log,
136
-								IMailer $mailer,
137
-								IURLGenerator $urlGenerator,
138
-								IAppManager $appManager,
139
-								IAvatarManager $avatarManager,
140
-								AccountManager $accountManager,
141
-								ISecureRandom $secureRandom,
142
-								NewUserMailHelper $newUserMailHelper,
143
-								ITimeFactory $timeFactory,
144
-								ICrypto $crypto,
145
-								Manager $keyManager,
146
-								IJobList $jobList,
147
-								IManager $encryptionManager) {
148
-		parent::__construct($appName, $request);
149
-		$this->userManager = $userManager;
150
-		$this->groupManager = $groupManager;
151
-		$this->userSession = $userSession;
152
-		$this->config = $config;
153
-		$this->isAdmin = $isAdmin;
154
-		$this->l10n = $l10n;
155
-		$this->log = $log;
156
-		$this->mailer = $mailer;
157
-		$this->appManager = $appManager;
158
-		$this->avatarManager = $avatarManager;
159
-		$this->accountManager = $accountManager;
160
-		$this->secureRandom = $secureRandom;
161
-		$this->newUserMailHelper = $newUserMailHelper;
162
-		$this->timeFactory = $timeFactory;
163
-		$this->crypto = $crypto;
164
-		$this->keyManager = $keyManager;
165
-		$this->jobList = $jobList;
166
-		$this->encryptionManager = $encryptionManager;
167
-
168
-		// check for encryption state - TODO see formatUserForIndex
169
-		$this->isEncryptionAppEnabled = $appManager->isEnabledForUser('encryption');
170
-		if($this->isEncryptionAppEnabled) {
171
-			// putting this directly in empty is possible in PHP 5.5+
172
-			$result = $config->getAppValue('encryption', 'recoveryAdminEnabled', 0);
173
-			$this->isRestoreEnabled = !empty($result);
174
-		}
175
-	}
176
-
177
-	/**
178
-	 * @param IUser $user
179
-	 * @param array $userGroups
180
-	 * @return array
181
-	 */
182
-	private function formatUserForIndex(IUser $user, array $userGroups = null) {
183
-
184
-		// TODO: eliminate this encryption specific code below and somehow
185
-		// hook in additional user info from other apps
186
-
187
-		// recovery isn't possible if admin or user has it disabled and encryption
188
-		// is enabled - so we eliminate the else paths in the conditional tree
189
-		// below
190
-		$restorePossible = false;
191
-
192
-		if ($this->isEncryptionAppEnabled) {
193
-			if ($this->isRestoreEnabled) {
194
-				// check for the users recovery setting
195
-				$recoveryMode = $this->config->getUserValue($user->getUID(), 'encryption', 'recoveryEnabled', '0');
196
-				// method call inside empty is possible with PHP 5.5+
197
-				$recoveryModeEnabled = !empty($recoveryMode);
198
-				if ($recoveryModeEnabled) {
199
-					// user also has recovery mode enabled
200
-					$restorePossible = true;
201
-				}
202
-			} else {
203
-				$modules = $this->encryptionManager->getEncryptionModules();
204
-				$restorePossible = true;
205
-				foreach ($modules as $id => $module) {
206
-					/* @var IEncryptionModule $instance */
207
-					$instance = call_user_func($module['callback']);
208
-					if ($instance->needDetailedAccessList()) {
209
-						$restorePossible = false;
210
-						break;
211
-					}
212
-				}
213
-			}
214
-		} else {
215
-			// recovery is possible if encryption is disabled (plain files are
216
-			// available)
217
-			$restorePossible = true;
218
-		}
219
-
220
-		$subAdminGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($user);
221
-		foreach($subAdminGroups as $key => $subAdminGroup) {
222
-			$subAdminGroups[$key] = $subAdminGroup->getGID();
223
-		}
224
-
225
-		$displayName = $user->getEMailAddress();
226
-		if (is_null($displayName)) {
227
-			$displayName = '';
228
-		}
229
-
230
-		$avatarAvailable = false;
231
-		try {
232
-			$avatarAvailable = $this->avatarManager->getAvatar($user->getUID())->exists();
233
-		} catch (\Exception $e) {
234
-			//No avatar yet
235
-		}
236
-
237
-		return [
238
-			'name' => $user->getUID(),
239
-			'displayname' => $user->getDisplayName(),
240
-			'groups' => (empty($userGroups)) ? $this->groupManager->getUserGroupIds($user) : $userGroups,
241
-			'subadmin' => $subAdminGroups,
242
-			'quota' => $user->getQuota(),
243
-			'storageLocation' => $user->getHome(),
244
-			'lastLogin' => $user->getLastLogin() * 1000,
245
-			'backend' => $user->getBackendClassName(),
246
-			'email' => $displayName,
247
-			'isRestoreDisabled' => !$restorePossible,
248
-			'isAvatarAvailable' => $avatarAvailable,
249
-			'isEnabled' => $user->isEnabled(),
250
-		];
251
-	}
252
-
253
-	/**
254
-	 * @param array $userIDs Array with schema [$uid => $displayName]
255
-	 * @return IUser[]
256
-	 */
257
-	private function getUsersForUID(array $userIDs) {
258
-		$users = [];
259
-		foreach ($userIDs as $uid => $displayName) {
260
-			$users[$uid] = $this->userManager->get($uid);
261
-		}
262
-		return $users;
263
-	}
264
-
265
-	/**
266
-	 * @NoAdminRequired
267
-	 *
268
-	 * @param int $offset
269
-	 * @param int $limit
270
-	 * @param string $gid GID to filter for
271
-	 * @param string $pattern Pattern to search for in the username
272
-	 * @param string $backend Backend to filter for (class-name)
273
-	 * @return DataResponse
274
-	 *
275
-	 * TODO: Tidy up and write unit tests - code is mainly static method calls
276
-	 */
277
-	public function index($offset = 0, $limit = 10, $gid = '', $pattern = '', $backend = '') {
278
-		// Remove backends
279
-		if(!empty($backend)) {
280
-			$activeBackends = $this->userManager->getBackends();
281
-			$this->userManager->clearBackends();
282
-			foreach($activeBackends as $singleActiveBackend) {
283
-				if($backend === get_class($singleActiveBackend)) {
284
-					$this->userManager->registerBackend($singleActiveBackend);
285
-					break;
286
-				}
287
-			}
288
-		}
289
-
290
-		$users = [];
291
-		if ($this->isAdmin) {
292
-			if($gid !== '' && $gid !== '_disabledUsers') {
293
-				$batch = $this->getUsersForUID($this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset));
294
-			} else {
295
-				$batch = $this->userManager->search($pattern, $limit, $offset);
296
-			}
297
-
298
-			foreach ($batch as $user) {
299
-				if( ($gid !== '_disabledUsers' && $user->isEnabled()) ||
300
-					($gid === '_disabledUsers' && !$user->isEnabled())
301
-				) {
302
-					$users[] = $this->formatUserForIndex($user);
303
-				}
304
-			}
305
-
306
-		} else {
307
-			$subAdminOfGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
308
-			// New class returns IGroup[] so convert back
309
-			$gids = [];
310
-			foreach ($subAdminOfGroups as $group) {
311
-				$gids[] = $group->getGID();
312
-			}
313
-			$subAdminOfGroups = $gids;
314
-
315
-			// Set the $gid parameter to an empty value if the subadmin has no rights to access a specific group
316
-			if($gid !== '' && $gid !== '_disabledUsers' && !in_array($gid, $subAdminOfGroups)) {
317
-				$gid = '';
318
-			}
319
-
320
-			// Batch all groups the user is subadmin of when a group is specified
321
-			$batch = [];
322
-			if($gid === '') {
323
-				foreach($subAdminOfGroups as $group) {
324
-					$groupUsers = $this->groupManager->displayNamesInGroup($group, $pattern, $limit, $offset);
325
-
326
-					foreach($groupUsers as $uid => $displayName) {
327
-						$batch[$uid] = $displayName;
328
-					}
329
-				}
330
-			} else {
331
-				$batch = $this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset);
332
-			}
333
-			$batch = $this->getUsersForUID($batch);
334
-
335
-			foreach ($batch as $user) {
336
-				// Only add the groups, this user is a subadmin of
337
-				$userGroups = array_values(array_intersect(
338
-					$this->groupManager->getUserGroupIds($user),
339
-					$subAdminOfGroups
340
-				));
341
-				if( ($gid !== '_disabledUsers' && $user->isEnabled()) ||
342
-					($gid === '_disabledUsers' && !$user->isEnabled())
343
-				) {
344
-					$users[] = $this->formatUserForIndex($user, $userGroups);
345
-				}
346
-			}
347
-		}
348
-
349
-		return new DataResponse($users);
350
-	}
351
-
352
-	/**
353
-	 * @NoAdminRequired
354
-	 * @PasswordConfirmationRequired
355
-	 *
356
-	 * @param string $username
357
-	 * @param string $password
358
-	 * @param array $groups
359
-	 * @param string $email
360
-	 * @return DataResponse
361
-	 */
362
-	public function create($username, $password, array $groups=[], $email='') {
363
-		if($email !== '' && !$this->mailer->validateMailAddress($email)) {
364
-			return new DataResponse(
365
-				[
366
-					'message' => (string)$this->l10n->t('Invalid mail address')
367
-				],
368
-				Http::STATUS_UNPROCESSABLE_ENTITY
369
-			);
370
-		}
371
-
372
-		$currentUser = $this->userSession->getUser();
373
-
374
-		if (!$this->isAdmin) {
375
-			if (!empty($groups)) {
376
-				foreach ($groups as $key => $group) {
377
-					$groupObject = $this->groupManager->get($group);
378
-					if($groupObject === null) {
379
-						unset($groups[$key]);
380
-						continue;
381
-					}
382
-
383
-					if (!$this->groupManager->getSubAdmin()->isSubAdminofGroup($currentUser, $groupObject)) {
384
-						unset($groups[$key]);
385
-					}
386
-				}
387
-			}
388
-
389
-			if (empty($groups)) {
390
-				return new DataResponse(
391
-					[
392
-						'message' => $this->l10n->t('No valid group selected'),
393
-					],
394
-					Http::STATUS_FORBIDDEN
395
-				);
396
-			}
397
-		}
398
-
399
-		if ($this->userManager->userExists($username)) {
400
-			return new DataResponse(
401
-				[
402
-					'message' => (string)$this->l10n->t('A user with that name already exists.')
403
-				],
404
-				Http::STATUS_CONFLICT
405
-			);
406
-		}
407
-
408
-		$generatePasswordResetToken = false;
409
-		if ($password === '') {
410
-			if ($email === '') {
411
-				return new DataResponse(
412
-					[
413
-						'message' => (string)$this->l10n->t('To send a password link to the user an email address is required.')
414
-					],
415
-					Http::STATUS_UNPROCESSABLE_ENTITY
416
-				);
417
-			}
418
-
419
-			$password = $this->secureRandom->generate(32);
420
-			$generatePasswordResetToken = true;
421
-		}
422
-
423
-		try {
424
-			$user = $this->userManager->createUser($username, $password);
425
-		} catch (\Exception $exception) {
426
-			$message = $exception->getMessage();
427
-			if (!$message) {
428
-				$message = $this->l10n->t('Unable to create user.');
429
-			}
430
-			return new DataResponse(
431
-				[
432
-					'message' => (string) $message,
433
-				],
434
-				Http::STATUS_FORBIDDEN
435
-			);
436
-		}
437
-
438
-		if($user instanceof IUser) {
439
-			if($groups !== null) {
440
-				foreach($groups as $groupName) {
441
-					$group = $this->groupManager->get($groupName);
442
-
443
-					if(empty($group)) {
444
-						$group = $this->groupManager->createGroup($groupName);
445
-					}
446
-					$group->addUser($user);
447
-				}
448
-			}
449
-			/**
450
-			 * Send new user mail only if a mail is set
451
-			 */
452
-			if($email !== '') {
453
-				$user->setEMailAddress($email);
454
-				try {
455
-					$emailTemplate = $this->newUserMailHelper->generateTemplate($user, $generatePasswordResetToken);
456
-					$this->newUserMailHelper->sendMail($user, $emailTemplate);
457
-				} catch(\Exception $e) {
458
-					$this->log->error("Can't send new user mail to $email: " . $e->getMessage(), ['app' => 'settings']);
459
-				}
460
-			}
461
-			// fetch users groups
462
-			$userGroups = $this->groupManager->getUserGroupIds($user);
463
-
464
-			return new DataResponse(
465
-				$this->formatUserForIndex($user, $userGroups),
466
-				Http::STATUS_CREATED
467
-			);
468
-		}
469
-
470
-		return new DataResponse(
471
-			[
472
-				'message' => (string) $this->l10n->t('Unable to create user.')
473
-			],
474
-			Http::STATUS_FORBIDDEN
475
-		);
476
-
477
-	}
478
-
479
-	/**
480
-	 * @NoAdminRequired
481
-	 * @PasswordConfirmationRequired
482
-	 *
483
-	 * @param string $id
484
-	 * @return DataResponse
485
-	 */
486
-	public function destroy($id) {
487
-		$userId = $this->userSession->getUser()->getUID();
488
-		$user = $this->userManager->get($id);
489
-
490
-		if($userId === $id) {
491
-			return new DataResponse(
492
-				[
493
-					'status' => 'error',
494
-					'data' => [
495
-						'message' => (string) $this->l10n->t('Unable to delete user.')
496
-					]
497
-				],
498
-				Http::STATUS_FORBIDDEN
499
-			);
500
-		}
501
-
502
-		if(!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
503
-			return new DataResponse(
504
-				[
505
-					'status' => 'error',
506
-					'data' => [
507
-						'message' => (string)$this->l10n->t('Authentication error')
508
-					]
509
-				],
510
-				Http::STATUS_FORBIDDEN
511
-			);
512
-		}
513
-
514
-		if($user) {
515
-			if($user->delete()) {
516
-				return new DataResponse(
517
-					[
518
-						'status' => 'success',
519
-						'data' => [
520
-							'username' => $id
521
-						]
522
-					],
523
-					Http::STATUS_NO_CONTENT
524
-				);
525
-			}
526
-		}
527
-
528
-		return new DataResponse(
529
-			[
530
-				'status' => 'error',
531
-				'data' => [
532
-					'message' => (string)$this->l10n->t('Unable to delete user.')
533
-				]
534
-			],
535
-			Http::STATUS_FORBIDDEN
536
-		);
537
-	}
538
-
539
-	/**
540
-	 * @NoAdminRequired
541
-	 *
542
-	 * @param string $id
543
-	 * @param int $enabled
544
-	 * @return DataResponse
545
-	 */
546
-	public function setEnabled($id, $enabled) {
547
-		$enabled = (bool)$enabled;
548
-		if($enabled) {
549
-			$errorMsgGeneral = (string) $this->l10n->t('Error while enabling user.');
550
-		} else {
551
-			$errorMsgGeneral = (string) $this->l10n->t('Error while disabling user.');
552
-		}
553
-
554
-		$userId = $this->userSession->getUser()->getUID();
555
-		$user = $this->userManager->get($id);
556
-
557
-		if ($userId === $id) {
558
-			return new DataResponse(
559
-				[
560
-					'status' => 'error',
561
-					'data' => [
562
-						'message' => $errorMsgGeneral
563
-					]
564
-				], Http::STATUS_FORBIDDEN
565
-			);
566
-		}
567
-
568
-		if($user) {
569
-			if (!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
570
-				return new DataResponse(
571
-					[
572
-						'status' => 'error',
573
-						'data' => [
574
-							'message' => (string) $this->l10n->t('Authentication error')
575
-						]
576
-					],
577
-					Http::STATUS_FORBIDDEN
578
-				);
579
-			}
580
-
581
-			$user->setEnabled($enabled);
582
-			return new DataResponse(
583
-				[
584
-					'status' => 'success',
585
-					'data' => [
586
-						'username' => $id,
587
-						'enabled' => $enabled
588
-					]
589
-				]
590
-			);
591
-		} else {
592
-			return new DataResponse(
593
-				[
594
-					'status' => 'error',
595
-					'data' => [
596
-						'message' => $errorMsgGeneral
597
-					]
598
-				],
599
-				Http::STATUS_FORBIDDEN
600
-			);
601
-		}
602
-
603
-	}
604
-
605
-	/**
606
-	 * Set the mail address of a user
607
-	 *
608
-	 * @NoAdminRequired
609
-	 * @NoSubadminRequired
610
-	 * @PasswordConfirmationRequired
611
-	 *
612
-	 * @param string $account
613
-	 * @param bool $onlyVerificationCode only return verification code without updating the data
614
-	 * @return DataResponse
615
-	 */
616
-	public function getVerificationCode($account, $onlyVerificationCode) {
617
-
618
-		$user = $this->userSession->getUser();
619
-
620
-		if ($user === null) {
621
-			return new DataResponse([], Http::STATUS_BAD_REQUEST);
622
-		}
623
-
624
-		$accountData = $this->accountManager->getUser($user);
625
-		$cloudId = $user->getCloudId();
626
-		$message = "Use my Federated Cloud ID to share with me: " . $cloudId;
627
-		$signature = $this->signMessage($user, $message);
628
-
629
-		$code = $message . ' ' . $signature;
630
-		$codeMd5 = $message . ' ' . md5($signature);
631
-
632
-		switch ($account) {
633
-			case 'verify-twitter':
634
-				$accountData[AccountManager::PROPERTY_TWITTER]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
635
-				$msg = $this->l10n->t('In order to verify your Twitter account, post the following tweet on Twitter (please make sure to post it without any line breaks):');
636
-				$code = $codeMd5;
637
-				$type = AccountManager::PROPERTY_TWITTER;
638
-				$data = $accountData[AccountManager::PROPERTY_TWITTER]['value'];
639
-				$accountData[AccountManager::PROPERTY_TWITTER]['signature'] = $signature;
640
-				break;
641
-			case 'verify-website':
642
-				$accountData[AccountManager::PROPERTY_WEBSITE]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
643
-				$msg = $this->l10n->t('In order to verify your Website, store the following content in your web-root at \'.well-known/CloudIdVerificationCode.txt\' (please make sure that the complete text is in one line):');
644
-				$type = AccountManager::PROPERTY_WEBSITE;
645
-				$data = $accountData[AccountManager::PROPERTY_WEBSITE]['value'];
646
-				$accountData[AccountManager::PROPERTY_WEBSITE]['signature'] = $signature;
647
-				break;
648
-			default:
649
-				return new DataResponse([], Http::STATUS_BAD_REQUEST);
650
-		}
651
-
652
-		if ($onlyVerificationCode === false) {
653
-			$this->accountManager->updateUser($user, $accountData);
654
-
655
-			$this->jobList->add('OC\Settings\BackgroundJobs\VerifyUserData',
656
-				[
657
-					'verificationCode' => $code,
658
-					'data' => $data,
659
-					'type' => $type,
660
-					'uid' => $user->getUID(),
661
-					'try' => 0,
662
-					'lastRun' => $this->getCurrentTime()
663
-				]
664
-			);
665
-		}
666
-
667
-		return new DataResponse(['msg' => $msg, 'code' => $code]);
668
-	}
669
-
670
-	/**
671
-	 * get current timestamp
672
-	 *
673
-	 * @return int
674
-	 */
675
-	protected function getCurrentTime() {
676
-		return time();
677
-	}
678
-
679
-	/**
680
-	 * sign message with users private key
681
-	 *
682
-	 * @param IUser $user
683
-	 * @param string $message
684
-	 *
685
-	 * @return string base64 encoded signature
686
-	 */
687
-	protected function signMessage(IUser $user, $message) {
688
-		$privateKey = $this->keyManager->getKey($user)->getPrivate();
689
-		openssl_sign(json_encode($message), $signature, $privateKey, OPENSSL_ALGO_SHA512);
690
-		$signatureBase64 = base64_encode($signature);
691
-
692
-		return $signatureBase64;
693
-	}
694
-
695
-	/**
696
-	 * @NoAdminRequired
697
-	 * @NoSubadminRequired
698
-	 * @PasswordConfirmationRequired
699
-	 *
700
-	 * @param string $avatarScope
701
-	 * @param string $displayname
702
-	 * @param string $displaynameScope
703
-	 * @param string $phone
704
-	 * @param string $phoneScope
705
-	 * @param string $email
706
-	 * @param string $emailScope
707
-	 * @param string $website
708
-	 * @param string $websiteScope
709
-	 * @param string $address
710
-	 * @param string $addressScope
711
-	 * @param string $twitter
712
-	 * @param string $twitterScope
713
-	 * @return DataResponse
714
-	 */
715
-	public function setUserSettings($avatarScope,
716
-									$displayname,
717
-									$displaynameScope,
718
-									$phone,
719
-									$phoneScope,
720
-									$email,
721
-									$emailScope,
722
-									$website,
723
-									$websiteScope,
724
-									$address,
725
-									$addressScope,
726
-									$twitter,
727
-									$twitterScope
728
-	) {
729
-
730
-		if (!empty($email) && !$this->mailer->validateMailAddress($email)) {
731
-			return new DataResponse(
732
-				[
733
-					'status' => 'error',
734
-					'data' => [
735
-						'message' => (string) $this->l10n->t('Invalid mail address')
736
-					]
737
-				],
738
-				Http::STATUS_UNPROCESSABLE_ENTITY
739
-			);
740
-		}
741
-
742
-		$user = $this->userSession->getUser();
743
-
744
-		$data = $this->accountManager->getUser($user);
745
-
746
-		$data[AccountManager::PROPERTY_AVATAR] =  ['scope' => $avatarScope];
747
-		if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
748
-			$data[AccountManager::PROPERTY_DISPLAYNAME] = ['value' => $displayname, 'scope' => $displaynameScope];
749
-			$data[AccountManager::PROPERTY_EMAIL] = ['value' => $email, 'scope' => $emailScope];
750
-		}
751
-
752
-		if ($this->appManager->isEnabledForUser('federatedfilesharing')) {
753
-			$federatedFileSharing = new \OCA\FederatedFileSharing\AppInfo\Application();
754
-			$shareProvider = $federatedFileSharing->getFederatedShareProvider();
755
-			if ($shareProvider->isLookupServerUploadEnabled()) {
756
-				$data[AccountManager::PROPERTY_WEBSITE] = ['value' => $website, 'scope' => $websiteScope];
757
-				$data[AccountManager::PROPERTY_ADDRESS] = ['value' => $address, 'scope' => $addressScope];
758
-				$data[AccountManager::PROPERTY_PHONE] = ['value' => $phone, 'scope' => $phoneScope];
759
-				$data[AccountManager::PROPERTY_TWITTER] = ['value' => $twitter, 'scope' => $twitterScope];
760
-			}
761
-		}
762
-
763
-		try {
764
-			$this->saveUserSettings($user, $data);
765
-			return new DataResponse(
766
-				[
767
-					'status' => 'success',
768
-					'data' => [
769
-						'userId' => $user->getUID(),
770
-						'avatarScope' => $data[AccountManager::PROPERTY_AVATAR]['scope'],
771
-						'displayname' => $data[AccountManager::PROPERTY_DISPLAYNAME]['value'],
772
-						'displaynameScope' => $data[AccountManager::PROPERTY_DISPLAYNAME]['scope'],
773
-						'email' => $data[AccountManager::PROPERTY_EMAIL]['value'],
774
-						'emailScope' => $data[AccountManager::PROPERTY_EMAIL]['scope'],
775
-						'website' => $data[AccountManager::PROPERTY_WEBSITE]['value'],
776
-						'websiteScope' => $data[AccountManager::PROPERTY_WEBSITE]['scope'],
777
-						'address' => $data[AccountManager::PROPERTY_ADDRESS]['value'],
778
-						'addressScope' => $data[AccountManager::PROPERTY_ADDRESS]['scope'],
779
-						'message' => (string) $this->l10n->t('Settings saved')
780
-					]
781
-				],
782
-				Http::STATUS_OK
783
-			);
784
-		} catch (ForbiddenException $e) {
785
-			return new DataResponse([
786
-				'status' => 'error',
787
-				'data' => [
788
-					'message' => $e->getMessage()
789
-				],
790
-			]);
791
-		}
792
-
793
-	}
794
-
795
-
796
-	/**
797
-	 * update account manager with new user data
798
-	 *
799
-	 * @param IUser $user
800
-	 * @param array $data
801
-	 * @throws ForbiddenException
802
-	 */
803
-	protected function saveUserSettings(IUser $user, $data) {
804
-
805
-		// keep the user back-end up-to-date with the latest display name and email
806
-		// address
807
-		$oldDisplayName = $user->getDisplayName();
808
-		$oldDisplayName = is_null($oldDisplayName) ? '' : $oldDisplayName;
809
-		if (isset($data[AccountManager::PROPERTY_DISPLAYNAME]['value'])
810
-			&& $oldDisplayName !== $data[AccountManager::PROPERTY_DISPLAYNAME]['value']
811
-		) {
812
-			$result = $user->setDisplayName($data[AccountManager::PROPERTY_DISPLAYNAME]['value']);
813
-			if ($result === false) {
814
-				throw new ForbiddenException($this->l10n->t('Unable to change full name'));
815
-			}
816
-		}
817
-
818
-		$oldEmailAddress = $user->getEMailAddress();
819
-		$oldEmailAddress = is_null($oldEmailAddress) ? '' : $oldEmailAddress;
820
-		if (isset($data[AccountManager::PROPERTY_EMAIL]['value'])
821
-			&& $oldEmailAddress !== $data[AccountManager::PROPERTY_EMAIL]['value']
822
-		) {
823
-			// this is the only permission a backend provides and is also used
824
-			// for the permission of setting a email address
825
-			if (!$user->canChangeDisplayName()) {
826
-				throw new ForbiddenException($this->l10n->t('Unable to change email address'));
827
-			}
828
-			$user->setEMailAddress($data[AccountManager::PROPERTY_EMAIL]['value']);
829
-		}
830
-
831
-		$this->accountManager->updateUser($user, $data);
832
-	}
833
-
834
-	/**
835
-	 * Count all unique users visible for the current admin/subadmin.
836
-	 *
837
-	 * @NoAdminRequired
838
-	 *
839
-	 * @return DataResponse
840
-	 */
841
-	public function stats() {
842
-		$userCount = 0;
843
-		if ($this->isAdmin) {
844
-			$countByBackend = $this->userManager->countUsers();
845
-
846
-			if (!empty($countByBackend)) {
847
-				foreach ($countByBackend as $count) {
848
-					$userCount += $count;
849
-				}
850
-			}
851
-		} else {
852
-			$groups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
853
-
854
-			$uniqueUsers = [];
855
-			foreach ($groups as $group) {
856
-				foreach($group->getUsers() as $uid => $displayName) {
857
-					$uniqueUsers[$uid] = true;
858
-				}
859
-			}
860
-
861
-			$userCount = count($uniqueUsers);
862
-		}
863
-
864
-		return new DataResponse(
865
-			[
866
-				'totalUsers' => $userCount
867
-			]
868
-		);
869
-	}
870
-
871
-
872
-	/**
873
-	 * Set the displayName of a user
874
-	 *
875
-	 * @NoAdminRequired
876
-	 * @NoSubadminRequired
877
-	 * @PasswordConfirmationRequired
878
-	 * @todo merge into saveUserSettings
879
-	 *
880
-	 * @param string $username
881
-	 * @param string $displayName
882
-	 * @return DataResponse
883
-	 */
884
-	public function setDisplayName($username, $displayName) {
885
-		$currentUser = $this->userSession->getUser();
886
-		$user = $this->userManager->get($username);
887
-
888
-		if ($user === null ||
889
-			!$user->canChangeDisplayName() ||
890
-			(
891
-				!$this->groupManager->isAdmin($currentUser->getUID()) &&
892
-				!$this->groupManager->getSubAdmin()->isUserAccessible($currentUser, $user) &&
893
-				$currentUser->getUID() !== $username
894
-
895
-			)
896
-		) {
897
-			return new DataResponse([
898
-				'status' => 'error',
899
-				'data' => [
900
-					'message' => $this->l10n->t('Authentication error'),
901
-				],
902
-			]);
903
-		}
904
-
905
-		$userData = $this->accountManager->getUser($user);
906
-		$userData[AccountManager::PROPERTY_DISPLAYNAME]['value'] = $displayName;
907
-
908
-
909
-		try {
910
-			$this->saveUserSettings($user, $userData);
911
-			return new DataResponse([
912
-				'status' => 'success',
913
-				'data' => [
914
-					'message' => $this->l10n->t('Your full name has been changed.'),
915
-					'username' => $username,
916
-					'displayName' => $displayName,
917
-				],
918
-			]);
919
-		} catch (ForbiddenException $e) {
920
-			return new DataResponse([
921
-				'status' => 'error',
922
-				'data' => [
923
-					'message' => $e->getMessage(),
924
-					'displayName' => $user->getDisplayName(),
925
-				],
926
-			]);
927
-		}
928
-	}
929
-
930
-	/**
931
-	 * Set the mail address of a user
932
-	 *
933
-	 * @NoAdminRequired
934
-	 * @NoSubadminRequired
935
-	 * @PasswordConfirmationRequired
936
-	 *
937
-	 * @param string $id
938
-	 * @param string $mailAddress
939
-	 * @return DataResponse
940
-	 */
941
-	public function setEMailAddress($id, $mailAddress) {
942
-		$user = $this->userManager->get($id);
943
-		if (!$this->isAdmin
944
-			&& !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)
945
-		) {
946
-			return new DataResponse(
947
-				[
948
-					'status' => 'error',
949
-					'data' => [
950
-						'message' => (string) $this->l10n->t('Forbidden')
951
-					]
952
-				],
953
-				Http::STATUS_FORBIDDEN
954
-			);
955
-		}
956
-
957
-		if($mailAddress !== '' && !$this->mailer->validateMailAddress($mailAddress)) {
958
-			return new DataResponse(
959
-				[
960
-					'status' => 'error',
961
-					'data' => [
962
-						'message' => (string) $this->l10n->t('Invalid mail address')
963
-					]
964
-				],
965
-				Http::STATUS_UNPROCESSABLE_ENTITY
966
-			);
967
-		}
968
-
969
-		if (!$user) {
970
-			return new DataResponse(
971
-				[
972
-					'status' => 'error',
973
-					'data' => [
974
-						'message' => (string) $this->l10n->t('Invalid user')
975
-					]
976
-				],
977
-				Http::STATUS_UNPROCESSABLE_ENTITY
978
-			);
979
-		}
980
-		// this is the only permission a backend provides and is also used
981
-		// for the permission of setting a email address
982
-		if (!$user->canChangeDisplayName()) {
983
-			return new DataResponse(
984
-				[
985
-					'status' => 'error',
986
-					'data' => [
987
-						'message' => (string) $this->l10n->t('Unable to change mail address')
988
-					]
989
-				],
990
-				Http::STATUS_FORBIDDEN
991
-			);
992
-		}
993
-
994
-		$userData = $this->accountManager->getUser($user);
995
-		$userData[AccountManager::PROPERTY_EMAIL]['value'] = $mailAddress;
996
-
997
-		try {
998
-			$this->saveUserSettings($user, $userData);
999
-			return new DataResponse(
1000
-				[
1001
-					'status' => 'success',
1002
-					'data' => [
1003
-						'username' => $id,
1004
-						'mailAddress' => $mailAddress,
1005
-						'message' => (string) $this->l10n->t('Email saved')
1006
-					]
1007
-				],
1008
-				Http::STATUS_OK
1009
-			);
1010
-		} catch (ForbiddenException $e) {
1011
-			return new DataResponse([
1012
-				'status' => 'error',
1013
-				'data' => [
1014
-					'message' => $e->getMessage()
1015
-				],
1016
-			]);
1017
-		}
1018
-	}
63
+    /** @var IL10N */
64
+    private $l10n;
65
+    /** @var IUserSession */
66
+    private $userSession;
67
+    /** @var bool */
68
+    private $isAdmin;
69
+    /** @var IUserManager */
70
+    private $userManager;
71
+    /** @var IGroupManager */
72
+    private $groupManager;
73
+    /** @var IConfig */
74
+    private $config;
75
+    /** @var ILogger */
76
+    private $log;
77
+    /** @var IMailer */
78
+    private $mailer;
79
+    /** @var bool contains the state of the encryption app */
80
+    private $isEncryptionAppEnabled;
81
+    /** @var bool contains the state of the admin recovery setting */
82
+    private $isRestoreEnabled = false;
83
+    /** @var IAppManager */
84
+    private $appManager;
85
+    /** @var IAvatarManager */
86
+    private $avatarManager;
87
+    /** @var AccountManager */
88
+    private $accountManager;
89
+    /** @var ISecureRandom */
90
+    private $secureRandom;
91
+    /** @var NewUserMailHelper */
92
+    private $newUserMailHelper;
93
+    /** @var ITimeFactory */
94
+    private $timeFactory;
95
+    /** @var ICrypto */
96
+    private $crypto;
97
+    /** @var Manager */
98
+    private $keyManager;
99
+    /** @var IJobList */
100
+    private $jobList;
101
+    /** @var IManager */
102
+    private $encryptionManager;
103
+
104
+    /**
105
+     * @param string $appName
106
+     * @param IRequest $request
107
+     * @param IUserManager $userManager
108
+     * @param IGroupManager $groupManager
109
+     * @param IUserSession $userSession
110
+     * @param IConfig $config
111
+     * @param bool $isAdmin
112
+     * @param IL10N $l10n
113
+     * @param ILogger $log
114
+     * @param IMailer $mailer
115
+     * @param IURLGenerator $urlGenerator
116
+     * @param IAppManager $appManager
117
+     * @param IAvatarManager $avatarManager
118
+     * @param AccountManager $accountManager
119
+     * @param ISecureRandom $secureRandom
120
+     * @param NewUserMailHelper $newUserMailHelper
121
+     * @param ITimeFactory $timeFactory
122
+     * @param ICrypto $crypto
123
+     * @param Manager $keyManager
124
+     * @param IJobList $jobList
125
+     * @param IManager $encryptionManager
126
+     */
127
+    public function __construct($appName,
128
+                                IRequest $request,
129
+                                IUserManager $userManager,
130
+                                IGroupManager $groupManager,
131
+                                IUserSession $userSession,
132
+                                IConfig $config,
133
+                                $isAdmin,
134
+                                IL10N $l10n,
135
+                                ILogger $log,
136
+                                IMailer $mailer,
137
+                                IURLGenerator $urlGenerator,
138
+                                IAppManager $appManager,
139
+                                IAvatarManager $avatarManager,
140
+                                AccountManager $accountManager,
141
+                                ISecureRandom $secureRandom,
142
+                                NewUserMailHelper $newUserMailHelper,
143
+                                ITimeFactory $timeFactory,
144
+                                ICrypto $crypto,
145
+                                Manager $keyManager,
146
+                                IJobList $jobList,
147
+                                IManager $encryptionManager) {
148
+        parent::__construct($appName, $request);
149
+        $this->userManager = $userManager;
150
+        $this->groupManager = $groupManager;
151
+        $this->userSession = $userSession;
152
+        $this->config = $config;
153
+        $this->isAdmin = $isAdmin;
154
+        $this->l10n = $l10n;
155
+        $this->log = $log;
156
+        $this->mailer = $mailer;
157
+        $this->appManager = $appManager;
158
+        $this->avatarManager = $avatarManager;
159
+        $this->accountManager = $accountManager;
160
+        $this->secureRandom = $secureRandom;
161
+        $this->newUserMailHelper = $newUserMailHelper;
162
+        $this->timeFactory = $timeFactory;
163
+        $this->crypto = $crypto;
164
+        $this->keyManager = $keyManager;
165
+        $this->jobList = $jobList;
166
+        $this->encryptionManager = $encryptionManager;
167
+
168
+        // check for encryption state - TODO see formatUserForIndex
169
+        $this->isEncryptionAppEnabled = $appManager->isEnabledForUser('encryption');
170
+        if($this->isEncryptionAppEnabled) {
171
+            // putting this directly in empty is possible in PHP 5.5+
172
+            $result = $config->getAppValue('encryption', 'recoveryAdminEnabled', 0);
173
+            $this->isRestoreEnabled = !empty($result);
174
+        }
175
+    }
176
+
177
+    /**
178
+     * @param IUser $user
179
+     * @param array $userGroups
180
+     * @return array
181
+     */
182
+    private function formatUserForIndex(IUser $user, array $userGroups = null) {
183
+
184
+        // TODO: eliminate this encryption specific code below and somehow
185
+        // hook in additional user info from other apps
186
+
187
+        // recovery isn't possible if admin or user has it disabled and encryption
188
+        // is enabled - so we eliminate the else paths in the conditional tree
189
+        // below
190
+        $restorePossible = false;
191
+
192
+        if ($this->isEncryptionAppEnabled) {
193
+            if ($this->isRestoreEnabled) {
194
+                // check for the users recovery setting
195
+                $recoveryMode = $this->config->getUserValue($user->getUID(), 'encryption', 'recoveryEnabled', '0');
196
+                // method call inside empty is possible with PHP 5.5+
197
+                $recoveryModeEnabled = !empty($recoveryMode);
198
+                if ($recoveryModeEnabled) {
199
+                    // user also has recovery mode enabled
200
+                    $restorePossible = true;
201
+                }
202
+            } else {
203
+                $modules = $this->encryptionManager->getEncryptionModules();
204
+                $restorePossible = true;
205
+                foreach ($modules as $id => $module) {
206
+                    /* @var IEncryptionModule $instance */
207
+                    $instance = call_user_func($module['callback']);
208
+                    if ($instance->needDetailedAccessList()) {
209
+                        $restorePossible = false;
210
+                        break;
211
+                    }
212
+                }
213
+            }
214
+        } else {
215
+            // recovery is possible if encryption is disabled (plain files are
216
+            // available)
217
+            $restorePossible = true;
218
+        }
219
+
220
+        $subAdminGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($user);
221
+        foreach($subAdminGroups as $key => $subAdminGroup) {
222
+            $subAdminGroups[$key] = $subAdminGroup->getGID();
223
+        }
224
+
225
+        $displayName = $user->getEMailAddress();
226
+        if (is_null($displayName)) {
227
+            $displayName = '';
228
+        }
229
+
230
+        $avatarAvailable = false;
231
+        try {
232
+            $avatarAvailable = $this->avatarManager->getAvatar($user->getUID())->exists();
233
+        } catch (\Exception $e) {
234
+            //No avatar yet
235
+        }
236
+
237
+        return [
238
+            'name' => $user->getUID(),
239
+            'displayname' => $user->getDisplayName(),
240
+            'groups' => (empty($userGroups)) ? $this->groupManager->getUserGroupIds($user) : $userGroups,
241
+            'subadmin' => $subAdminGroups,
242
+            'quota' => $user->getQuota(),
243
+            'storageLocation' => $user->getHome(),
244
+            'lastLogin' => $user->getLastLogin() * 1000,
245
+            'backend' => $user->getBackendClassName(),
246
+            'email' => $displayName,
247
+            'isRestoreDisabled' => !$restorePossible,
248
+            'isAvatarAvailable' => $avatarAvailable,
249
+            'isEnabled' => $user->isEnabled(),
250
+        ];
251
+    }
252
+
253
+    /**
254
+     * @param array $userIDs Array with schema [$uid => $displayName]
255
+     * @return IUser[]
256
+     */
257
+    private function getUsersForUID(array $userIDs) {
258
+        $users = [];
259
+        foreach ($userIDs as $uid => $displayName) {
260
+            $users[$uid] = $this->userManager->get($uid);
261
+        }
262
+        return $users;
263
+    }
264
+
265
+    /**
266
+     * @NoAdminRequired
267
+     *
268
+     * @param int $offset
269
+     * @param int $limit
270
+     * @param string $gid GID to filter for
271
+     * @param string $pattern Pattern to search for in the username
272
+     * @param string $backend Backend to filter for (class-name)
273
+     * @return DataResponse
274
+     *
275
+     * TODO: Tidy up and write unit tests - code is mainly static method calls
276
+     */
277
+    public function index($offset = 0, $limit = 10, $gid = '', $pattern = '', $backend = '') {
278
+        // Remove backends
279
+        if(!empty($backend)) {
280
+            $activeBackends = $this->userManager->getBackends();
281
+            $this->userManager->clearBackends();
282
+            foreach($activeBackends as $singleActiveBackend) {
283
+                if($backend === get_class($singleActiveBackend)) {
284
+                    $this->userManager->registerBackend($singleActiveBackend);
285
+                    break;
286
+                }
287
+            }
288
+        }
289
+
290
+        $users = [];
291
+        if ($this->isAdmin) {
292
+            if($gid !== '' && $gid !== '_disabledUsers') {
293
+                $batch = $this->getUsersForUID($this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset));
294
+            } else {
295
+                $batch = $this->userManager->search($pattern, $limit, $offset);
296
+            }
297
+
298
+            foreach ($batch as $user) {
299
+                if( ($gid !== '_disabledUsers' && $user->isEnabled()) ||
300
+                    ($gid === '_disabledUsers' && !$user->isEnabled())
301
+                ) {
302
+                    $users[] = $this->formatUserForIndex($user);
303
+                }
304
+            }
305
+
306
+        } else {
307
+            $subAdminOfGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
308
+            // New class returns IGroup[] so convert back
309
+            $gids = [];
310
+            foreach ($subAdminOfGroups as $group) {
311
+                $gids[] = $group->getGID();
312
+            }
313
+            $subAdminOfGroups = $gids;
314
+
315
+            // Set the $gid parameter to an empty value if the subadmin has no rights to access a specific group
316
+            if($gid !== '' && $gid !== '_disabledUsers' && !in_array($gid, $subAdminOfGroups)) {
317
+                $gid = '';
318
+            }
319
+
320
+            // Batch all groups the user is subadmin of when a group is specified
321
+            $batch = [];
322
+            if($gid === '') {
323
+                foreach($subAdminOfGroups as $group) {
324
+                    $groupUsers = $this->groupManager->displayNamesInGroup($group, $pattern, $limit, $offset);
325
+
326
+                    foreach($groupUsers as $uid => $displayName) {
327
+                        $batch[$uid] = $displayName;
328
+                    }
329
+                }
330
+            } else {
331
+                $batch = $this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset);
332
+            }
333
+            $batch = $this->getUsersForUID($batch);
334
+
335
+            foreach ($batch as $user) {
336
+                // Only add the groups, this user is a subadmin of
337
+                $userGroups = array_values(array_intersect(
338
+                    $this->groupManager->getUserGroupIds($user),
339
+                    $subAdminOfGroups
340
+                ));
341
+                if( ($gid !== '_disabledUsers' && $user->isEnabled()) ||
342
+                    ($gid === '_disabledUsers' && !$user->isEnabled())
343
+                ) {
344
+                    $users[] = $this->formatUserForIndex($user, $userGroups);
345
+                }
346
+            }
347
+        }
348
+
349
+        return new DataResponse($users);
350
+    }
351
+
352
+    /**
353
+     * @NoAdminRequired
354
+     * @PasswordConfirmationRequired
355
+     *
356
+     * @param string $username
357
+     * @param string $password
358
+     * @param array $groups
359
+     * @param string $email
360
+     * @return DataResponse
361
+     */
362
+    public function create($username, $password, array $groups=[], $email='') {
363
+        if($email !== '' && !$this->mailer->validateMailAddress($email)) {
364
+            return new DataResponse(
365
+                [
366
+                    'message' => (string)$this->l10n->t('Invalid mail address')
367
+                ],
368
+                Http::STATUS_UNPROCESSABLE_ENTITY
369
+            );
370
+        }
371
+
372
+        $currentUser = $this->userSession->getUser();
373
+
374
+        if (!$this->isAdmin) {
375
+            if (!empty($groups)) {
376
+                foreach ($groups as $key => $group) {
377
+                    $groupObject = $this->groupManager->get($group);
378
+                    if($groupObject === null) {
379
+                        unset($groups[$key]);
380
+                        continue;
381
+                    }
382
+
383
+                    if (!$this->groupManager->getSubAdmin()->isSubAdminofGroup($currentUser, $groupObject)) {
384
+                        unset($groups[$key]);
385
+                    }
386
+                }
387
+            }
388
+
389
+            if (empty($groups)) {
390
+                return new DataResponse(
391
+                    [
392
+                        'message' => $this->l10n->t('No valid group selected'),
393
+                    ],
394
+                    Http::STATUS_FORBIDDEN
395
+                );
396
+            }
397
+        }
398
+
399
+        if ($this->userManager->userExists($username)) {
400
+            return new DataResponse(
401
+                [
402
+                    'message' => (string)$this->l10n->t('A user with that name already exists.')
403
+                ],
404
+                Http::STATUS_CONFLICT
405
+            );
406
+        }
407
+
408
+        $generatePasswordResetToken = false;
409
+        if ($password === '') {
410
+            if ($email === '') {
411
+                return new DataResponse(
412
+                    [
413
+                        'message' => (string)$this->l10n->t('To send a password link to the user an email address is required.')
414
+                    ],
415
+                    Http::STATUS_UNPROCESSABLE_ENTITY
416
+                );
417
+            }
418
+
419
+            $password = $this->secureRandom->generate(32);
420
+            $generatePasswordResetToken = true;
421
+        }
422
+
423
+        try {
424
+            $user = $this->userManager->createUser($username, $password);
425
+        } catch (\Exception $exception) {
426
+            $message = $exception->getMessage();
427
+            if (!$message) {
428
+                $message = $this->l10n->t('Unable to create user.');
429
+            }
430
+            return new DataResponse(
431
+                [
432
+                    'message' => (string) $message,
433
+                ],
434
+                Http::STATUS_FORBIDDEN
435
+            );
436
+        }
437
+
438
+        if($user instanceof IUser) {
439
+            if($groups !== null) {
440
+                foreach($groups as $groupName) {
441
+                    $group = $this->groupManager->get($groupName);
442
+
443
+                    if(empty($group)) {
444
+                        $group = $this->groupManager->createGroup($groupName);
445
+                    }
446
+                    $group->addUser($user);
447
+                }
448
+            }
449
+            /**
450
+             * Send new user mail only if a mail is set
451
+             */
452
+            if($email !== '') {
453
+                $user->setEMailAddress($email);
454
+                try {
455
+                    $emailTemplate = $this->newUserMailHelper->generateTemplate($user, $generatePasswordResetToken);
456
+                    $this->newUserMailHelper->sendMail($user, $emailTemplate);
457
+                } catch(\Exception $e) {
458
+                    $this->log->error("Can't send new user mail to $email: " . $e->getMessage(), ['app' => 'settings']);
459
+                }
460
+            }
461
+            // fetch users groups
462
+            $userGroups = $this->groupManager->getUserGroupIds($user);
463
+
464
+            return new DataResponse(
465
+                $this->formatUserForIndex($user, $userGroups),
466
+                Http::STATUS_CREATED
467
+            );
468
+        }
469
+
470
+        return new DataResponse(
471
+            [
472
+                'message' => (string) $this->l10n->t('Unable to create user.')
473
+            ],
474
+            Http::STATUS_FORBIDDEN
475
+        );
476
+
477
+    }
478
+
479
+    /**
480
+     * @NoAdminRequired
481
+     * @PasswordConfirmationRequired
482
+     *
483
+     * @param string $id
484
+     * @return DataResponse
485
+     */
486
+    public function destroy($id) {
487
+        $userId = $this->userSession->getUser()->getUID();
488
+        $user = $this->userManager->get($id);
489
+
490
+        if($userId === $id) {
491
+            return new DataResponse(
492
+                [
493
+                    'status' => 'error',
494
+                    'data' => [
495
+                        'message' => (string) $this->l10n->t('Unable to delete user.')
496
+                    ]
497
+                ],
498
+                Http::STATUS_FORBIDDEN
499
+            );
500
+        }
501
+
502
+        if(!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
503
+            return new DataResponse(
504
+                [
505
+                    'status' => 'error',
506
+                    'data' => [
507
+                        'message' => (string)$this->l10n->t('Authentication error')
508
+                    ]
509
+                ],
510
+                Http::STATUS_FORBIDDEN
511
+            );
512
+        }
513
+
514
+        if($user) {
515
+            if($user->delete()) {
516
+                return new DataResponse(
517
+                    [
518
+                        'status' => 'success',
519
+                        'data' => [
520
+                            'username' => $id
521
+                        ]
522
+                    ],
523
+                    Http::STATUS_NO_CONTENT
524
+                );
525
+            }
526
+        }
527
+
528
+        return new DataResponse(
529
+            [
530
+                'status' => 'error',
531
+                'data' => [
532
+                    'message' => (string)$this->l10n->t('Unable to delete user.')
533
+                ]
534
+            ],
535
+            Http::STATUS_FORBIDDEN
536
+        );
537
+    }
538
+
539
+    /**
540
+     * @NoAdminRequired
541
+     *
542
+     * @param string $id
543
+     * @param int $enabled
544
+     * @return DataResponse
545
+     */
546
+    public function setEnabled($id, $enabled) {
547
+        $enabled = (bool)$enabled;
548
+        if($enabled) {
549
+            $errorMsgGeneral = (string) $this->l10n->t('Error while enabling user.');
550
+        } else {
551
+            $errorMsgGeneral = (string) $this->l10n->t('Error while disabling user.');
552
+        }
553
+
554
+        $userId = $this->userSession->getUser()->getUID();
555
+        $user = $this->userManager->get($id);
556
+
557
+        if ($userId === $id) {
558
+            return new DataResponse(
559
+                [
560
+                    'status' => 'error',
561
+                    'data' => [
562
+                        'message' => $errorMsgGeneral
563
+                    ]
564
+                ], Http::STATUS_FORBIDDEN
565
+            );
566
+        }
567
+
568
+        if($user) {
569
+            if (!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
570
+                return new DataResponse(
571
+                    [
572
+                        'status' => 'error',
573
+                        'data' => [
574
+                            'message' => (string) $this->l10n->t('Authentication error')
575
+                        ]
576
+                    ],
577
+                    Http::STATUS_FORBIDDEN
578
+                );
579
+            }
580
+
581
+            $user->setEnabled($enabled);
582
+            return new DataResponse(
583
+                [
584
+                    'status' => 'success',
585
+                    'data' => [
586
+                        'username' => $id,
587
+                        'enabled' => $enabled
588
+                    ]
589
+                ]
590
+            );
591
+        } else {
592
+            return new DataResponse(
593
+                [
594
+                    'status' => 'error',
595
+                    'data' => [
596
+                        'message' => $errorMsgGeneral
597
+                    ]
598
+                ],
599
+                Http::STATUS_FORBIDDEN
600
+            );
601
+        }
602
+
603
+    }
604
+
605
+    /**
606
+     * Set the mail address of a user
607
+     *
608
+     * @NoAdminRequired
609
+     * @NoSubadminRequired
610
+     * @PasswordConfirmationRequired
611
+     *
612
+     * @param string $account
613
+     * @param bool $onlyVerificationCode only return verification code without updating the data
614
+     * @return DataResponse
615
+     */
616
+    public function getVerificationCode($account, $onlyVerificationCode) {
617
+
618
+        $user = $this->userSession->getUser();
619
+
620
+        if ($user === null) {
621
+            return new DataResponse([], Http::STATUS_BAD_REQUEST);
622
+        }
623
+
624
+        $accountData = $this->accountManager->getUser($user);
625
+        $cloudId = $user->getCloudId();
626
+        $message = "Use my Federated Cloud ID to share with me: " . $cloudId;
627
+        $signature = $this->signMessage($user, $message);
628
+
629
+        $code = $message . ' ' . $signature;
630
+        $codeMd5 = $message . ' ' . md5($signature);
631
+
632
+        switch ($account) {
633
+            case 'verify-twitter':
634
+                $accountData[AccountManager::PROPERTY_TWITTER]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
635
+                $msg = $this->l10n->t('In order to verify your Twitter account, post the following tweet on Twitter (please make sure to post it without any line breaks):');
636
+                $code = $codeMd5;
637
+                $type = AccountManager::PROPERTY_TWITTER;
638
+                $data = $accountData[AccountManager::PROPERTY_TWITTER]['value'];
639
+                $accountData[AccountManager::PROPERTY_TWITTER]['signature'] = $signature;
640
+                break;
641
+            case 'verify-website':
642
+                $accountData[AccountManager::PROPERTY_WEBSITE]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
643
+                $msg = $this->l10n->t('In order to verify your Website, store the following content in your web-root at \'.well-known/CloudIdVerificationCode.txt\' (please make sure that the complete text is in one line):');
644
+                $type = AccountManager::PROPERTY_WEBSITE;
645
+                $data = $accountData[AccountManager::PROPERTY_WEBSITE]['value'];
646
+                $accountData[AccountManager::PROPERTY_WEBSITE]['signature'] = $signature;
647
+                break;
648
+            default:
649
+                return new DataResponse([], Http::STATUS_BAD_REQUEST);
650
+        }
651
+
652
+        if ($onlyVerificationCode === false) {
653
+            $this->accountManager->updateUser($user, $accountData);
654
+
655
+            $this->jobList->add('OC\Settings\BackgroundJobs\VerifyUserData',
656
+                [
657
+                    'verificationCode' => $code,
658
+                    'data' => $data,
659
+                    'type' => $type,
660
+                    'uid' => $user->getUID(),
661
+                    'try' => 0,
662
+                    'lastRun' => $this->getCurrentTime()
663
+                ]
664
+            );
665
+        }
666
+
667
+        return new DataResponse(['msg' => $msg, 'code' => $code]);
668
+    }
669
+
670
+    /**
671
+     * get current timestamp
672
+     *
673
+     * @return int
674
+     */
675
+    protected function getCurrentTime() {
676
+        return time();
677
+    }
678
+
679
+    /**
680
+     * sign message with users private key
681
+     *
682
+     * @param IUser $user
683
+     * @param string $message
684
+     *
685
+     * @return string base64 encoded signature
686
+     */
687
+    protected function signMessage(IUser $user, $message) {
688
+        $privateKey = $this->keyManager->getKey($user)->getPrivate();
689
+        openssl_sign(json_encode($message), $signature, $privateKey, OPENSSL_ALGO_SHA512);
690
+        $signatureBase64 = base64_encode($signature);
691
+
692
+        return $signatureBase64;
693
+    }
694
+
695
+    /**
696
+     * @NoAdminRequired
697
+     * @NoSubadminRequired
698
+     * @PasswordConfirmationRequired
699
+     *
700
+     * @param string $avatarScope
701
+     * @param string $displayname
702
+     * @param string $displaynameScope
703
+     * @param string $phone
704
+     * @param string $phoneScope
705
+     * @param string $email
706
+     * @param string $emailScope
707
+     * @param string $website
708
+     * @param string $websiteScope
709
+     * @param string $address
710
+     * @param string $addressScope
711
+     * @param string $twitter
712
+     * @param string $twitterScope
713
+     * @return DataResponse
714
+     */
715
+    public function setUserSettings($avatarScope,
716
+                                    $displayname,
717
+                                    $displaynameScope,
718
+                                    $phone,
719
+                                    $phoneScope,
720
+                                    $email,
721
+                                    $emailScope,
722
+                                    $website,
723
+                                    $websiteScope,
724
+                                    $address,
725
+                                    $addressScope,
726
+                                    $twitter,
727
+                                    $twitterScope
728
+    ) {
729
+
730
+        if (!empty($email) && !$this->mailer->validateMailAddress($email)) {
731
+            return new DataResponse(
732
+                [
733
+                    'status' => 'error',
734
+                    'data' => [
735
+                        'message' => (string) $this->l10n->t('Invalid mail address')
736
+                    ]
737
+                ],
738
+                Http::STATUS_UNPROCESSABLE_ENTITY
739
+            );
740
+        }
741
+
742
+        $user = $this->userSession->getUser();
743
+
744
+        $data = $this->accountManager->getUser($user);
745
+
746
+        $data[AccountManager::PROPERTY_AVATAR] =  ['scope' => $avatarScope];
747
+        if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
748
+            $data[AccountManager::PROPERTY_DISPLAYNAME] = ['value' => $displayname, 'scope' => $displaynameScope];
749
+            $data[AccountManager::PROPERTY_EMAIL] = ['value' => $email, 'scope' => $emailScope];
750
+        }
751
+
752
+        if ($this->appManager->isEnabledForUser('federatedfilesharing')) {
753
+            $federatedFileSharing = new \OCA\FederatedFileSharing\AppInfo\Application();
754
+            $shareProvider = $federatedFileSharing->getFederatedShareProvider();
755
+            if ($shareProvider->isLookupServerUploadEnabled()) {
756
+                $data[AccountManager::PROPERTY_WEBSITE] = ['value' => $website, 'scope' => $websiteScope];
757
+                $data[AccountManager::PROPERTY_ADDRESS] = ['value' => $address, 'scope' => $addressScope];
758
+                $data[AccountManager::PROPERTY_PHONE] = ['value' => $phone, 'scope' => $phoneScope];
759
+                $data[AccountManager::PROPERTY_TWITTER] = ['value' => $twitter, 'scope' => $twitterScope];
760
+            }
761
+        }
762
+
763
+        try {
764
+            $this->saveUserSettings($user, $data);
765
+            return new DataResponse(
766
+                [
767
+                    'status' => 'success',
768
+                    'data' => [
769
+                        'userId' => $user->getUID(),
770
+                        'avatarScope' => $data[AccountManager::PROPERTY_AVATAR]['scope'],
771
+                        'displayname' => $data[AccountManager::PROPERTY_DISPLAYNAME]['value'],
772
+                        'displaynameScope' => $data[AccountManager::PROPERTY_DISPLAYNAME]['scope'],
773
+                        'email' => $data[AccountManager::PROPERTY_EMAIL]['value'],
774
+                        'emailScope' => $data[AccountManager::PROPERTY_EMAIL]['scope'],
775
+                        'website' => $data[AccountManager::PROPERTY_WEBSITE]['value'],
776
+                        'websiteScope' => $data[AccountManager::PROPERTY_WEBSITE]['scope'],
777
+                        'address' => $data[AccountManager::PROPERTY_ADDRESS]['value'],
778
+                        'addressScope' => $data[AccountManager::PROPERTY_ADDRESS]['scope'],
779
+                        'message' => (string) $this->l10n->t('Settings saved')
780
+                    ]
781
+                ],
782
+                Http::STATUS_OK
783
+            );
784
+        } catch (ForbiddenException $e) {
785
+            return new DataResponse([
786
+                'status' => 'error',
787
+                'data' => [
788
+                    'message' => $e->getMessage()
789
+                ],
790
+            ]);
791
+        }
792
+
793
+    }
794
+
795
+
796
+    /**
797
+     * update account manager with new user data
798
+     *
799
+     * @param IUser $user
800
+     * @param array $data
801
+     * @throws ForbiddenException
802
+     */
803
+    protected function saveUserSettings(IUser $user, $data) {
804
+
805
+        // keep the user back-end up-to-date with the latest display name and email
806
+        // address
807
+        $oldDisplayName = $user->getDisplayName();
808
+        $oldDisplayName = is_null($oldDisplayName) ? '' : $oldDisplayName;
809
+        if (isset($data[AccountManager::PROPERTY_DISPLAYNAME]['value'])
810
+            && $oldDisplayName !== $data[AccountManager::PROPERTY_DISPLAYNAME]['value']
811
+        ) {
812
+            $result = $user->setDisplayName($data[AccountManager::PROPERTY_DISPLAYNAME]['value']);
813
+            if ($result === false) {
814
+                throw new ForbiddenException($this->l10n->t('Unable to change full name'));
815
+            }
816
+        }
817
+
818
+        $oldEmailAddress = $user->getEMailAddress();
819
+        $oldEmailAddress = is_null($oldEmailAddress) ? '' : $oldEmailAddress;
820
+        if (isset($data[AccountManager::PROPERTY_EMAIL]['value'])
821
+            && $oldEmailAddress !== $data[AccountManager::PROPERTY_EMAIL]['value']
822
+        ) {
823
+            // this is the only permission a backend provides and is also used
824
+            // for the permission of setting a email address
825
+            if (!$user->canChangeDisplayName()) {
826
+                throw new ForbiddenException($this->l10n->t('Unable to change email address'));
827
+            }
828
+            $user->setEMailAddress($data[AccountManager::PROPERTY_EMAIL]['value']);
829
+        }
830
+
831
+        $this->accountManager->updateUser($user, $data);
832
+    }
833
+
834
+    /**
835
+     * Count all unique users visible for the current admin/subadmin.
836
+     *
837
+     * @NoAdminRequired
838
+     *
839
+     * @return DataResponse
840
+     */
841
+    public function stats() {
842
+        $userCount = 0;
843
+        if ($this->isAdmin) {
844
+            $countByBackend = $this->userManager->countUsers();
845
+
846
+            if (!empty($countByBackend)) {
847
+                foreach ($countByBackend as $count) {
848
+                    $userCount += $count;
849
+                }
850
+            }
851
+        } else {
852
+            $groups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
853
+
854
+            $uniqueUsers = [];
855
+            foreach ($groups as $group) {
856
+                foreach($group->getUsers() as $uid => $displayName) {
857
+                    $uniqueUsers[$uid] = true;
858
+                }
859
+            }
860
+
861
+            $userCount = count($uniqueUsers);
862
+        }
863
+
864
+        return new DataResponse(
865
+            [
866
+                'totalUsers' => $userCount
867
+            ]
868
+        );
869
+    }
870
+
871
+
872
+    /**
873
+     * Set the displayName of a user
874
+     *
875
+     * @NoAdminRequired
876
+     * @NoSubadminRequired
877
+     * @PasswordConfirmationRequired
878
+     * @todo merge into saveUserSettings
879
+     *
880
+     * @param string $username
881
+     * @param string $displayName
882
+     * @return DataResponse
883
+     */
884
+    public function setDisplayName($username, $displayName) {
885
+        $currentUser = $this->userSession->getUser();
886
+        $user = $this->userManager->get($username);
887
+
888
+        if ($user === null ||
889
+            !$user->canChangeDisplayName() ||
890
+            (
891
+                !$this->groupManager->isAdmin($currentUser->getUID()) &&
892
+                !$this->groupManager->getSubAdmin()->isUserAccessible($currentUser, $user) &&
893
+                $currentUser->getUID() !== $username
894
+
895
+            )
896
+        ) {
897
+            return new DataResponse([
898
+                'status' => 'error',
899
+                'data' => [
900
+                    'message' => $this->l10n->t('Authentication error'),
901
+                ],
902
+            ]);
903
+        }
904
+
905
+        $userData = $this->accountManager->getUser($user);
906
+        $userData[AccountManager::PROPERTY_DISPLAYNAME]['value'] = $displayName;
907
+
908
+
909
+        try {
910
+            $this->saveUserSettings($user, $userData);
911
+            return new DataResponse([
912
+                'status' => 'success',
913
+                'data' => [
914
+                    'message' => $this->l10n->t('Your full name has been changed.'),
915
+                    'username' => $username,
916
+                    'displayName' => $displayName,
917
+                ],
918
+            ]);
919
+        } catch (ForbiddenException $e) {
920
+            return new DataResponse([
921
+                'status' => 'error',
922
+                'data' => [
923
+                    'message' => $e->getMessage(),
924
+                    'displayName' => $user->getDisplayName(),
925
+                ],
926
+            ]);
927
+        }
928
+    }
929
+
930
+    /**
931
+     * Set the mail address of a user
932
+     *
933
+     * @NoAdminRequired
934
+     * @NoSubadminRequired
935
+     * @PasswordConfirmationRequired
936
+     *
937
+     * @param string $id
938
+     * @param string $mailAddress
939
+     * @return DataResponse
940
+     */
941
+    public function setEMailAddress($id, $mailAddress) {
942
+        $user = $this->userManager->get($id);
943
+        if (!$this->isAdmin
944
+            && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)
945
+        ) {
946
+            return new DataResponse(
947
+                [
948
+                    'status' => 'error',
949
+                    'data' => [
950
+                        'message' => (string) $this->l10n->t('Forbidden')
951
+                    ]
952
+                ],
953
+                Http::STATUS_FORBIDDEN
954
+            );
955
+        }
956
+
957
+        if($mailAddress !== '' && !$this->mailer->validateMailAddress($mailAddress)) {
958
+            return new DataResponse(
959
+                [
960
+                    'status' => 'error',
961
+                    'data' => [
962
+                        'message' => (string) $this->l10n->t('Invalid mail address')
963
+                    ]
964
+                ],
965
+                Http::STATUS_UNPROCESSABLE_ENTITY
966
+            );
967
+        }
968
+
969
+        if (!$user) {
970
+            return new DataResponse(
971
+                [
972
+                    'status' => 'error',
973
+                    'data' => [
974
+                        'message' => (string) $this->l10n->t('Invalid user')
975
+                    ]
976
+                ],
977
+                Http::STATUS_UNPROCESSABLE_ENTITY
978
+            );
979
+        }
980
+        // this is the only permission a backend provides and is also used
981
+        // for the permission of setting a email address
982
+        if (!$user->canChangeDisplayName()) {
983
+            return new DataResponse(
984
+                [
985
+                    'status' => 'error',
986
+                    'data' => [
987
+                        'message' => (string) $this->l10n->t('Unable to change mail address')
988
+                    ]
989
+                ],
990
+                Http::STATUS_FORBIDDEN
991
+            );
992
+        }
993
+
994
+        $userData = $this->accountManager->getUser($user);
995
+        $userData[AccountManager::PROPERTY_EMAIL]['value'] = $mailAddress;
996
+
997
+        try {
998
+            $this->saveUserSettings($user, $userData);
999
+            return new DataResponse(
1000
+                [
1001
+                    'status' => 'success',
1002
+                    'data' => [
1003
+                        'username' => $id,
1004
+                        'mailAddress' => $mailAddress,
1005
+                        'message' => (string) $this->l10n->t('Email saved')
1006
+                    ]
1007
+                ],
1008
+                Http::STATUS_OK
1009
+            );
1010
+        } catch (ForbiddenException $e) {
1011
+            return new DataResponse([
1012
+                'status' => 'error',
1013
+                'data' => [
1014
+                    'message' => $e->getMessage()
1015
+                ],
1016
+            ]);
1017
+        }
1018
+    }
1019 1019
 
1020 1020
 }
Please login to merge, or discard this patch.