Completed
Pull Request — master (#5623)
by Thomas
16:49
created
lib/public/Encryption/IEncryptionModule.php 1 patch
Indentation   +156 added lines, -156 removed lines patch added patch discarded remove patch
@@ -35,161 +35,161 @@
 block discarded – undo
35 35
  */
36 36
 interface IEncryptionModule {
37 37
 
38
-	/**
39
-	 * @return string defining the technical unique id
40
-	 * @since 8.1.0
41
-	 */
42
-	public function getId();
43
-
44
-	/**
45
-	 * In comparison to getKey() this function returns a human readable (maybe translated) name
46
-	 *
47
-	 * @return string
48
-	 * @since 8.1.0
49
-	 */
50
-	public function getDisplayName();
51
-
52
-	/**
53
-	 * start receiving chunks from a file. This is the place where you can
54
-	 * perform some initial step before starting encrypting/decrypting the
55
-	 * chunks
56
-	 *
57
-	 * @param string $path to the file
58
-	 * @param string $user who read/write the file (null for public access)
59
-	 * @param string $mode php stream open mode
60
-	 * @param array $header contains the header data read from the file
61
-	 * @param array $accessList who has access to the file contains the key 'users' and 'public'
62
-	 *
63
-	 * $return array $header contain data as key-value pairs which should be
64
-	 *                       written to the header, in case of a write operation
65
-	 *                       or if no additional data is needed return a empty array
66
-	 * @since 8.1.0
67
-	 */
68
-	public function begin($path, $user, $mode, array $header, array $accessList);
69
-
70
-	/**
71
-	 * last chunk received. This is the place where you can perform some final
72
-	 * operation and return some remaining data if something is left in your
73
-	 * buffer.
74
-	 *
75
-	 * @param string $path to the file
76
-	 * @param string $position id of the last block (looks like "<Number>end")
77
-	 *
78
-	 * @return string remained data which should be written to the file in case
79
-	 *                of a write operation
80
-	 *
81
-	 * @since 8.1.0
82
-	 * @since 9.0.0 parameter $position added
83
-	 */
84
-	public function end($path, $position);
85
-
86
-	/**
87
-	 * encrypt data
88
-	 *
89
-	 * @param string $data you want to encrypt
90
-	 * @param string $position position of the block we want to encrypt (starts with '0')
91
-	 *
92
-	 * @return mixed encrypted data
93
-	 *
94
-	 * @since 8.1.0
95
-	 * @since 9.0.0 parameter $position added
96
-	 */
97
-	public function encrypt($data, $position);
98
-
99
-	/**
100
-	 * decrypt data
101
-	 *
102
-	 * @param string $data you want to decrypt
103
-	 * @param string $position position of the block we want to decrypt
104
-	 *
105
-	 * @return mixed decrypted data
106
-	 *
107
-	 * @since 8.1.0
108
-	 * @since 9.0.0 parameter $position added
109
-	 */
110
-	public function decrypt($data, $position);
111
-
112
-	/**
113
-	 * update encrypted file, e.g. give additional users access to the file
114
-	 *
115
-	 * @param string $path path to the file which should be updated
116
-	 * @param string $uid of the user who performs the operation
117
-	 * @param array $accessList who has access to the file contains the key 'users' and 'public'
118
-	 * @return boolean
119
-	 * @since 8.1.0
120
-	 */
121
-	public function update($path, $uid, array $accessList);
122
-
123
-	/**
124
-	 * should the file be encrypted or not
125
-	 *
126
-	 * @param string $path
127
-	 * @return boolean
128
-	 * @since 8.1.0
129
-	 */
130
-	public function shouldEncrypt($path);
131
-
132
-	/**
133
-	 * get size of the unencrypted payload per block.
134
-	 * ownCloud read/write files with a block size of 8192 byte
135
-	 *
136
-	 * @param bool $signed
137
-	 * @return int
138
-	 * @since 8.1.0 optional parameter $signed was added in 9.0.0
139
-	 */
140
-	public function getUnencryptedBlockSize($signed = false);
141
-
142
-	/**
143
-	 * check if the encryption module is able to read the file,
144
-	 * e.g. if all encryption keys exists
145
-	 *
146
-	 * @param string $path
147
-	 * @param string $uid user for whom we want to check if he can read the file
148
-	 * @return boolean
149
-	 * @since 8.1.0
150
-	 */
151
-	public function isReadable($path, $uid);
152
-
153
-	/**
154
-	 * Initial encryption of all files
155
-	 *
156
-	 * @param InputInterface $input
157
-	 * @param OutputInterface $output write some status information to the terminal during encryption
158
-	 * @since 8.2.0
159
-	 */
160
-	public function encryptAll(InputInterface $input, OutputInterface $output);
161
-
162
-	/**
163
-	 * prepare encryption module to decrypt all files
164
-	 *
165
-	 * @param InputInterface $input
166
-	 * @param OutputInterface $output write some status information to the terminal during encryption
167
-	 * @param $user (optional) for which the files should be decrypted, default = all users
168
-	 * @return bool return false on failure or if it isn't supported by the module
169
-	 * @since 8.2.0
170
-	 */
171
-	public function prepareDecryptAll(InputInterface $input, OutputInterface $output, $user = '');
172
-
173
-	/**
174
-	 * Check if the module is ready to be used by that specific user.
175
-	 * In case a module is not ready - because e.g. key pairs have not been generated
176
-	 * upon login this method can return false before any operation starts and might
177
-	 * cause issues during operations.
178
-	 *
179
-	 * @param string $user
180
-	 * @return boolean
181
-	 * @since 9.1.0
182
-	 */
183
-	public function isReadyForUser($user);
184
-
185
-	/**
186
-	 * Does the encryption module needs a detailed list of users with access to the file?
187
-	 * For example if the encryption module uses per-user encryption keys and needs to know
188
-	 * the users with access to the file to encrypt/decrypt it.
189
-	 *
190
-	 * @since 13.0.0
191
-	 * @return bool
192
-	 */
193
-	public function needDetailedAccessList();
38
+    /**
39
+     * @return string defining the technical unique id
40
+     * @since 8.1.0
41
+     */
42
+    public function getId();
43
+
44
+    /**
45
+     * In comparison to getKey() this function returns a human readable (maybe translated) name
46
+     *
47
+     * @return string
48
+     * @since 8.1.0
49
+     */
50
+    public function getDisplayName();
51
+
52
+    /**
53
+     * start receiving chunks from a file. This is the place where you can
54
+     * perform some initial step before starting encrypting/decrypting the
55
+     * chunks
56
+     *
57
+     * @param string $path to the file
58
+     * @param string $user who read/write the file (null for public access)
59
+     * @param string $mode php stream open mode
60
+     * @param array $header contains the header data read from the file
61
+     * @param array $accessList who has access to the file contains the key 'users' and 'public'
62
+     *
63
+     * $return array $header contain data as key-value pairs which should be
64
+     *                       written to the header, in case of a write operation
65
+     *                       or if no additional data is needed return a empty array
66
+     * @since 8.1.0
67
+     */
68
+    public function begin($path, $user, $mode, array $header, array $accessList);
69
+
70
+    /**
71
+     * last chunk received. This is the place where you can perform some final
72
+     * operation and return some remaining data if something is left in your
73
+     * buffer.
74
+     *
75
+     * @param string $path to the file
76
+     * @param string $position id of the last block (looks like "<Number>end")
77
+     *
78
+     * @return string remained data which should be written to the file in case
79
+     *                of a write operation
80
+     *
81
+     * @since 8.1.0
82
+     * @since 9.0.0 parameter $position added
83
+     */
84
+    public function end($path, $position);
85
+
86
+    /**
87
+     * encrypt data
88
+     *
89
+     * @param string $data you want to encrypt
90
+     * @param string $position position of the block we want to encrypt (starts with '0')
91
+     *
92
+     * @return mixed encrypted data
93
+     *
94
+     * @since 8.1.0
95
+     * @since 9.0.0 parameter $position added
96
+     */
97
+    public function encrypt($data, $position);
98
+
99
+    /**
100
+     * decrypt data
101
+     *
102
+     * @param string $data you want to decrypt
103
+     * @param string $position position of the block we want to decrypt
104
+     *
105
+     * @return mixed decrypted data
106
+     *
107
+     * @since 8.1.0
108
+     * @since 9.0.0 parameter $position added
109
+     */
110
+    public function decrypt($data, $position);
111
+
112
+    /**
113
+     * update encrypted file, e.g. give additional users access to the file
114
+     *
115
+     * @param string $path path to the file which should be updated
116
+     * @param string $uid of the user who performs the operation
117
+     * @param array $accessList who has access to the file contains the key 'users' and 'public'
118
+     * @return boolean
119
+     * @since 8.1.0
120
+     */
121
+    public function update($path, $uid, array $accessList);
122
+
123
+    /**
124
+     * should the file be encrypted or not
125
+     *
126
+     * @param string $path
127
+     * @return boolean
128
+     * @since 8.1.0
129
+     */
130
+    public function shouldEncrypt($path);
131
+
132
+    /**
133
+     * get size of the unencrypted payload per block.
134
+     * ownCloud read/write files with a block size of 8192 byte
135
+     *
136
+     * @param bool $signed
137
+     * @return int
138
+     * @since 8.1.0 optional parameter $signed was added in 9.0.0
139
+     */
140
+    public function getUnencryptedBlockSize($signed = false);
141
+
142
+    /**
143
+     * check if the encryption module is able to read the file,
144
+     * e.g. if all encryption keys exists
145
+     *
146
+     * @param string $path
147
+     * @param string $uid user for whom we want to check if he can read the file
148
+     * @return boolean
149
+     * @since 8.1.0
150
+     */
151
+    public function isReadable($path, $uid);
152
+
153
+    /**
154
+     * Initial encryption of all files
155
+     *
156
+     * @param InputInterface $input
157
+     * @param OutputInterface $output write some status information to the terminal during encryption
158
+     * @since 8.2.0
159
+     */
160
+    public function encryptAll(InputInterface $input, OutputInterface $output);
161
+
162
+    /**
163
+     * prepare encryption module to decrypt all files
164
+     *
165
+     * @param InputInterface $input
166
+     * @param OutputInterface $output write some status information to the terminal during encryption
167
+     * @param $user (optional) for which the files should be decrypted, default = all users
168
+     * @return bool return false on failure or if it isn't supported by the module
169
+     * @since 8.2.0
170
+     */
171
+    public function prepareDecryptAll(InputInterface $input, OutputInterface $output, $user = '');
172
+
173
+    /**
174
+     * Check if the module is ready to be used by that specific user.
175
+     * In case a module is not ready - because e.g. key pairs have not been generated
176
+     * upon login this method can return false before any operation starts and might
177
+     * cause issues during operations.
178
+     *
179
+     * @param string $user
180
+     * @return boolean
181
+     * @since 9.1.0
182
+     */
183
+    public function isReadyForUser($user);
184
+
185
+    /**
186
+     * Does the encryption module needs a detailed list of users with access to the file?
187
+     * For example if the encryption module uses per-user encryption keys and needs to know
188
+     * the users with access to the file to encrypt/decrypt it.
189
+     *
190
+     * @since 13.0.0
191
+     * @return bool
192
+     */
193
+    public function needDetailedAccessList();
194 194
 
195 195
 }
Please login to merge, or discard this patch.
lib/private/Encryption/Update.php 1 patch
Indentation   +157 added lines, -157 removed lines patch added patch discarded remove patch
@@ -33,162 +33,162 @@
 block discarded – undo
33 33
  */
34 34
 class Update {
35 35
 
36
-	/** @var \OC\Files\View */
37
-	protected $view;
38
-
39
-	/** @var \OC\Encryption\Util */
40
-	protected $util;
41
-
42
-	 /** @var \OC\Files\Mount\Manager */
43
-	protected $mountManager;
44
-
45
-	/** @var \OC\Encryption\Manager */
46
-	protected $encryptionManager;
47
-
48
-	/** @var string */
49
-	protected $uid;
50
-
51
-	/** @var \OC\Encryption\File */
52
-	protected $file;
53
-
54
-	/**
55
-	 *
56
-	 * @param \OC\Files\View $view
57
-	 * @param \OC\Encryption\Util $util
58
-	 * @param \OC\Files\Mount\Manager $mountManager
59
-	 * @param \OC\Encryption\Manager $encryptionManager
60
-	 * @param \OC\Encryption\File $file
61
-	 * @param string $uid
62
-	 */
63
-	public function __construct(
64
-			View $view,
65
-			Util $util,
66
-			Mount\Manager $mountManager,
67
-			Manager $encryptionManager,
68
-			File $file,
69
-			$uid
70
-		) {
71
-
72
-		$this->view = $view;
73
-		$this->util = $util;
74
-		$this->mountManager = $mountManager;
75
-		$this->encryptionManager = $encryptionManager;
76
-		$this->file = $file;
77
-		$this->uid = $uid;
78
-	}
79
-
80
-	/**
81
-	 * hook after file was shared
82
-	 *
83
-	 * @param array $params
84
-	 */
85
-	public function postShared($params) {
86
-		if ($this->encryptionManager->isEnabled()) {
87
-			if ($params['itemType'] === 'file' || $params['itemType'] === 'folder') {
88
-				$path = Filesystem::getPath($params['fileSource']);
89
-				list($owner, $ownerPath) = $this->getOwnerPath($path);
90
-				$absPath = '/' . $owner . '/files/' . $ownerPath;
91
-				$this->update($absPath);
92
-			}
93
-		}
94
-	}
95
-
96
-	/**
97
-	 * hook after file was unshared
98
-	 *
99
-	 * @param array $params
100
-	 */
101
-	public function postUnshared($params) {
102
-		if ($this->encryptionManager->isEnabled()) {
103
-			if ($params['itemType'] === 'file' || $params['itemType'] === 'folder') {
104
-				$path = Filesystem::getPath($params['fileSource']);
105
-				list($owner, $ownerPath) = $this->getOwnerPath($path);
106
-				$absPath = '/' . $owner . '/files/' . $ownerPath;
107
-				$this->update($absPath);
108
-			}
109
-		}
110
-	}
111
-
112
-	/**
113
-	 * inform encryption module that a file was restored from the trash bin,
114
-	 * e.g. to update the encryption keys
115
-	 *
116
-	 * @param array $params
117
-	 */
118
-	public function postRestore($params) {
119
-		if ($this->encryptionManager->isEnabled()) {
120
-			$path = Filesystem::normalizePath('/' . $this->uid . '/files/' . $params['filePath']);
121
-			$this->update($path);
122
-		}
123
-	}
124
-
125
-	/**
126
-	 * inform encryption module that a file was renamed,
127
-	 * e.g. to update the encryption keys
128
-	 *
129
-	 * @param array $params
130
-	 */
131
-	public function postRename($params) {
132
-		$source = $params['oldpath'];
133
-		$target = $params['newpath'];
134
-		if(
135
-			$this->encryptionManager->isEnabled() &&
136
-			dirname($source) !== dirname($target)
137
-		) {
138
-				list($owner, $ownerPath) = $this->getOwnerPath($target);
139
-				$absPath = '/' . $owner . '/files/' . $ownerPath;
140
-				$this->update($absPath);
141
-		}
142
-	}
143
-
144
-	/**
145
-	 * get owner and path relative to data/<owner>/files
146
-	 *
147
-	 * @param string $path path to file for current user
148
-	 * @return array ['owner' => $owner, 'path' => $path]
149
-	 * @throw \InvalidArgumentException
150
-	 */
151
-	protected function getOwnerPath($path) {
152
-		$info = Filesystem::getFileInfo($path);
153
-		$owner = Filesystem::getOwner($path);
154
-		$view = new View('/' . $owner . '/files');
155
-		$path = $view->getPath($info->getId());
156
-		if ($path === null) {
157
-			throw new \InvalidArgumentException('No file found for ' . $info->getId());
158
-		}
159
-
160
-		return array($owner, $path);
161
-	}
162
-
163
-	/**
164
-	 * notify encryption module about added/removed users from a file/folder
165
-	 *
166
-	 * @param string $path relative to data/
167
-	 * @throws Exceptions\ModuleDoesNotExistsException
168
-	 */
169
-	public function update($path) {
170
-
171
-		$encryptionModule = $this->encryptionManager->getEncryptionModule();
172
-
173
-		// if the encryption module doesn't encrypt the files on a per-user basis
174
-		// we have nothing to do here.
175
-		if ($encryptionModule->needDetailedAccessList() === false) {
176
-			return;
177
-		}
178
-
179
-		// if a folder was shared, get a list of all (sub-)folders
180
-		if ($this->view->is_dir($path)) {
181
-			$allFiles = $this->util->getAllFiles($path);
182
-		} else {
183
-			$allFiles = array($path);
184
-		}
185
-
186
-
187
-
188
-		foreach ($allFiles as $file) {
189
-			$usersSharing = $this->file->getAccessList($file);
190
-			$encryptionModule->update($file, $this->uid, $usersSharing);
191
-		}
192
-	}
36
+    /** @var \OC\Files\View */
37
+    protected $view;
38
+
39
+    /** @var \OC\Encryption\Util */
40
+    protected $util;
41
+
42
+        /** @var \OC\Files\Mount\Manager */
43
+    protected $mountManager;
44
+
45
+    /** @var \OC\Encryption\Manager */
46
+    protected $encryptionManager;
47
+
48
+    /** @var string */
49
+    protected $uid;
50
+
51
+    /** @var \OC\Encryption\File */
52
+    protected $file;
53
+
54
+    /**
55
+     *
56
+     * @param \OC\Files\View $view
57
+     * @param \OC\Encryption\Util $util
58
+     * @param \OC\Files\Mount\Manager $mountManager
59
+     * @param \OC\Encryption\Manager $encryptionManager
60
+     * @param \OC\Encryption\File $file
61
+     * @param string $uid
62
+     */
63
+    public function __construct(
64
+            View $view,
65
+            Util $util,
66
+            Mount\Manager $mountManager,
67
+            Manager $encryptionManager,
68
+            File $file,
69
+            $uid
70
+        ) {
71
+
72
+        $this->view = $view;
73
+        $this->util = $util;
74
+        $this->mountManager = $mountManager;
75
+        $this->encryptionManager = $encryptionManager;
76
+        $this->file = $file;
77
+        $this->uid = $uid;
78
+    }
79
+
80
+    /**
81
+     * hook after file was shared
82
+     *
83
+     * @param array $params
84
+     */
85
+    public function postShared($params) {
86
+        if ($this->encryptionManager->isEnabled()) {
87
+            if ($params['itemType'] === 'file' || $params['itemType'] === 'folder') {
88
+                $path = Filesystem::getPath($params['fileSource']);
89
+                list($owner, $ownerPath) = $this->getOwnerPath($path);
90
+                $absPath = '/' . $owner . '/files/' . $ownerPath;
91
+                $this->update($absPath);
92
+            }
93
+        }
94
+    }
95
+
96
+    /**
97
+     * hook after file was unshared
98
+     *
99
+     * @param array $params
100
+     */
101
+    public function postUnshared($params) {
102
+        if ($this->encryptionManager->isEnabled()) {
103
+            if ($params['itemType'] === 'file' || $params['itemType'] === 'folder') {
104
+                $path = Filesystem::getPath($params['fileSource']);
105
+                list($owner, $ownerPath) = $this->getOwnerPath($path);
106
+                $absPath = '/' . $owner . '/files/' . $ownerPath;
107
+                $this->update($absPath);
108
+            }
109
+        }
110
+    }
111
+
112
+    /**
113
+     * inform encryption module that a file was restored from the trash bin,
114
+     * e.g. to update the encryption keys
115
+     *
116
+     * @param array $params
117
+     */
118
+    public function postRestore($params) {
119
+        if ($this->encryptionManager->isEnabled()) {
120
+            $path = Filesystem::normalizePath('/' . $this->uid . '/files/' . $params['filePath']);
121
+            $this->update($path);
122
+        }
123
+    }
124
+
125
+    /**
126
+     * inform encryption module that a file was renamed,
127
+     * e.g. to update the encryption keys
128
+     *
129
+     * @param array $params
130
+     */
131
+    public function postRename($params) {
132
+        $source = $params['oldpath'];
133
+        $target = $params['newpath'];
134
+        if(
135
+            $this->encryptionManager->isEnabled() &&
136
+            dirname($source) !== dirname($target)
137
+        ) {
138
+                list($owner, $ownerPath) = $this->getOwnerPath($target);
139
+                $absPath = '/' . $owner . '/files/' . $ownerPath;
140
+                $this->update($absPath);
141
+        }
142
+    }
143
+
144
+    /**
145
+     * get owner and path relative to data/<owner>/files
146
+     *
147
+     * @param string $path path to file for current user
148
+     * @return array ['owner' => $owner, 'path' => $path]
149
+     * @throw \InvalidArgumentException
150
+     */
151
+    protected function getOwnerPath($path) {
152
+        $info = Filesystem::getFileInfo($path);
153
+        $owner = Filesystem::getOwner($path);
154
+        $view = new View('/' . $owner . '/files');
155
+        $path = $view->getPath($info->getId());
156
+        if ($path === null) {
157
+            throw new \InvalidArgumentException('No file found for ' . $info->getId());
158
+        }
159
+
160
+        return array($owner, $path);
161
+    }
162
+
163
+    /**
164
+     * notify encryption module about added/removed users from a file/folder
165
+     *
166
+     * @param string $path relative to data/
167
+     * @throws Exceptions\ModuleDoesNotExistsException
168
+     */
169
+    public function update($path) {
170
+
171
+        $encryptionModule = $this->encryptionManager->getEncryptionModule();
172
+
173
+        // if the encryption module doesn't encrypt the files on a per-user basis
174
+        // we have nothing to do here.
175
+        if ($encryptionModule->needDetailedAccessList() === false) {
176
+            return;
177
+        }
178
+
179
+        // if a folder was shared, get a list of all (sub-)folders
180
+        if ($this->view->is_dir($path)) {
181
+            $allFiles = $this->util->getAllFiles($path);
182
+        } else {
183
+            $allFiles = array($path);
184
+        }
185
+
186
+
187
+
188
+        foreach ($allFiles as $file) {
189
+            $usersSharing = $this->file->getAccessList($file);
190
+            $encryptionModule->update($file, $this->uid, $usersSharing);
191
+        }
192
+    }
193 193
 
194 194
 }
Please login to merge, or discard this patch.
lib/private/Files/Stream/Encryption.php 1 patch
Indentation   +468 added lines, -468 removed lines patch added patch discarded remove patch
@@ -32,473 +32,473 @@
 block discarded – undo
32 32
 
33 33
 class Encryption extends Wrapper {
34 34
 
35
-	/** @var \OC\Encryption\Util */
36
-	protected $util;
37
-
38
-	/** @var \OC\Encryption\File */
39
-	protected $file;
40
-
41
-	/** @var \OCP\Encryption\IEncryptionModule */
42
-	protected $encryptionModule;
43
-
44
-	/** @var \OC\Files\Storage\Storage */
45
-	protected $storage;
46
-
47
-	/** @var \OC\Files\Storage\Wrapper\Encryption */
48
-	protected $encryptionStorage;
49
-
50
-	/** @var string */
51
-	protected $internalPath;
52
-
53
-	/** @var string */
54
-	protected $cache;
55
-
56
-	/** @var integer */
57
-	protected $size;
58
-
59
-	/** @var integer */
60
-	protected $position;
61
-
62
-	/** @var integer */
63
-	protected $unencryptedSize;
64
-
65
-	/** @var integer */
66
-	protected $headerSize;
67
-
68
-	/** @var integer */
69
-	protected $unencryptedBlockSize;
70
-
71
-	/** @var array */
72
-	protected $header;
73
-
74
-	/** @var string */
75
-	protected $fullPath;
76
-
77
-	/** @var  bool */
78
-	protected $signed;
79
-
80
-	/**
81
-	 * header data returned by the encryption module, will be written to the file
82
-	 * in case of a write operation
83
-	 *
84
-	 * @var array
85
-	 */
86
-	protected $newHeader;
87
-
88
-	/**
89
-	 * user who perform the read/write operation null for public access
90
-	 *
91
-	 * @var string
92
-	 */
93
-	protected $uid;
94
-
95
-	/** @var bool */
96
-	protected $readOnly;
97
-
98
-	/** @var bool */
99
-	protected $writeFlag;
100
-
101
-	/** @var array */
102
-	protected $expectedContextProperties;
103
-
104
-	public function __construct() {
105
-		$this->expectedContextProperties = array(
106
-			'source',
107
-			'storage',
108
-			'internalPath',
109
-			'fullPath',
110
-			'encryptionModule',
111
-			'header',
112
-			'uid',
113
-			'file',
114
-			'util',
115
-			'size',
116
-			'unencryptedSize',
117
-			'encryptionStorage',
118
-			'headerSize',
119
-			'signed'
120
-		);
121
-	}
122
-
123
-
124
-	/**
125
-	 * Wraps a stream with the provided callbacks
126
-	 *
127
-	 * @param resource $source
128
-	 * @param string $internalPath relative to mount point
129
-	 * @param string $fullPath relative to data/
130
-	 * @param array $header
131
-	 * @param string $uid
132
-	 * @param \OCP\Encryption\IEncryptionModule $encryptionModule
133
-	 * @param \OC\Files\Storage\Storage $storage
134
-	 * @param \OC\Files\Storage\Wrapper\Encryption $encStorage
135
-	 * @param \OC\Encryption\Util $util
136
-	 * @param \OC\Encryption\File $file
137
-	 * @param string $mode
138
-	 * @param int $size
139
-	 * @param int $unencryptedSize
140
-	 * @param int $headerSize
141
-	 * @param bool $signed
142
-	 * @param string $wrapper stream wrapper class
143
-	 * @return resource
144
-	 *
145
-	 * @throws \BadMethodCallException
146
-	 */
147
-	public static function wrap($source, $internalPath, $fullPath, array $header,
148
-								$uid,
149
-								\OCP\Encryption\IEncryptionModule $encryptionModule,
150
-								\OC\Files\Storage\Storage $storage,
151
-								\OC\Files\Storage\Wrapper\Encryption $encStorage,
152
-								\OC\Encryption\Util $util,
153
-								 \OC\Encryption\File $file,
154
-								$mode,
155
-								$size,
156
-								$unencryptedSize,
157
-								$headerSize,
158
-								$signed,
159
-								$wrapper =  'OC\Files\Stream\Encryption') {
160
-
161
-		$context = stream_context_create(array(
162
-			'ocencryption' => array(
163
-				'source' => $source,
164
-				'storage' => $storage,
165
-				'internalPath' => $internalPath,
166
-				'fullPath' => $fullPath,
167
-				'encryptionModule' => $encryptionModule,
168
-				'header' => $header,
169
-				'uid' => $uid,
170
-				'util' => $util,
171
-				'file' => $file,
172
-				'size' => $size,
173
-				'unencryptedSize' => $unencryptedSize,
174
-				'encryptionStorage' => $encStorage,
175
-				'headerSize' => $headerSize,
176
-				'signed' => $signed
177
-			)
178
-		));
179
-
180
-		return self::wrapSource($source, $context, 'ocencryption', $wrapper, $mode);
181
-	}
182
-
183
-	/**
184
-	 * add stream wrapper
185
-	 *
186
-	 * @param resource $source
187
-	 * @param string $mode
188
-	 * @param resource $context
189
-	 * @param string $protocol
190
-	 * @param string $class
191
-	 * @return resource
192
-	 * @throws \BadMethodCallException
193
-	 */
194
-	protected static function wrapSource($source, $context, $protocol, $class, $mode = 'r+') {
195
-		try {
196
-			stream_wrapper_register($protocol, $class);
197
-			if (@rewinddir($source) === false) {
198
-				$wrapped = fopen($protocol . '://', $mode, false, $context);
199
-			} else {
200
-				$wrapped = opendir($protocol . '://', $context);
201
-			}
202
-		} catch (\BadMethodCallException $e) {
203
-			stream_wrapper_unregister($protocol);
204
-			throw $e;
205
-		}
206
-		stream_wrapper_unregister($protocol);
207
-		return $wrapped;
208
-	}
209
-
210
-	/**
211
-	 * Load the source from the stream context and return the context options
212
-	 *
213
-	 * @param string $name
214
-	 * @return array
215
-	 * @throws \BadMethodCallException
216
-	 */
217
-	protected function loadContext($name) {
218
-		$context = parent::loadContext($name);
219
-
220
-		foreach ($this->expectedContextProperties as $property) {
221
-			if (array_key_exists($property, $context)) {
222
-				$this->{$property} = $context[$property];
223
-			} else {
224
-				throw new \BadMethodCallException('Invalid context, "' . $property . '" options not set');
225
-			}
226
-		}
227
-		return $context;
228
-
229
-	}
230
-
231
-	public function stream_open($path, $mode, $options, &$opened_path) {
232
-		$this->loadContext('ocencryption');
233
-
234
-		$this->position = 0;
235
-		$this->cache = '';
236
-		$this->writeFlag = false;
237
-		$this->unencryptedBlockSize = $this->encryptionModule->getUnencryptedBlockSize($this->signed);
238
-
239
-		if (
240
-			$mode === 'w'
241
-			|| $mode === 'w+'
242
-			|| $mode === 'wb'
243
-			|| $mode === 'wb+'
244
-			|| $mode === 'r+'
245
-			|| $mode === 'rb+'
246
-		) {
247
-			$this->readOnly = false;
248
-		} else {
249
-			$this->readOnly = true;
250
-		}
251
-
252
-		$sharePath = $this->fullPath;
253
-		if (!$this->storage->file_exists($this->internalPath)) {
254
-			$sharePath = dirname($sharePath);
255
-		}
256
-
257
-		$accessList = [];
258
-		if ($this->encryptionModule->needDetailedAccessList()) {
259
-			$accessList = $this->file->getAccessList($sharePath);
260
-		}
261
-		$this->newHeader = $this->encryptionModule->begin($this->fullPath, $this->uid, $mode, $this->header, $accessList);
262
-
263
-		if (
264
-			$mode === 'w'
265
-			|| $mode === 'w+'
266
-			|| $mode === 'wb'
267
-			|| $mode === 'wb+'
268
-		) {
269
-			// We're writing a new file so start write counter with 0 bytes
270
-			$this->unencryptedSize = 0;
271
-			$this->writeHeader();
272
-			$this->headerSize = $this->util->getHeaderSize();
273
-			$this->size = $this->headerSize;
274
-		} else {
275
-			$this->skipHeader();
276
-		}
277
-
278
-		return true;
279
-
280
-	}
281
-
282
-	public function stream_eof() {
283
-		return $this->position >= $this->unencryptedSize;
284
-	}
285
-
286
-	public function stream_read($count) {
287
-
288
-		$result = '';
289
-
290
-		$count = min($count, $this->unencryptedSize - $this->position);
291
-		while ($count > 0) {
292
-			$remainingLength = $count;
293
-			// update the cache of the current block
294
-			$this->readCache();
295
-			// determine the relative position in the current block
296
-			$blockPosition = ($this->position % $this->unencryptedBlockSize);
297
-			// if entire read inside current block then only position needs to be updated
298
-			if ($remainingLength < ($this->unencryptedBlockSize - $blockPosition)) {
299
-				$result .= substr($this->cache, $blockPosition, $remainingLength);
300
-				$this->position += $remainingLength;
301
-				$count = 0;
302
-				// otherwise remainder of current block is fetched, the block is flushed and the position updated
303
-			} else {
304
-				$result .= substr($this->cache, $blockPosition);
305
-				$this->flush();
306
-				$this->position += ($this->unencryptedBlockSize - $blockPosition);
307
-				$count -= ($this->unencryptedBlockSize - $blockPosition);
308
-			}
309
-		}
310
-		return $result;
311
-
312
-	}
313
-
314
-	public function stream_write($data) {
315
-
316
-		$length = 0;
317
-		// loop over $data to fit it in 6126 sized unencrypted blocks
318
-		while (isset($data[0])) {
319
-			$remainingLength = strlen($data);
320
-
321
-			// set the cache to the current 6126 block
322
-			$this->readCache();
323
-
324
-			// for seekable streams the pointer is moved back to the beginning of the encrypted block
325
-			// flush will start writing there when the position moves to another block
326
-			$positionInFile = (int)floor($this->position / $this->unencryptedBlockSize) *
327
-				$this->util->getBlockSize() + $this->headerSize;
328
-			$resultFseek = $this->parentStreamSeek($positionInFile);
329
-
330
-			// only allow writes on seekable streams, or at the end of the encrypted stream
331
-			if (!($this->readOnly) && ($resultFseek || $positionInFile === $this->size)) {
332
-
333
-				// switch the writeFlag so flush() will write the block
334
-				$this->writeFlag = true;
335
-
336
-				// determine the relative position in the current block
337
-				$blockPosition = ($this->position % $this->unencryptedBlockSize);
338
-				// check if $data fits in current block
339
-				// if so, overwrite existing data (if any)
340
-				// update position and liberate $data
341
-				if ($remainingLength < ($this->unencryptedBlockSize - $blockPosition)) {
342
-					$this->cache = substr($this->cache, 0, $blockPosition)
343
-						. $data . substr($this->cache, $blockPosition + $remainingLength);
344
-					$this->position += $remainingLength;
345
-					$length += $remainingLength;
346
-					$data = '';
347
-					// if $data doesn't fit the current block, the fill the current block and reiterate
348
-					// after the block is filled, it is flushed and $data is updatedxxx
349
-				} else {
350
-					$this->cache = substr($this->cache, 0, $blockPosition) .
351
-						substr($data, 0, $this->unencryptedBlockSize - $blockPosition);
352
-					$this->flush();
353
-					$this->position += ($this->unencryptedBlockSize - $blockPosition);
354
-					$length += ($this->unencryptedBlockSize - $blockPosition);
355
-					$data = substr($data, $this->unencryptedBlockSize - $blockPosition);
356
-				}
357
-			} else {
358
-				$data = '';
359
-			}
360
-			$this->unencryptedSize = max($this->unencryptedSize, $this->position);
361
-		}
362
-		return $length;
363
-	}
364
-
365
-	public function stream_tell() {
366
-		return $this->position;
367
-	}
368
-
369
-	public function stream_seek($offset, $whence = SEEK_SET) {
370
-
371
-		$return = false;
372
-
373
-		switch ($whence) {
374
-			case SEEK_SET:
375
-				$newPosition = $offset;
376
-				break;
377
-			case SEEK_CUR:
378
-				$newPosition = $this->position + $offset;
379
-				break;
380
-			case SEEK_END:
381
-				$newPosition = $this->unencryptedSize + $offset;
382
-				break;
383
-			default:
384
-				return $return;
385
-		}
386
-
387
-		if ($newPosition > $this->unencryptedSize || $newPosition < 0) {
388
-			return $return;
389
-		}
390
-
391
-		$newFilePosition = floor($newPosition / $this->unencryptedBlockSize)
392
-			* $this->util->getBlockSize() + $this->headerSize;
393
-
394
-		$oldFilePosition = parent::stream_tell();
395
-		if ($this->parentStreamSeek($newFilePosition)) {
396
-			$this->parentStreamSeek($oldFilePosition);
397
-			$this->flush();
398
-			$this->parentStreamSeek($newFilePosition);
399
-			$this->position = $newPosition;
400
-			$return = true;
401
-		}
402
-		return $return;
403
-
404
-	}
405
-
406
-	public function stream_close() {
407
-		$this->flush('end');
408
-		$position = (int)floor($this->position/$this->unencryptedBlockSize);
409
-		$remainingData = $this->encryptionModule->end($this->fullPath, $position . 'end');
410
-		if ($this->readOnly === false) {
411
-			if(!empty($remainingData)) {
412
-				parent::stream_write($remainingData);
413
-			}
414
-			$this->encryptionStorage->updateUnencryptedSize($this->fullPath, $this->unencryptedSize);
415
-		}
416
-		return parent::stream_close();
417
-	}
418
-
419
-	/**
420
-	 * write block to file
421
-	 * @param string $positionPrefix
422
-	 */
423
-	protected function flush($positionPrefix = '') {
424
-		// write to disk only when writeFlag was set to 1
425
-		if ($this->writeFlag) {
426
-			// Disable the file proxies so that encryption is not
427
-			// automatically attempted when the file is written to disk -
428
-			// we are handling that separately here and we don't want to
429
-			// get into an infinite loop
430
-			$position = (int)floor($this->position/$this->unencryptedBlockSize);
431
-			$encrypted = $this->encryptionModule->encrypt($this->cache, $position . $positionPrefix);
432
-			$bytesWritten = parent::stream_write($encrypted);
433
-			$this->writeFlag = false;
434
-			// Check whether the write concerns the last block
435
-			// If so then update the encrypted filesize
436
-			// Note that the unencrypted pointer and filesize are NOT yet updated when flush() is called
437
-			// We recalculate the encrypted filesize as we do not know the context of calling flush()
438
-			$completeBlocksInFile=(int)floor($this->unencryptedSize/$this->unencryptedBlockSize);
439
-			if ($completeBlocksInFile === (int)floor($this->position/$this->unencryptedBlockSize)) {
440
-				$this->size = $this->util->getBlockSize() * $completeBlocksInFile;
441
-				$this->size += $bytesWritten;
442
-				$this->size += $this->headerSize;
443
-			}
444
-		}
445
-		// always empty the cache (otherwise readCache() will not fill it with the new block)
446
-		$this->cache = '';
447
-	}
448
-
449
-	/**
450
-	 * read block to file
451
-	 */
452
-	protected function readCache() {
453
-		// cache should always be empty string when this function is called
454
-		// don't try to fill the cache when trying to write at the end of the unencrypted file when it coincides with new block
455
-		if ($this->cache === '' && !($this->position === $this->unencryptedSize && ($this->position % $this->unencryptedBlockSize) === 0)) {
456
-			// Get the data from the file handle
457
-			$data = parent::stream_read($this->util->getBlockSize());
458
-			$position = (int)floor($this->position/$this->unencryptedBlockSize);
459
-			$numberOfChunks = (int)($this->unencryptedSize / $this->unencryptedBlockSize);
460
-			if($numberOfChunks === $position) {
461
-				$position .= 'end';
462
-			}
463
-			$this->cache = $this->encryptionModule->decrypt($data, $position);
464
-		}
465
-	}
466
-
467
-	/**
468
-	 * write header at beginning of encrypted file
469
-	 *
470
-	 * @return integer
471
-	 * @throws EncryptionHeaderKeyExistsException if header key is already in use
472
-	 */
473
-	protected function writeHeader() {
474
-		$header = $this->util->createHeader($this->newHeader, $this->encryptionModule);
475
-		return parent::stream_write($header);
476
-	}
477
-
478
-	/**
479
-	 * read first block to skip the header
480
-	 */
481
-	protected function skipHeader() {
482
-		parent::stream_read($this->headerSize);
483
-	}
484
-
485
-	/**
486
-	 * call stream_seek() from parent class
487
-	 *
488
-	 * @param integer $position
489
-	 * @return bool
490
-	 */
491
-	protected function parentStreamSeek($position) {
492
-		return parent::stream_seek($position);
493
-	}
494
-
495
-	/**
496
-	 * @param string $path
497
-	 * @param array $options
498
-	 * @return bool
499
-	 */
500
-	public function dir_opendir($path, $options) {
501
-		return false;
502
-	}
35
+    /** @var \OC\Encryption\Util */
36
+    protected $util;
37
+
38
+    /** @var \OC\Encryption\File */
39
+    protected $file;
40
+
41
+    /** @var \OCP\Encryption\IEncryptionModule */
42
+    protected $encryptionModule;
43
+
44
+    /** @var \OC\Files\Storage\Storage */
45
+    protected $storage;
46
+
47
+    /** @var \OC\Files\Storage\Wrapper\Encryption */
48
+    protected $encryptionStorage;
49
+
50
+    /** @var string */
51
+    protected $internalPath;
52
+
53
+    /** @var string */
54
+    protected $cache;
55
+
56
+    /** @var integer */
57
+    protected $size;
58
+
59
+    /** @var integer */
60
+    protected $position;
61
+
62
+    /** @var integer */
63
+    protected $unencryptedSize;
64
+
65
+    /** @var integer */
66
+    protected $headerSize;
67
+
68
+    /** @var integer */
69
+    protected $unencryptedBlockSize;
70
+
71
+    /** @var array */
72
+    protected $header;
73
+
74
+    /** @var string */
75
+    protected $fullPath;
76
+
77
+    /** @var  bool */
78
+    protected $signed;
79
+
80
+    /**
81
+     * header data returned by the encryption module, will be written to the file
82
+     * in case of a write operation
83
+     *
84
+     * @var array
85
+     */
86
+    protected $newHeader;
87
+
88
+    /**
89
+     * user who perform the read/write operation null for public access
90
+     *
91
+     * @var string
92
+     */
93
+    protected $uid;
94
+
95
+    /** @var bool */
96
+    protected $readOnly;
97
+
98
+    /** @var bool */
99
+    protected $writeFlag;
100
+
101
+    /** @var array */
102
+    protected $expectedContextProperties;
103
+
104
+    public function __construct() {
105
+        $this->expectedContextProperties = array(
106
+            'source',
107
+            'storage',
108
+            'internalPath',
109
+            'fullPath',
110
+            'encryptionModule',
111
+            'header',
112
+            'uid',
113
+            'file',
114
+            'util',
115
+            'size',
116
+            'unencryptedSize',
117
+            'encryptionStorage',
118
+            'headerSize',
119
+            'signed'
120
+        );
121
+    }
122
+
123
+
124
+    /**
125
+     * Wraps a stream with the provided callbacks
126
+     *
127
+     * @param resource $source
128
+     * @param string $internalPath relative to mount point
129
+     * @param string $fullPath relative to data/
130
+     * @param array $header
131
+     * @param string $uid
132
+     * @param \OCP\Encryption\IEncryptionModule $encryptionModule
133
+     * @param \OC\Files\Storage\Storage $storage
134
+     * @param \OC\Files\Storage\Wrapper\Encryption $encStorage
135
+     * @param \OC\Encryption\Util $util
136
+     * @param \OC\Encryption\File $file
137
+     * @param string $mode
138
+     * @param int $size
139
+     * @param int $unencryptedSize
140
+     * @param int $headerSize
141
+     * @param bool $signed
142
+     * @param string $wrapper stream wrapper class
143
+     * @return resource
144
+     *
145
+     * @throws \BadMethodCallException
146
+     */
147
+    public static function wrap($source, $internalPath, $fullPath, array $header,
148
+                                $uid,
149
+                                \OCP\Encryption\IEncryptionModule $encryptionModule,
150
+                                \OC\Files\Storage\Storage $storage,
151
+                                \OC\Files\Storage\Wrapper\Encryption $encStorage,
152
+                                \OC\Encryption\Util $util,
153
+                                    \OC\Encryption\File $file,
154
+                                $mode,
155
+                                $size,
156
+                                $unencryptedSize,
157
+                                $headerSize,
158
+                                $signed,
159
+                                $wrapper =  'OC\Files\Stream\Encryption') {
160
+
161
+        $context = stream_context_create(array(
162
+            'ocencryption' => array(
163
+                'source' => $source,
164
+                'storage' => $storage,
165
+                'internalPath' => $internalPath,
166
+                'fullPath' => $fullPath,
167
+                'encryptionModule' => $encryptionModule,
168
+                'header' => $header,
169
+                'uid' => $uid,
170
+                'util' => $util,
171
+                'file' => $file,
172
+                'size' => $size,
173
+                'unencryptedSize' => $unencryptedSize,
174
+                'encryptionStorage' => $encStorage,
175
+                'headerSize' => $headerSize,
176
+                'signed' => $signed
177
+            )
178
+        ));
179
+
180
+        return self::wrapSource($source, $context, 'ocencryption', $wrapper, $mode);
181
+    }
182
+
183
+    /**
184
+     * add stream wrapper
185
+     *
186
+     * @param resource $source
187
+     * @param string $mode
188
+     * @param resource $context
189
+     * @param string $protocol
190
+     * @param string $class
191
+     * @return resource
192
+     * @throws \BadMethodCallException
193
+     */
194
+    protected static function wrapSource($source, $context, $protocol, $class, $mode = 'r+') {
195
+        try {
196
+            stream_wrapper_register($protocol, $class);
197
+            if (@rewinddir($source) === false) {
198
+                $wrapped = fopen($protocol . '://', $mode, false, $context);
199
+            } else {
200
+                $wrapped = opendir($protocol . '://', $context);
201
+            }
202
+        } catch (\BadMethodCallException $e) {
203
+            stream_wrapper_unregister($protocol);
204
+            throw $e;
205
+        }
206
+        stream_wrapper_unregister($protocol);
207
+        return $wrapped;
208
+    }
209
+
210
+    /**
211
+     * Load the source from the stream context and return the context options
212
+     *
213
+     * @param string $name
214
+     * @return array
215
+     * @throws \BadMethodCallException
216
+     */
217
+    protected function loadContext($name) {
218
+        $context = parent::loadContext($name);
219
+
220
+        foreach ($this->expectedContextProperties as $property) {
221
+            if (array_key_exists($property, $context)) {
222
+                $this->{$property} = $context[$property];
223
+            } else {
224
+                throw new \BadMethodCallException('Invalid context, "' . $property . '" options not set');
225
+            }
226
+        }
227
+        return $context;
228
+
229
+    }
230
+
231
+    public function stream_open($path, $mode, $options, &$opened_path) {
232
+        $this->loadContext('ocencryption');
233
+
234
+        $this->position = 0;
235
+        $this->cache = '';
236
+        $this->writeFlag = false;
237
+        $this->unencryptedBlockSize = $this->encryptionModule->getUnencryptedBlockSize($this->signed);
238
+
239
+        if (
240
+            $mode === 'w'
241
+            || $mode === 'w+'
242
+            || $mode === 'wb'
243
+            || $mode === 'wb+'
244
+            || $mode === 'r+'
245
+            || $mode === 'rb+'
246
+        ) {
247
+            $this->readOnly = false;
248
+        } else {
249
+            $this->readOnly = true;
250
+        }
251
+
252
+        $sharePath = $this->fullPath;
253
+        if (!$this->storage->file_exists($this->internalPath)) {
254
+            $sharePath = dirname($sharePath);
255
+        }
256
+
257
+        $accessList = [];
258
+        if ($this->encryptionModule->needDetailedAccessList()) {
259
+            $accessList = $this->file->getAccessList($sharePath);
260
+        }
261
+        $this->newHeader = $this->encryptionModule->begin($this->fullPath, $this->uid, $mode, $this->header, $accessList);
262
+
263
+        if (
264
+            $mode === 'w'
265
+            || $mode === 'w+'
266
+            || $mode === 'wb'
267
+            || $mode === 'wb+'
268
+        ) {
269
+            // We're writing a new file so start write counter with 0 bytes
270
+            $this->unencryptedSize = 0;
271
+            $this->writeHeader();
272
+            $this->headerSize = $this->util->getHeaderSize();
273
+            $this->size = $this->headerSize;
274
+        } else {
275
+            $this->skipHeader();
276
+        }
277
+
278
+        return true;
279
+
280
+    }
281
+
282
+    public function stream_eof() {
283
+        return $this->position >= $this->unencryptedSize;
284
+    }
285
+
286
+    public function stream_read($count) {
287
+
288
+        $result = '';
289
+
290
+        $count = min($count, $this->unencryptedSize - $this->position);
291
+        while ($count > 0) {
292
+            $remainingLength = $count;
293
+            // update the cache of the current block
294
+            $this->readCache();
295
+            // determine the relative position in the current block
296
+            $blockPosition = ($this->position % $this->unencryptedBlockSize);
297
+            // if entire read inside current block then only position needs to be updated
298
+            if ($remainingLength < ($this->unencryptedBlockSize - $blockPosition)) {
299
+                $result .= substr($this->cache, $blockPosition, $remainingLength);
300
+                $this->position += $remainingLength;
301
+                $count = 0;
302
+                // otherwise remainder of current block is fetched, the block is flushed and the position updated
303
+            } else {
304
+                $result .= substr($this->cache, $blockPosition);
305
+                $this->flush();
306
+                $this->position += ($this->unencryptedBlockSize - $blockPosition);
307
+                $count -= ($this->unencryptedBlockSize - $blockPosition);
308
+            }
309
+        }
310
+        return $result;
311
+
312
+    }
313
+
314
+    public function stream_write($data) {
315
+
316
+        $length = 0;
317
+        // loop over $data to fit it in 6126 sized unencrypted blocks
318
+        while (isset($data[0])) {
319
+            $remainingLength = strlen($data);
320
+
321
+            // set the cache to the current 6126 block
322
+            $this->readCache();
323
+
324
+            // for seekable streams the pointer is moved back to the beginning of the encrypted block
325
+            // flush will start writing there when the position moves to another block
326
+            $positionInFile = (int)floor($this->position / $this->unencryptedBlockSize) *
327
+                $this->util->getBlockSize() + $this->headerSize;
328
+            $resultFseek = $this->parentStreamSeek($positionInFile);
329
+
330
+            // only allow writes on seekable streams, or at the end of the encrypted stream
331
+            if (!($this->readOnly) && ($resultFseek || $positionInFile === $this->size)) {
332
+
333
+                // switch the writeFlag so flush() will write the block
334
+                $this->writeFlag = true;
335
+
336
+                // determine the relative position in the current block
337
+                $blockPosition = ($this->position % $this->unencryptedBlockSize);
338
+                // check if $data fits in current block
339
+                // if so, overwrite existing data (if any)
340
+                // update position and liberate $data
341
+                if ($remainingLength < ($this->unencryptedBlockSize - $blockPosition)) {
342
+                    $this->cache = substr($this->cache, 0, $blockPosition)
343
+                        . $data . substr($this->cache, $blockPosition + $remainingLength);
344
+                    $this->position += $remainingLength;
345
+                    $length += $remainingLength;
346
+                    $data = '';
347
+                    // if $data doesn't fit the current block, the fill the current block and reiterate
348
+                    // after the block is filled, it is flushed and $data is updatedxxx
349
+                } else {
350
+                    $this->cache = substr($this->cache, 0, $blockPosition) .
351
+                        substr($data, 0, $this->unencryptedBlockSize - $blockPosition);
352
+                    $this->flush();
353
+                    $this->position += ($this->unencryptedBlockSize - $blockPosition);
354
+                    $length += ($this->unencryptedBlockSize - $blockPosition);
355
+                    $data = substr($data, $this->unencryptedBlockSize - $blockPosition);
356
+                }
357
+            } else {
358
+                $data = '';
359
+            }
360
+            $this->unencryptedSize = max($this->unencryptedSize, $this->position);
361
+        }
362
+        return $length;
363
+    }
364
+
365
+    public function stream_tell() {
366
+        return $this->position;
367
+    }
368
+
369
+    public function stream_seek($offset, $whence = SEEK_SET) {
370
+
371
+        $return = false;
372
+
373
+        switch ($whence) {
374
+            case SEEK_SET:
375
+                $newPosition = $offset;
376
+                break;
377
+            case SEEK_CUR:
378
+                $newPosition = $this->position + $offset;
379
+                break;
380
+            case SEEK_END:
381
+                $newPosition = $this->unencryptedSize + $offset;
382
+                break;
383
+            default:
384
+                return $return;
385
+        }
386
+
387
+        if ($newPosition > $this->unencryptedSize || $newPosition < 0) {
388
+            return $return;
389
+        }
390
+
391
+        $newFilePosition = floor($newPosition / $this->unencryptedBlockSize)
392
+            * $this->util->getBlockSize() + $this->headerSize;
393
+
394
+        $oldFilePosition = parent::stream_tell();
395
+        if ($this->parentStreamSeek($newFilePosition)) {
396
+            $this->parentStreamSeek($oldFilePosition);
397
+            $this->flush();
398
+            $this->parentStreamSeek($newFilePosition);
399
+            $this->position = $newPosition;
400
+            $return = true;
401
+        }
402
+        return $return;
403
+
404
+    }
405
+
406
+    public function stream_close() {
407
+        $this->flush('end');
408
+        $position = (int)floor($this->position/$this->unencryptedBlockSize);
409
+        $remainingData = $this->encryptionModule->end($this->fullPath, $position . 'end');
410
+        if ($this->readOnly === false) {
411
+            if(!empty($remainingData)) {
412
+                parent::stream_write($remainingData);
413
+            }
414
+            $this->encryptionStorage->updateUnencryptedSize($this->fullPath, $this->unencryptedSize);
415
+        }
416
+        return parent::stream_close();
417
+    }
418
+
419
+    /**
420
+     * write block to file
421
+     * @param string $positionPrefix
422
+     */
423
+    protected function flush($positionPrefix = '') {
424
+        // write to disk only when writeFlag was set to 1
425
+        if ($this->writeFlag) {
426
+            // Disable the file proxies so that encryption is not
427
+            // automatically attempted when the file is written to disk -
428
+            // we are handling that separately here and we don't want to
429
+            // get into an infinite loop
430
+            $position = (int)floor($this->position/$this->unencryptedBlockSize);
431
+            $encrypted = $this->encryptionModule->encrypt($this->cache, $position . $positionPrefix);
432
+            $bytesWritten = parent::stream_write($encrypted);
433
+            $this->writeFlag = false;
434
+            // Check whether the write concerns the last block
435
+            // If so then update the encrypted filesize
436
+            // Note that the unencrypted pointer and filesize are NOT yet updated when flush() is called
437
+            // We recalculate the encrypted filesize as we do not know the context of calling flush()
438
+            $completeBlocksInFile=(int)floor($this->unencryptedSize/$this->unencryptedBlockSize);
439
+            if ($completeBlocksInFile === (int)floor($this->position/$this->unencryptedBlockSize)) {
440
+                $this->size = $this->util->getBlockSize() * $completeBlocksInFile;
441
+                $this->size += $bytesWritten;
442
+                $this->size += $this->headerSize;
443
+            }
444
+        }
445
+        // always empty the cache (otherwise readCache() will not fill it with the new block)
446
+        $this->cache = '';
447
+    }
448
+
449
+    /**
450
+     * read block to file
451
+     */
452
+    protected function readCache() {
453
+        // cache should always be empty string when this function is called
454
+        // don't try to fill the cache when trying to write at the end of the unencrypted file when it coincides with new block
455
+        if ($this->cache === '' && !($this->position === $this->unencryptedSize && ($this->position % $this->unencryptedBlockSize) === 0)) {
456
+            // Get the data from the file handle
457
+            $data = parent::stream_read($this->util->getBlockSize());
458
+            $position = (int)floor($this->position/$this->unencryptedBlockSize);
459
+            $numberOfChunks = (int)($this->unencryptedSize / $this->unencryptedBlockSize);
460
+            if($numberOfChunks === $position) {
461
+                $position .= 'end';
462
+            }
463
+            $this->cache = $this->encryptionModule->decrypt($data, $position);
464
+        }
465
+    }
466
+
467
+    /**
468
+     * write header at beginning of encrypted file
469
+     *
470
+     * @return integer
471
+     * @throws EncryptionHeaderKeyExistsException if header key is already in use
472
+     */
473
+    protected function writeHeader() {
474
+        $header = $this->util->createHeader($this->newHeader, $this->encryptionModule);
475
+        return parent::stream_write($header);
476
+    }
477
+
478
+    /**
479
+     * read first block to skip the header
480
+     */
481
+    protected function skipHeader() {
482
+        parent::stream_read($this->headerSize);
483
+    }
484
+
485
+    /**
486
+     * call stream_seek() from parent class
487
+     *
488
+     * @param integer $position
489
+     * @return bool
490
+     */
491
+    protected function parentStreamSeek($position) {
492
+        return parent::stream_seek($position);
493
+    }
494
+
495
+    /**
496
+     * @param string $path
497
+     * @param array $options
498
+     * @return bool
499
+     */
500
+    public function dir_opendir($path, $options) {
501
+        return false;
502
+    }
503 503
 
504 504
 }
Please login to merge, or discard this patch.
apps/encryption/templates/settings-admin.php 2 patches
Spacing   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -7,19 +7,19 @@  discard block
 block discarded – undo
7 7
 ?>
8 8
 <form id="ocDefaultEncryptionModule" class="sub-section">
9 9
 	<h3><?php p($l->t("Default encryption module")); ?></h3>
10
-	<?php if(!$_["initStatus"] && $_['masterKeyEnabled'] === false): ?>
10
+	<?php if (!$_["initStatus"] && $_['masterKeyEnabled'] === false): ?>
11 11
 		<?php p($l->t("Encryption app is enabled but your keys are not initialized, please log-out and log-in again")); ?>
12 12
 	<?php else: ?>
13 13
 		<p id="encryptHomeStorageSetting">
14 14
 			<input type="checkbox" class="checkbox" name="encrypt_home_storage" id="encryptHomeStorage"
15 15
 				   value="1" <?php if ($_['encryptHomeStorage']) print_unescaped('checked="checked"'); ?> />
16
-			<label for="encryptHomeStorage"><?php p($l->t('Encrypt the home storage'));?></label></br>
17
-			<em><?php p( $l->t( "Enabling this option encrypts all files stored on the main storage, otherwise only files on external storage will be encrypted" ) ); ?></em>
16
+			<label for="encryptHomeStorage"><?php p($l->t('Encrypt the home storage')); ?></label></br>
17
+			<em><?php p($l->t("Enabling this option encrypts all files stored on the main storage, otherwise only files on external storage will be encrypted")); ?></em>
18 18
 		</p>
19 19
 		<br />
20
-		<?php if($_['masterKeyEnabled'] === false): ?>
20
+		<?php if ($_['masterKeyEnabled'] === false): ?>
21 21
 			<p id="encryptionSetRecoveryKey">
22
-				<?php $_["recoveryEnabled"] === '0' ?  p($l->t("Enable recovery key")) : p($l->t("Disable recovery key")); ?>
22
+				<?php $_["recoveryEnabled"] === '0' ? p($l->t("Enable recovery key")) : p($l->t("Disable recovery key")); ?>
23 23
 				<span class="msg"></span>
24 24
 				<br/>
25 25
 				<em>
@@ -38,11 +38,11 @@  discard block
 block discarded – undo
38 38
 					   name="enableRecoveryKey"
39 39
 					   id="enableRecoveryKey"
40 40
 					   status="<?php p($_["recoveryEnabled"]) ?>"
41
-					   value="<?php $_["recoveryEnabled"] === '0' ?  p($l->t("Enable recovery key")) : p($l->t("Disable recovery key")); ?>"/>
41
+					   value="<?php $_["recoveryEnabled"] === '0' ? p($l->t("Enable recovery key")) : p($l->t("Disable recovery key")); ?>"/>
42 42
 			</p>
43 43
 			<br/><br/>
44 44
 
45
-			<p name="changeRecoveryPasswordBlock" id="encryptionChangeRecoveryKey" <?php if($_['recoveryEnabled'] === '0') print_unescaped('class="hidden"');?>>
45
+			<p name="changeRecoveryPasswordBlock" id="encryptionChangeRecoveryKey" <?php if ($_['recoveryEnabled'] === '0') print_unescaped('class="hidden"'); ?>>
46 46
 				<?php p($l->t("Change recovery key password:")); ?>
47 47
 				<span class="msg"></span>
48 48
 				<br/>
Please login to merge, or discard this patch.
Braces   +9 added lines, -3 removed lines patch added patch discarded remove patch
@@ -9,10 +9,13 @@  discard block
 block discarded – undo
9 9
 	<h3><?php p($l->t("Default encryption module")); ?></h3>
10 10
 	<?php if(!$_["initStatus"] && $_['masterKeyEnabled'] === false): ?>
11 11
 		<?php p($l->t("Encryption app is enabled but your keys are not initialized, please log-out and log-in again")); ?>
12
-	<?php else: ?>
12
+	<?php else {
13
+    : ?>
13 14
 		<p id="encryptHomeStorageSetting">
14 15
 			<input type="checkbox" class="checkbox" name="encrypt_home_storage" id="encryptHomeStorage"
15
-				   value="1" <?php if ($_['encryptHomeStorage']) print_unescaped('checked="checked"'); ?> />
16
+				   value="1" <?php if ($_['encryptHomeStorage']) print_unescaped('checked="checked"');
17
+}
18
+?> />
16 19
 			<label for="encryptHomeStorage"><?php p($l->t('Encrypt the home storage'));?></label></br>
17 20
 			<em><?php p( $l->t( "Enabling this option encrypts all files stored on the main storage, otherwise only files on external storage will be encrypted" ) ); ?></em>
18 21
 		</p>
@@ -42,7 +45,10 @@  discard block
 block discarded – undo
42 45
 			</p>
43 46
 			<br/><br/>
44 47
 
45
-			<p name="changeRecoveryPasswordBlock" id="encryptionChangeRecoveryKey" <?php if($_['recoveryEnabled'] === '0') print_unescaped('class="hidden"');?>>
48
+			<p name="changeRecoveryPasswordBlock" id="encryptionChangeRecoveryKey" <?php if($_['recoveryEnabled'] === '0') {
49
+    print_unescaped('class="hidden"');
50
+}
51
+?>>
46 52
 				<?php p($l->t("Change recovery key password:")); ?>
47 53
 				<span class="msg"></span>
48 54
 				<br/>
Please login to merge, or discard this patch.
apps/encryption/lib/Util.php 1 patch
Indentation   +162 added lines, -162 removed lines patch added patch discarded remove patch
@@ -36,167 +36,167 @@
 block discarded – undo
36 36
 use OCP\PreConditionNotMetException;
37 37
 
38 38
 class Util {
39
-	/**
40
-	 * @var View
41
-	 */
42
-	private $files;
43
-	/**
44
-	 * @var Crypt
45
-	 */
46
-	private $crypt;
47
-	/**
48
-	 * @var ILogger
49
-	 */
50
-	private $logger;
51
-	/**
52
-	 * @var bool|IUser
53
-	 */
54
-	private $user;
55
-	/**
56
-	 * @var IConfig
57
-	 */
58
-	private $config;
59
-	/**
60
-	 * @var IUserManager
61
-	 */
62
-	private $userManager;
63
-
64
-	/**
65
-	 * Util constructor.
66
-	 *
67
-	 * @param View $files
68
-	 * @param Crypt $crypt
69
-	 * @param ILogger $logger
70
-	 * @param IUserSession $userSession
71
-	 * @param IConfig $config
72
-	 * @param IUserManager $userManager
73
-	 */
74
-	public function __construct(View $files,
75
-								Crypt $crypt,
76
-								ILogger $logger,
77
-								IUserSession $userSession,
78
-								IConfig $config,
79
-								IUserManager $userManager
80
-	) {
81
-		$this->files = $files;
82
-		$this->crypt = $crypt;
83
-		$this->logger = $logger;
84
-		$this->user = $userSession && $userSession->isLoggedIn() ? $userSession->getUser() : false;
85
-		$this->config = $config;
86
-		$this->userManager = $userManager;
87
-	}
88
-
89
-	/**
90
-	 * check if recovery key is enabled for user
91
-	 *
92
-	 * @param string $uid
93
-	 * @return bool
94
-	 */
95
-	public function isRecoveryEnabledForUser($uid) {
96
-		$recoveryMode = $this->config->getUserValue($uid,
97
-			'encryption',
98
-			'recoveryEnabled',
99
-			'0');
100
-
101
-		return ($recoveryMode === '1');
102
-	}
103
-
104
-	/**
105
-	 * check if the home storage should be encrypted
106
-	 *
107
-	 * @return bool
108
-	 */
109
-	public function shouldEncryptHomeStorage() {
110
-		$encryptHomeStorage = $this->config->getAppValue(
111
-			'encryption',
112
-			'encryptHomeStorage',
113
-			'1'
114
-		);
115
-
116
-		return ($encryptHomeStorage === '1');
117
-	}
118
-
119
-	/**
120
-	 * set the home storage encryption on/off
121
-	 *
122
-	 * @param bool $encryptHomeStorage
123
-	 */
124
-	public function setEncryptHomeStorage($encryptHomeStorage) {
125
-		$value = $encryptHomeStorage ? '1' : '0';
126
-		$this->config->setAppValue(
127
-			'encryption',
128
-			'encryptHomeStorage',
129
-			$value
130
-		);
131
-	}
132
-
133
-	/**
134
-	 * check if master key is enabled
135
-	 *
136
-	 * @return bool
137
-	 */
138
-	public function isMasterKeyEnabled() {
139
-		$userMasterKey = $this->config->getAppValue('encryption', 'useMasterKey', '1');
140
-		return ($userMasterKey === '1');
141
-	}
142
-
143
-	/**
144
-	 * @param $enabled
145
-	 * @return bool
146
-	 */
147
-	public function setRecoveryForUser($enabled) {
148
-		$value = $enabled ? '1' : '0';
149
-
150
-		try {
151
-			$this->config->setUserValue($this->user->getUID(),
152
-				'encryption',
153
-				'recoveryEnabled',
154
-				$value);
155
-			return true;
156
-		} catch (PreConditionNotMetException $e) {
157
-			return false;
158
-		}
159
-	}
160
-
161
-	/**
162
-	 * @param string $uid
163
-	 * @return bool
164
-	 */
165
-	public function userHasFiles($uid) {
166
-		return $this->files->file_exists($uid . '/files');
167
-	}
168
-
169
-	/**
170
-	 * get owner from give path, path relative to data/ expected
171
-	 *
172
-	 * @param string $path relative to data/
173
-	 * @return string
174
-	 * @throws \BadMethodCallException
175
-	 */
176
-	public function getOwner($path) {
177
-		$owner = '';
178
-		$parts = explode('/', $path, 3);
179
-		if (count($parts) > 1) {
180
-			$owner = $parts[1];
181
-			if ($this->userManager->userExists($owner) === false) {
182
-				throw new \BadMethodCallException('Unknown user: ' .
183
-				'method expects path to a user folder relative to the data folder');
184
-			}
185
-
186
-		}
187
-
188
-		return $owner;
189
-	}
190
-
191
-	/**
192
-	 * get storage of path
193
-	 *
194
-	 * @param string $path
195
-	 * @return \OC\Files\Storage\Storage
196
-	 */
197
-	public function getStorage($path) {
198
-		$storage = $this->files->getMount($path)->getStorage();
199
-		return $storage;
200
-	}
39
+    /**
40
+     * @var View
41
+     */
42
+    private $files;
43
+    /**
44
+     * @var Crypt
45
+     */
46
+    private $crypt;
47
+    /**
48
+     * @var ILogger
49
+     */
50
+    private $logger;
51
+    /**
52
+     * @var bool|IUser
53
+     */
54
+    private $user;
55
+    /**
56
+     * @var IConfig
57
+     */
58
+    private $config;
59
+    /**
60
+     * @var IUserManager
61
+     */
62
+    private $userManager;
63
+
64
+    /**
65
+     * Util constructor.
66
+     *
67
+     * @param View $files
68
+     * @param Crypt $crypt
69
+     * @param ILogger $logger
70
+     * @param IUserSession $userSession
71
+     * @param IConfig $config
72
+     * @param IUserManager $userManager
73
+     */
74
+    public function __construct(View $files,
75
+                                Crypt $crypt,
76
+                                ILogger $logger,
77
+                                IUserSession $userSession,
78
+                                IConfig $config,
79
+                                IUserManager $userManager
80
+    ) {
81
+        $this->files = $files;
82
+        $this->crypt = $crypt;
83
+        $this->logger = $logger;
84
+        $this->user = $userSession && $userSession->isLoggedIn() ? $userSession->getUser() : false;
85
+        $this->config = $config;
86
+        $this->userManager = $userManager;
87
+    }
88
+
89
+    /**
90
+     * check if recovery key is enabled for user
91
+     *
92
+     * @param string $uid
93
+     * @return bool
94
+     */
95
+    public function isRecoveryEnabledForUser($uid) {
96
+        $recoveryMode = $this->config->getUserValue($uid,
97
+            'encryption',
98
+            'recoveryEnabled',
99
+            '0');
100
+
101
+        return ($recoveryMode === '1');
102
+    }
103
+
104
+    /**
105
+     * check if the home storage should be encrypted
106
+     *
107
+     * @return bool
108
+     */
109
+    public function shouldEncryptHomeStorage() {
110
+        $encryptHomeStorage = $this->config->getAppValue(
111
+            'encryption',
112
+            'encryptHomeStorage',
113
+            '1'
114
+        );
115
+
116
+        return ($encryptHomeStorage === '1');
117
+    }
118
+
119
+    /**
120
+     * set the home storage encryption on/off
121
+     *
122
+     * @param bool $encryptHomeStorage
123
+     */
124
+    public function setEncryptHomeStorage($encryptHomeStorage) {
125
+        $value = $encryptHomeStorage ? '1' : '0';
126
+        $this->config->setAppValue(
127
+            'encryption',
128
+            'encryptHomeStorage',
129
+            $value
130
+        );
131
+    }
132
+
133
+    /**
134
+     * check if master key is enabled
135
+     *
136
+     * @return bool
137
+     */
138
+    public function isMasterKeyEnabled() {
139
+        $userMasterKey = $this->config->getAppValue('encryption', 'useMasterKey', '1');
140
+        return ($userMasterKey === '1');
141
+    }
142
+
143
+    /**
144
+     * @param $enabled
145
+     * @return bool
146
+     */
147
+    public function setRecoveryForUser($enabled) {
148
+        $value = $enabled ? '1' : '0';
149
+
150
+        try {
151
+            $this->config->setUserValue($this->user->getUID(),
152
+                'encryption',
153
+                'recoveryEnabled',
154
+                $value);
155
+            return true;
156
+        } catch (PreConditionNotMetException $e) {
157
+            return false;
158
+        }
159
+    }
160
+
161
+    /**
162
+     * @param string $uid
163
+     * @return bool
164
+     */
165
+    public function userHasFiles($uid) {
166
+        return $this->files->file_exists($uid . '/files');
167
+    }
168
+
169
+    /**
170
+     * get owner from give path, path relative to data/ expected
171
+     *
172
+     * @param string $path relative to data/
173
+     * @return string
174
+     * @throws \BadMethodCallException
175
+     */
176
+    public function getOwner($path) {
177
+        $owner = '';
178
+        $parts = explode('/', $path, 3);
179
+        if (count($parts) > 1) {
180
+            $owner = $parts[1];
181
+            if ($this->userManager->userExists($owner) === false) {
182
+                throw new \BadMethodCallException('Unknown user: ' .
183
+                'method expects path to a user folder relative to the data folder');
184
+            }
185
+
186
+        }
187
+
188
+        return $owner;
189
+    }
190
+
191
+    /**
192
+     * get storage of path
193
+     *
194
+     * @param string $path
195
+     * @return \OC\Files\Storage\Storage
196
+     */
197
+    public function getStorage($path) {
198
+        $storage = $this->files->getMount($path)->getStorage();
199
+        return $storage;
200
+    }
201 201
 
202 202
 }
Please login to merge, or discard this patch.
apps/encryption/lib/Crypto/Encryption.php 1 patch
Indentation   +535 added lines, -535 removed lines patch added patch discarded remove patch
@@ -43,539 +43,539 @@
 block discarded – undo
43 43
 
44 44
 class Encryption implements IEncryptionModule {
45 45
 
46
-	const ID = 'OC_DEFAULT_MODULE';
47
-	const DISPLAY_NAME = 'Default encryption module';
48
-
49
-	/**
50
-	 * @var Crypt
51
-	 */
52
-	private $crypt;
53
-
54
-	/** @var string */
55
-	private $cipher;
56
-
57
-	/** @var string */
58
-	private $path;
59
-
60
-	/** @var string */
61
-	private $user;
62
-
63
-	/** @var string */
64
-	private $fileKey;
65
-
66
-	/** @var string */
67
-	private $writeCache;
68
-
69
-	/** @var KeyManager */
70
-	private $keyManager;
71
-
72
-	/** @var array */
73
-	private $accessList;
74
-
75
-	/** @var boolean */
76
-	private $isWriteOperation;
77
-
78
-	/** @var Util */
79
-	private $util;
80
-
81
-	/** @var  Session */
82
-	private $session;
83
-
84
-	/** @var  ILogger */
85
-	private $logger;
86
-
87
-	/** @var IL10N */
88
-	private $l;
89
-
90
-	/** @var EncryptAll */
91
-	private $encryptAll;
92
-
93
-	/** @var  bool */
94
-	private $useMasterPassword;
95
-
96
-	/** @var DecryptAll  */
97
-	private $decryptAll;
98
-
99
-	/** @var int unencrypted block size if block contains signature */
100
-	private $unencryptedBlockSizeSigned = 6072;
101
-
102
-	/** @var int unencrypted block size */
103
-	private $unencryptedBlockSize = 6126;
104
-
105
-	/** @var int Current version of the file */
106
-	private $version = 0;
107
-
108
-	/** @var array remember encryption signature version */
109
-	private static $rememberVersion = [];
110
-
111
-
112
-	/**
113
-	 *
114
-	 * @param Crypt $crypt
115
-	 * @param KeyManager $keyManager
116
-	 * @param Util $util
117
-	 * @param Session $session
118
-	 * @param EncryptAll $encryptAll
119
-	 * @param DecryptAll $decryptAll
120
-	 * @param ILogger $logger
121
-	 * @param IL10N $il10n
122
-	 */
123
-	public function __construct(Crypt $crypt,
124
-								KeyManager $keyManager,
125
-								Util $util,
126
-								Session $session,
127
-								EncryptAll $encryptAll,
128
-								DecryptAll $decryptAll,
129
-								ILogger $logger,
130
-								IL10N $il10n) {
131
-		$this->crypt = $crypt;
132
-		$this->keyManager = $keyManager;
133
-		$this->util = $util;
134
-		$this->session = $session;
135
-		$this->encryptAll = $encryptAll;
136
-		$this->decryptAll = $decryptAll;
137
-		$this->logger = $logger;
138
-		$this->l = $il10n;
139
-		$this->useMasterPassword = $util->isMasterKeyEnabled();
140
-	}
141
-
142
-	/**
143
-	 * @return string defining the technical unique id
144
-	 */
145
-	public function getId() {
146
-		return self::ID;
147
-	}
148
-
149
-	/**
150
-	 * In comparison to getKey() this function returns a human readable (maybe translated) name
151
-	 *
152
-	 * @return string
153
-	 */
154
-	public function getDisplayName() {
155
-		return self::DISPLAY_NAME;
156
-	}
157
-
158
-	/**
159
-	 * start receiving chunks from a file. This is the place where you can
160
-	 * perform some initial step before starting encrypting/decrypting the
161
-	 * chunks
162
-	 *
163
-	 * @param string $path to the file
164
-	 * @param string $user who read/write the file
165
-	 * @param string $mode php stream open mode
166
-	 * @param array $header contains the header data read from the file
167
-	 * @param array $accessList who has access to the file contains the key 'users' and 'public'
168
-	 *
169
-	 * @return array $header contain data as key-value pairs which should be
170
-	 *                       written to the header, in case of a write operation
171
-	 *                       or if no additional data is needed return a empty array
172
-	 */
173
-	public function begin($path, $user, $mode, array $header, array $accessList) {
174
-		$this->path = $this->getPathToRealFile($path);
175
-		$this->accessList = $accessList;
176
-		$this->user = $user;
177
-		$this->isWriteOperation = false;
178
-		$this->writeCache = '';
179
-
180
-		if($this->session->isReady() === false) {
181
-			// if the master key is enabled we can initialize encryption
182
-			// with a empty password and user name
183
-			if ($this->util->isMasterKeyEnabled()) {
184
-				$this->keyManager->init('', '');
185
-			}
186
-		}
187
-
188
-		if ($this->session->decryptAllModeActivated()) {
189
-			$encryptedFileKey = $this->keyManager->getEncryptedFileKey($this->path);
190
-			$shareKey = $this->keyManager->getShareKey($this->path, $this->session->getDecryptAllUid());
191
-			$this->fileKey = $this->crypt->multiKeyDecrypt($encryptedFileKey,
192
-				$shareKey,
193
-				$this->session->getDecryptAllKey());
194
-		} else {
195
-			$this->fileKey = $this->keyManager->getFileKey($this->path, $this->user);
196
-		}
197
-
198
-		// always use the version from the original file, also part files
199
-		// need to have a correct version number if they get moved over to the
200
-		// final location
201
-		$this->version = (int)$this->keyManager->getVersion($this->stripPartFileExtension($path), new View());
202
-
203
-		if (
204
-			$mode === 'w'
205
-			|| $mode === 'w+'
206
-			|| $mode === 'wb'
207
-			|| $mode === 'wb+'
208
-		) {
209
-			$this->isWriteOperation = true;
210
-			if (empty($this->fileKey)) {
211
-				$this->fileKey = $this->crypt->generateFileKey();
212
-			}
213
-		} else {
214
-			// if we read a part file we need to increase the version by 1
215
-			// because the version number was also increased by writing
216
-			// the part file
217
-			if(Scanner::isPartialFile($path)) {
218
-				$this->version = $this->version + 1;
219
-			}
220
-		}
221
-
222
-		if ($this->isWriteOperation) {
223
-			$this->cipher = $this->crypt->getCipher();
224
-		} elseif (isset($header['cipher'])) {
225
-			$this->cipher = $header['cipher'];
226
-		} else {
227
-			// if we read a file without a header we fall-back to the legacy cipher
228
-			// which was used in <=oC6
229
-			$this->cipher = $this->crypt->getLegacyCipher();
230
-		}
231
-
232
-		return array('cipher' => $this->cipher, 'signed' => 'true');
233
-	}
234
-
235
-	/**
236
-	 * last chunk received. This is the place where you can perform some final
237
-	 * operation and return some remaining data if something is left in your
238
-	 * buffer.
239
-	 *
240
-	 * @param string $path to the file
241
-	 * @param int $position
242
-	 * @return string remained data which should be written to the file in case
243
-	 *                of a write operation
244
-	 * @throws PublicKeyMissingException
245
-	 * @throws \Exception
246
-	 * @throws \OCA\Encryption\Exceptions\MultiKeyEncryptException
247
-	 */
248
-	public function end($path, $position = 0) {
249
-		$result = '';
250
-		if ($this->isWriteOperation) {
251
-			$this->keyManager->setVersion($path, $this->version + 1, new View());
252
-			// in case of a part file we remember the new signature versions
253
-			// the version will be set later on update.
254
-			// This way we make sure that other apps listening to the pre-hooks
255
-			// still get the old version which should be the correct value for them
256
-			if (Scanner::isPartialFile($path)) {
257
-				self::$rememberVersion[$this->stripPartFileExtension($path)] = $this->version + 1;
258
-			}
259
-			if (!empty($this->writeCache)) {
260
-				$result = $this->crypt->symmetricEncryptFileContent($this->writeCache, $this->fileKey, $this->version + 1, $position);
261
-				$this->writeCache = '';
262
-			}
263
-			$publicKeys = array();
264
-			if ($this->useMasterPassword === true) {
265
-				$publicKeys[$this->keyManager->getMasterKeyId()] = $this->keyManager->getPublicMasterKey();
266
-			} else {
267
-				foreach ($this->accessList['users'] as $uid) {
268
-					try {
269
-						$publicKeys[$uid] = $this->keyManager->getPublicKey($uid);
270
-					} catch (PublicKeyMissingException $e) {
271
-						$this->logger->warning(
272
-							'no public key found for user "{uid}", user will not be able to read the file',
273
-							['app' => 'encryption', 'uid' => $uid]
274
-						);
275
-						// if the public key of the owner is missing we should fail
276
-						if ($uid === $this->user) {
277
-							throw $e;
278
-						}
279
-					}
280
-				}
281
-			}
282
-
283
-			$publicKeys = $this->keyManager->addSystemKeys($this->accessList, $publicKeys, $this->user);
284
-			$encryptedKeyfiles = $this->crypt->multiKeyEncrypt($this->fileKey, $publicKeys);
285
-			$this->keyManager->setAllFileKeys($this->path, $encryptedKeyfiles);
286
-		}
287
-		return $result;
288
-	}
289
-
290
-	/**
291
-	 * encrypt data
292
-	 *
293
-	 * @param string $data you want to encrypt
294
-	 * @param int $position
295
-	 * @return string encrypted data
296
-	 */
297
-	public function encrypt($data, $position = 0) {
298
-		// If extra data is left over from the last round, make sure it
299
-		// is integrated into the next block
300
-		if ($this->writeCache) {
301
-
302
-			// Concat writeCache to start of $data
303
-			$data = $this->writeCache . $data;
304
-
305
-			// Clear the write cache, ready for reuse - it has been
306
-			// flushed and its old contents processed
307
-			$this->writeCache = '';
308
-
309
-		}
310
-
311
-		$encrypted = '';
312
-		// While there still remains some data to be processed & written
313
-		while (strlen($data) > 0) {
314
-
315
-			// Remaining length for this iteration, not of the
316
-			// entire file (may be greater than 8192 bytes)
317
-			$remainingLength = strlen($data);
318
-
319
-			// If data remaining to be written is less than the
320
-			// size of 1 6126 byte block
321
-			if ($remainingLength < $this->unencryptedBlockSizeSigned) {
322
-
323
-				// Set writeCache to contents of $data
324
-				// The writeCache will be carried over to the
325
-				// next write round, and added to the start of
326
-				// $data to ensure that written blocks are
327
-				// always the correct length. If there is still
328
-				// data in writeCache after the writing round
329
-				// has finished, then the data will be written
330
-				// to disk by $this->flush().
331
-				$this->writeCache = $data;
332
-
333
-				// Clear $data ready for next round
334
-				$data = '';
335
-
336
-			} else {
337
-
338
-				// Read the chunk from the start of $data
339
-				$chunk = substr($data, 0, $this->unencryptedBlockSizeSigned);
340
-
341
-				$encrypted .= $this->crypt->symmetricEncryptFileContent($chunk, $this->fileKey, $this->version + 1, $position);
342
-
343
-				// Remove the chunk we just processed from
344
-				// $data, leaving only unprocessed data in $data
345
-				// var, for handling on the next round
346
-				$data = substr($data, $this->unencryptedBlockSizeSigned);
347
-
348
-			}
349
-
350
-		}
351
-
352
-		return $encrypted;
353
-	}
354
-
355
-	/**
356
-	 * decrypt data
357
-	 *
358
-	 * @param string $data you want to decrypt
359
-	 * @param int $position
360
-	 * @return string decrypted data
361
-	 * @throws DecryptionFailedException
362
-	 */
363
-	public function decrypt($data, $position = 0) {
364
-		if (empty($this->fileKey)) {
365
-			$msg = 'Can not decrypt this file, probably this is a shared file. Please ask the file owner to reshare the file with you.';
366
-			$hint = $this->l->t('Can not decrypt this file, probably this is a shared file. Please ask the file owner to reshare the file with you.');
367
-			$this->logger->error($msg);
368
-
369
-			throw new DecryptionFailedException($msg, $hint);
370
-		}
371
-
372
-		return $this->crypt->symmetricDecryptFileContent($data, $this->fileKey, $this->cipher, $this->version, $position);
373
-	}
374
-
375
-	/**
376
-	 * update encrypted file, e.g. give additional users access to the file
377
-	 *
378
-	 * @param string $path path to the file which should be updated
379
-	 * @param string $uid of the user who performs the operation
380
-	 * @param array $accessList who has access to the file contains the key 'users' and 'public'
381
-	 * @return boolean
382
-	 */
383
-	public function update($path, $uid, array $accessList) {
384
-
385
-		if (empty($accessList)) {
386
-			if (isset(self::$rememberVersion[$path])) {
387
-				$this->keyManager->setVersion($path, self::$rememberVersion[$path], new View());
388
-				unset(self::$rememberVersion[$path]);
389
-			}
390
-			return;
391
-		}
392
-
393
-		$fileKey = $this->keyManager->getFileKey($path, $uid);
394
-
395
-		if (!empty($fileKey)) {
396
-
397
-			$publicKeys = array();
398
-			if ($this->useMasterPassword === true) {
399
-				$publicKeys[$this->keyManager->getMasterKeyId()] = $this->keyManager->getPublicMasterKey();
400
-			} else {
401
-				foreach ($accessList['users'] as $user) {
402
-					try {
403
-						$publicKeys[$user] = $this->keyManager->getPublicKey($user);
404
-					} catch (PublicKeyMissingException $e) {
405
-						$this->logger->warning('Could not encrypt file for ' . $user . ': ' . $e->getMessage());
406
-					}
407
-				}
408
-			}
409
-
410
-			$publicKeys = $this->keyManager->addSystemKeys($accessList, $publicKeys, $uid);
411
-
412
-			$encryptedFileKey = $this->crypt->multiKeyEncrypt($fileKey, $publicKeys);
413
-
414
-			$this->keyManager->deleteAllFileKeys($path);
415
-
416
-			$this->keyManager->setAllFileKeys($path, $encryptedFileKey);
417
-
418
-		} else {
419
-			$this->logger->debug('no file key found, we assume that the file "{file}" is not encrypted',
420
-				array('file' => $path, 'app' => 'encryption'));
421
-
422
-			return false;
423
-		}
424
-
425
-		return true;
426
-	}
427
-
428
-	/**
429
-	 * should the file be encrypted or not
430
-	 *
431
-	 * @param string $path
432
-	 * @return boolean
433
-	 */
434
-	public function shouldEncrypt($path) {
435
-		if ($this->util->shouldEncryptHomeStorage() === false) {
436
-			$storage = $this->util->getStorage($path);
437
-			if ($storage->instanceOfStorage('\OCP\Files\IHomeStorage')) {
438
-				return false;
439
-			}
440
-		}
441
-		$parts = explode('/', $path);
442
-		if (count($parts) < 4) {
443
-			return false;
444
-		}
445
-
446
-		if ($parts[2] == 'files') {
447
-			return true;
448
-		}
449
-		if ($parts[2] == 'files_versions') {
450
-			return true;
451
-		}
452
-		if ($parts[2] == 'files_trashbin') {
453
-			return true;
454
-		}
455
-
456
-		return false;
457
-	}
458
-
459
-	/**
460
-	 * get size of the unencrypted payload per block.
461
-	 * Nextcloud read/write files with a block size of 8192 byte
462
-	 *
463
-	 * @param bool $signed
464
-	 * @return int
465
-	 */
466
-	public function getUnencryptedBlockSize($signed = false) {
467
-		if ($signed === false) {
468
-			return $this->unencryptedBlockSize;
469
-		}
470
-
471
-		return $this->unencryptedBlockSizeSigned;
472
-	}
473
-
474
-	/**
475
-	 * check if the encryption module is able to read the file,
476
-	 * e.g. if all encryption keys exists
477
-	 *
478
-	 * @param string $path
479
-	 * @param string $uid user for whom we want to check if he can read the file
480
-	 * @return bool
481
-	 * @throws DecryptionFailedException
482
-	 */
483
-	public function isReadable($path, $uid) {
484
-		$fileKey = $this->keyManager->getFileKey($path, $uid);
485
-		if (empty($fileKey)) {
486
-			$owner = $this->util->getOwner($path);
487
-			if ($owner !== $uid) {
488
-				// if it is a shared file we throw a exception with a useful
489
-				// error message because in this case it means that the file was
490
-				// shared with the user at a point where the user didn't had a
491
-				// valid private/public key
492
-				$msg = 'Encryption module "' . $this->getDisplayName() .
493
-					'" is not able to read ' . $path;
494
-				$hint = $this->l->t('Can not read this file, probably this is a shared file. Please ask the file owner to reshare the file with you.');
495
-				$this->logger->warning($msg);
496
-				throw new DecryptionFailedException($msg, $hint);
497
-			}
498
-			return false;
499
-		}
500
-
501
-		return true;
502
-	}
503
-
504
-	/**
505
-	 * Initial encryption of all files
506
-	 *
507
-	 * @param InputInterface $input
508
-	 * @param OutputInterface $output write some status information to the terminal during encryption
509
-	 */
510
-	public function encryptAll(InputInterface $input, OutputInterface $output) {
511
-		$this->encryptAll->encryptAll($input, $output);
512
-	}
513
-
514
-	/**
515
-	 * prepare module to perform decrypt all operation
516
-	 *
517
-	 * @param InputInterface $input
518
-	 * @param OutputInterface $output
519
-	 * @param string $user
520
-	 * @return bool
521
-	 */
522
-	public function prepareDecryptAll(InputInterface $input, OutputInterface $output, $user = '') {
523
-		return $this->decryptAll->prepare($input, $output, $user);
524
-	}
525
-
526
-
527
-	/**
528
-	 * @param string $path
529
-	 * @return string
530
-	 */
531
-	protected function getPathToRealFile($path) {
532
-		$realPath = $path;
533
-		$parts = explode('/', $path);
534
-		if ($parts[2] === 'files_versions') {
535
-			$realPath = '/' . $parts[1] . '/files/' . implode('/', array_slice($parts, 3));
536
-			$length = strrpos($realPath, '.');
537
-			$realPath = substr($realPath, 0, $length);
538
-		}
539
-
540
-		return $realPath;
541
-	}
542
-
543
-	/**
544
-	 * remove .part file extension and the ocTransferId from the file to get the
545
-	 * original file name
546
-	 *
547
-	 * @param string $path
548
-	 * @return string
549
-	 */
550
-	protected function stripPartFileExtension($path) {
551
-		if (pathinfo($path, PATHINFO_EXTENSION) === 'part') {
552
-			$pos = strrpos($path, '.', -6);
553
-			$path = substr($path, 0, $pos);
554
-		}
555
-
556
-		return $path;
557
-	}
558
-
559
-	/**
560
-	 * Check if the module is ready to be used by that specific user.
561
-	 * In case a module is not ready - because e.g. key pairs have not been generated
562
-	 * upon login this method can return false before any operation starts and might
563
-	 * cause issues during operations.
564
-	 *
565
-	 * @param string $user
566
-	 * @return boolean
567
-	 * @since 9.1.0
568
-	 */
569
-	public function isReadyForUser($user) {
570
-		return $this->keyManager->userHasKeys($user);
571
-	}
572
-
573
-	/**
574
-	 * We only need a detailed access list if the master key is not enabled
575
-	 *
576
-	 * @return bool
577
-	 */
578
-	public function needDetailedAccessList() {
579
-		return !$this->util->isMasterKeyEnabled();
580
-	}
46
+    const ID = 'OC_DEFAULT_MODULE';
47
+    const DISPLAY_NAME = 'Default encryption module';
48
+
49
+    /**
50
+     * @var Crypt
51
+     */
52
+    private $crypt;
53
+
54
+    /** @var string */
55
+    private $cipher;
56
+
57
+    /** @var string */
58
+    private $path;
59
+
60
+    /** @var string */
61
+    private $user;
62
+
63
+    /** @var string */
64
+    private $fileKey;
65
+
66
+    /** @var string */
67
+    private $writeCache;
68
+
69
+    /** @var KeyManager */
70
+    private $keyManager;
71
+
72
+    /** @var array */
73
+    private $accessList;
74
+
75
+    /** @var boolean */
76
+    private $isWriteOperation;
77
+
78
+    /** @var Util */
79
+    private $util;
80
+
81
+    /** @var  Session */
82
+    private $session;
83
+
84
+    /** @var  ILogger */
85
+    private $logger;
86
+
87
+    /** @var IL10N */
88
+    private $l;
89
+
90
+    /** @var EncryptAll */
91
+    private $encryptAll;
92
+
93
+    /** @var  bool */
94
+    private $useMasterPassword;
95
+
96
+    /** @var DecryptAll  */
97
+    private $decryptAll;
98
+
99
+    /** @var int unencrypted block size if block contains signature */
100
+    private $unencryptedBlockSizeSigned = 6072;
101
+
102
+    /** @var int unencrypted block size */
103
+    private $unencryptedBlockSize = 6126;
104
+
105
+    /** @var int Current version of the file */
106
+    private $version = 0;
107
+
108
+    /** @var array remember encryption signature version */
109
+    private static $rememberVersion = [];
110
+
111
+
112
+    /**
113
+     *
114
+     * @param Crypt $crypt
115
+     * @param KeyManager $keyManager
116
+     * @param Util $util
117
+     * @param Session $session
118
+     * @param EncryptAll $encryptAll
119
+     * @param DecryptAll $decryptAll
120
+     * @param ILogger $logger
121
+     * @param IL10N $il10n
122
+     */
123
+    public function __construct(Crypt $crypt,
124
+                                KeyManager $keyManager,
125
+                                Util $util,
126
+                                Session $session,
127
+                                EncryptAll $encryptAll,
128
+                                DecryptAll $decryptAll,
129
+                                ILogger $logger,
130
+                                IL10N $il10n) {
131
+        $this->crypt = $crypt;
132
+        $this->keyManager = $keyManager;
133
+        $this->util = $util;
134
+        $this->session = $session;
135
+        $this->encryptAll = $encryptAll;
136
+        $this->decryptAll = $decryptAll;
137
+        $this->logger = $logger;
138
+        $this->l = $il10n;
139
+        $this->useMasterPassword = $util->isMasterKeyEnabled();
140
+    }
141
+
142
+    /**
143
+     * @return string defining the technical unique id
144
+     */
145
+    public function getId() {
146
+        return self::ID;
147
+    }
148
+
149
+    /**
150
+     * In comparison to getKey() this function returns a human readable (maybe translated) name
151
+     *
152
+     * @return string
153
+     */
154
+    public function getDisplayName() {
155
+        return self::DISPLAY_NAME;
156
+    }
157
+
158
+    /**
159
+     * start receiving chunks from a file. This is the place where you can
160
+     * perform some initial step before starting encrypting/decrypting the
161
+     * chunks
162
+     *
163
+     * @param string $path to the file
164
+     * @param string $user who read/write the file
165
+     * @param string $mode php stream open mode
166
+     * @param array $header contains the header data read from the file
167
+     * @param array $accessList who has access to the file contains the key 'users' and 'public'
168
+     *
169
+     * @return array $header contain data as key-value pairs which should be
170
+     *                       written to the header, in case of a write operation
171
+     *                       or if no additional data is needed return a empty array
172
+     */
173
+    public function begin($path, $user, $mode, array $header, array $accessList) {
174
+        $this->path = $this->getPathToRealFile($path);
175
+        $this->accessList = $accessList;
176
+        $this->user = $user;
177
+        $this->isWriteOperation = false;
178
+        $this->writeCache = '';
179
+
180
+        if($this->session->isReady() === false) {
181
+            // if the master key is enabled we can initialize encryption
182
+            // with a empty password and user name
183
+            if ($this->util->isMasterKeyEnabled()) {
184
+                $this->keyManager->init('', '');
185
+            }
186
+        }
187
+
188
+        if ($this->session->decryptAllModeActivated()) {
189
+            $encryptedFileKey = $this->keyManager->getEncryptedFileKey($this->path);
190
+            $shareKey = $this->keyManager->getShareKey($this->path, $this->session->getDecryptAllUid());
191
+            $this->fileKey = $this->crypt->multiKeyDecrypt($encryptedFileKey,
192
+                $shareKey,
193
+                $this->session->getDecryptAllKey());
194
+        } else {
195
+            $this->fileKey = $this->keyManager->getFileKey($this->path, $this->user);
196
+        }
197
+
198
+        // always use the version from the original file, also part files
199
+        // need to have a correct version number if they get moved over to the
200
+        // final location
201
+        $this->version = (int)$this->keyManager->getVersion($this->stripPartFileExtension($path), new View());
202
+
203
+        if (
204
+            $mode === 'w'
205
+            || $mode === 'w+'
206
+            || $mode === 'wb'
207
+            || $mode === 'wb+'
208
+        ) {
209
+            $this->isWriteOperation = true;
210
+            if (empty($this->fileKey)) {
211
+                $this->fileKey = $this->crypt->generateFileKey();
212
+            }
213
+        } else {
214
+            // if we read a part file we need to increase the version by 1
215
+            // because the version number was also increased by writing
216
+            // the part file
217
+            if(Scanner::isPartialFile($path)) {
218
+                $this->version = $this->version + 1;
219
+            }
220
+        }
221
+
222
+        if ($this->isWriteOperation) {
223
+            $this->cipher = $this->crypt->getCipher();
224
+        } elseif (isset($header['cipher'])) {
225
+            $this->cipher = $header['cipher'];
226
+        } else {
227
+            // if we read a file without a header we fall-back to the legacy cipher
228
+            // which was used in <=oC6
229
+            $this->cipher = $this->crypt->getLegacyCipher();
230
+        }
231
+
232
+        return array('cipher' => $this->cipher, 'signed' => 'true');
233
+    }
234
+
235
+    /**
236
+     * last chunk received. This is the place where you can perform some final
237
+     * operation and return some remaining data if something is left in your
238
+     * buffer.
239
+     *
240
+     * @param string $path to the file
241
+     * @param int $position
242
+     * @return string remained data which should be written to the file in case
243
+     *                of a write operation
244
+     * @throws PublicKeyMissingException
245
+     * @throws \Exception
246
+     * @throws \OCA\Encryption\Exceptions\MultiKeyEncryptException
247
+     */
248
+    public function end($path, $position = 0) {
249
+        $result = '';
250
+        if ($this->isWriteOperation) {
251
+            $this->keyManager->setVersion($path, $this->version + 1, new View());
252
+            // in case of a part file we remember the new signature versions
253
+            // the version will be set later on update.
254
+            // This way we make sure that other apps listening to the pre-hooks
255
+            // still get the old version which should be the correct value for them
256
+            if (Scanner::isPartialFile($path)) {
257
+                self::$rememberVersion[$this->stripPartFileExtension($path)] = $this->version + 1;
258
+            }
259
+            if (!empty($this->writeCache)) {
260
+                $result = $this->crypt->symmetricEncryptFileContent($this->writeCache, $this->fileKey, $this->version + 1, $position);
261
+                $this->writeCache = '';
262
+            }
263
+            $publicKeys = array();
264
+            if ($this->useMasterPassword === true) {
265
+                $publicKeys[$this->keyManager->getMasterKeyId()] = $this->keyManager->getPublicMasterKey();
266
+            } else {
267
+                foreach ($this->accessList['users'] as $uid) {
268
+                    try {
269
+                        $publicKeys[$uid] = $this->keyManager->getPublicKey($uid);
270
+                    } catch (PublicKeyMissingException $e) {
271
+                        $this->logger->warning(
272
+                            'no public key found for user "{uid}", user will not be able to read the file',
273
+                            ['app' => 'encryption', 'uid' => $uid]
274
+                        );
275
+                        // if the public key of the owner is missing we should fail
276
+                        if ($uid === $this->user) {
277
+                            throw $e;
278
+                        }
279
+                    }
280
+                }
281
+            }
282
+
283
+            $publicKeys = $this->keyManager->addSystemKeys($this->accessList, $publicKeys, $this->user);
284
+            $encryptedKeyfiles = $this->crypt->multiKeyEncrypt($this->fileKey, $publicKeys);
285
+            $this->keyManager->setAllFileKeys($this->path, $encryptedKeyfiles);
286
+        }
287
+        return $result;
288
+    }
289
+
290
+    /**
291
+     * encrypt data
292
+     *
293
+     * @param string $data you want to encrypt
294
+     * @param int $position
295
+     * @return string encrypted data
296
+     */
297
+    public function encrypt($data, $position = 0) {
298
+        // If extra data is left over from the last round, make sure it
299
+        // is integrated into the next block
300
+        if ($this->writeCache) {
301
+
302
+            // Concat writeCache to start of $data
303
+            $data = $this->writeCache . $data;
304
+
305
+            // Clear the write cache, ready for reuse - it has been
306
+            // flushed and its old contents processed
307
+            $this->writeCache = '';
308
+
309
+        }
310
+
311
+        $encrypted = '';
312
+        // While there still remains some data to be processed & written
313
+        while (strlen($data) > 0) {
314
+
315
+            // Remaining length for this iteration, not of the
316
+            // entire file (may be greater than 8192 bytes)
317
+            $remainingLength = strlen($data);
318
+
319
+            // If data remaining to be written is less than the
320
+            // size of 1 6126 byte block
321
+            if ($remainingLength < $this->unencryptedBlockSizeSigned) {
322
+
323
+                // Set writeCache to contents of $data
324
+                // The writeCache will be carried over to the
325
+                // next write round, and added to the start of
326
+                // $data to ensure that written blocks are
327
+                // always the correct length. If there is still
328
+                // data in writeCache after the writing round
329
+                // has finished, then the data will be written
330
+                // to disk by $this->flush().
331
+                $this->writeCache = $data;
332
+
333
+                // Clear $data ready for next round
334
+                $data = '';
335
+
336
+            } else {
337
+
338
+                // Read the chunk from the start of $data
339
+                $chunk = substr($data, 0, $this->unencryptedBlockSizeSigned);
340
+
341
+                $encrypted .= $this->crypt->symmetricEncryptFileContent($chunk, $this->fileKey, $this->version + 1, $position);
342
+
343
+                // Remove the chunk we just processed from
344
+                // $data, leaving only unprocessed data in $data
345
+                // var, for handling on the next round
346
+                $data = substr($data, $this->unencryptedBlockSizeSigned);
347
+
348
+            }
349
+
350
+        }
351
+
352
+        return $encrypted;
353
+    }
354
+
355
+    /**
356
+     * decrypt data
357
+     *
358
+     * @param string $data you want to decrypt
359
+     * @param int $position
360
+     * @return string decrypted data
361
+     * @throws DecryptionFailedException
362
+     */
363
+    public function decrypt($data, $position = 0) {
364
+        if (empty($this->fileKey)) {
365
+            $msg = 'Can not decrypt this file, probably this is a shared file. Please ask the file owner to reshare the file with you.';
366
+            $hint = $this->l->t('Can not decrypt this file, probably this is a shared file. Please ask the file owner to reshare the file with you.');
367
+            $this->logger->error($msg);
368
+
369
+            throw new DecryptionFailedException($msg, $hint);
370
+        }
371
+
372
+        return $this->crypt->symmetricDecryptFileContent($data, $this->fileKey, $this->cipher, $this->version, $position);
373
+    }
374
+
375
+    /**
376
+     * update encrypted file, e.g. give additional users access to the file
377
+     *
378
+     * @param string $path path to the file which should be updated
379
+     * @param string $uid of the user who performs the operation
380
+     * @param array $accessList who has access to the file contains the key 'users' and 'public'
381
+     * @return boolean
382
+     */
383
+    public function update($path, $uid, array $accessList) {
384
+
385
+        if (empty($accessList)) {
386
+            if (isset(self::$rememberVersion[$path])) {
387
+                $this->keyManager->setVersion($path, self::$rememberVersion[$path], new View());
388
+                unset(self::$rememberVersion[$path]);
389
+            }
390
+            return;
391
+        }
392
+
393
+        $fileKey = $this->keyManager->getFileKey($path, $uid);
394
+
395
+        if (!empty($fileKey)) {
396
+
397
+            $publicKeys = array();
398
+            if ($this->useMasterPassword === true) {
399
+                $publicKeys[$this->keyManager->getMasterKeyId()] = $this->keyManager->getPublicMasterKey();
400
+            } else {
401
+                foreach ($accessList['users'] as $user) {
402
+                    try {
403
+                        $publicKeys[$user] = $this->keyManager->getPublicKey($user);
404
+                    } catch (PublicKeyMissingException $e) {
405
+                        $this->logger->warning('Could not encrypt file for ' . $user . ': ' . $e->getMessage());
406
+                    }
407
+                }
408
+            }
409
+
410
+            $publicKeys = $this->keyManager->addSystemKeys($accessList, $publicKeys, $uid);
411
+
412
+            $encryptedFileKey = $this->crypt->multiKeyEncrypt($fileKey, $publicKeys);
413
+
414
+            $this->keyManager->deleteAllFileKeys($path);
415
+
416
+            $this->keyManager->setAllFileKeys($path, $encryptedFileKey);
417
+
418
+        } else {
419
+            $this->logger->debug('no file key found, we assume that the file "{file}" is not encrypted',
420
+                array('file' => $path, 'app' => 'encryption'));
421
+
422
+            return false;
423
+        }
424
+
425
+        return true;
426
+    }
427
+
428
+    /**
429
+     * should the file be encrypted or not
430
+     *
431
+     * @param string $path
432
+     * @return boolean
433
+     */
434
+    public function shouldEncrypt($path) {
435
+        if ($this->util->shouldEncryptHomeStorage() === false) {
436
+            $storage = $this->util->getStorage($path);
437
+            if ($storage->instanceOfStorage('\OCP\Files\IHomeStorage')) {
438
+                return false;
439
+            }
440
+        }
441
+        $parts = explode('/', $path);
442
+        if (count($parts) < 4) {
443
+            return false;
444
+        }
445
+
446
+        if ($parts[2] == 'files') {
447
+            return true;
448
+        }
449
+        if ($parts[2] == 'files_versions') {
450
+            return true;
451
+        }
452
+        if ($parts[2] == 'files_trashbin') {
453
+            return true;
454
+        }
455
+
456
+        return false;
457
+    }
458
+
459
+    /**
460
+     * get size of the unencrypted payload per block.
461
+     * Nextcloud read/write files with a block size of 8192 byte
462
+     *
463
+     * @param bool $signed
464
+     * @return int
465
+     */
466
+    public function getUnencryptedBlockSize($signed = false) {
467
+        if ($signed === false) {
468
+            return $this->unencryptedBlockSize;
469
+        }
470
+
471
+        return $this->unencryptedBlockSizeSigned;
472
+    }
473
+
474
+    /**
475
+     * check if the encryption module is able to read the file,
476
+     * e.g. if all encryption keys exists
477
+     *
478
+     * @param string $path
479
+     * @param string $uid user for whom we want to check if he can read the file
480
+     * @return bool
481
+     * @throws DecryptionFailedException
482
+     */
483
+    public function isReadable($path, $uid) {
484
+        $fileKey = $this->keyManager->getFileKey($path, $uid);
485
+        if (empty($fileKey)) {
486
+            $owner = $this->util->getOwner($path);
487
+            if ($owner !== $uid) {
488
+                // if it is a shared file we throw a exception with a useful
489
+                // error message because in this case it means that the file was
490
+                // shared with the user at a point where the user didn't had a
491
+                // valid private/public key
492
+                $msg = 'Encryption module "' . $this->getDisplayName() .
493
+                    '" is not able to read ' . $path;
494
+                $hint = $this->l->t('Can not read this file, probably this is a shared file. Please ask the file owner to reshare the file with you.');
495
+                $this->logger->warning($msg);
496
+                throw new DecryptionFailedException($msg, $hint);
497
+            }
498
+            return false;
499
+        }
500
+
501
+        return true;
502
+    }
503
+
504
+    /**
505
+     * Initial encryption of all files
506
+     *
507
+     * @param InputInterface $input
508
+     * @param OutputInterface $output write some status information to the terminal during encryption
509
+     */
510
+    public function encryptAll(InputInterface $input, OutputInterface $output) {
511
+        $this->encryptAll->encryptAll($input, $output);
512
+    }
513
+
514
+    /**
515
+     * prepare module to perform decrypt all operation
516
+     *
517
+     * @param InputInterface $input
518
+     * @param OutputInterface $output
519
+     * @param string $user
520
+     * @return bool
521
+     */
522
+    public function prepareDecryptAll(InputInterface $input, OutputInterface $output, $user = '') {
523
+        return $this->decryptAll->prepare($input, $output, $user);
524
+    }
525
+
526
+
527
+    /**
528
+     * @param string $path
529
+     * @return string
530
+     */
531
+    protected function getPathToRealFile($path) {
532
+        $realPath = $path;
533
+        $parts = explode('/', $path);
534
+        if ($parts[2] === 'files_versions') {
535
+            $realPath = '/' . $parts[1] . '/files/' . implode('/', array_slice($parts, 3));
536
+            $length = strrpos($realPath, '.');
537
+            $realPath = substr($realPath, 0, $length);
538
+        }
539
+
540
+        return $realPath;
541
+    }
542
+
543
+    /**
544
+     * remove .part file extension and the ocTransferId from the file to get the
545
+     * original file name
546
+     *
547
+     * @param string $path
548
+     * @return string
549
+     */
550
+    protected function stripPartFileExtension($path) {
551
+        if (pathinfo($path, PATHINFO_EXTENSION) === 'part') {
552
+            $pos = strrpos($path, '.', -6);
553
+            $path = substr($path, 0, $pos);
554
+        }
555
+
556
+        return $path;
557
+    }
558
+
559
+    /**
560
+     * Check if the module is ready to be used by that specific user.
561
+     * In case a module is not ready - because e.g. key pairs have not been generated
562
+     * upon login this method can return false before any operation starts and might
563
+     * cause issues during operations.
564
+     *
565
+     * @param string $user
566
+     * @return boolean
567
+     * @since 9.1.0
568
+     */
569
+    public function isReadyForUser($user) {
570
+        return $this->keyManager->userHasKeys($user);
571
+    }
572
+
573
+    /**
574
+     * We only need a detailed access list if the master key is not enabled
575
+     *
576
+     * @return bool
577
+     */
578
+    public function needDetailedAccessList() {
579
+        return !$this->util->isMasterKeyEnabled();
580
+    }
581 581
 }
Please login to merge, or discard this patch.
apps/encryption/lib/Migration/SetMasterKeyStatus.php 1 patch
Indentation   +32 added lines, -32 removed lines patch added patch discarded remove patch
@@ -35,43 +35,43 @@
 block discarded – undo
35 35
 class SetMasterKeyStatus implements IRepairStep {
36 36
 
37 37
 
38
-	/** @var  IConfig */
39
-	private $config;
38
+    /** @var  IConfig */
39
+    private $config;
40 40
 
41 41
 
42
-	public function __construct(IConfig $config) {
43
-		$this->config = $config;
44
-	}
42
+    public function __construct(IConfig $config) {
43
+        $this->config = $config;
44
+    }
45 45
 
46
-	/**
47
-	 * Returns the step's name
48
-	 *
49
-	 * @return string
50
-	 * @since 9.1.0
51
-	 */
52
-	public function getName() {
53
-		return 'Write default encryption module configuration to the database';
54
-	}
46
+    /**
47
+     * Returns the step's name
48
+     *
49
+     * @return string
50
+     * @since 9.1.0
51
+     */
52
+    public function getName() {
53
+        return 'Write default encryption module configuration to the database';
54
+    }
55 55
 
56
-	/**
57
-	 * @param IOutput $output
58
-	 */
59
-	public function run(IOutput $output) {
60
-		if (!$this->shouldRun()) {
61
-			return;
62
-		}
56
+    /**
57
+     * @param IOutput $output
58
+     */
59
+    public function run(IOutput $output) {
60
+        if (!$this->shouldRun()) {
61
+            return;
62
+        }
63 63
 
64
-		// if no config for the master key is set we set it explicitly to '0' in
65
-		// order not to break old installations because the default changed to '1'.
66
-		$configAlreadySet = $this->config->getAppValue('encryption', 'useMasterKey', false);
67
-		if ($configAlreadySet === false) {
68
-			$this->config->setAppValue('encryption', 'useMasterKey', '0');
69
-		}
70
-	}
64
+        // if no config for the master key is set we set it explicitly to '0' in
65
+        // order not to break old installations because the default changed to '1'.
66
+        $configAlreadySet = $this->config->getAppValue('encryption', 'useMasterKey', false);
67
+        if ($configAlreadySet === false) {
68
+            $this->config->setAppValue('encryption', 'useMasterKey', '0');
69
+        }
70
+    }
71 71
 
72
-	protected function shouldRun() {
73
-		$appVersion = $this->config->getAppValue('encryption', 'installed_version', '0.0.0');
74
-		return version_compare($appVersion, '2.0.0', '<');
75
-	}
72
+    protected function shouldRun() {
73
+        $appVersion = $this->config->getAppValue('encryption', 'installed_version', '0.0.0');
74
+        return version_compare($appVersion, '2.0.0', '<');
75
+    }
76 76
 
77 77
 }
Please login to merge, or discard this patch.
apps/encryption/lib/Controller/StatusController.php 2 patches
Indentation   +68 added lines, -68 removed lines patch added patch discarded remove patch
@@ -34,79 +34,79 @@
 block discarded – undo
34 34
 
35 35
 class StatusController extends Controller {
36 36
 
37
-	/** @var IL10N */
38
-	private $l;
37
+    /** @var IL10N */
38
+    private $l;
39 39
 
40
-	/** @var Session */
41
-	private $session;
40
+    /** @var Session */
41
+    private $session;
42 42
 
43
-	/** @var IManager */
44
-	private $encryptionManager;
43
+    /** @var IManager */
44
+    private $encryptionManager;
45 45
 
46
-	/**
47
-	 * @param string $AppName
48
-	 * @param IRequest $request
49
-	 * @param IL10N $l10n
50
-	 * @param Session $session
51
-	 * @param IManager $encryptionManager
52
-	 */
53
-	public function __construct($AppName,
54
-								IRequest $request,
55
-								IL10N $l10n,
56
-								Session $session,
57
-								IManager $encryptionManager
58
-								) {
59
-		parent::__construct($AppName, $request);
60
-		$this->l = $l10n;
61
-		$this->session = $session;
62
-		$this->encryptionManager = $encryptionManager;
63
-	}
46
+    /**
47
+     * @param string $AppName
48
+     * @param IRequest $request
49
+     * @param IL10N $l10n
50
+     * @param Session $session
51
+     * @param IManager $encryptionManager
52
+     */
53
+    public function __construct($AppName,
54
+                                IRequest $request,
55
+                                IL10N $l10n,
56
+                                Session $session,
57
+                                IManager $encryptionManager
58
+                                ) {
59
+        parent::__construct($AppName, $request);
60
+        $this->l = $l10n;
61
+        $this->session = $session;
62
+        $this->encryptionManager = $encryptionManager;
63
+    }
64 64
 
65
-	/**
66
-	 * @NoAdminRequired
67
-	 * @return DataResponse
68
-	 */
69
-	public function getStatus() {
65
+    /**
66
+     * @NoAdminRequired
67
+     * @return DataResponse
68
+     */
69
+    public function getStatus() {
70 70
 
71
-		$status = 'error';
72
-		$message = 'no valid init status';
73
-		switch( $this->session->getStatus()) {
74
-			case Session::RUN_MIGRATION:
75
-				$status = 'interactionNeeded';
76
-				$message = (string)$this->l->t(
77
-					'You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one. Please run \'occ encryption:migrate\' or contact your administrator'
78
-				);
79
-				break;
80
-			case Session::INIT_EXECUTED:
81
-				$status = 'interactionNeeded';
82
-				$message = (string)$this->l->t(
83
-					'Invalid private key for encryption app. Please update your private key password in your personal settings to recover access to your encrypted files.'
84
-				);
85
-				break;
86
-			case Session::NOT_INITIALIZED:
87
-				$status = 'interactionNeeded';
88
-				if ($this->encryptionManager->isEnabled()) {
89
-					$message = (string)$this->l->t(
90
-						'Encryption App is enabled, but your keys are not initialized. Please log-out and log-in again.'
91
-					);
92
-				} else {
93
-					$message = (string)$this->l->t(
94
-						'Please enable server side encryption in the admin settings in order to use the encryption module.'
95
-					);
96
-				}
97
-				break;
98
-			case Session::INIT_SUCCESSFUL:
99
-				$status = 'success';
100
-				$message = (string)$this->l->t('Encryption app is enabled and ready');
101
-		}
71
+        $status = 'error';
72
+        $message = 'no valid init status';
73
+        switch( $this->session->getStatus()) {
74
+            case Session::RUN_MIGRATION:
75
+                $status = 'interactionNeeded';
76
+                $message = (string)$this->l->t(
77
+                    'You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one. Please run \'occ encryption:migrate\' or contact your administrator'
78
+                );
79
+                break;
80
+            case Session::INIT_EXECUTED:
81
+                $status = 'interactionNeeded';
82
+                $message = (string)$this->l->t(
83
+                    'Invalid private key for encryption app. Please update your private key password in your personal settings to recover access to your encrypted files.'
84
+                );
85
+                break;
86
+            case Session::NOT_INITIALIZED:
87
+                $status = 'interactionNeeded';
88
+                if ($this->encryptionManager->isEnabled()) {
89
+                    $message = (string)$this->l->t(
90
+                        'Encryption App is enabled, but your keys are not initialized. Please log-out and log-in again.'
91
+                    );
92
+                } else {
93
+                    $message = (string)$this->l->t(
94
+                        'Please enable server side encryption in the admin settings in order to use the encryption module.'
95
+                    );
96
+                }
97
+                break;
98
+            case Session::INIT_SUCCESSFUL:
99
+                $status = 'success';
100
+                $message = (string)$this->l->t('Encryption app is enabled and ready');
101
+        }
102 102
 
103
-		return new DataResponse(
104
-			[
105
-				'status' => $status,
106
-				'data' => [
107
-					'message' => $message]
108
-			]
109
-		);
110
-	}
103
+        return new DataResponse(
104
+            [
105
+                'status' => $status,
106
+                'data' => [
107
+                    'message' => $message]
108
+            ]
109
+        );
110
+    }
111 111
 
112 112
 }
Please login to merge, or discard this patch.
Spacing   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -70,34 +70,34 @@
 block discarded – undo
70 70
 
71 71
 		$status = 'error';
72 72
 		$message = 'no valid init status';
73
-		switch( $this->session->getStatus()) {
73
+		switch ($this->session->getStatus()) {
74 74
 			case Session::RUN_MIGRATION:
75 75
 				$status = 'interactionNeeded';
76
-				$message = (string)$this->l->t(
76
+				$message = (string) $this->l->t(
77 77
 					'You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one. Please run \'occ encryption:migrate\' or contact your administrator'
78 78
 				);
79 79
 				break;
80 80
 			case Session::INIT_EXECUTED:
81 81
 				$status = 'interactionNeeded';
82
-				$message = (string)$this->l->t(
82
+				$message = (string) $this->l->t(
83 83
 					'Invalid private key for encryption app. Please update your private key password in your personal settings to recover access to your encrypted files.'
84 84
 				);
85 85
 				break;
86 86
 			case Session::NOT_INITIALIZED:
87 87
 				$status = 'interactionNeeded';
88 88
 				if ($this->encryptionManager->isEnabled()) {
89
-					$message = (string)$this->l->t(
89
+					$message = (string) $this->l->t(
90 90
 						'Encryption App is enabled, but your keys are not initialized. Please log-out and log-in again.'
91 91
 					);
92 92
 				} else {
93
-					$message = (string)$this->l->t(
93
+					$message = (string) $this->l->t(
94 94
 						'Please enable server side encryption in the admin settings in order to use the encryption module.'
95 95
 					);
96 96
 				}
97 97
 				break;
98 98
 			case Session::INIT_SUCCESSFUL:
99 99
 				$status = 'success';
100
-				$message = (string)$this->l->t('Encryption app is enabled and ready');
100
+				$message = (string) $this->l->t('Encryption app is enabled and ready');
101 101
 		}
102 102
 
103 103
 		return new DataResponse(
Please login to merge, or discard this patch.
apps/encryption/lib/Command/DisableMasterKey.php 2 patches
Indentation   +52 added lines, -52 removed lines patch added patch discarded remove patch
@@ -33,57 +33,57 @@
 block discarded – undo
33 33
 
34 34
 class DisableMasterKey extends Command {
35 35
 
36
-	/** @var Util */
37
-	protected $util;
38
-
39
-	/** @var IConfig */
40
-	protected $config;
41
-
42
-	/** @var  QuestionHelper */
43
-	protected $questionHelper;
44
-
45
-	/**
46
-	 * @param Util $util
47
-	 * @param IConfig $config
48
-	 * @param QuestionHelper $questionHelper
49
-	 */
50
-	public function __construct(Util $util,
51
-								IConfig $config,
52
-								QuestionHelper $questionHelper) {
53
-
54
-		$this->util = $util;
55
-		$this->config = $config;
56
-		$this->questionHelper = $questionHelper;
57
-		parent::__construct();
58
-	}
59
-
60
-	protected function configure() {
61
-		$this
62
-			->setName('encryption:disable-master-key')
63
-			->setDescription('Disable the master key and use per-user keys instead. Only available for fresh installations with no existing encrypted data! There is no way to enable it again.');
64
-	}
65
-
66
-	protected function execute(InputInterface $input, OutputInterface $output) {
67
-
68
-		$isMasterKeyEnabled = $this->util->isMasterKeyEnabled();
69
-
70
-		if(!$isMasterKeyEnabled) {
71
-			$output->writeln('Master key already disabled');
72
-		} else {
73
-			$question = new ConfirmationQuestion(
74
-				'Warning: Only perform this operation for a fresh installations with no existing encrypted data! '
75
-				. 'There is no way to enable the master key again. '
76
-				. 'We strongly recommend to keep the master key, it provides significant performance improvements '
77
-				. 'and is easier to handle for both, users and administrators. '
78
-				. 'Do you really want to switch to per-user keys? (y/n) ', false);
79
-			if ($this->questionHelper->ask($input, $output, $question)) {
80
-				$this->config->setAppValue('encryption', 'useMasterKey', '0');
81
-				$output->writeln('Master key successfully disabled.');
82
-			} else {
83
-				$output->writeln('aborted.');
84
-			}
85
-		}
86
-
87
-	}
36
+    /** @var Util */
37
+    protected $util;
38
+
39
+    /** @var IConfig */
40
+    protected $config;
41
+
42
+    /** @var  QuestionHelper */
43
+    protected $questionHelper;
44
+
45
+    /**
46
+     * @param Util $util
47
+     * @param IConfig $config
48
+     * @param QuestionHelper $questionHelper
49
+     */
50
+    public function __construct(Util $util,
51
+                                IConfig $config,
52
+                                QuestionHelper $questionHelper) {
53
+
54
+        $this->util = $util;
55
+        $this->config = $config;
56
+        $this->questionHelper = $questionHelper;
57
+        parent::__construct();
58
+    }
59
+
60
+    protected function configure() {
61
+        $this
62
+            ->setName('encryption:disable-master-key')
63
+            ->setDescription('Disable the master key and use per-user keys instead. Only available for fresh installations with no existing encrypted data! There is no way to enable it again.');
64
+    }
65
+
66
+    protected function execute(InputInterface $input, OutputInterface $output) {
67
+
68
+        $isMasterKeyEnabled = $this->util->isMasterKeyEnabled();
69
+
70
+        if(!$isMasterKeyEnabled) {
71
+            $output->writeln('Master key already disabled');
72
+        } else {
73
+            $question = new ConfirmationQuestion(
74
+                'Warning: Only perform this operation for a fresh installations with no existing encrypted data! '
75
+                . 'There is no way to enable the master key again. '
76
+                . 'We strongly recommend to keep the master key, it provides significant performance improvements '
77
+                . 'and is easier to handle for both, users and administrators. '
78
+                . 'Do you really want to switch to per-user keys? (y/n) ', false);
79
+            if ($this->questionHelper->ask($input, $output, $question)) {
80
+                $this->config->setAppValue('encryption', 'useMasterKey', '0');
81
+                $output->writeln('Master key successfully disabled.');
82
+            } else {
83
+                $output->writeln('aborted.');
84
+            }
85
+        }
86
+
87
+    }
88 88
 
89 89
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -67,7 +67,7 @@
 block discarded – undo
67 67
 
68 68
 		$isMasterKeyEnabled = $this->util->isMasterKeyEnabled();
69 69
 
70
-		if(!$isMasterKeyEnabled) {
70
+		if (!$isMasterKeyEnabled) {
71 71
 			$output->writeln('Master key already disabled');
72 72
 		} else {
73 73
 			$question = new ConfirmationQuestion(
Please login to merge, or discard this patch.