Completed
Push — master ( 36f793...6cdf09 )
by
unknown
42:22 queued 15:32
created
apps/encryption/lib/Command/DropLegacyFileKey.php 2 patches
Indentation   +127 added lines, -127 removed lines patch added patch discarded remove patch
@@ -20,131 +20,131 @@
 block discarded – undo
20 20
 use Symfony\Component\Console\Output\OutputInterface;
21 21
 
22 22
 class DropLegacyFileKey extends Command {
23
-	private View $rootView;
24
-
25
-	public function __construct(
26
-		private IUserManager $userManager,
27
-		private KeyManager $keyManager,
28
-	) {
29
-		parent::__construct();
30
-
31
-		$this->rootView = new View();
32
-	}
33
-
34
-	protected function configure(): void {
35
-		$this
36
-			->setName('encryption:drop-legacy-filekey')
37
-			->setDescription('Scan the files for the legacy filekey format using RC4 and get rid of it (if master key is enabled)');
38
-	}
39
-
40
-	protected function execute(InputInterface $input, OutputInterface $output): int {
41
-		$result = true;
42
-
43
-		$output->writeln('<info>Scanning all files for legacy filekey</info>');
44
-
45
-		foreach ($this->userManager->getBackends() as $backend) {
46
-			$limit = 500;
47
-			$offset = 0;
48
-			do {
49
-				$users = $backend->getUsers('', $limit, $offset);
50
-				foreach ($users as $user) {
51
-					$output->writeln('Scanning all files for ' . $user);
52
-					$this->setupUserFS($user);
53
-					$result = $result && $this->scanFolder($output, '/' . $user);
54
-				}
55
-				$offset += $limit;
56
-			} while (count($users) >= $limit);
57
-		}
58
-
59
-		if ($result) {
60
-			$output->writeln('All scanned files are properly encrypted.');
61
-			return self::SUCCESS;
62
-		}
63
-
64
-		return self::FAILURE;
65
-	}
66
-
67
-	private function scanFolder(OutputInterface $output, string $folder): bool {
68
-		$clean = true;
69
-
70
-		foreach ($this->rootView->getDirectoryContent($folder) as $item) {
71
-			$path = $folder . '/' . $item['name'];
72
-			if ($this->rootView->is_dir($path)) {
73
-				if ($this->scanFolder($output, $path) === false) {
74
-					$clean = false;
75
-				}
76
-			} else {
77
-				if (!$item->isEncrypted()) {
78
-					// ignore
79
-					continue;
80
-				}
81
-
82
-				$stats = $this->rootView->stat($path);
83
-				if (!isset($stats['hasHeader']) || $stats['hasHeader'] === false) {
84
-					$clean = false;
85
-					$output->writeln('<error>' . $path . ' does not have a proper header</error>');
86
-				} else {
87
-					try {
88
-						$legacyFileKey = $this->keyManager->getFileKey($path, true);
89
-						if ($legacyFileKey === '') {
90
-							$output->writeln('Got an empty legacy filekey for ' . $path . ', continuing', OutputInterface::VERBOSITY_VERBOSE);
91
-							continue;
92
-						}
93
-					} catch (GenericEncryptionException $e) {
94
-						$output->writeln('Got a decryption error for legacy filekey for ' . $path . ', continuing', OutputInterface::VERBOSITY_VERBOSE);
95
-						continue;
96
-					}
97
-					/* If that did not throw and filekey is not empty, a legacy filekey is used */
98
-					$clean = false;
99
-					$output->writeln($path . ' is using a legacy filekey, migrating');
100
-					$this->migrateSinglefile($path, $item, $output);
101
-				}
102
-			}
103
-		}
104
-
105
-		return $clean;
106
-	}
107
-
108
-	private function migrateSinglefile(string $path, FileInfo $fileInfo, OutputInterface $output): void {
109
-		$source = $path;
110
-		$target = $path . '.reencrypted.' . time();
111
-
112
-		try {
113
-			$this->rootView->copy($source, $target);
114
-			$copyResource = $this->rootView->fopen($target, 'r');
115
-			$sourceResource = $this->rootView->fopen($source, 'w');
116
-			if ($copyResource === false || $sourceResource === false) {
117
-				throw new DecryptionFailedException('Failed to open ' . $source . ' or ' . $target);
118
-			}
119
-			if (stream_copy_to_stream($copyResource, $sourceResource) === false) {
120
-				$output->writeln('<error>Failed to copy ' . $target . ' data into ' . $source . '</error>');
121
-				$output->writeln('<error>Leaving both files in there to avoid data loss</error>');
122
-				return;
123
-			}
124
-			$this->rootView->touch($source, $fileInfo->getMTime());
125
-			$this->rootView->unlink($target);
126
-			$output->writeln('<info>Migrated ' . $source . '</info>', OutputInterface::VERBOSITY_VERBOSE);
127
-		} catch (DecryptionFailedException $e) {
128
-			if ($this->rootView->file_exists($target)) {
129
-				$this->rootView->unlink($target);
130
-			}
131
-			$output->writeln('<error>Failed to migrate ' . $path . '</error>');
132
-			$output->writeln('<error>' . $e . '</error>', OutputInterface::VERBOSITY_VERBOSE);
133
-		} finally {
134
-			if (is_resource($copyResource)) {
135
-				fclose($copyResource);
136
-			}
137
-			if (is_resource($sourceResource)) {
138
-				fclose($sourceResource);
139
-			}
140
-		}
141
-	}
142
-
143
-	/**
144
-	 * setup user file system
145
-	 */
146
-	protected function setupUserFS(string $uid): void {
147
-		\OC_Util::tearDownFS();
148
-		\OC_Util::setupFS($uid);
149
-	}
23
+    private View $rootView;
24
+
25
+    public function __construct(
26
+        private IUserManager $userManager,
27
+        private KeyManager $keyManager,
28
+    ) {
29
+        parent::__construct();
30
+
31
+        $this->rootView = new View();
32
+    }
33
+
34
+    protected function configure(): void {
35
+        $this
36
+            ->setName('encryption:drop-legacy-filekey')
37
+            ->setDescription('Scan the files for the legacy filekey format using RC4 and get rid of it (if master key is enabled)');
38
+    }
39
+
40
+    protected function execute(InputInterface $input, OutputInterface $output): int {
41
+        $result = true;
42
+
43
+        $output->writeln('<info>Scanning all files for legacy filekey</info>');
44
+
45
+        foreach ($this->userManager->getBackends() as $backend) {
46
+            $limit = 500;
47
+            $offset = 0;
48
+            do {
49
+                $users = $backend->getUsers('', $limit, $offset);
50
+                foreach ($users as $user) {
51
+                    $output->writeln('Scanning all files for ' . $user);
52
+                    $this->setupUserFS($user);
53
+                    $result = $result && $this->scanFolder($output, '/' . $user);
54
+                }
55
+                $offset += $limit;
56
+            } while (count($users) >= $limit);
57
+        }
58
+
59
+        if ($result) {
60
+            $output->writeln('All scanned files are properly encrypted.');
61
+            return self::SUCCESS;
62
+        }
63
+
64
+        return self::FAILURE;
65
+    }
66
+
67
+    private function scanFolder(OutputInterface $output, string $folder): bool {
68
+        $clean = true;
69
+
70
+        foreach ($this->rootView->getDirectoryContent($folder) as $item) {
71
+            $path = $folder . '/' . $item['name'];
72
+            if ($this->rootView->is_dir($path)) {
73
+                if ($this->scanFolder($output, $path) === false) {
74
+                    $clean = false;
75
+                }
76
+            } else {
77
+                if (!$item->isEncrypted()) {
78
+                    // ignore
79
+                    continue;
80
+                }
81
+
82
+                $stats = $this->rootView->stat($path);
83
+                if (!isset($stats['hasHeader']) || $stats['hasHeader'] === false) {
84
+                    $clean = false;
85
+                    $output->writeln('<error>' . $path . ' does not have a proper header</error>');
86
+                } else {
87
+                    try {
88
+                        $legacyFileKey = $this->keyManager->getFileKey($path, true);
89
+                        if ($legacyFileKey === '') {
90
+                            $output->writeln('Got an empty legacy filekey for ' . $path . ', continuing', OutputInterface::VERBOSITY_VERBOSE);
91
+                            continue;
92
+                        }
93
+                    } catch (GenericEncryptionException $e) {
94
+                        $output->writeln('Got a decryption error for legacy filekey for ' . $path . ', continuing', OutputInterface::VERBOSITY_VERBOSE);
95
+                        continue;
96
+                    }
97
+                    /* If that did not throw and filekey is not empty, a legacy filekey is used */
98
+                    $clean = false;
99
+                    $output->writeln($path . ' is using a legacy filekey, migrating');
100
+                    $this->migrateSinglefile($path, $item, $output);
101
+                }
102
+            }
103
+        }
104
+
105
+        return $clean;
106
+    }
107
+
108
+    private function migrateSinglefile(string $path, FileInfo $fileInfo, OutputInterface $output): void {
109
+        $source = $path;
110
+        $target = $path . '.reencrypted.' . time();
111
+
112
+        try {
113
+            $this->rootView->copy($source, $target);
114
+            $copyResource = $this->rootView->fopen($target, 'r');
115
+            $sourceResource = $this->rootView->fopen($source, 'w');
116
+            if ($copyResource === false || $sourceResource === false) {
117
+                throw new DecryptionFailedException('Failed to open ' . $source . ' or ' . $target);
118
+            }
119
+            if (stream_copy_to_stream($copyResource, $sourceResource) === false) {
120
+                $output->writeln('<error>Failed to copy ' . $target . ' data into ' . $source . '</error>');
121
+                $output->writeln('<error>Leaving both files in there to avoid data loss</error>');
122
+                return;
123
+            }
124
+            $this->rootView->touch($source, $fileInfo->getMTime());
125
+            $this->rootView->unlink($target);
126
+            $output->writeln('<info>Migrated ' . $source . '</info>', OutputInterface::VERBOSITY_VERBOSE);
127
+        } catch (DecryptionFailedException $e) {
128
+            if ($this->rootView->file_exists($target)) {
129
+                $this->rootView->unlink($target);
130
+            }
131
+            $output->writeln('<error>Failed to migrate ' . $path . '</error>');
132
+            $output->writeln('<error>' . $e . '</error>', OutputInterface::VERBOSITY_VERBOSE);
133
+        } finally {
134
+            if (is_resource($copyResource)) {
135
+                fclose($copyResource);
136
+            }
137
+            if (is_resource($sourceResource)) {
138
+                fclose($sourceResource);
139
+            }
140
+        }
141
+    }
142
+
143
+    /**
144
+     * setup user file system
145
+     */
146
+    protected function setupUserFS(string $uid): void {
147
+        \OC_Util::tearDownFS();
148
+        \OC_Util::setupFS($uid);
149
+    }
150 150
 }
Please login to merge, or discard this patch.
Spacing   +13 added lines, -13 removed lines patch added patch discarded remove patch
@@ -48,9 +48,9 @@  discard block
 block discarded – undo
48 48
 			do {
49 49
 				$users = $backend->getUsers('', $limit, $offset);
50 50
 				foreach ($users as $user) {
51
-					$output->writeln('Scanning all files for ' . $user);
51
+					$output->writeln('Scanning all files for '.$user);
52 52
 					$this->setupUserFS($user);
53
-					$result = $result && $this->scanFolder($output, '/' . $user);
53
+					$result = $result && $this->scanFolder($output, '/'.$user);
54 54
 				}
55 55
 				$offset += $limit;
56 56
 			} while (count($users) >= $limit);
@@ -68,7 +68,7 @@  discard block
 block discarded – undo
68 68
 		$clean = true;
69 69
 
