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