70 70
 		foreach ($this->rootView->getDirectoryContent($folder) as $item) {
71
-			$path = $folder . '/' . $item['name'];
71
+			$path = $folder.'/'.$item['name'];
72 72
 			if ($this->rootView->is_dir($path)) {
73 73
 				if ($this->scanFolder($output, $path) === false) {
74 74
 					$clean = false;
@@ -82,21 +82,21 @@  discard block
 block discarded – undo
82 82
 				$stats = $this->rootView->stat($path);
83 83
 				if (!isset($stats['hasHeader']) || $stats['hasHeader'] === false) {
84 84
 					$clean = false;
85
-					$output->writeln('<error>' . $path . ' does not have a proper header</error>');
85
+					$output->writeln('<error>'.$path.' does not have a proper header</error>');
86 86
 				} else {
87 87
 					try {
88 88
 						$legacyFileKey = $this->keyManager->getFileKey($path, true);
89 89
 						if ($legacyFileKey === '') {
90
-							$output->writeln('Got an empty legacy filekey for ' . $path . ', continuing', OutputInterface::VERBOSITY_VERBOSE);
90
+							$output->writeln('Got an empty legacy filekey for '.$path.', continuing', OutputInterface::VERBOSITY_VERBOSE);
91 91
 							continue;
92 92
 						}
93 93
 					} catch (GenericEncryptionException $e) {
94
-						$output->writeln('Got a decryption error for legacy filekey for ' . $path . ', continuing', OutputInterface::VERBOSITY_VERBOSE);
94
+						$output->writeln('Got a decryption error for legacy filekey for '.$path.', continuing', OutputInterface::VERBOSITY_VERBOSE);
95 95
 						continue;
96 96
 					}
97 97
 					/* If that did not throw and filekey is not empty, a legacy filekey is used */
98 98
 					$clean = false;
99
-					$output->writeln($path . ' is using a legacy filekey, migrating');
99
+					$output->writeln($path.' is using a legacy filekey, migrating');
100 100
 					$this->migrateSinglefile($path, $item, $output);
101 101
 				}
102 102
 			}
@@ -107,29 +107,29 @@  discard block
 block discarded – undo
107 107
 
108 108
 	private function migrateSinglefile(string $path, FileInfo $fileInfo, OutputInterface $output): void {
109 109
 		$source = $path;
110
-		$target = $path . '.reencrypted.' . time();
110
+		$target = $path.'.reencrypted.'.time();
111 111
 
112 112
 		try {
113 113
 			$this->rootView->copy($source, $target);
114 114
 			$copyResource = $this->rootView->fopen($target, 'r');
115 115
 			$sourceResource = $this->rootView->fopen($source, 'w');
116 116
 			if ($copyResource === false || $sourceResource === false) {
117
-				throw new DecryptionFailedException('Failed to open ' . $source . ' or ' . $target);
117
+				throw new DecryptionFailedException('Failed to open '.$source.' or '.$target);
118 118
 			}
119 119
 			if (stream_copy_to_stream($copyResource, $sourceResource) === false) {
120
-				$output->writeln('<error>Failed to copy ' . $target . ' data into ' . $source . '</error>');
120
+				$output->writeln('<error>Failed to copy '.$target.' data into '.$source.'</error>');
121 121
 				$output->writeln('<error>Leaving both files in there to avoid data loss</error>');
122 122
 				return;
123 123
 			}
124 124
 			$this->rootView->touch($source, $fileInfo->getMTime());
125 125
 			$this->rootView->unlink($target);
126
-			$output->writeln('<info>Migrated ' . $source . '</info>', OutputInterface::VERBOSITY_VERBOSE);
126
+			$output->writeln('<info>Migrated '.$source.'</info>', OutputInterface::VERBOSITY_VERBOSE);
127 127
 		} catch (DecryptionFailedException $e) {
128 128
 			if ($this->rootView->file_exists($target)) {
129 129
 				$this->rootView->unlink($target);
130 130
 			}
131
-			$output->writeln('<error>Failed to migrate ' . $path . '</error>');
132
-			$output->writeln('<error>' . $e . '</error>', OutputInterface::VERBOSITY_VERBOSE);
131
+			$output->writeln('<error>Failed to migrate '.$path.'</error>');
132
+			$output->writeln('<error>'.$e.'</error>', OutputInterface::VERBOSITY_VERBOSE);
133 133
 		} finally {
134 134
 			if (is_resource($copyResource)) {
135 135
 				fclose($copyResource);
Please login to merge, or discard this patch.
apps/encryption/lib/Recovery.php 2 patches
Indentation   +238 added lines, -238 removed lines patch added patch discarded remove patch
@@ -16,242 +16,242 @@
 block discarded – undo
16 16
 use OCP\PreConditionNotMetException;
17 17
 
18 18
 class Recovery {
19
-	/**
20
-	 * @var null|IUser
21
-	 */
22
-	protected $user;
23
-
24
-	/**
25
-	 * @param IUserSession $userSession
26
-	 * @param Crypt $crypt
27
-	 * @param KeyManager $keyManager
28
-	 * @param IConfig $config
29
-	 * @param IFile $file
30
-	 * @param View $view
31
-	 */
32
-	public function __construct(
33
-		IUserSession $userSession,
34
-		protected Crypt $crypt,
35
-		private KeyManager $keyManager,
36
-		private IConfig $config,
37
-		private IFile $file,
38
-		private View $view,
39
-	) {
40
-		$this->user = ($userSession->isLoggedIn()) ? $userSession->getUser() : null;
41
-	}
42
-
43
-	/**
44
-	 * @param string $password
45
-	 * @return bool
46
-	 */
47
-	public function enableAdminRecovery($password) {
48
-		$appConfig = $this->config;
49
-		$keyManager = $this->keyManager;
50
-
51
-		if (!$keyManager->recoveryKeyExists()) {
52
-			$keyPair = $this->crypt->createKeyPair();
53
-			if (!is_array($keyPair)) {
54
-				return false;
55
-			}
56
-
57
-			$this->keyManager->setRecoveryKey($password, $keyPair);
58
-		}
59
-
60
-		if ($keyManager->checkRecoveryPassword($password)) {
61
-			$appConfig->setAppValue('encryption', 'recoveryAdminEnabled', '1');
62
-			return true;
63
-		}
64
-
65
-		return false;
66
-	}
67
-
68
-	/**
69
-	 * change recovery key id
70
-	 */
71
-	public function changeRecoveryKeyPassword(string $newPassword, string $oldPassword): bool {
72
-		$recoveryKey = $this->keyManager->getSystemPrivateKey($this->keyManager->getRecoveryKeyId());
73
-		$decryptedRecoveryKey = $this->crypt->decryptPrivateKey($recoveryKey, $oldPassword);
74
-		if ($decryptedRecoveryKey === false) {
75
-			return false;
76
-		}
77
-		$encryptedRecoveryKey = $this->crypt->encryptPrivateKey($decryptedRecoveryKey, $newPassword);
78
-		$header = $this->crypt->generateHeader();
79
-		if ($encryptedRecoveryKey !== false) {
80
-			$this->keyManager->setSystemPrivateKey($this->keyManager->getRecoveryKeyId(), $header . $encryptedRecoveryKey);
81
-			return true;
82
-		}
83
-		return false;
84
-	}
85
-
86
-	/**
87
-	 * @param string $recoveryPassword
88
-	 * @return bool
89
-	 */
90
-	public function disableAdminRecovery($recoveryPassword) {
91
-		$keyManager = $this->keyManager;
92
-
93
-		if ($keyManager->checkRecoveryPassword($recoveryPassword)) {
94
-			// Set recoveryAdmin as disabled
95
-			$this->config->setAppValue('encryption', 'recoveryAdminEnabled', '0');
96
-			return true;
97
-		}
98
-		return false;
99
-	}
100
-
101
-	/**
102
-	 * check if recovery is enabled for user
103
-	 *
104
-	 * @param string $user if no user is given we check the current logged-in user
105
-	 *
106
-	 * @return bool
107
-	 */
108
-	public function isRecoveryEnabledForUser($user = '') {
109
-		$uid = $user === '' ? $this->user->getUID() : $user;
110
-		$recoveryMode = $this->config->getUserValue($uid,
111
-			'encryption',
112
-			'recoveryEnabled',
113
-			0);
114
-
115
-		return ($recoveryMode === '1');
116
-	}
117
-
118
-	/**
119
-	 * check if recovery is key is enabled by the administrator
120
-	 *
121
-	 * @return bool
122
-	 */
123
-	public function isRecoveryKeyEnabled() {
124
-		$enabled = $this->config->getAppValue('encryption', 'recoveryAdminEnabled', '0');
125
-
126
-		return ($enabled === '1');
127
-	}
128
-
129
-	/**
130
-	 * @param string $value
131
-	 * @return bool
132
-	 */
133
-	public function setRecoveryForUser($value) {
134
-		try {
135
-			$this->config->setUserValue($this->user->getUID(),
136
-				'encryption',
137
-				'recoveryEnabled',
138
-				$value);
139
-
140
-			if ($value === '1') {
141
-				$this->addRecoveryKeys('/' . $this->user->getUID() . '/files/');
142
-			} else {
143
-				$this->removeRecoveryKeys('/' . $this->user->getUID() . '/files/');
144
-			}
145
-
146
-			return true;
147
-		} catch (PreConditionNotMetException $e) {
148
-			return false;
149
-		}
150
-	}
151
-
152
-	/**
153
-	 * add recovery key to all encrypted files
154
-	 */
155
-	private function addRecoveryKeys(string $path): void {
156
-		$dirContent = $this->view->getDirectoryContent($path);
157
-		foreach ($dirContent as $item) {
158
-			$filePath = $item->getPath();
159
-			if ($item['type'] === 'dir') {
160
-				$this->addRecoveryKeys($filePath . '/');
161
-			} else {
162
-				$fileKey = $this->keyManager->getFileKey($filePath, null);
163
-				if (!empty($fileKey)) {
164
-					$accessList = $this->file->getAccessList($filePath);
165
-					$publicKeys = [];
166
-					foreach ($accessList['users'] as $uid) {
167
-						$publicKeys[$uid] = $this->keyManager->getPublicKey($uid);
168
-					}
169
-
170
-					$publicKeys = $this->keyManager->addSystemKeys($accessList, $publicKeys, $this->user->getUID());
171
-
172
-					$shareKeys = $this->crypt->multiKeyEncrypt($fileKey, $publicKeys);
173
-					$this->keyManager->deleteLegacyFileKey($filePath);
174
-					foreach ($shareKeys as $uid => $keyFile) {
175
-						$this->keyManager->setShareKey($filePath, $uid, $keyFile);
176
-					}
177
-				}
178
-			}
179
-		}
180
-	}
181
-
182
-	/**
183
-	 * remove recovery key to all encrypted files
184
-	 */
185
-	private function removeRecoveryKeys(string $path): void {
186
-		$dirContent = $this->view->getDirectoryContent($path);
187
-		foreach ($dirContent as $item) {
188
-			$filePath = $item->getPath();
189
-			if ($item['type'] === 'dir') {
190
-				$this->removeRecoveryKeys($filePath . '/');
191
-			} else {
192
-				$this->keyManager->deleteShareKey($filePath, $this->keyManager->getRecoveryKeyId());
193
-			}
194
-		}
195
-	}
196
-
197
-	/**
198
-	 * recover users files with the recovery key
199
-	 */
200
-	public function recoverUsersFiles(string $recoveryPassword, string $user): void {
201
-		$encryptedKey = $this->keyManager->getSystemPrivateKey($this->keyManager->getRecoveryKeyId());
202
-
203
-		$privateKey = $this->crypt->decryptPrivateKey($encryptedKey, $recoveryPassword);
204
-		if ($privateKey !== false) {
205
-			$this->recoverAllFiles('/' . $user . '/files/', $privateKey, $user);
206
-		}
207
-	}
208
-
209
-	/**
210
-	 * recover users files
211
-	 */
212
-	private function recoverAllFiles(string $path, string $privateKey, string $uid): void {
213
-		$dirContent = $this->view->getDirectoryContent($path);
214
-
215
-		foreach ($dirContent as $item) {
216
-			// Get relative path from encryption/keyfiles
217
-			$filePath = $item->getPath();
218
-			if ($this->view->is_dir($filePath)) {
219
-				$this->recoverAllFiles($filePath . '/', $privateKey, $uid);
220
-			} else {
221
-				$this->recoverFile($filePath, $privateKey, $uid);
222
-			}
223
-		}
224
-	}
225
-
226
-	/**
227
-	 * recover file
228
-	 */
229
-	private function recoverFile(string $path, string $privateKey, string $uid): void {
230
-		$encryptedFileKey = $this->keyManager->getEncryptedFileKey($path);
231
-		$shareKey = $this->keyManager->getShareKey($path, $this->keyManager->getRecoveryKeyId());
232
-
233
-		if ($encryptedFileKey && $shareKey && $privateKey) {
234
-			$fileKey = $this->crypt->multiKeyDecryptLegacy($encryptedFileKey,
235
-				$shareKey,
236
-				$privateKey);
237
-		} elseif ($shareKey && $privateKey) {
238
-			$fileKey = $this->crypt->multiKeyDecrypt($shareKey, $privateKey);
239
-		}
240
-
241
-		if (!empty($fileKey)) {
242
-			$accessList = $this->file->getAccessList($path);
243
-			$publicKeys = [];
244
-			foreach ($accessList['users'] as $user) {
245
-				$publicKeys[$user] = $this->keyManager->getPublicKey($user);
246
-			}
247
-
248
-			$publicKeys = $this->keyManager->addSystemKeys($accessList, $publicKeys, $uid);
249
-
250
-			$shareKeys = $this->crypt->multiKeyEncrypt($fileKey, $publicKeys);
251
-			$this->keyManager->deleteLegacyFileKey($path);
252
-			foreach ($shareKeys as $uid => $keyFile) {
253
-				$this->keyManager->setShareKey($path, $uid, $keyFile);
254
-			}
255
-		}
256
-	}
19
+    /**
20
+     * @var null|IUser
21
+     */
22
+    protected $user;
23
+
24
+    /**
25
+     * @param IUserSession $userSession
26
+     * @param Crypt $crypt
27
+     * @param KeyManager $keyManager
28
+     * @param IConfig $config
29
+     * @param IFile $file
30
+     * @param View $view
31
+     */
32
+    public function __construct(
33
+        IUserSession $userSession,
34
+        protected Crypt $crypt,
35
+        private KeyManager $keyManager,
36
+        private IConfig $config,
37
+        private IFile $file,
38
+        private View $view,
39
+    ) {
40
+        $this->user = ($userSession->isLoggedIn()) ? $userSession->getUser() : null;
41
+    }
42
+
43
+    /**
44
+     * @param string $password
45
+     * @return bool
46
+     */
47
+    public function enableAdminRecovery($password) {
48
+        $appConfig = $this->config;
49
+        $keyManager = $this->keyManager;
50
+
51
+        if (!$keyManager->recoveryKeyExists()) {
52
+            $keyPair = $this->crypt->createKeyPair();
53
+            if (!is_array($keyPair)) {
54
+                return false;
55
+            }
56
+
57
+            $this->keyManager->setRecoveryKey($password, $keyPair);
58
+        }
59
+
60
+        if ($keyManager->checkRecoveryPassword($password)) {
61
+            $appConfig->setAppValue('encryption', 'recoveryAdminEnabled', '1');
62
+            return true;
63
+        }
64
+
65
+        return false;
66
+    }
67
+
68
+    /**
69
+     * change recovery key id
70
+     */
71
+    public function changeRecoveryKeyPassword(string $newPassword, string $oldPassword): bool {
72
+        $recoveryKey = $this->keyManager->getSystemPrivateKey($this->keyManager->getRecoveryKeyId());
73
+        $decryptedRecoveryKey = $this->crypt->decryptPrivateKey($recoveryKey, $oldPassword);
74
+        if ($decryptedRecoveryKey === false) {
75
+            return false;
76
+        }
77
+        $encryptedRecoveryKey = $this->crypt->encryptPrivateKey($decryptedRecoveryKey, $newPassword);
78
+        $header = $this->crypt->generateHeader();
79
+        if ($encryptedRecoveryKey !== false) {
80
+            $this->keyManager->setSystemPrivateKey($this->keyManager->getRecoveryKeyId(), $header . $encryptedRecoveryKey);
81
+            return true;
82
+        }
83
+        return false;
84
+    }
85
+
86
+    /**
87
+     * @param string $recoveryPassword
88
+     * @return bool
89
+     */
90
+    public function disableAdminRecovery($recoveryPassword) {
91
+        $keyManager = $this->keyManager;
92
+
93
+        if ($keyManager->checkRecoveryPassword($recoveryPassword)) {
94
+            // Set recoveryAdmin as disabled
95
+            $this->config->setAppValue('encryption', 'recoveryAdminEnabled', '0');
96
+            return true;
97
+        }
98
+        return false;
99
+    }
100
+
101
+    /**
102
+     * check if recovery is enabled for user
103
+     *
104
+     * @param string $user if no user is given we check the current logged-in user
105
+     *
106
+     * @return bool
107
+     */
108
+    public function isRecoveryEnabledForUser($user = '') {
109
+        $uid = $user === '' ? $this->user->getUID() : $user;
110
+        $recoveryMode = $this->config->getUserValue($uid,
111
+            'encryption',
112
+            'recoveryEnabled',
113
+            0);
114
+
115
+        return ($recoveryMode === '1');
116
+    }
117
+
118
+    /**
119
+     * check if recovery is key is enabled by the administrator
120
+     *
121
+     * @return bool
122
+     */
123
+    public function isRecoveryKeyEnabled() {
124
+        $enabled = $this->config->getAppValue('encryption', 'recoveryAdminEnabled', '0');
125
+
126
+        return ($enabled === '1');
127
+    }
128
+
129
+    /**
130
+     * @param string $value
131
+     * @return bool
132
+     */
133
+    public function setRecoveryForUser($value) {
134
+        try {
135
+            $this->config->setUserValue($this->user->getUID(),
136
+                'encryption',
137
+                'recoveryEnabled',
138
+                $value);
139
+
140
+            if ($value === '1') {
141
+                $this->addRecoveryKeys('/' . $this->user->getUID() . '/files/');
142
+            } else {
143
+                $this->removeRecoveryKeys('/' . $this->user->getUID() . '/files/');
144
+            }
145
+
146
+            return true;
147
+        } catch (PreConditionNotMetException $e) {
148
+            return false;
149
+        }
150
+    }
151
+
152
+    /**
153
+     * add recovery key to all encrypted files
154
+     */
155
+    private function addRecoveryKeys(string $path): void {
156
+        $dirContent = $this->view->getDirectoryContent($path);
157
+        foreach ($dirContent as $item) {
158
+            $filePath = $item->getPath();
159
+            if ($item['type'] === 'dir') {
160
+                $this->addRecoveryKeys($filePath . '/');
161
+            } else {
162
+                $fileKey = $this->keyManager->getFileKey($filePath, null);
163
+                if (!empty($fileKey)) {
164
+                    $accessList = $this->file->getAccessList($filePath);
165
+                    $publicKeys = [];
166
+                    foreach ($accessList['users'] as $uid) {
167
+                        $publicKeys[$uid] = $this->keyManager->getPublicKey($uid);
168
+                    }
169
+
170
+                    $publicKeys = $this->keyManager->addSystemKeys($accessList, $publicKeys, $this->user->getUID());
171
+
172
+                    $shareKeys = $this->crypt->multiKeyEncrypt($fileKey, $publicKeys);
173
+                    $this->keyManager->deleteLegacyFileKey($filePath);
174
+                    foreach ($shareKeys as $uid => $keyFile) {
175
+                        $this->keyManager->setShareKey($filePath, $uid, $keyFile);
176
+                    }
177
+                }
178
+            }
179
+        }
180
+    }
181
+
182
+    /**
183
+     * remove recovery key to all encrypted files
184
+     */
185
+    private function removeRecoveryKeys(string $path): void {
186
+        $dirContent = $this->view->getDirectoryContent($path);
187
+        foreach ($dirContent as $item) {
188
+            $filePath = $item->getPath();
189
+            if ($item['type'] === 'dir') {
190
+                $this->removeRecoveryKeys($filePath . '/');
191
+            } else {
192
+                $this->keyManager->deleteShareKey($filePath, $this->keyManager->getRecoveryKeyId());
193
+            }
194
+        }
195
+    }
196
+
197
+    /**
198
+     * recover users files with the recovery key
199
+     */
200
+    public function recoverUsersFiles(string $recoveryPassword, string $user): void {
201
+        $encryptedKey = $this->keyManager->getSystemPrivateKey($this->keyManager->getRecoveryKeyId());
202
+
203
+        $privateKey = $this->crypt->decryptPrivateKey($encryptedKey, $recoveryPassword);
204
+        if ($privateKey !== false) {
205
+            $this->recoverAllFiles('/' . $user . '/files/', $privateKey, $user);
206
+        }
207
+    }
208
+
209
+    /**
210
+     * recover users files
211
+     */
212
+    private function recoverAllFiles(string $path, string $privateKey, string $uid): void {
213
+        $dirContent = $this->view->getDirectoryContent($path);
214
+
215
+        foreach ($dirContent as $item) {
216
+            // Get relative path from encryption/keyfiles
217
+            $filePath = $item->getPath();
218
+            if ($this->view->is_dir($filePath)) {
219
+                $this->recoverAllFiles($filePath . '/', $privateKey, $uid);
220
+            } else {
221
+                $this->recoverFile($filePath, $privateKey, $uid);
222
+            }
223
+        }
224
+    }
225
+
226
+    /**
227
+     * recover file
228
+     */
229
+    private function recoverFile(string $path, string $privateKey, string $uid): void {
230
+        $encryptedFileKey = $this->keyManager->getEncryptedFileKey($path);
231
+        $shareKey = $this->keyManager->getShareKey($path, $this->keyManager->getRecoveryKeyId());
232
+
233
+        if ($encryptedFileKey && $shareKey && $privateKey) {
234
+            $fileKey = $this->crypt->multiKeyDecryptLegacy($encryptedFileKey,
235
+                $shareKey,
236
+                $privateKey);
237
+        } elseif ($shareKey && $privateKey) {
238
+            $fileKey = $this->crypt->multiKeyDecrypt($shareKey, $privateKey);
239
+        }
240
+
241
+        if (!empty($fileKey)) {
242
+            $accessList = $this->file->getAccessList($path);
243
+            $publicKeys = [];
244
+            foreach ($accessList['users'] as $user) {
245
+                $publicKeys[$user] = $this->keyManager->getPublicKey($user);
246
+            }
247
+
248
+            $publicKeys = $this->keyManager->addSystemKeys($accessList, $publicKeys, $uid);
249
+
250
+            $shareKeys = $this->crypt->multiKeyEncrypt($fileKey, $publicKeys);
251
+            $this->keyManager->deleteLegacyFileKey($path);
252
+            foreach ($shareKeys as $uid => $keyFile) {
253
+                $this->keyManager->setShareKey($path, $uid, $keyFile);
254
+            }
255
+        }
256
+    }
257 257
 }
Please login to merge, or discard this patch.
Spacing   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -77,7 +77,7 @@  discard block
 block discarded – undo
77 77
 		$encryptedRecoveryKey = $this->crypt->encryptPrivateKey($decryptedRecoveryKey, $newPassword);
78 78
 		$header = $this->crypt->generateHeader();
79 79
 		if ($encryptedRecoveryKey !== false) {
80
-			$this->keyManager->setSystemPrivateKey($this->keyManager->getRecoveryKeyId(), $header . $encryptedRecoveryKey);
80
+			$this->keyManager->setSystemPrivateKey($this->keyManager->getRecoveryKeyId(), $header.$encryptedRecoveryKey);
81 81
 			return true;
82 82
 		}
83 83
 		return false;
@@ -138,9 +138,9 @@  discard block
 block discarded – undo
138 138
 				$value);
139 139
 
140 140
 			if ($value === '1') {
141
-				$this->addRecoveryKeys('/' . $this->user->getUID() . '/files/');
141
+				$this->addRecoveryKeys('/'.$this->user->getUID().'/files/');
142 142
 			} else {
143
-				$this->removeRecoveryKeys('/' . $this->user->getUID() . '/files/');
143
+				$this->removeRecoveryKeys('/'.$this->user->getUID().'/files/');
144 144
 			}
145 145
 
146 146
 			return true;
@@ -157,7 +157,7 @@  discard block
 block discarded – undo
157 157
 		foreach ($dirContent as $item) {
158 158
 			$filePath = $item->getPath();
159 159
 			if ($item['type'] === 'dir') {
160
-				$this->addRecoveryKeys($filePath . '/');
160
+				$this->addRecoveryKeys($filePath.'/');
161 161
 			} else {
162 162
 				$fileKey = $this->keyManager->getFileKey($filePath, null);
163 163
 				if (!empty($fileKey)) {
@@ -187,7 +187,7 @@  discard block
 block discarded – undo
187 187
 		foreach ($dirContent as $item) {
188 188
 			$filePath = $item->getPath();
189 189
 			if ($item['type'] === 'dir') {
190
-				$this->removeRecoveryKeys($filePath . '/');
190
+				$this->removeRecoveryKeys($filePath.'/');
191 191
 			} else {
192 192
 				$this->keyManager->deleteShareKey($filePath, $this->keyManager->getRecoveryKeyId());
193 193
 			}
@@ -202,7 +202,7 @@  discard block
 block discarded – undo
202 202
 
203 203
 		$privateKey = $this->crypt->decryptPrivateKey($encryptedKey, $recoveryPassword);
204 204
 		if ($privateKey !== false) {
205
-			$this->recoverAllFiles('/' . $user . '/files/', $privateKey, $user);
205
+			$this->recoverAllFiles('/'.$user.'/files/', $privateKey, $user);
206 206
 		}
207 207
 	}
208 208
 
@@ -216,7 +216,7 @@  discard block
 block discarded – undo
216 216
 			// Get relative path from encryption/keyfiles
217 217
 			$filePath = $item->getPath();
218 218
 			if ($this->view->is_dir($filePath)) {
219
-				$this->recoverAllFiles($filePath . '/', $privateKey, $uid);
219
+				$this->recoverAllFiles($filePath.'/', $privateKey, $uid);
220 220
 			} else {
221 221
 				$this->recoverFile($filePath, $privateKey, $uid);
222 222
 			}
Please login to merge, or discard this patch.
apps/encryption/lib/Session.php 1 patch
Indentation   +137 added lines, -137 removed lines patch added patch discarded remove patch
@@ -14,141 +14,141 @@
 block discarded – undo
14 14
 use OCP\ISession;
15 15
 
16 16
 class Session {
17
-	public const NOT_INITIALIZED = '0';
18
-	public const INIT_EXECUTED = '1';
19
-	public const INIT_SUCCESSFUL = '2';
20
-
21
-	public function __construct(
22
-		protected ISession $session,
23
-	) {
24
-	}
25
-
26
-	/**
27
-	 * Sets status of encryption app
28
-	 *
29
-	 * @param string $status INIT_SUCCESSFUL, INIT_EXECUTED, NOT_INITIALIZED
30
-	 */
31
-	public function setStatus(string $status): void {
32
-		$this->session->set('encryptionInitialized', $status);
33
-	}
34
-
35
-	/**
36
-	 * Gets status if we already tried to initialize the encryption app
37
-	 *
38
-	 * @return string init status INIT_SUCCESSFUL, INIT_EXECUTED, NOT_INITIALIZED
39
-	 */
40
-	public function getStatus(): string {
41
-		$status = $this->session->get('encryptionInitialized');
42
-		if (is_null($status)) {
43
-			$status = self::NOT_INITIALIZED;
44
-		}
45
-
46
-		return $status;
47
-	}
48
-
49
-	/**
50
-	 * check if encryption was initialized successfully
51
-	 */
52
-	public function isReady(): bool {
53
-		$status = $this->getStatus();
54
-		return $status === self::INIT_SUCCESSFUL;
55
-	}
56
-
57
-	/**
58
-	 * Gets user or public share private key from session
59
-	 *
60
-	 * @return string $privateKey The user's plaintext private key
61
-	 * @throws Exceptions\PrivateKeyMissingException
62
-	 */
63
-	public function getPrivateKey(): string {
64
-		$key = $this->session->get('privateKey');
65
-		if (is_null($key)) {
66
-			throw new PrivateKeyMissingException('please try to log-out and log-in again');
67
-		}
68
-		return $key;
69
-	}
70
-
71
-	/**
72
-	 * check if private key is set
73
-	 */
74
-	public function isPrivateKeySet(): bool {
75
-		$key = $this->session->get('privateKey');
76
-		if (is_null($key)) {
77
-			return false;
78
-		}
79
-
80
-		return true;
81
-	}
82
-
83
-	/**
84
-	 * Sets user private key to session
85
-	 *
86
-	 * @param string $key users private key
87
-	 *
88
-	 * @note this should only be set on login
89
-	 */
90
-	public function setPrivateKey(string $key): void {
91
-		$this->session->set('privateKey', $key);
92
-	}
93
-
94
-	/**
95
-	 * store data needed for the decrypt all operation in the session
96
-	 */
97
-	public function prepareDecryptAll(string $user, string $key): void {
98
-		$this->session->set('decryptAll', true);
99
-		$this->session->set('decryptAllKey', $key);
100
-		$this->session->set('decryptAllUid', $user);
101
-	}
102
-
103
-	/**
104
-	 * check if we are in decrypt all mode
105
-	 */
106
-	public function decryptAllModeActivated(): bool {
107
-		$decryptAll = $this->session->get('decryptAll');
108
-		return ($decryptAll === true);
109
-	}
110
-
111
-	/**
112
-	 * get uid used for decrypt all operation
113
-	 *
114
-	 * @throws \Exception
115
-	 */
116
-	public function getDecryptAllUid(): string {
117
-		$uid = $this->session->get('decryptAllUid');
118
-		if (is_null($uid) && $this->decryptAllModeActivated()) {
119
-			throw new \Exception('No uid found while in decrypt all mode');
120
-		} elseif (is_null($uid)) {
121
-			throw new \Exception('Please activate decrypt all mode first');
122
-		}
123
-
124
-		return $uid;
125
-	}
126
-
127
-	/**
128
-	 * get private key for decrypt all operation
129
-	 *
130
-	 * @throws PrivateKeyMissingException
131
-	 */
132
-	public function getDecryptAllKey(): string {
133
-		$privateKey = $this->session->get('decryptAllKey');
134
-		if (is_null($privateKey) && $this->decryptAllModeActivated()) {
135
-			throw new PrivateKeyMissingException('No private key found while in decrypt all mode');
136
-		} elseif (is_null($privateKey)) {
137
-			throw new PrivateKeyMissingException('Please activate decrypt all mode first');
138
-		}
139
-
140
-		return $privateKey;
141
-	}
142
-
143
-	/**
144
-	 * remove keys from session
145
-	 */
146
-	public function clear(): void {
147
-		$this->session->remove('publicSharePrivateKey');
148
-		$this->session->remove('privateKey');
149
-		$this->session->remove('encryptionInitialized');
150
-		$this->session->remove('decryptAll');
151
-		$this->session->remove('decryptAllKey');
152
-		$this->session->remove('decryptAllUid');
153
-	}
17
+    public const NOT_INITIALIZED = '0';
18
+    public const INIT_EXECUTED = '1';
19
+    public const INIT_SUCCESSFUL = '2';
20
+
21
+    public function __construct(
22
+        protected ISession $session,
23
+    ) {
24
+    }
25
+
26
+    /**
27
+     * Sets status of encryption app
28
+     *
29
+     * @param string $status INIT_SUCCESSFUL, INIT_EXECUTED, NOT_INITIALIZED
30
+     */
31
+    public function setStatus(string $status): void {
32
+        $this->session->set('encryptionInitialized', $status);
33
+    }
34
+
35
+    /**
36
+     * Gets status if we already tried to initialize the encryption app
37
+     *
38
+     * @return string init status INIT_SUCCESSFUL, INIT_EXECUTED, NOT_INITIALIZED
39
+     */
40
+    public function getStatus(): string {
41
+        $status = $this->session->get('encryptionInitialized');
42
+        if (is_null($status)) {
43
+            $status = self::NOT_INITIALIZED;
44
+        }
45
+
46
+        return $status;
47
+    }
48
+
49
+    /**
50
+     * check if encryption was initialized successfully
51
+     */
52
+    public function isReady(): bool {
53
+        $status = $this->getStatus();
54
+        return $status === self::INIT_SUCCESSFUL;
55
+    }
56
+
57
+    /**
58
+     * Gets user or public share private key from session
59
+     *
60
+     * @return string $privateKey The user's plaintext private key
61
+     * @throws Exceptions\PrivateKeyMissingException
62
+     */
63
+    public function getPrivateKey(): string {
64
+        $key = $this->session->get('privateKey');
65
+        if (is_null($key)) {
66
+            throw new PrivateKeyMissingException('please try to log-out and log-in again');
67
+        }
68
+        return $key;
69
+    }
70
+
71
+    /**
72
+     * check if private key is set
73
+     */
74
+    public function isPrivateKeySet(): bool {
75
+        $key = $this->session->get('privateKey');
76
+        if (is_null($key)) {
77
+            return false;
78
+        }
79
+
80
+        return true;
81
+    }
82
+
83
+    /**
84
+     * Sets user private key to session
85
+     *
86
+     * @param string $key users private key
87
+     *
88
+     * @note this should only be set on login
89
+     */
90
+    public function setPrivateKey(string $key): void {
91
+        $this->session->set('privateKey', $key);
92
+    }
93
+
94
+    /**
95
+     * store data needed for the decrypt all operation in the session
96
+     */
97
+    public function prepareDecryptAll(string $user, string $key): void {
98
+        $this->session->set('decryptAll', true);
99
+        $this->session->set('decryptAllKey', $key);
100
+        $this->session->set('decryptAllUid', $user);
101
+    }
102
+
103
+    /**
104
+     * check if we are in decrypt all mode
105
+     */
106
+    public function decryptAllModeActivated(): bool {
107
+        $decryptAll = $this->session->get('decryptAll');
108
+        return ($decryptAll === true);
109
+    }
110
+
111
+    /**
112
+     * get uid used for decrypt all operation
113
+     *
114
+     * @throws \Exception
115
+     */
116
+    public function getDecryptAllUid(): string {
117
+        $uid = $this->session->get('decryptAllUid');
118
+        if (is_null($uid) && $this->decryptAllModeActivated()) {
119
+            throw new \Exception('No uid found while in decrypt all mode');
120
+        } elseif (is_null($uid)) {
121
+            throw new \Exception('Please activate decrypt all mode first');
122
+        }
123
+
124
+        return $uid;
125
+    }
126
+
127
+    /**
128
+     * get private key for decrypt all operation
129
+     *
130
+     * @throws PrivateKeyMissingException
131
+     */
132
+    public function getDecryptAllKey(): string {
133
+        $privateKey = $this->session->get('decryptAllKey');
134
+        if (is_null($privateKey) && $this->decryptAllModeActivated()) {
135
+            throw new PrivateKeyMissingException('No private key found while in decrypt all mode');
136
+        } elseif (is_null($privateKey)) {
137
+            throw new PrivateKeyMissingException('Please activate decrypt all mode first');
138
+        }
139
+
140
+        return $privateKey;
141
+    }
142
+
143
+    /**
144
+     * remove keys from session
145
+     */
146
+    public function clear(): void {
147
+        $this->session->remove('publicSharePrivateKey');
148
+        $this->session->remove('privateKey');
149
+        $this->session->remove('encryptionInitialized');
150
+        $this->session->remove('decryptAll');
151
+        $this->session->remove('decryptAllKey');
152
+        $this->session->remove('decryptAllUid');
153
+    }
154 154
 }
Please login to merge, or discard this patch.
apps/encryption/tests/Crypto/EncryptionTest.php 1 patch
Indentation   +374 added lines, -374 removed lines patch added patch discarded remove patch
@@ -29,378 +29,378 @@
 block discarded – undo
29 29
 
30 30
 class EncryptionTest extends TestCase {
31 31
 
32
-	protected Encryption $instance;
33
-
34
-	protected KeyManager&MockObject $keyManagerMock;
35
-	protected EncryptAll&MockObject $encryptAllMock;
36
-	protected DecryptAll&MockObject $decryptAllMock;
37
-	protected Session&MockObject $sessionMock;
38
-	protected Crypt&MockObject $cryptMock;
39
-	protected Util&MockObject $utilMock;
40
-	protected LoggerInterface&MockObject $loggerMock;
41
-	protected IL10N&MockObject $l10nMock;
42
-	protected IStorage&MockObject $storageMock;
43
-
44
-	protected function setUp(): void {
45
-		parent::setUp();
46
-
47
-		$this->storageMock = $this->getMockBuilder(IStorage::class)
48
-			->disableOriginalConstructor()->getMock();
49
-		$this->cryptMock = $this->getMockBuilder(Crypt::class)
50
-			->disableOriginalConstructor()
51
-			->getMock();
52
-		$this->utilMock = $this->getMockBuilder(Util::class)
53
-			->disableOriginalConstructor()
54
-			->getMock();
55
-		$this->keyManagerMock = $this->getMockBuilder(KeyManager::class)
56
-			->disableOriginalConstructor()
57
-			->getMock();
58
-		$this->sessionMock = $this->getMockBuilder(Session::class)
59
-			->disableOriginalConstructor()
60
-			->getMock();
61
-		$this->encryptAllMock = $this->getMockBuilder(EncryptAll::class)
62
-			->disableOriginalConstructor()
63
-			->getMock();
64
-		$this->decryptAllMock = $this->getMockBuilder(DecryptAll::class)
65
-			->disableOriginalConstructor()
66
-			->getMock();
67
-		$this->loggerMock = $this->getMockBuilder(LoggerInterface::class)
68
-			->disableOriginalConstructor()
69
-			->getMock();
70
-		$this->l10nMock = $this->getMockBuilder(IL10N::class)
71
-			->disableOriginalConstructor()
72
-			->getMock();
73
-		$this->l10nMock->expects($this->any())
74
-			->method('t')
75
-			->with($this->anything())
76
-			->willReturnArgument(0);
77
-
78
-		$this->instance = new Encryption(
79
-			$this->cryptMock,
80
-			$this->keyManagerMock,
81
-			$this->utilMock,
82
-			$this->sessionMock,
83
-			$this->encryptAllMock,
84
-			$this->decryptAllMock,
85
-			$this->loggerMock,
86
-			$this->l10nMock
87
-		);
88
-	}
89
-
90
-	/**
91
-	 * test if public key from one of the recipients is missing
92
-	 */
93
-	public function testEndUser1(): void {
94
-		$this->sessionMock->expects($this->once())
95
-			->method('decryptAllModeActivated')
96
-			->willReturn(false);
97
-
98
-		$this->instance->begin('/foo/bar', 'user1', 'r', [], ['users' => ['user1', 'user2', 'user3']]);
99
-		$this->endTest();
100
-	}
101
-
102
-	/**
103
-	 * test if public key from owner is missing
104
-	 *
105
-	 */
106
-	public function testEndUser2(): void {
107
-		$this->sessionMock->expects($this->once())
108
-			->method('decryptAllModeActivated')
109
-			->willReturn(false);
110
-
111
-		$this->expectException(PublicKeyMissingException::class);
112
-
113
-		$this->instance->begin('/foo/bar', 'user2', 'r', [], ['users' => ['user1', 'user2', 'user3']]);
114
-		$this->endTest();
115
-	}
116
-
117
-	/**
118
-	 * common part of testEndUser1 and testEndUser2
119
-	 *
120
-	 * @throws PublicKeyMissingException
121
-	 */
122
-	public function endTest() {
123
-		// prepare internal variables
124
-		self::invokePrivate($this->instance, 'isWriteOperation', [true]);
125
-		self::invokePrivate($this->instance, 'writeCache', ['']);
126
-
127
-		$this->keyManagerMock->expects($this->any())
128
-			->method('getPublicKey')
129
-			->willReturnCallback([$this, 'getPublicKeyCallback']);
130
-		$this->keyManagerMock->expects($this->any())
131
-			->method('addSystemKeys')
132
-			->willReturnCallback([$this, 'addSystemKeysCallback']);
133
-		$this->cryptMock->expects($this->any())
134
-			->method('multiKeyEncrypt')
135
-			->willReturn([]);
136
-
137
-		$this->instance->end('/foo/bar');
138
-	}
139
-
140
-
141
-	public function getPublicKeyCallback($uid) {
142
-		if ($uid === 'user2') {
143
-			throw new PublicKeyMissingException($uid);
144
-		}
145
-		return $uid;
146
-	}
147
-
148
-	public function addSystemKeysCallback($accessList, $publicKeys) {
149
-		$this->assertSame(2, count($publicKeys));
150
-		$this->assertArrayHasKey('user1', $publicKeys);
151
-		$this->assertArrayHasKey('user3', $publicKeys);
152
-		return $publicKeys;
153
-	}
154
-
155
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataProviderForTestGetPathToRealFile')]
156
-	public function testGetPathToRealFile($path, $expected): void {
157
-		$this->assertSame($expected,
158
-			self::invokePrivate($this->instance, 'getPathToRealFile', [$path])
159
-		);
160
-	}
161
-
162
-	public static function dataProviderForTestGetPathToRealFile(): array {
163
-		return [
164
-			['/user/files/foo/bar.txt', '/user/files/foo/bar.txt'],
165
-			['/user/files/foo.txt', '/user/files/foo.txt'],
166
-			['/user/files_versions/foo.txt.v543534', '/user/files/foo.txt'],
167
-			['/user/files_versions/foo/bar.txt.v5454', '/user/files/foo/bar.txt'],
168
-		];
169
-	}
170
-
171
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestBegin')]
172
-	public function testBegin($mode, $header, $legacyCipher, $defaultCipher, $fileKey, $expected): void {
173
-		$this->sessionMock->expects($this->once())
174
-			->method('decryptAllModeActivated')
175
-			->willReturn(false);
176
-
177
-		$this->sessionMock->expects($this->never())->method('getDecryptAllUid');
178
-		$this->sessionMock->expects($this->never())->method('getDecryptAllKey');
179
-		$this->keyManagerMock->expects($this->never())->method('getEncryptedFileKey');
180
-		$this->keyManagerMock->expects($this->never())->method('getShareKey');
181
-		$this->cryptMock->expects($this->never())->method('multiKeyDecrypt');
182
-
183
-		$this->cryptMock->expects($this->any())
184
-			->method('getCipher')
185
-			->willReturn($defaultCipher);
186
-		$this->cryptMock->expects($this->any())
187
-			->method('getLegacyCipher')
188
-			->willReturn($legacyCipher);
189
-		if (empty($fileKey)) {
190
-			$this->cryptMock->expects($this->once())
191
-				->method('generateFileKey')
192
-				->willReturn('fileKey');
193
-		} else {
194
-			$this->cryptMock->expects($this->never())
195
-				->method('generateFileKey');
196
-		}
197
-
198
-		$this->keyManagerMock->expects($this->once())
199
-			->method('getFileKey')
200
-			->willReturn($fileKey);
201
-
202
-		$result = $this->instance->begin('/user/files/foo.txt', 'user', $mode, $header, []);
203
-
204
-		$this->assertArrayHasKey('cipher', $result);
205
-		$this->assertSame($expected, $result['cipher']);
206
-		if ($mode === 'w') {
207
-			$this->assertTrue(self::invokePrivate($this->instance, 'isWriteOperation'));
208
-		} else {
209
-			$this->assertFalse(self::invokePrivate($this->instance, 'isWriteOperation'));
210
-		}
211
-	}
212
-
213
-	public static function dataTestBegin(): array {
214
-		return [
215
-			['w', ['cipher' => 'myCipher'], 'legacyCipher', 'defaultCipher', 'fileKey', 'defaultCipher'],
216
-			['r', ['cipher' => 'myCipher'], 'legacyCipher', 'defaultCipher', 'fileKey', 'myCipher'],
217
-			['w', [], 'legacyCipher', 'defaultCipher', '', 'defaultCipher'],
218
-			['r', [], 'legacyCipher', 'defaultCipher', 'file_key', 'legacyCipher'],
219
-		];
220
-	}
221
-
222
-
223
-	/**
224
-	 * test begin() if decryptAll mode was activated
225
-	 */
226
-	public function testBeginDecryptAll(): void {
227
-		$path = '/user/files/foo.txt';
228
-		$fileKey = 'fileKey';
229
-
230
-		$this->sessionMock->expects($this->once())
231
-			->method('decryptAllModeActivated')
232
-			->willReturn(true);
233
-		$this->keyManagerMock->expects($this->once())
234
-			->method('getFileKey')
235
-			->with($path, null, true)
236
-			->willReturn($fileKey);
237
-
238
-		$this->instance->begin($path, 'user', 'r', [], []);
239
-
240
-		$this->assertSame($fileKey,
241
-			$this->invokePrivate($this->instance, 'fileKey')
242
-		);
243
-	}
244
-
245
-	/**
246
-	 * test begin() if encryption is not initialized but the master key is enabled
247
-	 * in this case we can initialize the encryption without a username/password
248
-	 * and continue
249
-	 */
250
-	public function testBeginInitMasterKey(): void {
251
-		$this->sessionMock->expects($this->once())
252
-			->method('decryptAllModeActivated')
253
-			->willReturn(false);
254
-
255
-		$this->sessionMock->expects($this->once())->method('isReady')->willReturn(false);
256
-		$this->utilMock->expects($this->once())->method('isMasterKeyEnabled')
257
-			->willReturn(true);
258
-		$this->keyManagerMock->expects($this->once())->method('init')->with('', '');
259
-
260
-		$this->instance->begin('/user/files/welcome.txt', 'user', 'r', [], []);
261
-	}
262
-
263
-	/**
264
-	 *
265
-	 * @param string $fileKey
266
-	 * @param boolean $expected
267
-	 */
268
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestUpdate')]
269
-	public function testUpdate($fileKey, $expected): void {
270
-		$this->keyManagerMock->expects($this->once())
271
-			->method('getFileKey')->willReturn($fileKey);
272
-
273
-		$this->keyManagerMock->expects($this->any())
274
-			->method('getPublicKey')->willReturn('publicKey');
275
-
276
-		$this->keyManagerMock->expects($this->any())
277
-			->method('addSystemKeys')
278
-			->willReturnCallback(function ($accessList, $publicKeys) {
279
-				return $publicKeys;
280
-			});
281
-
282
-		$this->keyManagerMock->expects($this->never())->method('getVersion');
283
-		$this->keyManagerMock->expects($this->never())->method('setVersion');
284
-
285
-		$this->assertSame($expected,
286
-			$this->instance->update('path', 'user1', ['users' => ['user1']])
287
-		);
288
-	}
289
-
290
-	public static function dataTestUpdate(): array {
291
-		return [
292
-			['', false],
293
-			['fileKey', true]
294
-		];
295
-	}
296
-
297
-	public function testUpdateNoUsers(): void {
298
-		$this->invokePrivate($this->instance, 'rememberVersion', [['path' => 2]]);
299
-
300
-		$this->keyManagerMock->expects($this->never())->method('getFileKey');
301
-		$this->keyManagerMock->expects($this->never())->method('getPublicKey');
302
-		$this->keyManagerMock->expects($this->never())->method('addSystemKeys');
303
-		$this->keyManagerMock->expects($this->once())->method('setVersion')
304
-			->willReturnCallback(function ($path, $version, $view): void {
305
-				$this->assertSame('path', $path);
306
-				$this->assertSame(2, $version);
307
-				$this->assertTrue($view instanceof View);
308
-			});
309
-		$this->instance->update('path', 'user1', []);
310
-	}
311
-
312
-	/**
313
-	 * Test case if the public key is missing. Nextcloud should still encrypt
314
-	 * the file for the remaining users
315
-	 */
316
-	public function testUpdateMissingPublicKey(): void {
317
-		$this->keyManagerMock->expects($this->once())
318
-			->method('getFileKey')->willReturn('fileKey');
319
-
320
-		$this->keyManagerMock->expects($this->any())
321
-			->method('getPublicKey')->willReturnCallback(
322
-				function ($user): void {
323
-					throw new PublicKeyMissingException($user);
324
-				}
325
-			);
326
-
327
-		$this->keyManagerMock->expects($this->any())
328
-			->method('addSystemKeys')
329
-			->willReturnCallback(function ($accessList, $publicKeys) {
330
-				return $publicKeys;
331
-			});
332
-
333
-		$this->cryptMock->expects($this->once())->method('multiKeyEncrypt')
334
-			->willReturnCallback(
335
-				function ($fileKey, $publicKeys) {
336
-					$this->assertEmpty($publicKeys);
337
-					$this->assertSame('fileKey', $fileKey);
338
-					return [];
339
-				}
340
-			);
341
-
342
-		$this->keyManagerMock->expects($this->never())->method('getVersion');
343
-		$this->keyManagerMock->expects($this->never())->method('setVersion');
344
-
345
-		$this->assertTrue(
346
-			$this->instance->update('path', 'user1', ['users' => ['user1']])
347
-		);
348
-	}
349
-
350
-	/**
351
-	 * by default the encryption module should encrypt regular files, files in
352
-	 * files_versions and files in files_trashbin
353
-	 */
354
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestShouldEncrypt')]
355
-	public function testShouldEncrypt($path, $shouldEncryptHomeStorage, $isHomeStorage, $expected): void {
356
-		$this->utilMock->expects($this->once())->method('shouldEncryptHomeStorage')
357
-			->willReturn($shouldEncryptHomeStorage);
358
-
359
-		if ($shouldEncryptHomeStorage === false) {
360
-			$this->storageMock->expects($this->once())->method('instanceOfStorage')
361
-				->with('\OCP\Files\IHomeStorage')->willReturn($isHomeStorage);
362
-			$this->utilMock->expects($this->once())->method('getStorage')->with($path)
363
-				->willReturn($this->storageMock);
364
-		}
365
-
366
-		$this->assertSame($expected,
367
-			$this->instance->shouldEncrypt($path)
368
-		);
369
-	}
370
-
371
-	public static function dataTestShouldEncrypt(): array {
372
-		return [
373
-			['/user1/files/foo.txt', true, true, true],
374
-			['/user1/files_versions/foo.txt', true, true, true],
375
-			['/user1/files_trashbin/foo.txt', true, true, true],
376
-			['/user1/some_folder/foo.txt', true, true, false],
377
-			['/user1/foo.txt', true, true, false],
378
-			['/user1/files', true, true, false],
379
-			['/user1/files_trashbin', true, true, false],
380
-			['/user1/files_versions', true, true, false],
381
-			// test if shouldEncryptHomeStorage is set to false
382
-			['/user1/files/foo.txt', false, true, false],
383
-			['/user1/files_versions/foo.txt', false, false, true],
384
-		];
385
-	}
386
-
387
-
388
-	public function testDecrypt(): void {
389
-		$this->expectException(DecryptionFailedException::class);
390
-		$this->expectExceptionMessage('Cannot decrypt this file, probably this is a shared file. Please ask the file owner to reshare the file with you.');
391
-
392
-		$this->instance->decrypt('abc');
393
-	}
394
-
395
-	public function testPrepareDecryptAll(): void {
396
-		/** @var \Symfony\Component\Console\Input\InputInterface $input */
397
-		$input = $this->createMock(InputInterface::class);
398
-		/** @var \Symfony\Component\Console\Output\OutputInterface $output */
399
-		$output = $this->createMock(OutputInterface::class);
400
-
401
-		$this->decryptAllMock->expects($this->once())->method('prepare')
402
-			->with($input, $output, 'user');
403
-
404
-		$this->instance->prepareDecryptAll($input, $output, 'user');
405
-	}
32
+    protected Encryption $instance;
33
+
34
+    protected KeyManager&MockObject $keyManagerMock;
35
+    protected EncryptAll&MockObject $encryptAllMock;
36
+    protected DecryptAll&MockObject $decryptAllMock;
37
+    protected Session&MockObject $sessionMock;
38
+    protected Crypt&MockObject $cryptMock;
39
+    protected Util&MockObject $utilMock;
40
+    protected LoggerInterface&MockObject $loggerMock;
41
+    protected IL10N&MockObject $l10nMock;
42
+    protected IStorage&MockObject $storageMock;
43
+
44
+    protected function setUp(): void {
45
+        parent::setUp();
46
+
47
+        $this->storageMock = $this->getMockBuilder(IStorage::class)
48
+            ->disableOriginalConstructor()->getMock();
49
+        $this->cryptMock = $this->getMockBuilder(Crypt::class)
50
+            ->disableOriginalConstructor()
51
+            ->getMock();
52
+        $this->utilMock = $this->getMockBuilder(Util::class)
53
+            ->disableOriginalConstructor()
54
+            ->getMock();
55
+        $this->keyManagerMock = $this->getMockBuilder(KeyManager::class)
56
+            ->disableOriginalConstructor()
57
+            ->getMock();
58
+        $this->sessionMock = $this->getMockBuilder(Session::class)
59
+            ->disableOriginalConstructor()
60
+            ->getMock();
61
+        $this->encryptAllMock = $this->getMockBuilder(EncryptAll::class)
62
+            ->disableOriginalConstructor()
63
+            ->getMock();
64
+        $this->decryptAllMock = $this->getMockBuilder(DecryptAll::class)
65
+            ->disableOriginalConstructor()
66
+            ->getMock();
67
+        $this->loggerMock = $this->getMockBuilder(LoggerInterface::class)
68
+            ->disableOriginalConstructor()
69
+            ->getMock();
70
+        $this->l10nMock = $this->getMockBuilder(IL10N::class)
71
+            ->disableOriginalConstructor()
72
+            ->getMock();
73
+        $this->l10nMock->expects($this->any())
74
+            ->method('t')
75
+            ->with($this->anything())
76
+            ->willReturnArgument(0);
77
+
78
+        $this->instance = new Encryption(
79
+            $this->cryptMock,
80
+            $this->keyManagerMock,
81
+            $this->utilMock,
82
+            $this->sessionMock,
83
+            $this->encryptAllMock,
84
+            $this->decryptAllMock,
85
+            $this->loggerMock,
86
+            $this->l10nMock
87
+        );
88
+    }
89
+
90
+    /**
91
+     * test if public key from one of the recipients is missing
92
+     */
93
+    public function testEndUser1(): void {
94
+        $this->sessionMock->expects($this->once())
95
+            ->method('decryptAllModeActivated')
96
+            ->willReturn(false);
97
+
98
+        $this->instance->begin('/foo/bar', 'user1', 'r', [], ['users' => ['user1', 'user2', 'user3']]);
99
+        $this->endTest();
100
+    }
101
+
102
+    /**
103
+     * test if public key from owner is missing
104
+     *
105
+     */
106
+    public function testEndUser2(): void {
107
+        $this->sessionMock->expects($this->once())
108
+            ->method('decryptAllModeActivated')
109
+            ->willReturn(false);
110
+
111
+        $this->expectException(PublicKeyMissingException::class);
112
+
113
+        $this->instance->begin('/foo/bar', 'user2', 'r', [], ['users' => ['user1', 'user2', 'user3']]);
114
+        $this->endTest();
115
+    }
116
+
117
+    /**
118
+     * common part of testEndUser1 and testEndUser2
119
+     *
120
+     * @throws PublicKeyMissingException
121
+     */
122
+    public function endTest() {
123
+        // prepare internal variables
124
+        self::invokePrivate($this->instance, 'isWriteOperation', [true]);
125
+        self::invokePrivate($this->instance, 'writeCache', ['']);
126
+
127
+        $this->keyManagerMock->expects($this->any())
128
+            ->method('getPublicKey')
129
+            ->willReturnCallback([$this, 'getPublicKeyCallback']);
130
+        $this->keyManagerMock->expects($this->any())
131
+            ->method('addSystemKeys')
132
+            ->willReturnCallback([$this, 'addSystemKeysCallback']);
133
+        $this->cryptMock->expects($this->any())
134
+            ->method('multiKeyEncrypt')
135
+            ->willReturn([]);
136
+
137
+        $this->instance->end('/foo/bar');
138
+    }
139
+
140
+
141
+    public function getPublicKeyCallback($uid) {
142
+        if ($uid === 'user2') {
143
+            throw new PublicKeyMissingException($uid);
144
+        }
145
+        return $uid;
146
+    }
147
+
148
+    public function addSystemKeysCallback($accessList, $publicKeys) {
149
+        $this->assertSame(2, count($publicKeys));
150
+        $this->assertArrayHasKey('user1', $publicKeys);
151
+        $this->assertArrayHasKey('user3', $publicKeys);
152
+        return $publicKeys;
153
+    }
154
+
155
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataProviderForTestGetPathToRealFile')]
156
+    public function testGetPathToRealFile($path, $expected): void {
157
+        $this->assertSame($expected,
158
+            self::invokePrivate($this->instance, 'getPathToRealFile', [$path])
159
+        );
160
+    }
161
+
162
+    public static function dataProviderForTestGetPathToRealFile(): array {
163
+        return [
164
+            ['/user/files/foo/bar.txt', '/user/files/foo/bar.txt'],
165
+            ['/user/files/foo.txt', '/user/files/foo.txt'],
166
+            ['/user/files_versions/foo.txt.v543534', '/user/files/foo.txt'],
167
+            ['/user/files_versions/foo/bar.txt.v5454', '/user/files/foo/bar.txt'],
168
+        ];
169
+    }
170
+
171
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestBegin')]
172
+    public function testBegin($mode, $header, $legacyCipher, $defaultCipher, $fileKey, $expected): void {
173
+        $this->sessionMock->expects($this->once())
174
+            ->method('decryptAllModeActivated')
175
+            ->willReturn(false);
176
+
177
+        $this->sessionMock->expects($this->never())->method('getDecryptAllUid');
178
+        $this->sessionMock->expects($this->never())->method('getDecryptAllKey');
179
+        $this->keyManagerMock->expects($this->never())->method('getEncryptedFileKey');
180
+        $this->keyManagerMock->expects($this->never())->method('getShareKey');
181
+        $this->cryptMock->expects($this->never())->method('multiKeyDecrypt');
182
+
183
+        $this->cryptMock->expects($this->any())
184
+            ->method('getCipher')
185
+            ->willReturn($defaultCipher);
186
+        $this->cryptMock->expects($this->any())
187
+            ->method('getLegacyCipher')
188
+            ->willReturn($legacyCipher);
189
+        if (empty($fileKey)) {
190
+            $this->cryptMock->expects($this->once())
191
+                ->method('generateFileKey')
192
+                ->willReturn('fileKey');
193
+        } else {
194
+            $this->cryptMock->expects($this->never())
195
+                ->method('generateFileKey');
196
+        }
197
+
198
+        $this->keyManagerMock->expects($this->once())
199
+            ->method('getFileKey')
200
+            ->willReturn($fileKey);
201
+
202
+        $result = $this->instance->begin('/user/files/foo.txt', 'user', $mode, $header, []);
203
+
204
+        $this->assertArrayHasKey('cipher', $result);
205
+        $this->assertSame($expected, $result['cipher']);
206
+        if ($mode === 'w') {
207
+            $this->assertTrue(self::invokePrivate($this->instance, 'isWriteOperation'));
208
+        } else {
209
+            $this->assertFalse(self::invokePrivate($this->instance, 'isWriteOperation'));
210
+        }
211
+    }
212
+
213
+    public static function dataTestBegin(): array {
214
+        return [
215
+            ['w', ['cipher' => 'myCipher'], 'legacyCipher', 'defaultCipher', 'fileKey', 'defaultCipher'],
216
+            ['r', ['cipher' => 'myCipher'], 'legacyCipher', 'defaultCipher', 'fileKey', 'myCipher'],
217
+            ['w', [], 'legacyCipher', 'defaultCipher', '', 'defaultCipher'],
218
+            ['r', [], 'legacyCipher', 'defaultCipher', 'file_key', 'legacyCipher'],
219
+        ];
220
+    }
221
+
222
+
223
+    /**
224
+     * test begin() if decryptAll mode was activated
225
+     */
226
+    public function testBeginDecryptAll(): void {
227
+        $path = '/user/files/foo.txt';
228
+        $fileKey = 'fileKey';
229
+
230
+        $this->sessionMock->expects($this->once())
231
+            ->method('decryptAllModeActivated')
232
+            ->willReturn(true);
233
+        $this->keyManagerMock->expects($this->once())
234
+            ->method('getFileKey')
235
+            ->with($path, null, true)
236
+            ->willReturn($fileKey);
237
+
238
+        $this->instance->begin($path, 'user', 'r', [], []);
239
+
240
+        $this->assertSame($fileKey,
241
+            $this->invokePrivate($this->instance, 'fileKey')
242
+        );
243
+    }
244
+
245
+    /**
246
+     * test begin() if encryption is not initialized but the master key is enabled
247
+     * in this case we can initialize the encryption without a username/password
248
+     * and continue
249
+     */
250
+    public function testBeginInitMasterKey(): void {
251
+        $this->sessionMock->expects($this->once())
252
+            ->method('decryptAllModeActivated')
253
+            ->willReturn(false);
254
+
255
+        $this->sessionMock->expects($this->once())->method('isReady')->willReturn(false);
256
+        $this->utilMock->expects($this->once())->method('isMasterKeyEnabled')
257
+            ->willReturn(true);
258
+        $this->keyManagerMock->expects($this->once())->method('init')->with('', '');
259
+
260
+        $this->instance->begin('/user/files/welcome.txt', 'user', 'r', [], []);
261
+    }
262
+
263
+    /**
264
+     *
265
+     * @param string $fileKey
266
+     * @param boolean $expected
267
+     */
268
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestUpdate')]
269
+    public function testUpdate($fileKey, $expected): void {
270
+        $this->keyManagerMock->expects($this->once())
271
+            ->method('getFileKey')->willReturn($fileKey);
272
+
273
+        $this->keyManagerMock->expects($this->any())
274
+            ->method('getPublicKey')->willReturn('publicKey');
275
+
276
+        $this->keyManagerMock->expects($this->any())
277
+            ->method('addSystemKeys')
278
+            ->willReturnCallback(function ($accessList, $publicKeys) {
279
+                return $publicKeys;
280
+            });
281
+
282
+        $this->keyManagerMock->expects($this->never())->method('getVersion');
283
+        $this->keyManagerMock->expects($this->never())->method('setVersion');
284
+
285
+        $this->assertSame($expected,
286
+            $this->instance->update('path', 'user1', ['users' => ['user1']])
287
+        );
288
+    }
289
+
290
+    public static function dataTestUpdate(): array {
291
+        return [
292
+            ['', false],
293
+            ['fileKey', true]
294
+        ];
295
+    }
296
+
297
+    public function testUpdateNoUsers(): void {
298
+        $this->invokePrivate($this->instance, 'rememberVersion', [['path' => 2]]);
299
+
300
+        $this->keyManagerMock->expects($this->never())->method('getFileKey');
301
+        $this->keyManagerMock->expects($this->never())->method('getPublicKey');
302
+        $this->keyManagerMock->expects($this->never())->method('addSystemKeys');
303
+        $this->keyManagerMock->expects($this->once())->method('setVersion')
304
+            ->willReturnCallback(function ($path, $version, $view): void {
305
+                $this->assertSame('path', $path);
306
+                $this->assertSame(2, $version);
307
+                $this->assertTrue($view instanceof View);
308
+            });
309
+        $this->instance->update('path', 'user1', []);
310
+    }
311
+
312
+    /**
313
+     * Test case if the public key is missing. Nextcloud should still encrypt
314
+     * the file for the remaining users
315
+     */
316
+    public function testUpdateMissingPublicKey(): void {
317
+        $this->keyManagerMock->expects($this->once())
318
+            ->method('getFileKey')->willReturn('fileKey');
319
+
320
+        $this->keyManagerMock->expects($this->any())
321
+            ->method('getPublicKey')->willReturnCallback(
322
+                function ($user): void {
323
+                    throw new PublicKeyMissingException($user);
324
+                }
325
+            );
326
+
327
+        $this->keyManagerMock->expects($this->any())
328
+            ->method('addSystemKeys')
329
+            ->willReturnCallback(function ($accessList, $publicKeys) {
330
+                return $publicKeys;
331
+            });
332
+
333
+        $this->cryptMock->expects($this->once())->method('multiKeyEncrypt')
334
+            ->willReturnCallback(
335
+                function ($fileKey, $publicKeys) {
336
+                    $this->assertEmpty($publicKeys);
337
+                    $this->assertSame('fileKey', $fileKey);
338
+                    return [];
339
+                }
340
+            );
341
+
342
+        $this->keyManagerMock->expects($this->never())->method('getVersion');
343
+        $this->keyManagerMock->expects($this->never())->method('setVersion');
344
+
345
+        $this->assertTrue(
346
+            $this->instance->update('path', 'user1', ['users' => ['user1']])
347
+        );
348
+    }
349
+
350
+    /**
351
+     * by default the encryption module should encrypt regular files, files in
352
+     * files_versions and files in files_trashbin
353
+     */
354
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestShouldEncrypt')]
355
+    public function testShouldEncrypt($path, $shouldEncryptHomeStorage, $isHomeStorage, $expected): void {
356
+        $this->utilMock->expects($this->once())->method('shouldEncryptHomeStorage')
357
+            ->willReturn($shouldEncryptHomeStorage);
358
+
359
+        if ($shouldEncryptHomeStorage === false) {
360
+            $this->storageMock->expects($this->once())->method('instanceOfStorage')
361
+                ->with('\OCP\Files\IHomeStorage')->willReturn($isHomeStorage);
362
+            $this->utilMock->expects($this->once())->method('getStorage')->with($path)
363
+                ->willReturn($this->storageMock);
364
+        }
365
+
366
+        $this->assertSame($expected,
367
+            $this->instance->shouldEncrypt($path)
368
+        );
369
+    }
370
+
371
+    public static function dataTestShouldEncrypt(): array {
372
+        return [
373
+            ['/user1/files/foo.txt', true, true, true],
374
+            ['/user1/files_versions/foo.txt', true, true, true],
375
+            ['/user1/files_trashbin/foo.txt', true, true, true],
376
+            ['/user1/some_folder/foo.txt', true, true, false],
377
+            ['/user1/foo.txt', true, true, false],
378
+            ['/user1/files', true, true, false],
379
+            ['/user1/files_trashbin', true, true, false],
380
+            ['/user1/files_versions', true, true, false],
381
+            // test if shouldEncryptHomeStorage is set to false
382
+            ['/user1/files/foo.txt', false, true, false],
383
+            ['/user1/files_versions/foo.txt', false, false, true],
384
+        ];
385
+    }
386
+
387
+
388
+    public function testDecrypt(): void {
389
+        $this->expectException(DecryptionFailedException::class);
390
+        $this->expectExceptionMessage('Cannot decrypt this file, probably this is a shared file. Please ask the file owner to reshare the file with you.');
391
+
392
+        $this->instance->decrypt('abc');
393
+    }
394
+
395
+    public function testPrepareDecryptAll(): void {
396
+        /** @var \Symfony\Component\Console\Input\InputInterface $input */
397
+        $input = $this->createMock(InputInterface::class);
398
+        /** @var \Symfony\Component\Console\Output\OutputInterface $output */
399
+        $output = $this->createMock(OutputInterface::class);
400
+
401
+        $this->decryptAllMock->expects($this->once())->method('prepare')
402
+            ->with($input, $output, 'user');
403
+
404
+        $this->instance->prepareDecryptAll($input, $output, 'user');
405
+    }
406 406
 }
Please login to merge, or discard this patch.
apps/encryption/tests/RecoveryTest.php 1 patch
Indentation   +265 added lines, -265 removed lines patch added patch discarded remove patch
@@ -22,269 +22,269 @@
 block discarded – undo
22 22
 use Test\TestCase;
23 23
 
24 24
 class RecoveryTest extends TestCase {
25
-	private static $tempStorage = [];
26
-
27
-	private IFile&MockObject $fileMock;
28
-	private View&MockObject $viewMock;
29
-	private IUserSession&MockObject $userSessionMock;
30
-	private IUser&MockObject $user;
31
-	private KeyManager&MockObject $keyManagerMock;
32
-	private IConfig&MockObject $configMock;
33
-	private Crypt&MockObject $cryptMock;
34
-
35
-	private Recovery $instance;
36
-
37
-	public function testEnableAdminRecoverySuccessful(): void {
38
-		$this->keyManagerMock->expects($this->exactly(2))
39
-			->method('recoveryKeyExists')
40
-			->willReturnOnConsecutiveCalls(false, true);
41
-
42
-		$this->cryptMock->expects($this->once())
43
-			->method('createKeyPair')
44
-			->willReturn([
45
-				'publicKey' => 'privateKey',
46
-				'privateKey' => 'publicKey',
47
-			]);
48
-
49
-		$this->keyManagerMock->expects($this->once())
50
-			->method('setRecoveryKey')
51
-			->willReturn(false);
52
-
53
-		$this->keyManagerMock->expects($this->exactly(2))
54
-			->method('checkRecoveryPassword')
55
-			->willReturnOnConsecutiveCalls(true, true);
56
-
57
-		$this->assertTrue($this->instance->enableAdminRecovery('password'));
58
-		$this->assertArrayHasKey('recoveryAdminEnabled', self::$tempStorage);
59
-		$this->assertEquals(1, self::$tempStorage['recoveryAdminEnabled']);
60
-
61
-		$this->assertTrue($this->instance->enableAdminRecovery('password'));
62
-	}
63
-
64
-	public function testEnableAdminRecoveryCouldNotCheckPassword(): void {
65
-		$this->keyManagerMock->expects($this->exactly(2))
66
-			->method('recoveryKeyExists')
67
-			->willReturnOnConsecutiveCalls(false, true);
68
-
69
-		$this->cryptMock->expects($this->once())
70
-			->method('createKeyPair')
71
-			->willReturn([
72
-				'publicKey' => 'privateKey',
73
-				'privateKey' => 'publicKey',
74
-			]);
75
-
76
-		$this->keyManagerMock->expects($this->once())
77
-			->method('setRecoveryKey')
78
-			->willReturn(false);
79
-
80
-		$this->keyManagerMock->expects($this->exactly(2))
81
-			->method('checkRecoveryPassword')
82
-			->willReturnOnConsecutiveCalls(true, false);
83
-
84
-		$this->assertTrue($this->instance->enableAdminRecovery('password'));
85
-		$this->assertArrayHasKey('recoveryAdminEnabled', self::$tempStorage);
86
-		$this->assertEquals(1, self::$tempStorage['recoveryAdminEnabled']);
87
-
88
-		$this->assertFalse($this->instance->enableAdminRecovery('password'));
89
-	}
90
-
91
-	public function testEnableAdminRecoveryCouldNotCreateKey(): void {
92
-		$this->keyManagerMock->expects($this->once())
93
-			->method('recoveryKeyExists')
94
-			->willReturn(false);
95
-
96
-		$this->cryptMock->expects($this->once())
97
-			->method('createKeyPair')
98
-			->willReturn(false);
99
-
100
-		$this->assertFalse($this->instance->enableAdminRecovery('password'));
101
-	}
102
-
103
-	public function testChangeRecoveryKeyPasswordSuccessful(): void {
104
-		$this->assertFalse($this->instance->changeRecoveryKeyPassword('password', 'passwordOld'));
105
-
106
-		$this->keyManagerMock->expects($this->once())
107
-			->method('getSystemPrivateKey')
108
-			->willReturn('privateKey');
109
-
110
-		$this->cryptMock->expects($this->once())
111
-			->method('decryptPrivateKey')
112
-			->with('privateKey', 'passwordOld')
113
-			->willReturn('decryptedPrivateKey');
114
-
115
-		$this->cryptMock->expects($this->once())
116
-			->method('encryptPrivateKey')
117
-			->with('decryptedPrivateKey', 'password')
118
-			->willReturn('privateKey');
119
-
120
-		$this->assertTrue($this->instance->changeRecoveryKeyPassword('password', 'passwordOld'));
121
-	}
122
-
123
-	public function testChangeRecoveryKeyPasswordCouldNotDecryptPrivateRecoveryKey(): void {
124
-		$this->assertFalse($this->instance->changeRecoveryKeyPassword('password', 'passwordOld'));
125
-
126
-		$this->keyManagerMock->expects($this->once())
127
-			->method('getSystemPrivateKey');
128
-
129
-		$this->cryptMock->expects($this->once())
130
-			->method('decryptPrivateKey')
131
-			->willReturn(false);
132
-
133
-		$this->assertFalse($this->instance->changeRecoveryKeyPassword('password', 'passwordOld'));
134
-	}
135
-
136
-	public function testDisableAdminRecovery(): void {
137
-		$this->keyManagerMock->expects($this->exactly(2))
138
-			->method('checkRecoveryPassword')
139
-			->willReturnOnConsecutiveCalls(true, false);
140
-
141
-		$this->assertArrayHasKey('recoveryAdminEnabled', self::$tempStorage);
142
-		$this->assertTrue($this->instance->disableAdminRecovery('password'));
143
-		$this->assertEquals(0, self::$tempStorage['recoveryAdminEnabled']);
144
-
145
-		$this->assertFalse($this->instance->disableAdminRecovery('password'));
146
-	}
147
-
148
-	public function testIsRecoveryEnabledForUser(): void {
149
-		$this->configMock->expects($this->exactly(2))
150
-			->method('getUserValue')
151
-			->willReturnOnConsecutiveCalls('1', '0');
152
-
153
-		$this->assertTrue($this->instance->isRecoveryEnabledForUser());
154
-		$this->assertFalse($this->instance->isRecoveryEnabledForUser('admin'));
155
-	}
156
-
157
-	public function testIsRecoveryKeyEnabled(): void {
158
-		$this->assertFalse($this->instance->isRecoveryKeyEnabled());
159
-		self::$tempStorage['recoveryAdminEnabled'] = '1';
160
-		$this->assertTrue($this->instance->isRecoveryKeyEnabled());
161
-	}
162
-
163
-	public function testSetRecoveryFolderForUser(): void {
164
-		$this->viewMock->expects($this->exactly(2))
165
-			->method('getDirectoryContent')
166
-			->willReturn([]);
167
-		$this->assertTrue($this->instance->setRecoveryForUser(0));
168
-		$this->assertTrue($this->instance->setRecoveryForUser('1'));
169
-	}
170
-
171
-	public function testRecoverUserFiles(): void {
172
-		$this->viewMock->expects($this->once())
173
-			->method('getDirectoryContent')
174
-			->willReturn([]);
175
-
176
-		$this->cryptMock->expects($this->once())
177
-			->method('decryptPrivateKey')
178
-			->willReturn('privateKey');
179
-		$this->instance->recoverUsersFiles('password', 'admin');
180
-		$this->addToAssertionCount(1);
181
-	}
182
-
183
-	public function testRecoverFile(): void {
184
-		$this->keyManagerMock->expects($this->once())
185
-			->method('getEncryptedFileKey')
186
-			->willReturn(true);
187
-
188
-		$this->keyManagerMock->expects($this->once())
189
-			->method('getShareKey')
190
-			->willReturn(true);
191
-
192
-		$this->cryptMock->expects($this->once())
193
-			->method('multiKeyDecryptLegacy')
194
-			->willReturn('multiKeyDecryptLegacyResult');
195
-
196
-		$this->fileMock->expects($this->once())
197
-			->method('getAccessList')
198
-			->willReturn(['users' => ['admin']]);
199
-
200
-		$this->keyManagerMock->expects($this->once())
201
-			->method('getPublicKey')
202
-			->willReturn('publicKey');
203
-
204
-		$this->keyManagerMock->expects($this->once())
205
-			->method('addSystemKeys')
206
-			->with($this->anything(), $this->anything(), $this->equalTo('admin'))
207
-			->willReturn(['admin' => 'publicKey']);
208
-
209
-
210
-		$this->cryptMock->expects($this->once())
211
-			->method('multiKeyEncrypt')
212
-			->willReturn(['admin' => 'shareKey']);
213
-
214
-		$this->keyManagerMock->expects($this->once())
215
-			->method('deleteLegacyFileKey');
216
-		$this->keyManagerMock->expects($this->once())
217
-			->method('setShareKey');
218
-
219
-		$this->assertNull(self::invokePrivate($this->instance,
220
-			'recoverFile',
221
-			['/', 'testkey', 'admin']));
222
-	}
223
-
224
-	protected function setUp(): void {
225
-		parent::setUp();
226
-
227
-		$this->user = $this->createMock(IUser::class);
228
-		$this->user->expects($this->any())
229
-			->method('getUID')
230
-			->willReturn('admin');
231
-
232
-		$this->userSessionMock = $this->createMock(IUserSession::class);
233
-		$this->userSessionMock->expects($this->any())
234
-			->method('getUser')
235
-			->willReturn($this->user);
236
-		$this->userSessionMock->expects($this->any())
237
-			->method('isLoggedIn')
238
-			->willReturn(true);
239
-
240
-		$this->cryptMock = $this->getMockBuilder(Crypt::class)->disableOriginalConstructor()->getMock();
241
-		$this->keyManagerMock = $this->getMockBuilder(KeyManager::class)->disableOriginalConstructor()->getMock();
242
-		$this->configMock = $this->createMock(IConfig::class);
243
-		$this->fileMock = $this->createMock(IFile::class);
244
-		$this->viewMock = $this->createMock(View::class);
245
-
246
-		$this->configMock->expects($this->any())
247
-			->method('setAppValue')
248
-			->willReturnCallback([$this, 'setValueTester']);
249
-
250
-		$this->configMock->expects($this->any())
251
-			->method('getAppValue')
252
-			->willReturnCallback([$this, 'getValueTester']);
253
-
254
-		$this->instance = new Recovery($this->userSessionMock,
255
-			$this->cryptMock,
256
-			$this->keyManagerMock,
257
-			$this->configMock,
258
-			$this->fileMock,
259
-			$this->viewMock);
260
-	}
261
-
262
-
263
-	/**
264
-	 * @param $app
265
-	 * @param $key
266
-	 * @param $value
267
-	 */
268
-	public function setValueTester($app, $key, $value) {
269
-		self::$tempStorage[$key] = $value;
270
-	}
271
-
272
-	/**
273
-	 * @param $key
274
-	 */
275
-	public function removeValueTester($key) {
276
-		unset(self::$tempStorage[$key]);
277
-	}
278
-
279
-	/**
280
-	 * @param $app
281
-	 * @param $key
282
-	 * @return mixed
283
-	 */
284
-	public function getValueTester($app, $key) {
285
-		if (!empty(self::$tempStorage[$key])) {
286
-			return self::$tempStorage[$key];
287
-		}
288
-		return null;
289
-	}
25
+    private static $tempStorage = [];
26
+
27
+    private IFile&MockObject $fileMock;
28
+    private View&MockObject $viewMock;
29
+    private IUserSession&MockObject $userSessionMock;
30
+    private IUser&MockObject $user;
31
+    private KeyManager&MockObject $keyManagerMock;
32
+    private IConfig&MockObject $configMock;
33
+    private Crypt&MockObject $cryptMock;
34
+
35
+    private Recovery $instance;
36
+
37
+    public function testEnableAdminRecoverySuccessful(): void {
38
+        $this->keyManagerMock->expects($this->exactly(2))
39
+            ->method('recoveryKeyExists')
40
+            ->willReturnOnConsecutiveCalls(false, true);
41
+
42
+        $this->cryptMock->expects($this->once())
43
+            ->method('createKeyPair')
44
+            ->willReturn([
45
+                'publicKey' => 'privateKey',
46
+                'privateKey' => 'publicKey',
47
+            ]);
48
+
49
+        $this->keyManagerMock->expects($this->once())
50
+            ->method('setRecoveryKey')
51
+            ->willReturn(false);
52
+
53
+        $this->keyManagerMock->expects($this->exactly(2))
54
+            ->method('checkRecoveryPassword')
55
+            ->willReturnOnConsecutiveCalls(true, true);
56
+
57
+        $this->assertTrue($this->instance->enableAdminRecovery('password'));
58
+        $this->assertArrayHasKey('recoveryAdminEnabled', self::$tempStorage);
59
+        $this->assertEquals(1, self::$tempStorage['recoveryAdminEnabled']);
60
+
61
+        $this->assertTrue($this->instance->enableAdminRecovery('password'));
62
+    }
63
+
64
+    public function testEnableAdminRecoveryCouldNotCheckPassword(): void {
65
+        $this->keyManagerMock->expects($this->exactly(2))
66
+            ->method('recoveryKeyExists')
67
+            ->willReturnOnConsecutiveCalls(false, true);
68
+
69
+        $this->cryptMock->expects($this->once())
70
+            ->method('createKeyPair')
71
+            ->willReturn([
72
+                'publicKey' => 'privateKey',
73
+                'privateKey' => 'publicKey',
74
+            ]);
75
+
76
+        $this->keyManagerMock->expects($this->once())
77
+            ->method('setRecoveryKey')
78
+            ->willReturn(false);
79
+
80
+        $this->keyManagerMock->expects($this->exactly(2))
81
+            ->method('checkRecoveryPassword')
82
+            ->willReturnOnConsecutiveCalls(true, false);
83
+
84
+        $this->assertTrue($this->instance->enableAdminRecovery('password'));
85
+        $this->assertArrayHasKey('recoveryAdminEnabled', self::$tempStorage);
86
+        $this->assertEquals(1, self::$tempStorage['recoveryAdminEnabled']);
87
+
88
+        $this->assertFalse($this->instance->enableAdminRecovery('password'));
89
+    }
90
+
91
+    public function testEnableAdminRecoveryCouldNotCreateKey(): void {
92
+        $this->keyManagerMock->expects($this->once())
93
+            ->method('recoveryKeyExists')
94
+            ->willReturn(false);
95
+
96
+        $this->cryptMock->expects($this->once())
97
+            ->method('createKeyPair')
98
+            ->willReturn(false);
99
+
100
+        $this->assertFalse($this->instance->enableAdminRecovery('password'));
101
+    }
102
+
103
+    public function testChangeRecoveryKeyPasswordSuccessful(): void {
104
+        $this->assertFalse($this->instance->changeRecoveryKeyPassword('password', 'passwordOld'));
105
+
106
+        $this->keyManagerMock->expects($this->once())
107
+            ->method('getSystemPrivateKey')
108
+            ->willReturn('privateKey');
109
+
110
+        $this->cryptMock->expects($this->once())
111
+            ->method('decryptPrivateKey')
112
+            ->with('privateKey', 'passwordOld')
113
+            ->willReturn('decryptedPrivateKey');
114
+
115
+        $this->cryptMock->expects($this->once())
116
+            ->method('encryptPrivateKey')
117
+            ->with('decryptedPrivateKey', 'password')
118
+            ->willReturn('privateKey');
119
+
120
+        $this->assertTrue($this->instance->changeRecoveryKeyPassword('password', 'passwordOld'));
121
+    }
122
+
123
+    public function testChangeRecoveryKeyPasswordCouldNotDecryptPrivateRecoveryKey(): void {
124
+        $this->assertFalse($this->instance->changeRecoveryKeyPassword('password', 'passwordOld'));
125
+
126
+        $this->keyManagerMock->expects($this->once())
127
+            ->method('getSystemPrivateKey');
128
+
129
+        $this->cryptMock->expects($this->once())
130
+            ->method('decryptPrivateKey')
131
+            ->willReturn(false);
132
+
133
+        $this->assertFalse($this->instance->changeRecoveryKeyPassword('password', 'passwordOld'));
134
+    }
135
+
136
+    public function testDisableAdminRecovery(): void {
137
+        $this->keyManagerMock->expects($this->exactly(2))
138
+            ->method('checkRecoveryPassword')
139
+            ->willReturnOnConsecutiveCalls(true, false);
140
+
141
+        $this->assertArrayHasKey('recoveryAdminEnabled', self::$tempStorage);
142
+        $this->assertTrue($this->instance->disableAdminRecovery('password'));
143
+        $this->assertEquals(0, self::$tempStorage['recoveryAdminEnabled']);
144
+
145
+        $this->assertFalse($this->instance->disableAdminRecovery('password'));
146
+    }
147
+
148
+    public function testIsRecoveryEnabledForUser(): void {
149
+        $this->configMock->expects($this->exactly(2))
150
+            ->method('getUserValue')
151
+            ->willReturnOnConsecutiveCalls('1', '0');
152
+
153
+        $this->assertTrue($this->instance->isRecoveryEnabledForUser());
154
+        $this->assertFalse($this->instance->isRecoveryEnabledForUser('admin'));
155
+    }
156
+
157
+    public function testIsRecoveryKeyEnabled(): void {
158
+        $this->assertFalse($this->instance->isRecoveryKeyEnabled());
159
+        self::$tempStorage['recoveryAdminEnabled'] = '1';
160
+        $this->assertTrue($this->instance->isRecoveryKeyEnabled());
161
+    }
162
+
163
+    public function testSetRecoveryFolderForUser(): void {
164
+        $this->viewMock->expects($this->exactly(2))
165
+            ->method('getDirectoryContent')
166
+            ->willReturn([]);
167
+        $this->assertTrue($this->instance->setRecoveryForUser(0));
168
+        $this->assertTrue($this->instance->setRecoveryForUser('1'));
169
+    }
170
+
171
+    public function testRecoverUserFiles(): void {
172
+        $this->viewMock->expects($this->once())
173
+            ->method('getDirectoryContent')
174
+            ->willReturn([]);
175
+
176
+        $this->cryptMock->expects($this->once())
177
+            ->method('decryptPrivateKey')
178
+            ->willReturn('privateKey');
179
+        $this->instance->recoverUsersFiles('password', 'admin');
180
+        $this->addToAssertionCount(1);
181
+    }
182
+
183
+    public function testRecoverFile(): void {
184
+        $this->keyManagerMock->expects($this->once())
185
+            ->method('getEncryptedFileKey')
186
+            ->willReturn(true);
187
+
188
+        $this->keyManagerMock->expects($this->once())
189
+            ->method('getShareKey')
190
+            ->willReturn(true);
191
+
192
+        $this->cryptMock->expects($this->once())
193
+            ->method('multiKeyDecryptLegacy')
194
+            ->willReturn('multiKeyDecryptLegacyResult');
195
+
196
+        $this->fileMock->expects($this->once())
197
+            ->method('getAccessList')
198
+            ->willReturn(['users' => ['admin']]);
199
+
200
+        $this->keyManagerMock->expects($this->once())
201
+            ->method('getPublicKey')
202
+            ->willReturn('publicKey');
203
+
204
+        $this->keyManagerMock->expects($this->once())
205
+            ->method('addSystemKeys')
206
+            ->with($this->anything(), $this->anything(), $this->equalTo('admin'))
207
+            ->willReturn(['admin' => 'publicKey']);
208
+
209
+
210
+        $this->cryptMock->expects($this->once())
211
+            ->method('multiKeyEncrypt')
212
+            ->willReturn(['admin' => 'shareKey']);
213
+
214
+        $this->keyManagerMock->expects($this->once())
215
+            ->method('deleteLegacyFileKey');
216
+        $this->keyManagerMock->expects($this->once())
217
+            ->method('setShareKey');
218
+
219
+        $this->assertNull(self::invokePrivate($this->instance,
220
+            'recoverFile',
221
+            ['/', 'testkey', 'admin']));
222
+    }
223
+
224
+    protected function setUp(): void {
225
+        parent::setUp();
226
+
227
+        $this->user = $this->createMock(IUser::class);
228
+        $this->user->expects($this->any())
229
+            ->method('getUID')
230
+            ->willReturn('admin');
231
+
232
+        $this->userSessionMock = $this->createMock(IUserSession::class);
233
+        $this->userSessionMock->expects($this->any())
234
+            ->method('getUser')
235
+            ->willReturn($this->user);
236
+        $this->userSessionMock->expects($this->any())
237
+            ->method('isLoggedIn')
238
+            ->willReturn(true);
239
+
240
+        $this->cryptMock = $this->getMockBuilder(Crypt::class)->disableOriginalConstructor()->getMock();
241
+        $this->keyManagerMock = $this->getMockBuilder(KeyManager::class)->disableOriginalConstructor()->getMock();
242
+        $this->configMock = $this->createMock(IConfig::class);
243
+        $this->fileMock = $this->createMock(IFile::class);
244
+        $this->viewMock = $this->createMock(View::class);
245
+
246
+        $this->configMock->expects($this->any())
247
+            ->method('setAppValue')
248
+            ->willReturnCallback([$this, 'setValueTester']);
249
+
250
+        $this->configMock->expects($this->any())
251
+            ->method('getAppValue')
252
+            ->willReturnCallback([$this, 'getValueTester']);
253
+
254
+        $this->instance = new Recovery($this->userSessionMock,
255
+            $this->cryptMock,
256
+            $this->keyManagerMock,
257
+            $this->configMock,
258
+            $this->fileMock,
259
+            $this->viewMock);
260
+    }
261
+
262
+
263
+    /**
264
+     * @param $app
265
+     * @param $key
266
+     * @param $value
267
+     */
268
+    public function setValueTester($app, $key, $value) {
269
+        self::$tempStorage[$key] = $value;
270
+    }
271
+
272
+    /**
273
+     * @param $key
274
+     */
275
+    public function removeValueTester($key) {
276
+        unset(self::$tempStorage[$key]);
277
+    }
278
+
279
+    /**
280
+     * @param $app
281
+     * @param $key
282
+     * @return mixed
283
+     */
284
+    public function getValueTester($app, $key) {
285
+        if (!empty(self::$tempStorage[$key])) {
286
+            return self::$tempStorage[$key];
287
+        }
288
+        return null;
289
+    }
290 290
 }
Please login to merge, or discard this patch.
apps/encryption/tests/SessionTest.php 1 patch
Indentation   +186 added lines, -186 removed lines patch added patch discarded remove patch
@@ -16,190 +16,190 @@
 block discarded – undo
16 16
 use Test\TestCase;
17 17
 
18 18
 class SessionTest extends TestCase {
19
-	private static $tempStorage = [];
20
-
21
-	protected Session $instance;
22
-	protected ISession&MockObject $sessionMock;
23
-
24
-	public function testThatGetPrivateKeyThrowsExceptionWhenNotSet(): void {
25
-		$this->expectException(PrivateKeyMissingException::class);
26
-		$this->expectExceptionMessage('Private Key missing for user: please try to log-out and log-in again');
27
-
28
-		$this->instance->getPrivateKey();
29
-	}
30
-
31
-	/**
32
-	 * @depends testThatGetPrivateKeyThrowsExceptionWhenNotSet
33
-	 */
34
-	public function testSetAndGetPrivateKey(): void {
35
-		$this->instance->setPrivateKey('dummyPrivateKey');
36
-		$this->assertEquals('dummyPrivateKey', $this->instance->getPrivateKey());
37
-	}
38
-
39
-	/**
40
-	 * @depends testSetAndGetPrivateKey
41
-	 */
42
-	public function testIsPrivateKeySet(): void {
43
-		$this->instance->setPrivateKey('dummyPrivateKey');
44
-		$this->assertTrue($this->instance->isPrivateKeySet());
45
-
46
-		unset(self::$tempStorage['privateKey']);
47
-		$this->assertFalse($this->instance->isPrivateKeySet());
48
-
49
-		// Set private key back so we can test clear method
50
-		self::$tempStorage['privateKey'] = 'dummyPrivateKey';
51
-	}
52
-
53
-	public function testDecryptAllModeActivated(): void {
54
-		$this->instance->prepareDecryptAll('user1', 'usersKey');
55
-		$this->assertTrue($this->instance->decryptAllModeActivated());
56
-		$this->assertSame('user1', $this->instance->getDecryptAllUid());
57
-		$this->assertSame('usersKey', $this->instance->getDecryptAllKey());
58
-	}
59
-
60
-	public function testDecryptAllModeDeactivated(): void {
61
-		$this->assertFalse($this->instance->decryptAllModeActivated());
62
-	}
63
-
64
-	/**
65
-	 * @expectExceptionMessage 'Please activate decrypt all mode first'
66
-	 */
67
-	public function testGetDecryptAllUidException(): void {
68
-		$this->expectException(\Exception::class);
69
-
70
-		$this->instance->getDecryptAllUid();
71
-	}
72
-
73
-	/**
74
-	 * @expectExceptionMessage 'No uid found while in decrypt all mode'
75
-	 */
76
-	public function testGetDecryptAllUidException2(): void {
77
-		$this->expectException(\Exception::class);
78
-
79
-		$this->instance->prepareDecryptAll('', 'key');
80
-		$this->instance->getDecryptAllUid();
81
-	}
82
-
83
-	/**
84
-	 * @expectExceptionMessage 'Please activate decrypt all mode first'
85
-	 */
86
-	public function testGetDecryptAllKeyException(): void {
87
-		$this->expectException(PrivateKeyMissingException::class);
88
-
89
-		$this->instance->getDecryptAllKey();
90
-	}
91
-
92
-	/**
93
-	 * @expectExceptionMessage 'No key found while in decrypt all mode'
94
-	 */
95
-	public function testGetDecryptAllKeyException2(): void {
96
-		$this->expectException(PrivateKeyMissingException::class);
97
-
98
-		$this->instance->prepareDecryptAll('user', '');
99
-		$this->instance->getDecryptAllKey();
100
-	}
101
-
102
-
103
-	public function testSetAndGetStatusWillSetAndReturn(): void {
104
-		// Check if get status will return 0 if it has not been set before
105
-		$this->assertEquals(0, $this->instance->getStatus());
106
-
107
-		$this->instance->setStatus(Session::NOT_INITIALIZED);
108
-		$this->assertEquals(0, $this->instance->getStatus());
109
-
110
-		$this->instance->setStatus(Session::INIT_EXECUTED);
111
-		$this->assertEquals(1, $this->instance->getStatus());
112
-
113
-		$this->instance->setStatus(Session::INIT_SUCCESSFUL);
114
-		$this->assertEquals(2, $this->instance->getStatus());
115
-	}
116
-
117
-	/**
118
-	 *
119
-	 * @param int $status
120
-	 * @param bool $expected
121
-	 */
122
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestIsReady')]
123
-	public function testIsReady($status, $expected): void {
124
-		/** @var Session&MockObject $instance */
125
-		$instance = $this->getMockBuilder(Session::class)
126
-			->setConstructorArgs([$this->sessionMock])
127
-			->onlyMethods(['getStatus'])
128
-			->getMock();
129
-
130
-		$instance->expects($this->once())->method('getStatus')
131
-			->willReturn($status);
132
-
133
-		$this->assertSame($expected, $instance->isReady());
134
-	}
135
-
136
-	public static function dataTestIsReady(): array {
137
-		return [
138
-			[Session::INIT_SUCCESSFUL, true],
139
-			[Session::INIT_EXECUTED, false],
140
-			[Session::NOT_INITIALIZED, false],
141
-		];
142
-	}
143
-
144
-	/**
145
-	 * @param $key
146
-	 * @param $value
147
-	 */
148
-	public function setValueTester($key, $value) {
149
-		self::$tempStorage[$key] = $value;
150
-	}
151
-
152
-	/**
153
-	 * @param $key
154
-	 */
155
-	public function removeValueTester($key) {
156
-		unset(self::$tempStorage[$key]);
157
-	}
158
-
159
-	/**
160
-	 * @param $key
161
-	 * @return mixed
162
-	 */
163
-	public function getValueTester($key) {
164
-		if (!empty(self::$tempStorage[$key])) {
165
-			return self::$tempStorage[$key];
166
-		}
167
-		return null;
168
-	}
169
-
170
-
171
-	public function testClearWillRemoveValues(): void {
172
-		$this->instance->setPrivateKey('privateKey');
173
-		$this->instance->setStatus('initStatus');
174
-		$this->instance->prepareDecryptAll('user', 'key');
175
-		$this->assertNotEmpty(self::$tempStorage);
176
-		$this->instance->clear();
177
-		$this->assertEmpty(self::$tempStorage);
178
-	}
179
-
180
-
181
-	protected function setUp(): void {
182
-		parent::setUp();
183
-		$this->sessionMock = $this->createMock(ISession::class);
184
-
185
-		$this->sessionMock->expects($this->any())
186
-			->method('set')
187
-			->willReturnCallback([$this, 'setValueTester']);
188
-
189
-		$this->sessionMock->expects($this->any())
190
-			->method('get')
191
-			->willReturnCallback([$this, 'getValueTester']);
192
-
193
-		$this->sessionMock->expects($this->any())
194
-			->method('remove')
195
-			->willReturnCallback([$this, 'removeValueTester']);
196
-
197
-
198
-		$this->instance = new Session($this->sessionMock);
199
-	}
200
-
201
-	protected function tearDown(): void {
202
-		self::$tempStorage = [];
203
-		parent::tearDown();
204
-	}
19
+    private static $tempStorage = [];
20
+
21
+    protected Session $instance;
22
+    protected ISession&MockObject $sessionMock;
23
+
24
+    public function testThatGetPrivateKeyThrowsExceptionWhenNotSet(): void {
25
+        $this->expectException(PrivateKeyMissingException::class);
26
+        $this->expectExceptionMessage('Private Key missing for user: please try to log-out and log-in again');
27
+
28
+        $this->instance->getPrivateKey();
29
+    }
30
+
31
+    /**
32
+     * @depends testThatGetPrivateKeyThrowsExceptionWhenNotSet
33
+     */
34
+    public function testSetAndGetPrivateKey(): void {
35
+        $this->instance->setPrivateKey('dummyPrivateKey');
36
+        $this->assertEquals('dummyPrivateKey', $this->instance->getPrivateKey());
37
+    }
38
+
39
+    /**
40
+     * @depends testSetAndGetPrivateKey
41
+     */
42
+    public function testIsPrivateKeySet(): void {
43
+        $this->instance->setPrivateKey('dummyPrivateKey');
44
+        $this->assertTrue($this->instance->isPrivateKeySet());
45
+
46
+        unset(self::$tempStorage['privateKey']);
47
+        $this->assertFalse($this->instance->isPrivateKeySet());
48
+
49
+        // Set private key back so we can test clear method
50
+        self::$tempStorage['privateKey'] = 'dummyPrivateKey';
51
+    }
52
+
53
+    public function testDecryptAllModeActivated(): void {
54
+        $this->instance->prepareDecryptAll('user1', 'usersKey');
55
+        $this->assertTrue($this->instance->decryptAllModeActivated());
56
+        $this->assertSame('user1', $this->instance->getDecryptAllUid());
57
+        $this->assertSame('usersKey', $this->instance->getDecryptAllKey());
58
+    }
59
+
60
+    public function testDecryptAllModeDeactivated(): void {
61
+        $this->assertFalse($this->instance->decryptAllModeActivated());
62
+    }
63
+
64
+    /**
65
+     * @expectExceptionMessage 'Please activate decrypt all mode first'
66
+     */
67
+    public function testGetDecryptAllUidException(): void {
68
+        $this->expectException(\Exception::class);
69
+
70
+        $this->instance->getDecryptAllUid();
71
+    }
72
+
73
+    /**
74
+     * @expectExceptionMessage 'No uid found while in decrypt all mode'
75
+     */
76
+    public function testGetDecryptAllUidException2(): void {
77
+        $this->expectException(\Exception::class);
78
+
79
+        $this->instance->prepareDecryptAll('', 'key');
80
+        $this->instance->getDecryptAllUid();
81
+    }
82
+
83
+    /**
84
+     * @expectExceptionMessage 'Please activate decrypt all mode first'
85
+     */
86
+    public function testGetDecryptAllKeyException(): void {
87
+        $this->expectException(PrivateKeyMissingException::class);
88
+
89
+        $this->instance->getDecryptAllKey();
90
+    }
91
+
92
+    /**
93
+     * @expectExceptionMessage 'No key found while in decrypt all mode'
94
+     */
95
+    public function testGetDecryptAllKeyException2(): void {
96
+        $this->expectException(PrivateKeyMissingException::class);
97
+
98
+        $this->instance->prepareDecryptAll('user', '');
99
+        $this->instance->getDecryptAllKey();
100
+    }
101
+
102
+
103
+    public function testSetAndGetStatusWillSetAndReturn(): void {
104
+        // Check if get status will return 0 if it has not been set before
105
+        $this->assertEquals(0, $this->instance->getStatus());
106
+
107
+        $this->instance->setStatus(Session::NOT_INITIALIZED);
108
+        $this->assertEquals(0, $this->instance->getStatus());
109
+
110
+        $this->instance->setStatus(Session::INIT_EXECUTED);
111
+        $this->assertEquals(1, $this->instance->getStatus());
112
+
113
+        $this->instance->setStatus(Session::INIT_SUCCESSFUL);
114
+        $this->assertEquals(2, $this->instance->getStatus());
115
+    }
116
+
117
+    /**
118
+     *
119
+     * @param int $status
120
+     * @param bool $expected
121
+     */
122
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestIsReady')]
123
+    public function testIsReady($status, $expected): void {
124
+        /** @var Session&MockObject $instance */
125
+        $instance = $this->getMockBuilder(Session::class)
126
+            ->setConstructorArgs([$this->sessionMock])
127
+            ->onlyMethods(['getStatus'])
128
+            ->getMock();
129
+
130
+        $instance->expects($this->once())->method('getStatus')
131
+            ->willReturn($status);
132
+
133
+        $this->assertSame($expected, $instance->isReady());
134
+    }
135
+
136
+    public static function dataTestIsReady(): array {
137
+        return [
138
+            [Session::INIT_SUCCESSFUL, true],
139
+            [Session::INIT_EXECUTED, false],
140
+            [Session::NOT_INITIALIZED, false],
141
+        ];
142
+    }
143
+
144
+    /**
145
+     * @param $key
146
+     * @param $value
147
+     */
148
+    public function setValueTester($key, $value) {
149
+        self::$tempStorage[$key] = $value;
150
+    }
151
+
152
+    /**
153
+     * @param $key
154
+     */
155
+    public function removeValueTester($key) {
156
+        unset(self::$tempStorage[$key]);
157
+    }
158
+
159
+    /**
160
+     * @param $key
161
+     * @return mixed
162
+     */
163
+    public function getValueTester($key) {
164
+        if (!empty(self::$tempStorage[$key])) {
165
+            return self::$tempStorage[$key];
166
+        }
167
+        return null;
168
+    }
169
+
170
+
171
+    public function testClearWillRemoveValues(): void {
172
+        $this->instance->setPrivateKey('privateKey');
173
+        $this->instance->setStatus('initStatus');
174
+        $this->instance->prepareDecryptAll('user', 'key');
175
+        $this->assertNotEmpty(self::$tempStorage);
176
+        $this->instance->clear();
177
+        $this->assertEmpty(self::$tempStorage);
178
+    }
179
+
180
+
181
+    protected function setUp(): void {
182
+        parent::setUp();
183
+        $this->sessionMock = $this->createMock(ISession::class);
184
+
185
+        $this->sessionMock->expects($this->any())
186
+            ->method('set')
187
+            ->willReturnCallback([$this, 'setValueTester']);
188
+
189
+        $this->sessionMock->expects($this->any())
190
+            ->method('get')
191
+            ->willReturnCallback([$this, 'getValueTester']);
192
+
193
+        $this->sessionMock->expects($this->any())
194
+            ->method('remove')
195
+            ->willReturnCallback([$this, 'removeValueTester']);
196
+
197
+
198
+        $this->instance = new Session($this->sessionMock);
199
+    }
200
+
201
+    protected function tearDown(): void {
202
+        self::$tempStorage = [];
203
+        parent::tearDown();
204
+    }
205 205
 }
Please login to merge, or discard this patch.
apps/encryption/tests/Controller/RecoveryControllerTest.php 1 patch
Indentation   +137 added lines, -137 removed lines patch added patch discarded remove patch
@@ -19,141 +19,141 @@
 block discarded – undo
19 19
 use Test\TestCase;
20 20
 
21 21
 class RecoveryControllerTest extends TestCase {
22
-	protected RecoveryController $controller;
23
-
24
-	protected IRequest&MockObject $requestMock;
25
-	protected IConfig&MockObject $configMock;
26
-	protected IL10N&MockObject $l10nMock;
27
-	protected Recovery&MockObject $recoveryMock;
28
-
29
-	public static function adminRecoveryProvider(): array {
30
-		return [
31
-			['test', 'test', '1', 'Recovery key successfully enabled', Http::STATUS_OK],
32
-			['', 'test', '1', 'Missing recovery key password', Http::STATUS_BAD_REQUEST],
33
-			['test', '', '1', 'Please repeat the recovery key password', Http::STATUS_BAD_REQUEST],
34
-			['test', 'something that doesn\'t match', '1', 'Repeated recovery key password does not match the provided recovery key password', Http::STATUS_BAD_REQUEST],
35
-			['test', 'test', '0', 'Recovery key successfully disabled', Http::STATUS_OK],
36
-		];
37
-	}
38
-
39
-	/**
40
-	 * @param $recoveryPassword
41
-	 * @param $passConfirm
42
-	 * @param $enableRecovery
43
-	 * @param $expectedMessage
44
-	 * @param $expectedStatus
45
-	 */
46
-	#[\PHPUnit\Framework\Attributes\DataProvider('adminRecoveryProvider')]
47
-	public function testAdminRecovery($recoveryPassword, $passConfirm, $enableRecovery, $expectedMessage, $expectedStatus): void {
48
-		$this->recoveryMock->expects($this->any())
49
-			->method('enableAdminRecovery')
50
-			->willReturn(true);
51
-
52
-		$this->recoveryMock->expects($this->any())
53
-			->method('disableAdminRecovery')
54
-			->willReturn(true);
55
-
56
-		$response = $this->controller->adminRecovery($recoveryPassword,
57
-			$passConfirm,
58
-			$enableRecovery);
59
-
60
-
61
-		$this->assertEquals($expectedMessage, $response->getData()['data']['message']);
62
-		$this->assertEquals($expectedStatus, $response->getStatus());
63
-	}
64
-
65
-	public static function changeRecoveryPasswordProvider(): array {
66
-		return [
67
-			['test', 'test', 'oldtestFail', 'Could not change the password. Maybe the old password was not correct.', Http::STATUS_BAD_REQUEST],
68
-			['test', 'test', 'oldtest', 'Password successfully changed.', Http::STATUS_OK],
69
-			['test', 'notmatch', 'oldtest', 'Repeated recovery key password does not match the provided recovery key password', Http::STATUS_BAD_REQUEST],
70
-			['', 'test', 'oldtest', 'Please provide a new recovery password', Http::STATUS_BAD_REQUEST],
71
-			['test', 'test', '', 'Please provide the old recovery password', Http::STATUS_BAD_REQUEST]
72
-		];
73
-	}
74
-
75
-	/**
76
-	 * @param $password
77
-	 * @param $confirmPassword
78
-	 * @param $oldPassword
79
-	 * @param $expectedMessage
80
-	 * @param $expectedStatus
81
-	 */
82
-	#[\PHPUnit\Framework\Attributes\DataProvider('changeRecoveryPasswordProvider')]
83
-	public function testChangeRecoveryPassword($password, $confirmPassword, $oldPassword, $expectedMessage, $expectedStatus): void {
84
-		$this->recoveryMock->expects($this->any())
85
-			->method('changeRecoveryKeyPassword')
86
-			->with($password, $oldPassword)
87
-			->willReturnMap([
88
-				['test', 'oldtestFail', false],
89
-				['test', 'oldtest', true]
90
-			]);
91
-
92
-		$response = $this->controller->changeRecoveryPassword($password,
93
-			$oldPassword,
94
-			$confirmPassword);
95
-
96
-		$this->assertEquals($expectedMessage, $response->getData()['data']['message']);
97
-		$this->assertEquals($expectedStatus, $response->getStatus());
98
-	}
99
-
100
-	public static function userSetRecoveryProvider(): array {
101
-		return [
102
-			['1', 'Recovery Key enabled', Http::STATUS_OK],
103
-			['0', 'Could not enable the recovery key, please try again or contact your administrator', Http::STATUS_BAD_REQUEST]
104
-		];
105
-	}
106
-
107
-	/**
108
-	 * @param $enableRecovery
109
-	 * @param $expectedMessage
110
-	 * @param $expectedStatus
111
-	 */
112
-	#[\PHPUnit\Framework\Attributes\DataProvider('userSetRecoveryProvider')]
113
-	public function testUserSetRecovery($enableRecovery, $expectedMessage, $expectedStatus): void {
114
-		$this->recoveryMock->expects($this->any())
115
-			->method('setRecoveryForUser')
116
-			->with($enableRecovery)
117
-			->willReturnMap([
118
-				['1', true],
119
-				['0', false]
120
-			]);
121
-
122
-
123
-		$response = $this->controller->userSetRecovery($enableRecovery);
124
-
125
-		$this->assertEquals($expectedMessage, $response->getData()['data']['message']);
126
-		$this->assertEquals($expectedStatus, $response->getStatus());
127
-	}
128
-
129
-	protected function setUp(): void {
130
-		parent::setUp();
131
-
132
-		$this->requestMock = $this->getMockBuilder(IRequest::class)
133
-			->disableOriginalConstructor()
134
-			->getMock();
135
-
136
-		$this->configMock = $this->getMockBuilder(IConfig::class)
137
-			->disableOriginalConstructor()
138
-			->getMock();
139
-
140
-		$this->l10nMock = $this->getMockBuilder(IL10N::class)
141
-			->disableOriginalConstructor()
142
-			->getMock();
143
-
144
-		// Make l10n work in our tests
145
-		$this->l10nMock->expects($this->any())
146
-			->method('t')
147
-			->willReturnArgument(0);
148
-
149
-		$this->recoveryMock = $this->getMockBuilder(Recovery::class)
150
-			->disableOriginalConstructor()
151
-			->getMock();
152
-
153
-		$this->controller = new RecoveryController('encryption',
154
-			$this->requestMock,
155
-			$this->configMock,
156
-			$this->l10nMock,
157
-			$this->recoveryMock);
158
-	}
22
+    protected RecoveryController $controller;
23
+
24
+    protected IRequest&MockObject $requestMock;
25
+    protected IConfig&MockObject $configMock;
26
+    protected IL10N&MockObject $l10nMock;
27
+    protected Recovery&MockObject $recoveryMock;
28
+
29
+    public static function adminRecoveryProvider(): array {
30
+        return [
31
+            ['test', 'test', '1', 'Recovery key successfully enabled', Http::STATUS_OK],
32
+            ['', 'test', '1', 'Missing recovery key password', Http::STATUS_BAD_REQUEST],
33
+            ['test', '', '1', 'Please repeat the recovery key password', Http::STATUS_BAD_REQUEST],
34
+            ['test', 'something that doesn\'t match', '1', 'Repeated recovery key password does not match the provided recovery key password', Http::STATUS_BAD_REQUEST],
35
+            ['test', 'test', '0', 'Recovery key successfully disabled', Http::STATUS_OK],
36
+        ];
37
+    }
38
+
39
+    /**
40
+     * @param $recoveryPassword
41
+     * @param $passConfirm
42
+     * @param $enableRecovery
43
+     * @param $expectedMessage
44
+     * @param $expectedStatus
45
+     */
46
+    #[\PHPUnit\Framework\Attributes\DataProvider('adminRecoveryProvider')]
47
+    public function testAdminRecovery($recoveryPassword, $passConfirm, $enableRecovery, $expectedMessage, $expectedStatus): void {
48
+        $this->recoveryMock->expects($this->any())
49
+            ->method('enableAdminRecovery')
50
+            ->willReturn(true);
51
+
52
+        $this->recoveryMock->expects($this->any())
53
+            ->method('disableAdminRecovery')
54
+            ->willReturn(true);
55
+
56
+        $response = $this->controller->adminRecovery($recoveryPassword,
57
+            $passConfirm,
58
+            $enableRecovery);
59
+
60
+
61
+        $this->assertEquals($expectedMessage, $response->getData()['data']['message']);
62
+        $this->assertEquals($expectedStatus, $response->getStatus());
63
+    }
64
+
65
+    public static function changeRecoveryPasswordProvider(): array {
66
+        return [
67
+            ['test', 'test', 'oldtestFail', 'Could not change the password. Maybe the old password was not correct.', Http::STATUS_BAD_REQUEST],
68
+            ['test', 'test', 'oldtest', 'Password successfully changed.', Http::STATUS_OK],
69
+            ['test', 'notmatch', 'oldtest', 'Repeated recovery key password does not match the provided recovery key password', Http::STATUS_BAD_REQUEST],
70
+            ['', 'test', 'oldtest', 'Please provide a new recovery password', Http::STATUS_BAD_REQUEST],
71
+            ['test', 'test', '', 'Please provide the old recovery password', Http::STATUS_BAD_REQUEST]
72
+        ];
73
+    }
74
+
75
+    /**
76
+     * @param $password
77
+     * @param $confirmPassword
78
+     * @param $oldPassword
79
+     * @param $expectedMessage
80
+     * @param $expectedStatus
81
+     */
82
+    #[\PHPUnit\Framework\Attributes\DataProvider('changeRecoveryPasswordProvider')]
83
+    public function testChangeRecoveryPassword($password, $confirmPassword, $oldPassword, $expectedMessage, $expectedStatus): void {
84
+        $this->recoveryMock->expects($this->any())
85
+            ->method('changeRecoveryKeyPassword')
86
+            ->with($password, $oldPassword)
87
+            ->willReturnMap([
88
+                ['test', 'oldtestFail', false],
89
+                ['test', 'oldtest', true]
90
+            ]);
91
+
92
+        $response = $this->controller->changeRecoveryPassword($password,
93
+            $oldPassword,
94
+            $confirmPassword);
95
+
96
+        $this->assertEquals($expectedMessage, $response->getData()['data']['message']);
97
+        $this->assertEquals($expectedStatus, $response->getStatus());
98
+    }
99
+
100
+    public static function userSetRecoveryProvider(): array {
101
+        return [
102
+            ['1', 'Recovery Key enabled', Http::STATUS_OK],
103
+            ['0', 'Could not enable the recovery key, please try again or contact your administrator', Http::STATUS_BAD_REQUEST]
104
+        ];
105
+    }
106
+
107
+    /**
108
+     * @param $enableRecovery
109
+     * @param $expectedMessage
110
+     * @param $expectedStatus
111
+     */
112
+    #[\PHPUnit\Framework\Attributes\DataProvider('userSetRecoveryProvider')]
113
+    public function testUserSetRecovery($enableRecovery, $expectedMessage, $expectedStatus): void {
114
+        $this->recoveryMock->expects($this->any())
115
+            ->method('setRecoveryForUser')
116
+            ->with($enableRecovery)
117
+            ->willReturnMap([
118
+                ['1', true],
119
+                ['0', false]
120
+            ]);
121
+
122
+
123
+        $response = $this->controller->userSetRecovery($enableRecovery);
124
+
125
+        $this->assertEquals($expectedMessage, $response->getData()['data']['message']);
126
+        $this->assertEquals($expectedStatus, $response->getStatus());
127
+    }
128
+
129
+    protected function setUp(): void {
130
+        parent::setUp();
131
+
132
+        $this->requestMock = $this->getMockBuilder(IRequest::class)
133
+            ->disableOriginalConstructor()
134
+            ->getMock();
135
+
136
+        $this->configMock = $this->getMockBuilder(IConfig::class)
137
+            ->disableOriginalConstructor()
138
+            ->getMock();
139
+
140
+        $this->l10nMock = $this->getMockBuilder(IL10N::class)
141
+            ->disableOriginalConstructor()
142
+            ->getMock();
143
+
144
+        // Make l10n work in our tests
145
+        $this->l10nMock->expects($this->any())
146
+            ->method('t')
147
+            ->willReturnArgument(0);
148
+
149
+        $this->recoveryMock = $this->getMockBuilder(Recovery::class)
150
+            ->disableOriginalConstructor()
151
+            ->getMock();
152
+
153
+        $this->controller = new RecoveryController('encryption',
154
+            $this->requestMock,
155
+            $this->configMock,
156
+            $this->l10nMock,
157
+            $this->recoveryMock);
158
+    }
159 159
 }
Please login to merge, or discard this patch.
apps/encryption/tests/KeyManagerTest.php 1 patch
Indentation   +668 added lines, -668 removed lines patch added patch discarded remove patch
@@ -31,672 +31,672 @@
 block discarded – undo
31 31
 
32 32
 class KeyManagerTest extends TestCase {
33 33
 
34
-	protected KeyManager $instance;
35
-
36
-	protected string $userId;
37
-	protected string $systemKeyId;
38
-	protected IStorage&MockObject $keyStorageMock;
39
-	protected Crypt&MockObject $cryptMock;
40
-	protected IUserSession&MockObject $userMock;
41
-	protected Session&MockObject $sessionMock;
42
-	protected LoggerInterface&MockObject $logMock;
43
-	protected Util&MockObject $utilMock;
44
-	protected IConfig&MockObject $configMock;
45
-	protected ILockingProvider&MockObject $lockingProviderMock;
46
-
47
-	protected function setUp(): void {
48
-		parent::setUp();
49
-		$this->userId = 'user1';
50
-		$this->systemKeyId = 'systemKeyId';
51
-		$this->keyStorageMock = $this->createMock(IStorage::class);
52
-		$this->cryptMock = $this->getMockBuilder(Crypt::class)
53
-			->disableOriginalConstructor()
54
-			->getMock();
55
-		$this->configMock = $this->createMock(IConfig::class);
56
-		$this->configMock->expects($this->any())
57
-			->method('getAppValue')
58
-			->willReturn($this->systemKeyId);
59
-		$this->userMock = $this->createMock(IUserSession::class);
60
-		$this->sessionMock = $this->getMockBuilder(Session::class)
61
-			->disableOriginalConstructor()
62
-			->getMock();
63
-		$this->logMock = $this->createMock(LoggerInterface::class);
64
-		$this->utilMock = $this->getMockBuilder(Util::class)
65
-			->disableOriginalConstructor()
66
-			->getMock();
67
-		$this->lockingProviderMock = $this->createMock(ILockingProvider::class);
68
-
69
-		$this->instance = new KeyManager(
70
-			$this->keyStorageMock,
71
-			$this->cryptMock,
72
-			$this->configMock,
73
-			$this->userMock,
74
-			$this->sessionMock,
75
-			$this->logMock,
76
-			$this->utilMock,
77
-			$this->lockingProviderMock
78
-		);
79
-	}
80
-
81
-	public function testDeleteShareKey(): void {
82
-		$this->keyStorageMock->expects($this->any())
83
-			->method('deleteFileKey')
84
-			->with($this->equalTo('/path'), $this->equalTo('keyId.shareKey'))
85
-			->willReturn(true);
86
-
87
-		$this->assertTrue(
88
-			$this->instance->deleteShareKey('/path', 'keyId')
89
-		);
90
-	}
91
-
92
-	public function testGetPrivateKey(): void {
93
-		$this->keyStorageMock->expects($this->any())
94
-			->method('getUserKey')
95
-			->with($this->equalTo($this->userId), $this->equalTo('privateKey'))
96
-			->willReturn('privateKey');
97
-
98
-
99
-		$this->assertSame('privateKey',
100
-			$this->instance->getPrivateKey($this->userId)
101
-		);
102
-	}
103
-
104
-	public function testGetPublicKey(): void {
105
-		$this->keyStorageMock->expects($this->any())
106
-			->method('getUserKey')
107
-			->with($this->equalTo($this->userId), $this->equalTo('publicKey'))
108
-			->willReturn('publicKey');
109
-
110
-
111
-		$this->assertSame('publicKey',
112
-			$this->instance->getPublicKey($this->userId)
113
-		);
114
-	}
115
-
116
-	public function testRecoveryKeyExists(): void {
117
-		$this->keyStorageMock->expects($this->any())
118
-			->method('getSystemUserKey')
119
-			->with($this->equalTo($this->systemKeyId . '.publicKey'))
120
-			->willReturn('recoveryKey');
121
-
122
-
123
-		$this->assertTrue($this->instance->recoveryKeyExists());
124
-	}
125
-
126
-	public function testCheckRecoveryKeyPassword(): void {
127
-		$this->keyStorageMock->expects($this->any())
128
-			->method('getSystemUserKey')
129
-			->with($this->equalTo($this->systemKeyId . '.privateKey'))
130
-			->willReturn('recoveryKey');
131
-		$this->cryptMock->expects($this->any())
132
-			->method('decryptPrivateKey')
133
-			->with($this->equalTo('recoveryKey'), $this->equalTo('pass'))
134
-			->willReturn('decryptedRecoveryKey');
135
-
136
-		$this->assertTrue($this->instance->checkRecoveryPassword('pass'));
137
-	}
138
-
139
-	public function testSetPublicKey(): void {
140
-		$this->keyStorageMock->expects($this->any())
141
-			->method('setUserKey')
142
-			->with(
143
-				$this->equalTo($this->userId),
144
-				$this->equalTo('publicKey'),
145
-				$this->equalTo('key'))
146
-			->willReturn(true);
147
-
148
-
149
-		$this->assertTrue(
150
-			$this->instance->setPublicKey($this->userId, 'key')
151
-		);
152
-	}
153
-
154
-	public function testSetPrivateKey(): void {
155
-		$this->keyStorageMock->expects($this->any())
156
-			->method('setUserKey')
157
-			->with(
158
-				$this->equalTo($this->userId),
159
-				$this->equalTo('privateKey'),
160
-				$this->equalTo('key'))
161
-			->willReturn(true);
162
-
163
-
164
-		$this->assertTrue(
165
-			$this->instance->setPrivateKey($this->userId, 'key')
166
-		);
167
-	}
168
-
169
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestUserHasKeys')]
170
-	public function testUserHasKeys($key, $expected): void {
171
-		$this->keyStorageMock->expects($this->exactly(2))
172
-			->method('getUserKey')
173
-			->with($this->equalTo($this->userId), $this->anything())
174
-			->willReturn($key);
175
-
176
-
177
-		$this->assertSame($expected,
178
-			$this->instance->userHasKeys($this->userId)
179
-		);
180
-	}
181
-
182
-	public static function dataTestUserHasKeys(): array {
183
-		return [
184
-			['key', true],
185
-			['', false]
186
-		];
187
-	}
188
-
189
-
190
-	public function testUserHasKeysMissingPrivateKey(): void {
191
-		$this->expectException(PrivateKeyMissingException::class);
192
-
193
-		$this->keyStorageMock->expects($this->exactly(2))
194
-			->method('getUserKey')
195
-			->willReturnCallback(function ($uid, $keyID, $encryptionModuleId) {
196
-				if ($keyID === 'privateKey') {
197
-					return '';
198
-				}
199
-				return 'key';
200
-			});
201
-
202
-		$this->instance->userHasKeys($this->userId);
203
-	}
204
-
205
-
206
-	public function testUserHasKeysMissingPublicKey(): void {
207
-		$this->expectException(PublicKeyMissingException::class);
208
-
209
-		$this->keyStorageMock->expects($this->exactly(2))
210
-			->method('getUserKey')
211
-			->willReturnCallback(function ($uid, $keyID, $encryptionModuleId) {
212
-				if ($keyID === 'publicKey') {
213
-					return '';
214
-				}
215
-				return 'key';
216
-			});
217
-
218
-		$this->instance->userHasKeys($this->userId);
219
-	}
220
-
221
-	/**
222
-	 * @param bool $useMasterKey
223
-	 */
224
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestInit')]
225
-	public function testInit($useMasterKey): void {
226
-		/** @var KeyManager&MockObject $instance */
227
-		$instance = $this->getMockBuilder(KeyManager::class)
228
-			->setConstructorArgs(
229
-				[
230
-					$this->keyStorageMock,
231
-					$this->cryptMock,
232
-					$this->configMock,
233
-					$this->userMock,
234
-					$this->sessionMock,
235
-					$this->logMock,
236
-					$this->utilMock,
237
-					$this->lockingProviderMock
238
-				]
239
-			)->onlyMethods(['getMasterKeyId', 'getMasterKeyPassword', 'getSystemPrivateKey', 'getPrivateKey'])
240
-			->getMock();
241
-
242
-		$this->utilMock->expects($this->once())->method('isMasterKeyEnabled')
243
-			->willReturn($useMasterKey);
244
-
245
-		$sessionSetStatusCalls = [];
246
-		$this->sessionMock->expects($this->exactly(2))
247
-			->method('setStatus')
248
-			->willReturnCallback(function (string $status) use (&$sessionSetStatusCalls): void {
249
-				$sessionSetStatusCalls[] = $status;
250
-			});
251
-
252
-		$instance->expects($this->any())->method('getMasterKeyId')->willReturn('masterKeyId');
253
-		$instance->expects($this->any())->method('getMasterKeyPassword')->willReturn('masterKeyPassword');
254
-		$instance->expects($this->any())->method('getSystemPrivateKey')->with('masterKeyId')->willReturn('privateMasterKey');
255
-		$instance->expects($this->any())->method('getPrivateKey')->with($this->userId)->willReturn('privateUserKey');
256
-
257
-		if ($useMasterKey) {
258
-			$this->cryptMock->expects($this->once())->method('decryptPrivateKey')
259
-				->with('privateMasterKey', 'masterKeyPassword', 'masterKeyId')
260
-				->willReturn('key');
261
-		} else {
262
-			$this->cryptMock->expects($this->once())->method('decryptPrivateKey')
263
-				->with('privateUserKey', 'pass', $this->userId)
264
-				->willReturn('key');
265
-		}
266
-
267
-		$this->sessionMock->expects($this->once())->method('setPrivateKey')
268
-			->with('key');
269
-
270
-		$this->assertTrue($instance->init($this->userId, 'pass'));
271
-		self::assertEquals([
272
-			Session::INIT_EXECUTED,
273
-			Session::INIT_SUCCESSFUL,
274
-		], $sessionSetStatusCalls);
275
-	}
276
-
277
-	public static function dataTestInit(): array {
278
-		return [
279
-			[true],
280
-			[false]
281
-		];
282
-	}
283
-
284
-
285
-	public function testSetRecoveryKey(): void {
286
-		$this->keyStorageMock->expects($this->exactly(2))
287
-			->method('setSystemUserKey')
288
-			->willReturn(true);
289
-		$this->cryptMock->expects($this->any())
290
-			->method('encryptPrivateKey')
291
-			->with($this->equalTo('privateKey'), $this->equalTo('pass'))
292
-			->willReturn('decryptedPrivateKey');
293
-
294
-
295
-		$this->assertTrue(
296
-			$this->instance->setRecoveryKey('pass',
297
-				['publicKey' => 'publicKey', 'privateKey' => 'privateKey'])
298
-		);
299
-	}
300
-
301
-	public function testSetSystemPrivateKey(): void {
302
-		$this->keyStorageMock->expects($this->exactly(1))
303
-			->method('setSystemUserKey')
304
-			->with($this->equalTo('keyId.privateKey'), $this->equalTo('key'))
305
-			->willReturn(true);
306
-
307
-
308
-		$this->assertTrue(
309
-			$this->instance->setSystemPrivateKey('keyId', 'key')
310
-		);
311
-	}
312
-
313
-	public function testGetSystemPrivateKey(): void {
314
-		$this->keyStorageMock->expects($this->exactly(1))
315
-			->method('getSystemUserKey')
316
-			->with($this->equalTo('keyId.privateKey'))
317
-			->willReturn('systemPrivateKey');
318
-
319
-
320
-		$this->assertSame('systemPrivateKey',
321
-			$this->instance->getSystemPrivateKey('keyId')
322
-		);
323
-	}
324
-
325
-	public function testGetEncryptedFileKey(): void {
326
-		$this->keyStorageMock->expects($this->once())
327
-			->method('getFileKey')
328
-			->with('/', 'fileKey')
329
-			->willReturn(true);
330
-
331
-		$this->assertTrue($this->instance->getEncryptedFileKey('/'));
332
-	}
333
-
334
-	public static function dataTestGetFileKey(): array {
335
-		return [
336
-			['user1', false, 'privateKey', 'legacyKey', 'multiKeyDecryptResult'],
337
-			['user1', false, 'privateKey', '', 'multiKeyDecryptResult'],
338
-			['user1', false, '', 'legacyKey', ''],
339
-			['user1', false, '', '', ''],
340
-			['user1', true, 'privateKey', 'legacyKey', 'multiKeyDecryptResult'],
341
-			['user1', true, 'privateKey', '', 'multiKeyDecryptResult'],
342
-			['user1', true, '', 'legacyKey', ''],
343
-			['user1', true, '', '', ''],
344
-			[null, false, 'privateKey', 'legacyKey', 'multiKeyDecryptResult'],
345
-			[null, false, 'privateKey', '', 'multiKeyDecryptResult'],
346
-			[null, false, '', 'legacyKey', ''],
347
-			[null, false, '', '', ''],
348
-			[null, true, 'privateKey', 'legacyKey', 'multiKeyDecryptResult'],
349
-			[null, true, 'privateKey', '', 'multiKeyDecryptResult'],
350
-			[null, true, '', 'legacyKey', ''],
351
-			[null, true, '', '', ''],
352
-		];
353
-	}
354
-
355
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestGetFileKey')]
356
-	public function testGetFileKey(?string $uid, bool $isMasterKeyEnabled, string $privateKey, string $encryptedFileKey, string $expected): void {
357
-		$path = '/foo.txt';
358
-
359
-		if ($isMasterKeyEnabled) {
360
-			$expectedUid = 'masterKeyId';
361
-			$this->configMock->expects($this->any())->method('getSystemValue')->with('secret')
362
-				->willReturn('password');
363
-		} elseif (!$uid) {
364
-			$expectedUid = 'systemKeyId';
365
-		} else {
366
-			$expectedUid = $uid;
367
-		}
368
-
369
-		$this->invokePrivate($this->instance, 'masterKeyId', ['masterKeyId']);
370
-		$this->invokePrivate($this->instance, 'keyUid', [$uid]);
371
-
372
-		$this->keyStorageMock->expects($this->exactly(2))
373
-			->method('getFileKey')
374
-			->willReturnMap([
375
-				[$path, 'fileKey', 'OC_DEFAULT_MODULE', $encryptedFileKey],
376
-				[$path, $expectedUid . '.shareKey', 'OC_DEFAULT_MODULE', 'fileKey'],
377
-			]);
378
-
379
-		$this->utilMock->expects($this->any())->method('isMasterKeyEnabled')
380
-			->willReturn($isMasterKeyEnabled);
381
-
382
-		if (is_null($uid)) {
383
-			$this->keyStorageMock->expects($this->once())
384
-				->method('getSystemUserKey')
385
-				->willReturn(true);
386
-			$this->cryptMock->expects($this->once())
387
-				->method('decryptPrivateKey')
388
-				->willReturn($privateKey);
389
-		} else {
390
-			$this->keyStorageMock->expects($this->never())
391
-				->method('getSystemUserKey');
392
-			$this->sessionMock->expects($this->once())->method('getPrivateKey')->willReturn($privateKey);
393
-		}
394
-
395
-		if (!empty($encryptedFileKey)) {
396
-			$this->cryptMock->expects($this->never())
397
-				->method('multiKeyDecrypt');
398
-			if ($privateKey) {
399
-				$this->cryptMock->expects($this->once())
400
-					->method('multiKeyDecryptLegacy')
401
-					->willReturn('multiKeyDecryptResult');
402
-			} else {
403
-				$this->cryptMock->expects($this->never())
404
-					->method('multiKeyDecryptLegacy');
405
-			}
406
-		} else {
407
-			$this->cryptMock->expects($this->never())
408
-				->method('multiKeyDecryptLegacy');
409
-			if ($privateKey) {
410
-				$this->cryptMock->expects($this->once())
411
-					->method('multiKeyDecrypt')
412
-					->willReturn('multiKeyDecryptResult');
413
-			} else {
414
-				$this->cryptMock->expects($this->never())
415
-					->method('multiKeyDecrypt');
416
-			}
417
-		}
418
-
419
-		$this->assertSame($expected,
420
-			$this->instance->getFileKey($path, null)
421
-		);
422
-	}
423
-
424
-	public function testDeletePrivateKey(): void {
425
-		$this->keyStorageMock->expects($this->once())
426
-			->method('deleteUserKey')
427
-			->with('user1', 'privateKey')
428
-			->willReturn(true);
429
-
430
-		$this->assertTrue(self::invokePrivate($this->instance,
431
-			'deletePrivateKey',
432
-			[$this->userId]));
433
-	}
434
-
435
-	public function testDeleteAllFileKeys(): void {
436
-		$this->keyStorageMock->expects($this->once())
437
-			->method('deleteAllFileKeys')
438
-			->willReturn(true);
439
-
440
-		$this->assertTrue($this->instance->deleteAllFileKeys('/'));
441
-	}
442
-
443
-	/**
444
-	 * test add public share key and or recovery key to the list of public keys
445
-	 *
446
-	 *
447
-	 * @param array $accessList
448
-	 * @param array $publicKeys
449
-	 * @param string $uid
450
-	 * @param array $expectedKeys
451
-	 */
452
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestAddSystemKeys')]
453
-	public function testAddSystemKeys($accessList, $publicKeys, $uid, $expectedKeys): void {
454
-		$publicShareKeyId = 'publicShareKey';
455
-		$recoveryKeyId = 'recoveryKey';
456
-
457
-		$this->keyStorageMock->expects($this->any())
458
-			->method('getSystemUserKey')
459
-			->willReturnCallback(function ($keyId, $encryptionModuleId) {
460
-				return $keyId;
461
-			});
462
-
463
-		$this->utilMock->expects($this->any())
464
-			->method('isRecoveryEnabledForUser')
465
-			->willReturnCallback(function ($uid) {
466
-				if ($uid === 'user1') {
467
-					return true;
468
-				}
469
-				return false;
470
-			});
471
-
472
-		// set key IDs
473
-		self::invokePrivate($this->instance, 'publicShareKeyId', [$publicShareKeyId]);
474
-		self::invokePrivate($this->instance, 'recoveryKeyId', [$recoveryKeyId]);
475
-
476
-		$result = $this->instance->addSystemKeys($accessList, $publicKeys, $uid);
477
-
478
-		foreach ($expectedKeys as $expected) {
479
-			$this->assertArrayHasKey($expected, $result);
480
-		}
481
-
482
-		$this->assertSameSize($expectedKeys, $result);
483
-	}
484
-
485
-	/**
486
-	 * data provider for testAddSystemKeys()
487
-	 *
488
-	 * @return array
489
-	 */
490
-	public static function dataTestAddSystemKeys(): array {
491
-		return [
492
-			[['public' => true],[], 'user1', ['publicShareKey', 'recoveryKey']],
493
-			[['public' => false], [], 'user1', ['recoveryKey']],
494
-			[['public' => true],[], 'user2', ['publicShareKey']],
495
-			[['public' => false], [], 'user2', []],
496
-		];
497
-	}
498
-
499
-	public function testGetMasterKeyId(): void {
500
-		$this->assertSame('systemKeyId', $this->instance->getMasterKeyId());
501
-	}
502
-
503
-	public function testGetPublicMasterKey(): void {
504
-		$this->keyStorageMock->expects($this->once())->method('getSystemUserKey')
505
-			->with('systemKeyId.publicKey', Encryption::ID)
506
-			->willReturn(true);
507
-
508
-		$this->assertTrue(
509
-			$this->instance->getPublicMasterKey()
510
-		);
511
-	}
512
-
513
-	public function testGetMasterKeyPassword(): void {
514
-		$this->configMock->expects($this->once())->method('getSystemValue')->with('secret')
515
-			->willReturn('password');
516
-
517
-		$this->assertSame('password',
518
-			$this->invokePrivate($this->instance, 'getMasterKeyPassword', [])
519
-		);
520
-	}
521
-
522
-
523
-	public function testGetMasterKeyPasswordException(): void {
524
-		$this->expectException(\Exception::class);
525
-
526
-		$this->configMock->expects($this->once())->method('getSystemValue')->with('secret')
527
-			->willReturn('');
528
-
529
-		$this->invokePrivate($this->instance, 'getMasterKeyPassword', []);
530
-	}
531
-
532
-	/**
533
-	 * @param $masterKey
534
-	 */
535
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestValidateMasterKey')]
536
-	public function testValidateMasterKey($masterKey): void {
537
-		/** @var KeyManager&MockObject $instance */
538
-		$instance = $this->getMockBuilder(KeyManager::class)
539
-			->setConstructorArgs(
540
-				[
541
-					$this->keyStorageMock,
542
-					$this->cryptMock,
543
-					$this->configMock,
544
-					$this->userMock,
545
-					$this->sessionMock,
546
-					$this->logMock,
547
-					$this->utilMock,
548
-					$this->lockingProviderMock
549
-				]
550
-			)->onlyMethods(['getPublicMasterKey', 'setSystemPrivateKey', 'getMasterKeyPassword'])
551
-			->getMock();
552
-
553
-		$this->utilMock->expects($this->once())->method('isMasterKeyEnabled')
554
-			->willReturn(true);
555
-
556
-		$instance->expects($this->once())->method('getPublicMasterKey')
557
-			->willReturn($masterKey);
558
-
559
-		$instance->expects($this->any())->method('getMasterKeyPassword')->willReturn('masterKeyPassword');
560
-		$this->cryptMock->expects($this->any())->method('generateHeader')->willReturn('header');
561
-
562
-		if (empty($masterKey)) {
563
-			$this->cryptMock->expects($this->once())->method('createKeyPair')
564
-				->willReturn(['publicKey' => 'public', 'privateKey' => 'private']);
565
-			$this->keyStorageMock->expects($this->once())->method('setSystemUserKey')
566
-				->with('systemKeyId.publicKey', 'public', Encryption::ID);
567
-			$this->cryptMock->expects($this->once())->method('encryptPrivateKey')
568
-				->with('private', 'masterKeyPassword', 'systemKeyId')
569
-				->willReturn('EncryptedKey');
570
-			$this->lockingProviderMock->expects($this->once())
571
-				->method('acquireLock');
572
-			$instance->expects($this->once())->method('setSystemPrivateKey')
573
-				->with('systemKeyId', 'headerEncryptedKey');
574
-		} else {
575
-			$this->cryptMock->expects($this->never())->method('createKeyPair');
576
-			$this->keyStorageMock->expects($this->never())->method('setSystemUserKey');
577
-			$this->cryptMock->expects($this->never())->method('encryptPrivateKey');
578
-			$instance->expects($this->never())->method('setSystemPrivateKey');
579
-		}
580
-
581
-		$instance->validateMasterKey();
582
-	}
583
-
584
-	public function testValidateMasterKeyLocked(): void {
585
-		/** @var KeyManager&MockObject $instance */
586
-		$instance = $this->getMockBuilder(KeyManager::class)
587
-			->setConstructorArgs([
588
-				$this->keyStorageMock,
589
-				$this->cryptMock,
590
-				$this->configMock,
591
-				$this->userMock,
592
-				$this->sessionMock,
593
-				$this->logMock,
594
-				$this->utilMock,
595
-				$this->lockingProviderMock
596
-			])
597
-			->onlyMethods(['getPublicMasterKey', 'getPrivateMasterKey', 'setSystemPrivateKey', 'getMasterKeyPassword'])
598
-			->getMock();
599
-
600
-		$this->utilMock->expects($this->once())->method('isMasterKeyEnabled')
601
-			->willReturn(true);
602
-
603
-		$instance->expects($this->once())->method('getPublicMasterKey')
604
-			->willReturn('');
605
-		$instance->expects($this->once())->method('getPrivateMasterKey')
606
-			->willReturn('');
607
-
608
-		$instance->expects($this->any())->method('getMasterKeyPassword')->willReturn('masterKeyPassword');
609
-		$this->cryptMock->expects($this->any())->method('generateHeader')->willReturn('header');
610
-
611
-		$this->lockingProviderMock->expects($this->once())
612
-			->method('acquireLock')
613
-			->willThrowException(new LockedException('encryption-generateMasterKey'));
614
-
615
-		$this->expectException(LockedException::class);
616
-		$instance->validateMasterKey();
617
-	}
618
-
619
-	public static function dataTestValidateMasterKey(): array {
620
-		return [
621
-			['masterKey'],
622
-			['']
623
-		];
624
-	}
625
-
626
-	public function testGetVersionWithoutFileInfo(): void {
627
-		$view = $this->getMockBuilder(View::class)
628
-			->disableOriginalConstructor()->getMock();
629
-		$view->expects($this->once())
630
-			->method('getFileInfo')
631
-			->with('/admin/files/myfile.txt')
632
-			->willReturn(false);
633
-
634
-		/** @var View $view */
635
-		$this->assertSame(0, $this->instance->getVersion('/admin/files/myfile.txt', $view));
636
-	}
637
-
638
-	public function testGetVersionWithFileInfo(): void {
639
-		$view = $this->getMockBuilder(View::class)
640
-			->disableOriginalConstructor()->getMock();
641
-		$fileInfo = $this->getMockBuilder(FileInfo::class)
642
-			->disableOriginalConstructor()->getMock();
643
-		$fileInfo->expects($this->once())
644
-			->method('getEncryptedVersion')
645
-			->willReturn(1337);
646
-		$view->expects($this->once())
647
-			->method('getFileInfo')
648
-			->with('/admin/files/myfile.txt')
649
-			->willReturn($fileInfo);
650
-
651
-		/** @var View $view */
652
-		$this->assertSame(1337, $this->instance->getVersion('/admin/files/myfile.txt', $view));
653
-	}
654
-
655
-	public function testSetVersionWithFileInfo(): void {
656
-		$view = $this->getMockBuilder(View::class)
657
-			->disableOriginalConstructor()->getMock();
658
-		$cache = $this->getMockBuilder(ICache::class)
659
-			->disableOriginalConstructor()->getMock();
660
-		$cache->expects($this->once())
661
-			->method('update')
662
-			->with(123, ['encrypted' => 5, 'encryptedVersion' => 5]);
663
-		$storage = $this->getMockBuilder(FilesIStorage::class)
664
-			->disableOriginalConstructor()->getMock();
665
-		$storage->expects($this->once())
666
-			->method('getCache')
667
-			->willReturn($cache);
668
-		$fileInfo = $this->getMockBuilder(FileInfo::class)
669
-			->disableOriginalConstructor()->getMock();
670
-		$fileInfo->expects($this->once())
671
-			->method('getStorage')
672
-			->willReturn($storage);
673
-		$fileInfo->expects($this->once())
674
-			->method('getId')
675
-			->willReturn(123);
676
-		$view->expects($this->once())
677
-			->method('getFileInfo')
678
-			->with('/admin/files/myfile.txt')
679
-			->willReturn($fileInfo);
680
-
681
-		/** @var View $view */
682
-		$this->instance->setVersion('/admin/files/myfile.txt', 5, $view);
683
-	}
684
-
685
-	public function testSetVersionWithoutFileInfo(): void {
686
-		$view = $this->getMockBuilder(View::class)
687
-			->disableOriginalConstructor()->getMock();
688
-		$view->expects($this->once())
689
-			->method('getFileInfo')
690
-			->with('/admin/files/myfile.txt')
691
-			->willReturn(false);
692
-
693
-		/** @var View $view */
694
-		$this->instance->setVersion('/admin/files/myfile.txt', 5, $view);
695
-	}
696
-
697
-	public function testBackupUserKeys(): void {
698
-		$this->keyStorageMock->expects($this->once())->method('backupUserKeys')
699
-			->with('OC_DEFAULT_MODULE', 'test', 'user1');
700
-		$this->instance->backupUserKeys('test', 'user1');
701
-	}
34
+    protected KeyManager $instance;
35
+
36
+    protected string $userId;
37
+    protected string $systemKeyId;
38
+    protected IStorage&MockObject $keyStorageMock;
39
+    protected Crypt&MockObject $cryptMock;
40
+    protected IUserSession&MockObject $userMock;
41
+    protected Session&MockObject $sessionMock;
42
+    protected LoggerInterface&MockObject $logMock;
43
+    protected Util&MockObject $utilMock;
44
+    protected IConfig&MockObject $configMock;
45
+    protected ILockingProvider&MockObject $lockingProviderMock;
46
+
47
+    protected function setUp(): void {
48
+        parent::setUp();
49
+        $this->userId = 'user1';
50
+        $this->systemKeyId = 'systemKeyId';
51
+        $this->keyStorageMock = $this->createMock(IStorage::class);
52
+        $this->cryptMock = $this->getMockBuilder(Crypt::class)
53
+            ->disableOriginalConstructor()
54
+            ->getMock();
55
+        $this->configMock = $this->createMock(IConfig::class);
56
+        $this->configMock->expects($this->any())
57
+            ->method('getAppValue')
58
+            ->willReturn($this->systemKeyId);
59
+        $this->userMock = $this->createMock(IUserSession::class);
60
+        $this->sessionMock = $this->getMockBuilder(Session::class)
61
+            ->disableOriginalConstructor()
62
+            ->getMock();
63
+        $this->logMock = $this->createMock(LoggerInterface::class);
64
+        $this->utilMock = $this->getMockBuilder(Util::class)
65
+            ->disableOriginalConstructor()
66
+            ->getMock();
67
+        $this->lockingProviderMock = $this->createMock(ILockingProvider::class);
68
+
69
+        $this->instance = new KeyManager(
70
+            $this->keyStorageMock,
71
+            $this->cryptMock,
72
+            $this->configMock,
73
+            $this->userMock,
74
+            $this->sessionMock,
75
+            $this->logMock,
76
+            $this->utilMock,
77
+            $this->lockingProviderMock
78
+        );
79
+    }
80
+
81
+    public function testDeleteShareKey(): void {
82
+        $this->keyStorageMock->expects($this->any())
83
+            ->method('deleteFileKey')
84
+            ->with($this->equalTo('/path'), $this->equalTo('keyId.shareKey'))
85
+            ->willReturn(true);
86
+
87
+        $this->assertTrue(
88
+            $this->instance->deleteShareKey('/path', 'keyId')
89
+        );
90
+    }
91
+
92
+    public function testGetPrivateKey(): void {
93
+        $this->keyStorageMock->expects($this->any())
94
+            ->method('getUserKey')
95
+            ->with($this->equalTo($this->userId), $this->equalTo('privateKey'))
96
+            ->willReturn('privateKey');
97
+
98
+
99
+        $this->assertSame('privateKey',
100
+            $this->instance->getPrivateKey($this->userId)
101
+        );
102
+    }
103
+
104
+    public function testGetPublicKey(): void {
105
+        $this->keyStorageMock->expects($this->any())
106
+            ->method('getUserKey')
107
+            ->with($this->equalTo($this->userId), $this->equalTo('publicKey'))
108
+            ->willReturn('publicKey');
109
+
110
+
111
+        $this->assertSame('publicKey',
112
+            $this->instance->getPublicKey($this->userId)
113
+        );
114
+    }
115
+
116
+    public function testRecoveryKeyExists(): void {
117
+        $this->keyStorageMock->expects($this->any())
118
+            ->method('getSystemUserKey')
119
+            ->with($this->equalTo($this->systemKeyId . '.publicKey'))
120
+            ->willReturn('recoveryKey');
121
+
122
+
123
+        $this->assertTrue($this->instance->recoveryKeyExists());
124
+    }
125
+
126
+    public function testCheckRecoveryKeyPassword(): void {
127
+        $this->keyStorageMock->expects($this->any())
128
+            ->method('getSystemUserKey')
129
+            ->with($this->equalTo($this->systemKeyId . '.privateKey'))
130
+            ->willReturn('recoveryKey');
131
+        $this->cryptMock->expects($this->any())
132
+            ->method('decryptPrivateKey')
133
+            ->with($this->equalTo('recoveryKey'), $this->equalTo('pass'))
134
+            ->willReturn('decryptedRecoveryKey');
135
+
136
+        $this->assertTrue($this->instance->checkRecoveryPassword('pass'));
137
+    }
138
+
139
+    public function testSetPublicKey(): void {
140
+        $this->keyStorageMock->expects($this->any())
141
+            ->method('setUserKey')
142
+            ->with(
143
+                $this->equalTo($this->userId),
144
+                $this->equalTo('publicKey'),
145
+                $this->equalTo('key'))
146
+            ->willReturn(true);
147
+
148
+
149
+        $this->assertTrue(
150
+            $this->instance->setPublicKey($this->userId, 'key')
151
+        );
152
+    }
153
+
154
+    public function testSetPrivateKey(): void {
155
+        $this->keyStorageMock->expects($this->any())
156
+            ->method('setUserKey')
157
+            ->with(
158
+                $this->equalTo($this->userId),
159
+                $this->equalTo('privateKey'),
160
+                $this->equalTo('key'))
161
+            ->willReturn(true);
162
+
163
+
164
+        $this->assertTrue(
165
+            $this->instance->setPrivateKey($this->userId, 'key')
166
+        );
167
+    }
168
+
169
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestUserHasKeys')]
170
+    public function testUserHasKeys($key, $expected): void {
171
+        $this->keyStorageMock->expects($this->exactly(2))
172
+            ->method('getUserKey')
173
+            ->with($this->equalTo($this->userId), $this->anything())
174
+            ->willReturn($key);
175
+
176
+
177
+        $this->assertSame($expected,
178
+            $this->instance->userHasKeys($this->userId)
179
+        );
180
+    }
181
+
182
+    public static function dataTestUserHasKeys(): array {
183
+        return [
184
+            ['key', true],
185
+            ['', false]
186
+        ];
187
+    }
188
+
189
+
190
+    public function testUserHasKeysMissingPrivateKey(): void {
191
+        $this->expectException(PrivateKeyMissingException::class);
192
+
193
+        $this->keyStorageMock->expects($this->exactly(2))
194
+            ->method('getUserKey')
195
+            ->willReturnCallback(function ($uid, $keyID, $encryptionModuleId) {
196
+                if ($keyID === 'privateKey') {
197
+                    return '';
198
+                }
199
+                return 'key';
200
+            });
201
+
202
+        $this->instance->userHasKeys($this->userId);
203
+    }
204
+
205
+
206
+    public function testUserHasKeysMissingPublicKey(): void {
207
+        $this->expectException(PublicKeyMissingException::class);
208
+
209
+        $this->keyStorageMock->expects($this->exactly(2))
210
+            ->method('getUserKey')
211
+            ->willReturnCallback(function ($uid, $keyID, $encryptionModuleId) {
212
+                if ($keyID === 'publicKey') {
213
+                    return '';
214
+                }
215
+                return 'key';
216
+            });
217
+
218
+        $this->instance->userHasKeys($this->userId);
219
+    }
220
+
221
+    /**
222
+     * @param bool $useMasterKey
223
+     */
224
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestInit')]
225
+    public function testInit($useMasterKey): void {
226
+        /** @var KeyManager&MockObject $instance */
227
+        $instance = $this->getMockBuilder(KeyManager::class)
228
+            ->setConstructorArgs(
229
+                [
230
+                    $this->keyStorageMock,
231
+                    $this->cryptMock,
232
+                    $this->configMock,
233
+                    $this->userMock,
234
+                    $this->sessionMock,
235
+                    $this->logMock,
236
+                    $this->utilMock,
237
+                    $this->lockingProviderMock
238
+                ]
239
+            )->onlyMethods(['getMasterKeyId', 'getMasterKeyPassword', 'getSystemPrivateKey', 'getPrivateKey'])
240
+            ->getMock();
241
+
242
+        $this->utilMock->expects($this->once())->method('isMasterKeyEnabled')
243
+            ->willReturn($useMasterKey);
244
+
245
+        $sessionSetStatusCalls = [];
246
+        $this->sessionMock->expects($this->exactly(2))
247
+            ->method('setStatus')
248
+            ->willReturnCallback(function (string $status) use (&$sessionSetStatusCalls): void {
249
+                $sessionSetStatusCalls[] = $status;
250
+            });
251
+
252
+        $instance->expects($this->any())->method('getMasterKeyId')->willReturn('masterKeyId');
253
+        $instance->expects($this->any())->method('getMasterKeyPassword')->willReturn('masterKeyPassword');
254
+        $instance->expects($this->any())->method('getSystemPrivateKey')->with('masterKeyId')->willReturn('privateMasterKey');
255
+        $instance->expects($this->any())->method('getPrivateKey')->with($this->userId)->willReturn('privateUserKey');
256
+
257
+        if ($useMasterKey) {
258
+            $this->cryptMock->expects($this->once())->method('decryptPrivateKey')
259
+                ->with('privateMasterKey', 'masterKeyPassword', 'masterKeyId')
260
+                ->willReturn('key');
261
+        } else {
262
+            $this->cryptMock->expects($this->once())->method('decryptPrivateKey')
263
+                ->with('privateUserKey', 'pass', $this->userId)
264
+                ->willReturn('key');
265
+        }
266
+
267
+        $this->sessionMock->expects($this->once())->method('setPrivateKey')
268
+            ->with('key');
269
+
270
+        $this->assertTrue($instance->init($this->userId, 'pass'));
271
+        self::assertEquals([
272
+            Session::INIT_EXECUTED,
273
+            Session::INIT_SUCCESSFUL,
274
+        ], $sessionSetStatusCalls);
275
+    }
276
+
277
+    public static function dataTestInit(): array {
278
+        return [
279
+            [true],
280
+            [false]
281
+        ];
282
+    }
283
+
284
+
285
+    public function testSetRecoveryKey(): void {
286
+        $this->keyStorageMock->expects($this->exactly(2))
287
+            ->method('setSystemUserKey')
288
+            ->willReturn(true);
289
+        $this->cryptMock->expects($this->any())
290
+            ->method('encryptPrivateKey')
291
+            ->with($this->equalTo('privateKey'), $this->equalTo('pass'))
292
+            ->willReturn('decryptedPrivateKey');
293
+
294
+
295
+        $this->assertTrue(
296
+            $this->instance->setRecoveryKey('pass',
297
+                ['publicKey' => 'publicKey', 'privateKey' => 'privateKey'])
298
+        );
299
+    }
300
+
301
+    public function testSetSystemPrivateKey(): void {
302
+        $this->keyStorageMock->expects($this->exactly(1))
303
+            ->method('setSystemUserKey')
304
+            ->with($this->equalTo('keyId.privateKey'), $this->equalTo('key'))
305
+            ->willReturn(true);
306
+
307
+
308
+        $this->assertTrue(
309
+            $this->instance->setSystemPrivateKey('keyId', 'key')
310
+        );
311
+    }
312
+
313
+    public function testGetSystemPrivateKey(): void {
314
+        $this->keyStorageMock->expects($this->exactly(1))
315
+            ->method('getSystemUserKey')
316
+            ->with($this->equalTo('keyId.privateKey'))
317
+            ->willReturn('systemPrivateKey');
318
+
319
+
320
+        $this->assertSame('systemPrivateKey',
321
+            $this->instance->getSystemPrivateKey('keyId')
322
+        );
323
+    }
324
+
325
+    public function testGetEncryptedFileKey(): void {
326
+        $this->keyStorageMock->expects($this->once())
327
+            ->method('getFileKey')
328
+            ->with('/', 'fileKey')
329
+            ->willReturn(true);
330
+
331
+        $this->assertTrue($this->instance->getEncryptedFileKey('/'));
332
+    }
333
+
334
+    public static function dataTestGetFileKey(): array {
335
+        return [
336
+            ['user1', false, 'privateKey', 'legacyKey', 'multiKeyDecryptResult'],
337
+            ['user1', false, 'privateKey', '', 'multiKeyDecryptResult'],
338
+            ['user1', false, '', 'legacyKey', ''],
339
+            ['user1', false, '', '', ''],
340
+            ['user1', true, 'privateKey', 'legacyKey', 'multiKeyDecryptResult'],
341
+            ['user1', true, 'privateKey', '', 'multiKeyDecryptResult'],
342
+            ['user1', true, '', 'legacyKey', ''],
343
+            ['user1', true, '', '', ''],
344
+            [null, false, 'privateKey', 'legacyKey', 'multiKeyDecryptResult'],
345
+            [null, false, 'privateKey', '', 'multiKeyDecryptResult'],
346
+            [null, false, '', 'legacyKey', ''],
347
+            [null, false, '', '', ''],
348
+            [null, true, 'privateKey', 'legacyKey', 'multiKeyDecryptResult'],
349
+            [null, true, 'privateKey', '', 'multiKeyDecryptResult'],
350
+            [null, true, '', 'legacyKey', ''],
351
+            [null, true, '', '', ''],
352
+        ];
353
+    }
354
+
355
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestGetFileKey')]
356
+    public function testGetFileKey(?string $uid, bool $isMasterKeyEnabled, string $privateKey, string $encryptedFileKey, string $expected): void {
357
+        $path = '/foo.txt';
358
+
359
+        if ($isMasterKeyEnabled) {
360
+            $expectedUid = 'masterKeyId';
361
+            $this->configMock->expects($this->any())->method('getSystemValue')->with('secret')
362
+                ->willReturn('password');
363
+        } elseif (!$uid) {
364
+            $expectedUid = 'systemKeyId';
365
+        } else {
366
+            $expectedUid = $uid;
367
+        }
368
+
369
+        $this->invokePrivate($this->instance, 'masterKeyId', ['masterKeyId']);
370
+        $this->invokePrivate($this->instance, 'keyUid', [$uid]);
371
+
372
+        $this->keyStorageMock->expects($this->exactly(2))
373
+            ->method('getFileKey')
374
+            ->willReturnMap([
375
+                [$path, 'fileKey', 'OC_DEFAULT_MODULE', $encryptedFileKey],
376
+                [$path, $expectedUid . '.shareKey', 'OC_DEFAULT_MODULE', 'fileKey'],
377
+            ]);
378
+
379
+        $this->utilMock->expects($this->any())->method('isMasterKeyEnabled')
380
+            ->willReturn($isMasterKeyEnabled);
381
+
382
+        if (is_null($uid)) {
383
+            $this->keyStorageMock->expects($this->once())
384
+                ->method('getSystemUserKey')
385
+                ->willReturn(true);
386
+            $this->cryptMock->expects($this->once())
387
+                ->method('decryptPrivateKey')
388
+                ->willReturn($privateKey);
389
+        } else {
390
+            $this->keyStorageMock->expects($this->never())
391
+                ->method('getSystemUserKey');
392
+            $this->sessionMock->expects($this->once())->method('getPrivateKey')->willReturn($privateKey);
393
+        }
394
+
395
+        if (!empty($encryptedFileKey)) {
396
+            $this->cryptMock->expects($this->never())
397
+                ->method('multiKeyDecrypt');
398
+            if ($privateKey) {
399
+                $this->cryptMock->expects($this->once())
400
+                    ->method('multiKeyDecryptLegacy')
401
+                    ->willReturn('multiKeyDecryptResult');
402
+            } else {
403
+                $this->cryptMock->expects($this->never())
404
+                    ->method('multiKeyDecryptLegacy');
405
+            }
406
+        } else {
407
+            $this->cryptMock->expects($this->never())
408
+                ->method('multiKeyDecryptLegacy');
409
+            if ($privateKey) {
410
+                $this->cryptMock->expects($this->once())
411
+                    ->method('multiKeyDecrypt')
412
+                    ->willReturn('multiKeyDecryptResult');
413
+            } else {
414
+                $this->cryptMock->expects($this->never())
415
+                    ->method('multiKeyDecrypt');
416
+            }
417
+        }
418
+
419
+        $this->assertSame($expected,
420
+            $this->instance->getFileKey($path, null)
421
+        );
422
+    }
423
+
424
+    public function testDeletePrivateKey(): void {
425
+        $this->keyStorageMock->expects($this->once())
426
+            ->method('deleteUserKey')
427
+            ->with('user1', 'privateKey')
428
+            ->willReturn(true);
429
+
430
+        $this->assertTrue(self::invokePrivate($this->instance,
431
+            'deletePrivateKey',
432
+            [$this->userId]));
433
+    }
434
+
435
+    public function testDeleteAllFileKeys(): void {
436
+        $this->keyStorageMock->expects($this->once())
437
+            ->method('deleteAllFileKeys')
438
+            ->willReturn(true);
439
+
440
+        $this->assertTrue($this->instance->deleteAllFileKeys('/'));
441
+    }
442
+
443
+    /**
444
+     * test add public share key and or recovery key to the list of public keys
445
+     *
446
+     *
447
+     * @param array $accessList
448
+     * @param array $publicKeys
449
+     * @param string $uid
450
+     * @param array $expectedKeys
451
+     */
452
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestAddSystemKeys')]
453
+    public function testAddSystemKeys($accessList, $publicKeys, $uid, $expectedKeys): void {
454
+        $publicShareKeyId = 'publicShareKey';
455
+        $recoveryKeyId = 'recoveryKey';
456
+
457
+        $this->keyStorageMock->expects($this->any())
458
+            ->method('getSystemUserKey')
459
+            ->willReturnCallback(function ($keyId, $encryptionModuleId) {
460
+                return $keyId;
461
+            });
462
+
463
+        $this->utilMock->expects($this->any())
464
+            ->method('isRecoveryEnabledForUser')
465
+            ->willReturnCallback(function ($uid) {
466
+                if ($uid === 'user1') {
467
+                    return true;
468
+                }
469
+                return false;
470
+            });
471
+
472
+        // set key IDs
473
+        self::invokePrivate($this->instance, 'publicShareKeyId', [$publicShareKeyId]);
474
+        self::invokePrivate($this->instance, 'recoveryKeyId', [$recoveryKeyId]);
475
+
476
+        $result = $this->instance->addSystemKeys($accessList, $publicKeys, $uid);
477
+
478
+        foreach ($expectedKeys as $expected) {
479
+            $this->assertArrayHasKey($expected, $result);
480
+        }
481
+
482
+        $this->assertSameSize($expectedKeys, $result);
483
+    }
484
+
485
+    /**
486
+     * data provider for testAddSystemKeys()
487
+     *
488
+     * @return array
489
+     */
490
+    public static function dataTestAddSystemKeys(): array {
491
+        return [
492
+            [['public' => true],[], 'user1', ['publicShareKey', 'recoveryKey']],
493
+            [['public' => false], [], 'user1', ['recoveryKey']],
494
+            [['public' => true],[], 'user2', ['publicShareKey']],
495
+            [['public' => false], [], 'user2', []],
496
+        ];
497
+    }
498
+
499
+    public function testGetMasterKeyId(): void {
500
+        $this->assertSame('systemKeyId', $this->instance->getMasterKeyId());
501
+    }
502
+
503
+    public function testGetPublicMasterKey(): void {
504
+        $this->keyStorageMock->expects($this->once())->method('getSystemUserKey')
505
+            ->with('systemKeyId.publicKey', Encryption::ID)
506
+            ->willReturn(true);
507
+
508
+        $this->assertTrue(
509
+            $this->instance->getPublicMasterKey()
510
+        );
511
+    }
512
+
513
+    public function testGetMasterKeyPassword(): void {
514
+        $this->configMock->expects($this->once())->method('getSystemValue')->with('secret')
515
+            ->willReturn('password');
516
+
517
+        $this->assertSame('password',
518
+            $this->invokePrivate($this->instance, 'getMasterKeyPassword', [])
519
+        );
520
+    }
521
+
522
+
523
+    public function testGetMasterKeyPasswordException(): void {
524
+        $this->expectException(\Exception::class);
525
+
526
+        $this->configMock->expects($this->once())->method('getSystemValue')->with('secret')
527
+            ->willReturn('');
528
+
529
+        $this->invokePrivate($this->instance, 'getMasterKeyPassword', []);
530
+    }
531
+
532
+    /**
533
+     * @param $masterKey
534
+     */
535
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestValidateMasterKey')]
536
+    public function testValidateMasterKey($masterKey): void {
537
+        /** @var KeyManager&MockObject $instance */
538
+        $instance = $this->getMockBuilder(KeyManager::class)
539
+            ->setConstructorArgs(
540
+                [
541
+                    $this->keyStorageMock,
542
+                    $this->cryptMock,
543
+                    $this->configMock,
544
+                    $this->userMock,
545
+                    $this->sessionMock,
546
+                    $this->logMock,
547
+                    $this->utilMock,
548
+                    $this->lockingProviderMock
549
+                ]
550
+            )->onlyMethods(['getPublicMasterKey', 'setSystemPrivateKey', 'getMasterKeyPassword'])
551
+            ->getMock();
552
+
553
+        $this->utilMock->expects($this->once())->method('isMasterKeyEnabled')
554
+            ->willReturn(true);
555
+
556
+        $instance->expects($this->once())->method('getPublicMasterKey')
557
+            ->willReturn($masterKey);
558
+
559
+        $instance->expects($this->any())->method('getMasterKeyPassword')->willReturn('masterKeyPassword');
560
+        $this->cryptMock->expects($this->any())->method('generateHeader')->willReturn('header');
561
+
562
+        if (empty($masterKey)) {
563
+            $this->cryptMock->expects($this->once())->method('createKeyPair')
564
+                ->willReturn(['publicKey' => 'public', 'privateKey' => 'private']);
565
+            $this->keyStorageMock->expects($this->once())->method('setSystemUserKey')
566
+                ->with('systemKeyId.publicKey', 'public', Encryption::ID);
567
+            $this->cryptMock->expects($this->once())->method('encryptPrivateKey')
568
+                ->with('private', 'masterKeyPassword', 'systemKeyId')
569
+                ->willReturn('EncryptedKey');
570
+            $this->lockingProviderMock->expects($this->once())
571
+                ->method('acquireLock');
572
+            $instance->expects($this->once())->method('setSystemPrivateKey')
573
+                ->with('systemKeyId', 'headerEncryptedKey');
574
+        } else {
575
+            $this->cryptMock->expects($this->never())->method('createKeyPair');
576
+            $this->keyStorageMock->expects($this->never())->method('setSystemUserKey');
577
+            $this->cryptMock->expects($this->never())->method('encryptPrivateKey');
578
+            $instance->expects($this->never())->method('setSystemPrivateKey');
579
+        }
580
+
581
+        $instance->validateMasterKey();
582
+    }
583
+
584
+    public function testValidateMasterKeyLocked(): void {
585
+        /** @var KeyManager&MockObject $instance */
586
+        $instance = $this->getMockBuilder(KeyManager::class)
587
+            ->setConstructorArgs([
588
+                $this->keyStorageMock,
589
+                $this->cryptMock,
590
+                $this->configMock,
591
+                $this->userMock,
592
+                $this->sessionMock,
593
+                $this->logMock,
594
+                $this->utilMock,
595
+                $this->lockingProviderMock
596
+            ])
597
+            ->onlyMethods(['getPublicMasterKey', 'getPrivateMasterKey', 'setSystemPrivateKey', 'getMasterKeyPassword'])
598
+            ->getMock();
599
+
600
+        $this->utilMock->expects($this->once())->method('isMasterKeyEnabled')
601
+            ->willReturn(true);
602
+
603
+        $instance->expects($this->once())->method('getPublicMasterKey')
604
+            ->willReturn('');
605
+        $instance->expects($this->once())->method('getPrivateMasterKey')
606
+            ->willReturn('');
607
+
608
+        $instance->expects($this->any())->method('getMasterKeyPassword')->willReturn('masterKeyPassword');
609
+        $this->cryptMock->expects($this->any())->method('generateHeader')->willReturn('header');
610
+
611
+        $this->lockingProviderMock->expects($this->once())
612
+            ->method('acquireLock')
613
+            ->willThrowException(new LockedException('encryption-generateMasterKey'));
614
+
615
+        $this->expectException(LockedException::class);
616
+        $instance->validateMasterKey();
617
+    }
618
+
619
+    public static function dataTestValidateMasterKey(): array {
620
+        return [
621
+            ['masterKey'],
622
+            ['']
623
+        ];
624
+    }
625
+
626
+    public function testGetVersionWithoutFileInfo(): void {
627
+        $view = $this->getMockBuilder(View::class)
628
+            ->disableOriginalConstructor()->getMock();
629
+        $view->expects($this->once())
630
+            ->method('getFileInfo')
631
+            ->with('/admin/files/myfile.txt')
632
+            ->willReturn(false);
633
+
634
+        /** @var View $view */
635
+        $this->assertSame(0, $this->instance->getVersion('/admin/files/myfile.txt', $view));
636
+    }
637
+
638
+    public function testGetVersionWithFileInfo(): void {
639
+        $view = $this->getMockBuilder(View::class)
640
+            ->disableOriginalConstructor()->getMock();
641
+        $fileInfo = $this->getMockBuilder(FileInfo::class)
642
+            ->disableOriginalConstructor()->getMock();
643
+        $fileInfo->expects($this->once())
644
+            ->method('getEncryptedVersion')
645
+            ->willReturn(1337);
646
+        $view->expects($this->once())
647
+            ->method('getFileInfo')
648
+            ->with('/admin/files/myfile.txt')
649
+            ->willReturn($fileInfo);
650
+
651
+        /** @var View $view */
652
+        $this->assertSame(1337, $this->instance->getVersion('/admin/files/myfile.txt', $view));
653
+    }
654
+
655
+    public function testSetVersionWithFileInfo(): void {
656
+        $view = $this->getMockBuilder(View::class)
657
+            ->disableOriginalConstructor()->getMock();
658
+        $cache = $this->getMockBuilder(ICache::class)
659
+            ->disableOriginalConstructor()->getMock();
660
+        $cache->expects($this->once())
661
+            ->method('update')
662
+            ->with(123, ['encrypted' => 5, 'encryptedVersion' => 5]);
663
+        $storage = $this->getMockBuilder(FilesIStorage::class)
664
+            ->disableOriginalConstructor()->getMock();
665
+        $storage->expects($this->once())
666
+            ->method('getCache')
667
+            ->willReturn($cache);
668
+        $fileInfo = $this->getMockBuilder(FileInfo::class)
669
+            ->disableOriginalConstructor()->getMock();
670
+        $fileInfo->expects($this->once())
671
+            ->method('getStorage')
672
+            ->willReturn($storage);
673
+        $fileInfo->expects($this->once())
674
+            ->method('getId')
675
+            ->willReturn(123);
676
+        $view->expects($this->once())
677
+            ->method('getFileInfo')
678
+            ->with('/admin/files/myfile.txt')
679
+            ->willReturn($fileInfo);
680
+
681
+        /** @var View $view */
682
+        $this->instance->setVersion('/admin/files/myfile.txt', 5, $view);
683
+    }
684
+
685
+    public function testSetVersionWithoutFileInfo(): void {
686
+        $view = $this->getMockBuilder(View::class)
687
+            ->disableOriginalConstructor()->getMock();
688
+        $view->expects($this->once())
689
+            ->method('getFileInfo')
690
+            ->with('/admin/files/myfile.txt')
691
+            ->willReturn(false);
692
+
693
+        /** @var View $view */
694
+        $this->instance->setVersion('/admin/files/myfile.txt', 5, $view);
695
+    }
696
+
697
+    public function testBackupUserKeys(): void {
698
+        $this->keyStorageMock->expects($this->once())->method('backupUserKeys')
699
+            ->with('OC_DEFAULT_MODULE', 'test', 'user1');
700
+        $this->instance->backupUserKeys('test', 'user1');
701
+    }
702 702
 }
Please login to merge, or discard this patch.
tests/lib/Traits/EncryptionTrait.php 1 patch
Indentation   +96 added lines, -96 removed lines patch added patch discarded remove patch
@@ -27,100 +27,100 @@
 block discarded – undo
27 27
  * Enables encryption
28 28
  */
29 29
 trait EncryptionTrait {
30
-	// from MountProviderTrait
31
-	abstract protected function registerStorageWrapper($name, $wrapper);
32
-
33
-	// from phpunit
34
-	abstract protected static function markTestSkipped(string $message = ''): void;
35
-	abstract protected static function assertTrue($condition, string $message = ''): void;
36
-
37
-	private $encryptionWasEnabled;
38
-
39
-	private $originalEncryptionModule;
40
-
41
-	/** @var IUserManager */
42
-	private $userManager;
43
-	/** @var SetupManager */
44
-	private $setupManager;
45
-
46
-	/**
47
-	 * @var IConfig
48
-	 */
49
-	private $config;
50
-
51
-	/**
52
-	 * @var Application
53
-	 */
54
-	private $encryptionApp;
55
-
56
-	protected function loginWithEncryption($user = '') {
57
-		\OC_Util::tearDownFS();
58
-		\OC_User::setUserId('');
59
-		// needed for fully logout
60
-		Server::get(IUserSession::class)->setUser(null);
61
-
62
-		$this->setupManager->tearDown();
63
-
64
-		\OC_User::setUserId($user);
65
-		$this->postLogin();
66
-		\OC_Util::setupFS($user);
67
-		if ($this->userManager->userExists($user)) {
68
-			\OC::$server->getUserFolder($user);
69
-		}
70
-	}
71
-
72
-	protected function setupForUser($name, $password) {
73
-		$this->setupManager->tearDown();
74
-		$this->setupManager->setupForUser($this->userManager->get($name));
75
-
76
-		$container = $this->encryptionApp->getContainer();
77
-		/** @var KeyManager $keyManager */
78
-		$keyManager = $container->query(KeyManager::class);
79
-		/** @var Setup $userSetup */
80
-		$userSetup = $container->query(Setup::class);
81
-		$userSetup->setupUser($name, $password);
82
-		$encryptionManager = $container->query(IManager::class);
83
-		$this->encryptionApp->setUp($encryptionManager);
84
-		$keyManager->init($name, $password);
85
-		$this->invokePrivate($keyManager, 'keyUid', [$name]);
86
-	}
87
-
88
-	protected function postLogin() {
89
-		$encryptionWrapper = new EncryptionWrapper(
90
-			new ArrayCache(),
91
-			Server::get(\OCP\Encryption\IManager::class),
92
-			Server::get(LoggerInterface::class)
93
-		);
94
-
95
-		$this->registerStorageWrapper('oc_encryption', [$encryptionWrapper, 'wrapStorage']);
96
-	}
97
-
98
-	protected function setUpEncryptionTrait() {
99
-		$isReady = Server::get(\OCP\Encryption\IManager::class)->isReady();
100
-		if (!$isReady) {
101
-			$this->markTestSkipped('Encryption not ready');
102
-		}
103
-
104
-		$this->userManager = Server::get(IUserManager::class);
105
-		$this->setupManager = Server::get(SetupManager::class);
106
-
107
-		Server::get(IAppManager::class)->loadApp('encryption');
108
-
109
-		$this->encryptionApp = new Application([], $isReady);
110
-
111
-		$this->config = Server::get(IConfig::class);
112
-		$this->encryptionWasEnabled = $this->config->getAppValue('core', 'encryption_enabled', 'no');
113
-		$this->originalEncryptionModule = $this->config->getAppValue('core', 'default_encryption_module');
114
-		$this->config->setAppValue('core', 'default_encryption_module', Encryption::ID);
115
-		$this->config->setAppValue('core', 'encryption_enabled', 'yes');
116
-		$this->assertTrue(Server::get(\OCP\Encryption\IManager::class)->isEnabled());
117
-	}
118
-
119
-	protected function tearDownEncryptionTrait() {
120
-		if ($this->config) {
121
-			$this->config->setAppValue('core', 'encryption_enabled', $this->encryptionWasEnabled);
122
-			$this->config->setAppValue('core', 'default_encryption_module', $this->originalEncryptionModule);
123
-			$this->config->deleteAppValue('encryption', 'useMasterKey');
124
-		}
125
-	}
30
+    // from MountProviderTrait
31
+    abstract protected function registerStorageWrapper($name, $wrapper);
32
+
33
+    // from phpunit
34
+    abstract protected static function markTestSkipped(string $message = ''): void;
35
+    abstract protected static function assertTrue($condition, string $message = ''): void;
36
+
37
+    private $encryptionWasEnabled;
38
+
39
+    private $originalEncryptionModule;
40
+
41
+    /** @var IUserManager */
42
+    private $userManager;
43
+    /** @var SetupManager */
44
+    private $setupManager;
45
+
46
+    /**
47
+     * @var IConfig
48
+     */
49
+    private $config;
50
+
51
+    /**
52
+     * @var Application
53
+     */
54
+    private $encryptionApp;
55
+
56
+    protected function loginWithEncryption($user = '') {
57
+        \OC_Util::tearDownFS();
58
+        \OC_User::setUserId('');
59
+        // needed for fully logout
60
+        Server::get(IUserSession::class)->setUser(null);
61
+
62
+        $this->setupManager->tearDown();
63
+
64
+        \OC_User::setUserId($user);
65
+        $this->postLogin();
66
+        \OC_Util::setupFS($user);
67
+        if ($this->userManager->userExists($user)) {
68
+            \OC::$server->getUserFolder($user);
69
+        }
70
+    }
71
+
72
+    protected function setupForUser($name, $password) {
73
+        $this->setupManager->tearDown();
74
+        $this->setupManager->setupForUser($this->userManager->get($name));
75
+
76
+        $container = $this->encryptionApp->getContainer();
77
+        /** @var KeyManager $keyManager */
78
+        $keyManager = $container->query(KeyManager::class);
79
+        /** @var Setup $userSetup */
80
+        $userSetup = $container->query(Setup::class);
81
+        $userSetup->setupUser($name, $password);
82
+        $encryptionManager = $container->query(IManager::class);
83
+        $this->encryptionApp->setUp($encryptionManager);
84
+        $keyManager->init($name, $password);
85
+        $this->invokePrivate($keyManager, 'keyUid', [$name]);
86
+    }
87
+
88
+    protected function postLogin() {
89
+        $encryptionWrapper = new EncryptionWrapper(
90
+            new ArrayCache(),
91
+            Server::get(\OCP\Encryption\IManager::class),
92
+            Server::get(LoggerInterface::class)
93
+        );
94
+
95
+        $this->registerStorageWrapper('oc_encryption', [$encryptionWrapper, 'wrapStorage']);
96
+    }
97
+
98
+    protected function setUpEncryptionTrait() {
99
+        $isReady = Server::get(\OCP\Encryption\IManager::class)->isReady();
100
+        if (!$isReady) {
101
+            $this->markTestSkipped('Encryption not ready');
102
+        }
103
+
104
+        $this->userManager = Server::get(IUserManager::class);
105
+        $this->setupManager = Server::get(SetupManager::class);
106
+
107
+        Server::get(IAppManager::class)->loadApp('encryption');
108
+
109
+        $this->encryptionApp = new Application([], $isReady);
110
+
111
+        $this->config = Server::get(IConfig::class);
112
+        $this->encryptionWasEnabled = $this->config->getAppValue('core', 'encryption_enabled', 'no');
113
+        $this->originalEncryptionModule = $this->config->getAppValue('core', 'default_encryption_module');
114
+        $this->config->setAppValue('core', 'default_encryption_module', Encryption::ID);
115
+        $this->config->setAppValue('core', 'encryption_enabled', 'yes');
116
+        $this->assertTrue(Server::get(\OCP\Encryption\IManager::class)->isEnabled());
117
+    }
118
+
119
+    protected function tearDownEncryptionTrait() {
120
+        if ($this->config) {
121
+            $this->config->setAppValue('core', 'encryption_enabled', $this->encryptionWasEnabled);
122
+            $this->config->setAppValue('core', 'default_encryption_module', $this->originalEncryptionModule);
123
+            $this->config->deleteAppValue('encryption', 'useMasterKey');
124
+        }
125
+    }
126 126
 }
Please login to merge, or discard this patch.